Simplified QKeccakHash and added self-test function.

This commit is contained in:
LoRd_MuldeR 2012-11-27 01:02:55 +01:00
parent 5f0c30797c
commit 316da47f10
9 changed files with 193 additions and 200 deletions

View File

@ -28,173 +28,158 @@
#include "keccakimpl.cpp" #include "keccakimpl.cpp"
QKeccakHash::QKeccakHash() : QKeccakHash::QKeccakHash()
mState(0),
mHashBitLength(0)
{ {
} m_initialized = false;
m_state = new KeccakImpl::hashState;
QKeccakHash::QKeccakHash(const QString &asciiMessage, HashBits hashBits) : memset(m_state, 0, sizeof(KeccakImpl::hashState));
mState(0), m_hashResult.clear();
mHashBitLength(0)
{
if (!setHashBitLength(hashBits))
return;
bool success = false;
QByteArray msg = asciiMessage.toAscii();
mState = new KeccakImpl::hashState;
if (KeccakImpl::Init(mState, mHashBitLength) == KeccakImpl::SUCCESS)
{
if (KeccakImpl::Update(mState, (KeccakImpl::BitSequence*)msg.constData(), msg.size()*8) == KeccakImpl::SUCCESS)
{
if (KeccakImpl::Final(mState, (KeccakImpl::BitSequence*)mHashResult.data()) == KeccakImpl::SUCCESS)
success = true;
}
}
delete mState;
mState = 0;
if (!success)
{
mHashResult.clear();
qDebug() << "QKeccakHash::QKeccakHash(): hash construction failed";
}
} }
QKeccakHash::~QKeccakHash() QKeccakHash::~QKeccakHash()
{ {
if (mState) m_hashResult.clear();
delete mState;
if(m_state)
{
delete m_state;
m_state = NULL;
}
} }
QByteArray QKeccakHash::toRaw() const bool QKeccakHash::init(HashBits hashBits)
{ {
return mHashResult; if(m_initialized)
{
qWarning("QKeccakHash has already been initialized!");
return false;
}
m_hashResult.clear();
memset(m_state, 0, sizeof(KeccakImpl::hashState));
int hashBitLength = 0;
switch (hashBits)
{
case hb224: hashBitLength = 224; break;
case hb256: hashBitLength = 256; break;
case hb384: hashBitLength = 384; break;
case hb512: hashBitLength = 512; break;
default: throw "Invalid hash length!!";
}
if(KeccakImpl::Init(m_state, hashBitLength) != KeccakImpl::SUCCESS)
{
qWarning("KeccakImpl::Init() has failed unexpectedly!");
return false;
}
m_hashResult.fill(char(0), hashBitLength/8);
m_initialized = true;
return true;
} }
QByteArray QKeccakHash::toHex() const bool QKeccakHash::addData(const QByteArray &data)
{ {
return mHashResult.toHex(); return addData(data.constData(), data.size());
} }
QString QKeccakHash::toHexString() const bool QKeccakHash::addData(const char *data, int size)
{ {
return QString(mHashResult.toHex()); if(!m_initialized)
{
qWarning("QKeccakHash has not been initialized yet!");
return false;
}
if(KeccakImpl::Update(m_state, (KeccakImpl::BitSequence*)data, size*8) != KeccakImpl::SUCCESS)
{
qWarning("KeccakImpl::Update() has failed unexpectedly!");
m_hashResult.clear();
m_initialized = false;
return false;
}
return true;
} }
bool QKeccakHash::file(const QString &fileName, HashBits hashBits, int blockSize) const QByteArray &QKeccakHash::finalize()
{ {
if (isBatchRunning() || blockSize < 1) if(!m_initialized)
return false; {
if (!setHashBitLength(hashBits)) qWarning("QKeccakHash has not been initialized yet!");
return false; m_hashResult.clear();
QFile file(fileName); return m_hashResult;
if (file.open(QFile::ReadOnly)) }
{
qint64 fileSize = file.size(); if(KeccakImpl::Final(m_state, (KeccakImpl::BitSequence*)m_hashResult.data()) != KeccakImpl::SUCCESS)
qint64 readBytes = 0; {
if (!startBatch()) qWarning("KeccakImpl::Final() has failed unexpectedly!");
return false; m_hashResult.clear();
bool success = true; }
char *buffer = new char[blockSize];
// repeatedly read blockSize bytes of the file to buffer and pass it to putBatch: m_initialized = false;
while (file.error() == QFile::NoError) return m_hashResult;
{
readBytes = file.read(buffer, qMin(fileSize-file.pos(), (qint64)blockSize)); // read till end of file to buffer, but not more than blockSize bytes
if (readBytes > 0)
{
if (!putBatch(buffer, readBytes))
{
success = false;
break;
}
if (readBytes < blockSize) // that was the last block
break;
} else // error occured
{
success = false;
break;
}
}
delete buffer;
if (!stopBatch())
success = false;
return success;
} else
return false;
} }
bool QKeccakHash::startBatch(HashBits hashBits) bool QKeccakHash::selfTest(void)
{ {
if (isBatchRunning()) QKeccakHash hash;
return false; const QByteArray input("The quick brown fox jumps over the lazy dog");
if (!setHashBitLength(hashBits)) bool passed[4] = {false, false, false, false};
return false;
mState = new KeccakImpl::hashState;
bool success = KeccakImpl::Init(mState, mHashBitLength) == KeccakImpl::SUCCESS;
if (!success)
{
delete mState;
mState = 0;
mHashResult.clear();
}
return success;
}
bool QKeccakHash::putBatch(const QByteArray &ba) if(hash.init(QKeccakHash::hb224))
{ {
return putBatch(ba.constData(), ba.size()); if(hash.addData(input))
} {
QByteArray result = hash.finalize();
if(!result.isEmpty())
{
passed[0] = (_stricmp(result.toHex().constData(), "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe") == 0);
if(!passed[0]) qWarning("QKeccakHash self-test: Test #1 failed !!!");
}
}
}
bool QKeccakHash::putBatch(const char *data, int size) if(hash.init(QKeccakHash::hb256))
{ {
if (!isBatchRunning() || mHashBitLength == 0) if(hash.addData(input))
return false; {
bool success = KeccakImpl::Update(mState, (KeccakImpl::BitSequence*)data, size*8) == KeccakImpl::SUCCESS; QByteArray result = hash.finalize();
if (!success) if(!result.isEmpty())
{ {
delete mState; passed[1] = (_stricmp(result.toHex().constData(), "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15") == 0);
mState = 0; if(!passed[1]) qWarning("QKeccakHash self-test: Test #2 failed !!!");
mHashResult.clear(); }
} }
return success; }
}
if(hash.init(QKeccakHash::hb384))
{
if(hash.addData(input))
{
QByteArray result = hash.finalize();
if(!result.isEmpty())
{
passed[2] = (_stricmp(result.toHex().constData(), "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3") == 0);
if(!passed[2]) qWarning("QKeccakHash self-test: Test #3 failed !!!");
}
}
}
bool QKeccakHash::stopBatch() if(hash.init(QKeccakHash::hb512))
{ {
if (!isBatchRunning() || mHashBitLength == 0) if(hash.addData(input))
return false; {
bool success = KeccakImpl::Final(mState, (KeccakImpl::BitSequence*)mHashResult.data()) == KeccakImpl::SUCCESS; QByteArray result = hash.finalize();
delete mState; if(!result.isEmpty())
mState = 0; {
if (!success) passed[3] = (_stricmp(result.toHex().constData(), "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609") == 0);
mHashResult.clear(); if(!passed[3]) qWarning("QKeccakHash self-test: Test #4 failed !!!");
return success; }
} }
}
bool QKeccakHash::isBatchRunning() const return (passed[0] && passed[1] && passed[2] && passed[3]);
{
return mState;
} }
bool QKeccakHash::setHashBitLength(HashBits hashBits)
{
switch (hashBits)
{
case hb224: mHashBitLength = 224; break;
case hb256: mHashBitLength = 256; break;
case hb384: mHashBitLength = 384; break;
case hb512: mHashBitLength = 512; break;
default:
{
mHashBitLength = 0;
qDebug() << "QKeccakHash::setHashBitLength(): invalid hash bit value" << (int)hashBits << ", must be hb224, hb256, hb384 or hb512";
return false;
}
}
mHashResult.fill(0, mHashBitLength/8);
return true;
}

