2017-01-27 12:05:45 +00:00
|
|
|
// iterhash.cpp - originally written and placed in the public domain by Wei Dai
|
2015-11-05 06:59:46 +00:00
|
|
|
|
|
|
|
#ifndef __GNUC__
|
|
|
|
#define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "iterhash.h"
|
|
|
|
#include "misc.h"
|
2017-05-25 10:26:43 +00:00
|
|
|
#include "cpu.h"
|
2015-11-05 06:59:46 +00:00
|
|
|
|
|
|
|
NAMESPACE_BEGIN(CryptoPP)
|
|
|
|
|
2018-05-06 02:56:15 +00:00
|
|
|
template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, size_t length)
|
2015-11-05 06:59:46 +00:00
|
|
|
{
|
2018-05-06 02:56:15 +00:00
|
|
|
CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0));
|
|
|
|
if (length == 0) { return; }
|
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
|
2018-05-06 02:56:15 +00:00
|
|
|
if ((m_countLo = oldCountLo + HashWordType(length)) < oldCountLo)
|
2015-11-05 06:59:46 +00:00
|
|
|
m_countHi++; // carry from low to high
|
2018-05-06 02:56:15 +00:00
|
|
|
m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(length);
|
|
|
|
if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(length) != 0)
|
2015-11-05 06:59:46 +00:00
|
|
|
throw HashInputTooLong(this->AlgorithmName());
|
|
|
|
|
2015-11-18 20:32:28 +00:00
|
|
|
const unsigned int blockSize = this->BlockSize();
|
2015-11-05 06:59:46 +00:00
|
|
|
unsigned int num = ModPowerOf2(oldCountLo, blockSize);
|
|
|
|
|
|
|
|
T* dataBuf = this->DataBuf();
|
|
|
|
byte* data = (byte *)dataBuf;
|
|
|
|
|
|
|
|
if (num != 0) // process left over data
|
|
|
|
{
|
2018-05-06 02:56:15 +00:00
|
|
|
if (num+length >= blockSize)
|
2015-11-05 06:59:46 +00:00
|
|
|
{
|
2018-07-20 22:56:41 +00:00
|
|
|
if (input)
|
2018-07-21 00:12:54 +00:00
|
|
|
{std::memcpy(data+num, input, blockSize-num);}
|
2018-07-20 22:56:41 +00:00
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
HashBlock(dataBuf);
|
|
|
|
input += (blockSize-num);
|
2018-05-06 02:56:15 +00:00
|
|
|
length -= (blockSize-num);
|
2015-11-05 06:59:46 +00:00
|
|
|
num = 0;
|
|
|
|
// drop through and do the rest
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-07-20 22:56:41 +00:00
|
|
|
if (input && length)
|
2018-07-21 00:12:54 +00:00
|
|
|
{std::memcpy(data+num, input, length);}
|
2015-11-05 06:59:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// now process the input data in blocks of blockSize bytes and save the leftovers to m_data
|
2018-05-06 02:56:15 +00:00
|
|
|
if (length >= blockSize)
|
2015-11-05 06:59:46 +00:00
|
|
|
{
|
|
|
|
if (input == data)
|
|
|
|
{
|
2018-05-06 02:56:15 +00:00
|
|
|
CRYPTOPP_ASSERT(length == blockSize);
|
2015-11-05 06:59:46 +00:00
|
|
|
HashBlock(dataBuf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (IsAligned<T>(input))
|
|
|
|
{
|
2018-05-06 02:56:15 +00:00
|
|
|
size_t leftOver = HashMultipleBlocks((T *)(void*)input, length);
|
|
|
|
input += (length - leftOver);
|
|
|
|
length = leftOver;
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
else
|
2018-07-20 22:56:41 +00:00
|
|
|
{
|
2015-11-05 06:59:46 +00:00
|
|
|
do
|
|
|
|
{ // copy input first if it's not aligned correctly
|
2018-07-20 22:56:41 +00:00
|
|
|
if (input)
|
2018-07-21 00:12:54 +00:00
|
|
|
{ std::memcpy(data, input, blockSize); }
|
2018-07-20 22:56:41 +00:00
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
HashBlock(dataBuf);
|
|
|
|
input+=blockSize;
|
2018-05-06 02:56:15 +00:00
|
|
|
length-=blockSize;
|
|
|
|
} while (length >= blockSize);
|
2018-07-20 22:56:41 +00:00
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
2018-07-20 22:56:41 +00:00
|
|
|
if (input && data != input)
|
2018-07-21 00:12:54 +00:00
|
|
|
std::memcpy(data, input, length);
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
|
|
|
|
{
|
|
|
|
unsigned int blockSize = this->BlockSize();
|
|
|
|
unsigned int num = ModPowerOf2(m_countLo, blockSize);
|
|
|
|
size = blockSize - num;
|
|
|
|
return (byte *)DataBuf() + num;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
|
|
|
|
{
|
2018-07-21 00:12:54 +00:00
|
|
|
const unsigned int blockSize = this->BlockSize();
|
2017-05-25 10:46:40 +00:00
|
|
|
bool noReverse = NativeByteOrderIs(this->GetByteOrder());
|
2015-11-05 06:59:46 +00:00
|
|
|
T* dataBuf = this->DataBuf();
|
2018-07-20 22:56:41 +00:00
|
|
|
|
|
|
|
// IteratedHashBase Update calls this with an aligned input,
|
|
|
|
// but HashBlock may call it with an unaligned buffer.
|
2018-07-21 00:12:54 +00:00
|
|
|
// Alignment checks due to Issues 690/
|
2018-07-20 22:56:41 +00:00
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (noReverse)
|
2018-07-20 22:56:41 +00:00
|
|
|
{
|
|
|
|
if (IsAligned<word64>(input))
|
2018-07-21 00:12:54 +00:00
|
|
|
{
|
2018-07-20 22:56:41 +00:00
|
|
|
this->HashEndianCorrectedBlock(input);
|
2018-07-21 00:12:54 +00:00
|
|
|
}
|
2018-07-20 22:56:41 +00:00
|
|
|
else
|
|
|
|
{
|
2018-07-21 00:28:07 +00:00
|
|
|
std::memcpy(dataBuf, input, blockSize);
|
2018-07-20 22:56:41 +00:00
|
|
|
this->HashEndianCorrectedBlock(dataBuf);
|
|
|
|
}
|
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
else
|
|
|
|
{
|
2018-07-21 00:12:54 +00:00
|
|
|
if (IsAligned<word64>(input))
|
|
|
|
{
|
2018-07-21 00:28:07 +00:00
|
|
|
ByteReverse(dataBuf, input, blockSize);
|
2018-07-21 00:12:54 +00:00
|
|
|
this->HashEndianCorrectedBlock(dataBuf);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-07-21 00:28:07 +00:00
|
|
|
std::memcpy(dataBuf, input, blockSize);
|
|
|
|
ByteReverse(dataBuf, dataBuf, blockSize);
|
2018-07-21 00:12:54 +00:00
|
|
|
this->HashEndianCorrectedBlock(dataBuf);
|
|
|
|
}
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
input += blockSize/sizeof(T);
|
|
|
|
length -= blockSize;
|
|
|
|
}
|
|
|
|
while (length >= blockSize);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
|
|
|
|
{
|
|
|
|
unsigned int blockSize = this->BlockSize();
|
|
|
|
unsigned int num = ModPowerOf2(m_countLo, blockSize);
|
|
|
|
T* dataBuf = this->DataBuf();
|
|
|
|
byte* data = (byte *)dataBuf;
|
2018-07-20 22:56:41 +00:00
|
|
|
|
2015-11-05 06:59:46 +00:00
|
|
|
data[num++] = padFirst;
|
|
|
|
if (num <= lastBlockSize)
|
|
|
|
memset(data+num, 0, lastBlockSize-num);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset(data+num, 0, blockSize-num);
|
|
|
|
HashBlock(dataBuf);
|
|
|
|
memset(data, 0, lastBlockSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
|
|
|
|
{
|
|
|
|
m_countLo = m_countHi = 0;
|
|
|
|
Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
|
|
|
|
{
|
2018-05-06 02:56:15 +00:00
|
|
|
CRYPTOPP_ASSERT(digest != NULLPTR);
|
2015-11-05 06:59:46 +00:00
|
|
|
this->ThrowIfInvalidTruncatedSize(size);
|
|
|
|
|
|
|
|
T* dataBuf = this->DataBuf();
|
|
|
|
T* stateBuf = this->StateBuf();
|
|
|
|
unsigned int blockSize = this->BlockSize();
|
|
|
|
ByteOrder order = this->GetByteOrder();
|
|
|
|
|
|
|
|
PadLastBlock(blockSize - 2*sizeof(HashWordType));
|
|
|
|
dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
|
|
|
|
dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
|
|
|
|
|
|
|
|
HashBlock(dataBuf);
|
|
|
|
|
|
|
|
if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
|
2016-01-25 03:27:05 +00:00
|
|
|
ConditionalByteReverse<HashWordType>(order, (HashWordType *)(void*)digest, stateBuf, size);
|
2015-11-05 06:59:46 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
|
2018-07-20 22:56:41 +00:00
|
|
|
std::memcpy(digest, stateBuf, size);
|
2015-11-05 06:59:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->Restart(); // reinit for next use
|
|
|
|
}
|
|
|
|
|
2017-07-17 16:10:38 +00:00
|
|
|
#if defined(__GNUC__) || defined(__clang__)
|
2015-11-05 06:59:46 +00:00
|
|
|
template class IteratedHashBase<word64, HashTransformation>;
|
|
|
|
template class IteratedHashBase<word64, MessageAuthenticationCode>;
|
|
|
|
|
|
|
|
template class IteratedHashBase<word32, HashTransformation>;
|
|
|
|
template class IteratedHashBase<word32, MessageAuthenticationCode>;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
NAMESPACE_END
|