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"
|
||||
|
||||
QKeccakHash::QKeccakHash() :
|
||||
mState(0),
|
||||
mHashBitLength(0)
|
||||
QKeccakHash::QKeccakHash()
|
||||
{
|
||||
}
|
||||
|
||||
QKeccakHash::QKeccakHash(const QString &asciiMessage, HashBits hashBits) :
|
||||
mState(0),
|
||||
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";
|
||||
}
|
||||
m_initialized = false;
|
||||
m_state = new KeccakImpl::hashState;
|
||||
memset(m_state, 0, sizeof(KeccakImpl::hashState));
|
||||
m_hashResult.clear();
|
||||
}
|
||||
|
||||
QKeccakHash::~QKeccakHash()
|
||||
{
|
||||
if (mState)
|
||||
delete mState;
|
||||
m_hashResult.clear();
|
||||
|
||||
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)
|
||||
return false;
|
||||
if (!setHashBitLength(hashBits))
|
||||
return false;
|
||||
QFile file(fileName);
|
||||
if (file.open(QFile::ReadOnly))
|
||||
{
|
||||
qint64 fileSize = file.size();
|
||||
qint64 readBytes = 0;
|
||||
if (!startBatch())
|
||||
return false;
|
||||
bool success = true;
|
||||
char *buffer = new char[blockSize];
|
||||
// repeatedly read blockSize bytes of the file to buffer and pass it to putBatch:
|
||||
while (file.error() == QFile::NoError)
|
||||
{
|
||||
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;
|
||||
if(!m_initialized)
|
||||
{
|
||||
qWarning("QKeccakHash has not been initialized yet!");
|
||||
m_hashResult.clear();
|
||||
return m_hashResult;
|
||||
}
|
||||
|
||||
if(KeccakImpl::Final(m_state, (KeccakImpl::BitSequence*)m_hashResult.data()) != KeccakImpl::SUCCESS)
|
||||
{
|
||||
qWarning("KeccakImpl::Final() has failed unexpectedly!");
|
||||
m_hashResult.clear();
|
||||
}
|
||||
|
||||
m_initialized = false;
|
||||
return m_hashResult;
|
||||
}
|
||||
|
||||
bool QKeccakHash::startBatch(HashBits hashBits)
|
||||
bool QKeccakHash::selfTest(void)
|
||||
{
|
||||
if (isBatchRunning())
|
||||
return false;
|
||||
if (!setHashBitLength(hashBits))
|
||||
return false;
|
||||
mState = new KeccakImpl::hashState;
|
||||
bool success = KeccakImpl::Init(mState, mHashBitLength) == KeccakImpl::SUCCESS;
|
||||
if (!success)
|
||||
{
|
||||
delete mState;
|
||||
mState = 0;
|
||||
mHashResult.clear();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
QKeccakHash hash;
|
||||
const QByteArray input("The quick brown fox jumps over the lazy dog");
|
||||
bool passed[4] = {false, false, false, false};
|
||||
|
||||
bool QKeccakHash::putBatch(const QByteArray &ba)
|
||||
{
|
||||
return putBatch(ba.constData(), ba.size());
|
||||
}
|
||||
if(hash.init(QKeccakHash::hb224))
|
||||
{
|
||||
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 (!isBatchRunning() || mHashBitLength == 0)
|
||||
return false;
|
||||
bool success = KeccakImpl::Update(mState, (KeccakImpl::BitSequence*)data, size*8) == KeccakImpl::SUCCESS;
|
||||
if (!success)
|
||||
{
|
||||
delete mState;
|
||||
mState = 0;
|
||||
mHashResult.clear();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
if(hash.init(QKeccakHash::hb256))
|
||||
{
|
||||
if(hash.addData(input))
|
||||
{
|
||||
QByteArray result = hash.finalize();
|
||||
if(!result.isEmpty())
|
||||
{
|
||||
passed[1] = (_stricmp(result.toHex().constData(), "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15") == 0);
|
||||
if(!passed[1]) qWarning("QKeccakHash self-test: Test #2 failed !!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QKeccakHash::stopBatch()
|
||||
{
|
||||
if (!isBatchRunning() || mHashBitLength == 0)
|
||||
return false;
|
||||
bool success = KeccakImpl::Final(mState, (KeccakImpl::BitSequence*)mHashResult.data()) == KeccakImpl::SUCCESS;
|
||||
delete mState;
|
||||
mState = 0;
|
||||
if (!success)
|
||||
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::isBatchRunning() const
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
if(hash.init(QKeccakHash::hb512))
|
||||
{
|
||||
if(hash.addData(input))
|
||||
{
|
||||
QByteArray result = hash.finalize();
|
||||
if(!result.isEmpty())
|
||||
{
|
||||
passed[3] = (_stricmp(result.toHex().constData(), "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609") == 0);
|
||||
if(!passed[3]) qWarning("QKeccakHash self-test: Test #4 failed !!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return (passed[0] && passed[1] && passed[2] && passed[3]);
|
||||
}
|
||||
|
||||
|
@ -33,55 +33,54 @@
|
||||
// Section from KeccakSponge.h
|
||||
// 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.
|
||||
namespace KeccakImpl {
|
||||
#define KeccakPermutationSize 1600
|
||||
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
|
||||
#define KeccakMaximumRate 1536
|
||||
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8)
|
||||
namespace KeccakImpl
|
||||
{
|
||||
#define KeccakPermutationSize 1600
|
||||
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
|
||||
#define KeccakMaximumRate 1536
|
||||
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8)
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ALIGN __attribute__ ((aligned(32)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define ALIGN __declspec(align(32))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define ALIGN __attribute__ ((aligned(32)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define ALIGN __declspec(align(32))
|
||||
#else
|
||||
#define ALIGN
|
||||
#endif
|
||||
|
||||
ALIGN typedef struct spongeStateStruct {
|
||||
ALIGN unsigned char state[KeccakPermutationSizeInBytes];
|
||||
ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes];
|
||||
unsigned int rate;
|
||||
unsigned int capacity;
|
||||
unsigned int bitsInQueue;
|
||||
unsigned int fixedOutputLength;
|
||||
int squeezing;
|
||||
unsigned int bitsAvailableForSqueezing;
|
||||
} spongeState;
|
||||
typedef spongeState hashState;
|
||||
ALIGN typedef struct spongeStateStruct {
|
||||
ALIGN unsigned char state[KeccakPermutationSizeInBytes];
|
||||
ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes];
|
||||
unsigned int rate;
|
||||
unsigned int capacity;
|
||||
unsigned int bitsInQueue;
|
||||
unsigned int fixedOutputLength;
|
||||
int squeezing;
|
||||
unsigned int bitsAvailableForSqueezing;
|
||||
} spongeState;
|
||||
typedef spongeState hashState;
|
||||
}
|
||||
// End Section from KeccakSponge.h
|
||||
|
||||
class QKeccakHash
|
||||
{
|
||||
public:
|
||||
enum HashBits {hb224, hb256, hb384, hb512};
|
||||
QKeccakHash();
|
||||
QKeccakHash(const QString &asciiMessage, HashBits hashBits=hb256);
|
||||
~QKeccakHash();
|
||||
QByteArray toRaw() const;
|
||||
QByteArray toHex() const;
|
||||
QString toHexString() const;
|
||||
bool file(const QString &fileName, HashBits hashBits=hb256, int blockSize=8388608); // 8 KiB default blockSize
|
||||
bool startBatch(HashBits hashBits=hb256);
|
||||
bool putBatch(const QByteArray &ba);
|
||||
bool putBatch(const char *data, int size);
|
||||
bool stopBatch();
|
||||
bool isBatchRunning() const;
|
||||
enum HashBits {hb224, hb256, hb384, hb512};
|
||||
|
||||
QKeccakHash();
|
||||
~QKeccakHash();
|
||||
|
||||
static bool selfTest(void);
|
||||
|
||||
bool init(HashBits hashBits=hb256);
|
||||
bool addData(const QByteArray &data);
|
||||
bool addData(const char *data, int size);
|
||||
const QByteArray &finalize();
|
||||
|
||||
protected:
|
||||
bool setHashBitLength(HashBits hashBits);
|
||||
KeccakImpl::hashState *mState;
|
||||
QByteArray mHashResult;
|
||||
int mHashBitLength;
|
||||
bool m_initialized;
|
||||
KeccakImpl::hashState *m_state;
|
||||
QByteArray m_hashResult;
|
||||
};
|
||||
|
||||
#endif // QKECCAKHASH_H
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define VER_LAMEXP_MINOR_LO 7
|
||||
#define VER_LAMEXP_TYPE Alpha
|
||||
#define VER_LAMEXP_PATCH 4
|
||||
#define VER_LAMEXP_BUILD 1197
|
||||
#define VER_LAMEXP_BUILD 1198
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Tool versions (minimum expected versions!)
|
||||
|
@ -63,22 +63,20 @@ static QByteArray fileHash(QFile &file)
|
||||
{
|
||||
QKeccakHash keccak;
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
QByteArray seed = QByteArray::fromHex(g_seed);
|
||||
QByteArray salt = QByteArray::fromHex(g_salt);
|
||||
const QByteArray data = file.readAll();
|
||||
const QByteArray seed = QByteArray::fromHex(g_seed);
|
||||
const QByteArray salt = QByteArray::fromHex(g_salt);
|
||||
|
||||
if(keccak.startBatch(QKeccakHash::hb384))
|
||||
if(keccak.init(QKeccakHash::hb384))
|
||||
{
|
||||
bool ok[3];
|
||||
ok[0] = keccak.putBatch(seed);
|
||||
ok[1] = keccak.putBatch(data);
|
||||
ok[2] = keccak.putBatch(salt);
|
||||
if(ok[0] && ok[1] && ok[2])
|
||||
bool ok = true;
|
||||
ok = ok && keccak.addData(seed);
|
||||
ok = ok && keccak.addData(data);
|
||||
ok = ok && keccak.addData(salt);
|
||||
if(ok)
|
||||
{
|
||||
if(keccak.stopBatch())
|
||||
{
|
||||
hash = keccak.toHex();
|
||||
}
|
||||
const QByteArray digest = keccak.finalize();
|
||||
if(!digest.isEmpty()) hash = digest.toHex();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -224,3 +222,11 @@ const QString &LockedFile::filePath()
|
||||
{
|
||||
return m_filePath;
|
||||
}
|
||||
|
||||
void LockedFile::selfTest()
|
||||
{
|
||||
if(!QKeccakHash::selfTest())
|
||||
{
|
||||
qFatal("QKeccakHash self-test has failed!");
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ public:
|
||||
|
||||
const QString &filePath();
|
||||
|
||||
static void selfTest();
|
||||
|
||||
private:
|
||||
QString m_filePath;
|
||||
void *m_fileHandle;
|
||||
|
@ -217,6 +217,7 @@ void InitializationThread::run()
|
||||
pool->setMaxThreadCount(idealThreadCount * 2);
|
||||
}
|
||||
|
||||
LockedFile::selfTest();
|
||||
ExtractorTask::clearFlags();
|
||||
|
||||
QTime timer;
|
||||
|
Loading…
Reference in New Issue
Block a user