View File

@ -33,55 +33,54 @@
// Section from KeccakSponge.h // Section from KeccakSponge.h
// needed here, since hashState needs to be explicitly 32-byte aligned and therefore can't be // needed here, since hashState needs to be explicitly 32-byte aligned and therefore can't be
// transformed into a class (in order to forward declarate) like in the other hash wrappers. // transformed into a class (in order to forward declarate) like in the other hash wrappers.
namespace KeccakImpl { namespace KeccakImpl
#define KeccakPermutationSize 1600 {
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8) #define KeccakPermutationSize 1600
#define KeccakMaximumRate 1536 #define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8) #define KeccakMaximumRate 1536
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8)
#if defined(__GNUC__) #if defined(__GNUC__)
#define ALIGN __attribute__ ((aligned(32))) #define ALIGN __attribute__ ((aligned(32)))
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define ALIGN __declspec(align(32)) #define ALIGN __declspec(align(32))
#else #else
#define ALIGN #define ALIGN
#endif #endif
ALIGN typedef struct spongeStateStruct { ALIGN typedef struct spongeStateStruct {
ALIGN unsigned char state[KeccakPermutationSizeInBytes]; ALIGN unsigned char state[KeccakPermutationSizeInBytes];
ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes]; ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes];
unsigned int rate; unsigned int rate;
unsigned int capacity; unsigned int capacity;
unsigned int bitsInQueue; unsigned int bitsInQueue;
unsigned int fixedOutputLength; unsigned int fixedOutputLength;
int squeezing; int squeezing;
unsigned int bitsAvailableForSqueezing; unsigned int bitsAvailableForSqueezing;
} spongeState; } spongeState;
typedef spongeState hashState; typedef spongeState hashState;
} }
// End Section from KeccakSponge.h // End Section from KeccakSponge.h
class QKeccakHash class QKeccakHash
{ {
public: public:
enum HashBits {hb224, hb256, hb384, hb512}; enum HashBits {hb224, hb256, hb384, hb512};
QKeccakHash();
QKeccakHash(const QString &asciiMessage, HashBits hashBits=hb256); QKeccakHash();
~QKeccakHash(); ~QKeccakHash();
QByteArray toRaw() const;
QByteArray toHex() const; static bool selfTest(void);
QString toHexString() const;
bool file(const QString &fileName, HashBits hashBits=hb256, int blockSize=8388608); // 8 KiB default blockSize bool init(HashBits hashBits=hb256);
bool startBatch(HashBits hashBits=hb256); bool addData(const QByteArray &data);
bool putBatch(const QByteArray &ba); bool addData(const char *data, int size);
bool putBatch(const char *data, int size); const QByteArray &finalize();
bool stopBatch();
bool isBatchRunning() const;
protected: protected:
bool setHashBitLength(HashBits hashBits); bool m_initialized;
KeccakImpl::hashState *mState; KeccakImpl::hashState *m_state;
QByteArray mHashResult; QByteArray m_hashResult;
int mHashBitLength;
}; };
#endif // QKECCAKHASH_H #endif // QKECCAKHASH_H

