Most hash functions in use today are arguably MD5 and an older SHA, i.e. SHA-1, SHA-256, etc. (MD4, MD5 and SHA-1 are available in the Qt library via QCryptographicHash.)
However, these algorithms have quite a history and thus some security issues, especially MD5 can be considered broken – It’s frightening to see how many applications still use it. Developing new applications, It’s best to use one of the modern versions. They all have been tested for years by cryptography experts, and one of the five algorithms will become the new SHA-3.
The Hash Classes for Qt
My wrapper classes QBlakeHash, QGrostlHash, QJHHash, QKeccakHash and QSkeinHash all share an identical interface, so when you build your application, say with QSkeinHash, and you later want to switch to Grøstl, you just replace “QSkeinHash” with “QGrostlHash” in your code and that’s it. All algorithms provide 256 bit and 512 bit hashes, some even more (see below).
The interface is extremely easy, yet versatile.
First, you construct the object, then you pass the data that shall be hashed, then you call the “to(…)” functions to get the hash. As an example, we’ll use QGrostlHash for explanation of the API. (Note: In this section we don’t tell the class what hash length to calculate, so it defaults to 256 bit):
Hashing a string
QString hash = QGrostlHash("hello").toHexString();
This will calculate the grøstl-256 of “hello” and put the resulting hash in hex-representation into the string
If you wanted the hex-representation as QByteArray, you could also have called
toHex(). If you wanted the raw 32-byte (=256/8) QByteArray of the hash, call
Hashing a file
QGrostlHash gh; gh.file("/home/dermanu/sources.tar.gz"); QString hash = gh.toHexString();
This will successively load 8-kilobyte chunks from the file and progressively calculate the grostl-256 hash of the entire file. The result will be the same as loading the whole file to memory and calculating the hash at once, but will obviously consume far less memory.
file() function returns a bool value which indicates whether the hashing was successful or not. (If not, the file probably doesn’t exist or we don’t have read permissions.)
Hashing arbitrary data
QGrostlHash gh; gh.startBatch();
now you call as often as needed
and finally, you call
gh.stopBatch(); QString hash = gh.toHexString();
where data is a QByteArray or a
char*. In the latter case, you must pass the number of bytes to read from the char-array as second parameter.
This way, you can split up the possibly large chunk of data into smaller parts, allowing progressive hash calculation, for example when the data is being generated on-the-fly or being downloaded. Or of course, when you just want to keep memory consumption low, and maybe display a progress bar – It wouldn’t be smart to hash 16 gigabytes of data in one run.
That’s the gist of it.
Slightly more advanced usage
As mentioned in the introduction, the algorithms don’t only provide 256 bit hashes but at least also a 512 bit version. All three methods of generating a hash (On a string via constructor, on a file via
file(), on arbitrary data via
startBatch()) take an additional parameter
hashBits which is an enum of type
QGrostlHash::HashBits (in the Grøstl case). This enum contains the specific lengths the algorithm supports. These are:
So let’s calculate the skein-1024 of a file and get it as raw byte array:
QSkeinHash sh; sh.file("/home/dermanu/a_file", QSkeinHash::hb1024); QByteArray rawHash = sh.toRaw();
Since we’ve requested a hash of length 1024 bits, the byte array
rawHash will have a size of 128 bytes now.
Let’s calculate the Keccak-224 of the string “workslikeclockwork”, as a hex-string:
QString hash = QKeccakHash("workslikeclockwork", QKeccakHash::hb224).toHexString();
hash now has a length of 56. Why? Well we’ve calculated a hash of length 224 bits, those are 28 bytes. Since we’ve requested those 28 bytes to be transformed into a human-readable hexadecimal representation, and one byte (which can have 256 states) translates to two hexadecimal digits (each can have 16 states, so 16*16 is 256), we receive 28*2 = 56 hexadecimal digits, i.e. characters in the resulting string.
- Get the latest version of the hash classes you want from the download section at the bottom of this page.
- Use the q(…)hash.h and .cpp file like any other ordinary class file
- Make sure the (…)impl.cpp file is in the same directory as the .h/.cpp pair
For QtCreator users
- Right click on your project folder in the left sidebar, click the “Add existing file” (or similar) menu item. In the appearing file dialog, select the q(…)hash.h and .cpp file, to add them to your project
The file named (…)impl.cpp (e.g. grostlimpl.cpp) carries the actual implementation by the inventors of the respective algorithm, slightly modified by me to compile with C++ and the API. You don’t need to do anything with it, except make sure it’s in the same directory as the actual class files q(…)hash.h and q(…)hash.cpp (i.e. don’t build an object from it, q(…)hash.cpp includes it directly).
The packages also contain a small console application which demonstrates the usage of the class, in the example directory.
Blake hash class: qblakehash.tar.gz
Grøstl hash class: qgrostlhash.tar.gz
JH hash class qjhhash.tar.gz
Keccak hash class: qkeccakhash.tar.gz
Skein hash class: qskeinhash.tar.gz
Release date: 12.01.2012