[Solved] QCryptographicHash::hash() on QIODevice.read() and QCryptographicHash.addData(QIODevice).result() give different values
-
I want to generate an MD4 from a file. Reading a test file using the following two different approaches gives different results.
The result of the second approach is correct (as the third-party software that I want to emulate, aMule, shows).
The result of the first approach is incorrect.
I want to follow the first approach because, for files greater than the specified CHUNK_SIZE, I want to go on a loop and get MD4 hashes of each chunk.// Unexpected output. const qint64 CHUNK_SIZE = 9728000; char* data = new char[CHUNK_SIZE]; ioDevice.seek(0); ioDevice.read(data, CHUNK_SIZE); // Returns the expected size. QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md4); std::cout << "ioDevice.read() hash: " << hash.toHex().toStdString() << std::endl; // Expected output, aMule’s. ioDevice.seek(0); QCryptographicHash fileHash(QCryptographicHash::Md4); if (fileHash.addData(&ioDevice)) std::cout << "fileHash.addData() hash: " << fileHash.result().toHex().toStdString() << std::endl;
I’m obviously doing something wrong in the first approach. What is it?
Note: The code here assumes that the file fits CHUNK_SIZE, as this is just a test code to be used on a file that is much smaller than the specified CHUNK_SIZE.
-
Hi,
Your array contains uninitialized data and your read call won't necessarily fill it thus you will likely get different result for every call to that function. You are using more data that you read from the device.
Your second code sample will only read the content of the ioDevice nothing more.
Hope it helps
-
@SGaist Many thanks for your help.
The reported MD4 of both approaches stays the same on each call. Also, if I use strncpy() to copy the read data onto a new array that is only as big as the read data, I still get the same results:
const qint64 CHUNK_SIZE = 9728000; char* data = new char[CHUNK_SIZE]; ioDevice.seek(0); qint64 read_size = ioDevice.read(data, CHUNK_SIZE); char* actual_data = new char[read_size]; strncpy(actual_data, data, read_size); QByteArray hash = QCryptographicHash::hash(actual_data, QCryptographicHash::Md4); std::cout << "ioDevice.read() hash: " << hash.toHex().toStdString() << std::endl;
-
I’ve found out what my issue was. I was reading binary files, and char arrays end at null characters ('\0'), which binary files may have.
I found out that I can use a QByteArray all the way instead of an array of chars, resulting in a more readable that works regardless of the null characters in the binary file:
const qint64 CHUNK_SIZE = 9728000; ioDevice.seek(0); QByteArray data = ioDevice.read(CHUNK_SIZE); QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md4); std::cout << "ioDevice.read() hash: " << hash.toHex().toStdString() << std::endl;