Simplified QKeccakHash and added self-test function.
This commit is contained in:
parent
5f0c30797c
commit
316da47f10
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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!)
|
||||||
|
@ -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!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user