View File

@ -30,7 +30,7 @@
#define VER_LAMEXP_MINOR_LO 7 #define VER_LAMEXP_MINOR_LO 7
#define VER_LAMEXP_TYPE Alpha #define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 4 #define VER_LAMEXP_PATCH 4
#define VER_LAMEXP_BUILD 1197 #define VER_LAMEXP_BUILD 1198
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Tool versions (minimum expected versions!) // Tool versions (minimum expected versions!)

View File

@ -63,22 +63,20 @@ static QByteArray fileHash(QFile &file)
{ {
QKeccakHash keccak; QKeccakHash keccak;
QByteArray data = file.readAll(); const QByteArray data = file.readAll();
QByteArray seed = QByteArray::fromHex(g_seed); const QByteArray seed = QByteArray::fromHex(g_seed);
QByteArray salt = QByteArray::fromHex(g_salt); const QByteArray salt = QByteArray::fromHex(g_salt);
if(keccak.startBatch(QKeccakHash::hb384)) if(keccak.init(QKeccakHash::hb384))
{ {
bool ok[3]; bool ok = true;
ok[0] = keccak.putBatch(seed); ok = ok && keccak.addData(seed);
ok[1] = keccak.putBatch(data); ok = ok && keccak.addData(data);
ok[2] = keccak.putBatch(salt); ok = ok && keccak.addData(salt);
if(ok[0] && ok[1] && ok[2]) if(ok)
{ {
if(keccak.stopBatch()) const QByteArray digest = keccak.finalize();
{ if(!digest.isEmpty()) hash = digest.toHex();
hash = keccak.toHex();
}
} }
} }
} }
@ -223,4 +221,12 @@ LockedFile::~LockedFile(void)
const QString &LockedFile::filePath() const QString &LockedFile::filePath()
{ {
return m_filePath; return m_filePath;
} }
void LockedFile::selfTest()
{
if(!QKeccakHash::selfTest())
{
qFatal("QKeccakHash self-test has failed!");
}
}

View File

@ -32,6 +32,8 @@ public:
const QString &filePath(); const QString &filePath();
static void selfTest();
private: private:
QString m_filePath; QString m_filePath;
void *m_fileHandle; void *m_fileHandle;

View File

@ -217,6 +217,7 @@ void InitializationThread::run()
pool->setMaxThreadCount(idealThreadCount * 2); pool->setMaxThreadCount(idealThreadCount * 2);
} }
LockedFile::selfTest();
ExtractorTask::clearFlags(); ExtractorTask::clearFlags();
QTime timer; QTime timer;