libcryfs/vendor/cryptopp/vendor_cryptopp/iterhash.cpp

201 lines
5.5 KiB
C++
Raw Normal View History

2018-05-19 20:22:51 +02:00
// iterhash.cpp - originally written and placed in the public domain by Wei Dai
#ifndef __GNUC__
#define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
#endif
#include "iterhash.h"
#include "misc.h"
#include "cpu.h"
NAMESPACE_BEGIN(CryptoPP)
template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, size_t length)
2018-05-19 20:22:51 +02:00
{
CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0));
if (length == 0) { return; }
2018-05-19 20:22:51 +02:00
HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
if ((m_countLo = oldCountLo + HashWordType(length)) < oldCountLo)
2018-05-19 20:22:51 +02:00
m_countHi++; // carry from low to high
m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(length);
if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(length) != 0)
2018-05-19 20:22:51 +02:00
throw HashInputTooLong(this->AlgorithmName());
const unsigned int blockSize = this->BlockSize();
unsigned int num = ModPowerOf2(oldCountLo, blockSize);
T* dataBuf = this->DataBuf();
byte* data = (byte *)dataBuf;
if (num != 0) // process left over data
{
if (num+length >= blockSize)
2018-05-19 20:22:51 +02:00
{
if (input)
{std::memcpy(data+num, input, blockSize-num);}
2018-05-19 20:22:51 +02:00
HashBlock(dataBuf);
input += (blockSize-num);
length -= (blockSize-num);
2018-05-19 20:22:51 +02:00
num = 0;
// drop through and do the rest
}
else
{
if (input && length)
{std::memcpy(data+num, input, length);}
2018-05-19 20:22:51 +02:00
return;
}
}
// now process the input data in blocks of blockSize bytes and save the leftovers to m_data
if (length >= blockSize)
2018-05-19 20:22:51 +02:00
{
if (input == data)
{
CRYPTOPP_ASSERT(length == blockSize);
2018-05-19 20:22:51 +02:00
HashBlock(dataBuf);
return;
}
else if (IsAligned<T>(input))
{
size_t leftOver = HashMultipleBlocks((T *)(void*)input, length);
input += (length - leftOver);
length = leftOver;
2018-05-19 20:22:51 +02:00
}
else
{
2018-05-19 20:22:51 +02:00
do
{ // copy input first if it's not aligned correctly
if (input)
{ std::memcpy(data, input, blockSize); }
2018-05-19 20:22:51 +02:00
HashBlock(dataBuf);
input+=blockSize;
length-=blockSize;
} while (length >= blockSize);
}
2018-05-19 20:22:51 +02:00
}
if (input && data != input)
std::memcpy(data, input, length);
2018-05-19 20:22:51 +02: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)
{
const unsigned int blockSize = this->BlockSize();
2018-05-19 20:22:51 +02:00
bool noReverse = NativeByteOrderIs(this->GetByteOrder());
T* dataBuf = this->DataBuf();
// Alignment checks due to http://github.com/weidai11/cryptopp/issues/690.
// Sparc requires 8-byte aligned buffer when HashWordType is word64.
// We also had to provide a GetAlignmentOf specialization for word64 on Sparc.
2018-05-19 20:22:51 +02:00
do
{
if (noReverse)
{
if (IsAligned<HashWordType>(input))
{
// Sparc bus error with non-aligned input.
this->HashEndianCorrectedBlock(input);
}
else
{
std::memcpy(dataBuf, input, blockSize);
this->HashEndianCorrectedBlock(dataBuf);
}
}
2018-05-19 20:22:51 +02:00
else
{
if (IsAligned<HashWordType>(input))
{
// Sparc bus error with non-aligned input.
ByteReverse(dataBuf, input, blockSize);
this->HashEndianCorrectedBlock(dataBuf);
}
else
{
std::memcpy(dataBuf, input, blockSize);
ByteReverse(dataBuf, dataBuf, blockSize);
this->HashEndianCorrectedBlock(dataBuf);
}
2018-05-19 20:22:51 +02: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-05-19 20:22:51 +02: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)
{
CRYPTOPP_ASSERT(digest != NULLPTR);
2018-05-19 20:22:51 +02: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)
ConditionalByteReverse<HashWordType>(order, (HashWordType *)(void*)digest, stateBuf, size);
else
{
ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
std::memcpy(digest, stateBuf, size);
2018-05-19 20:22:51 +02:00
}
this->Restart(); // reinit for next use
}
#if defined(__GNUC__) || defined(__clang__)
template class IteratedHashBase<word64, HashTransformation>;
template class IteratedHashBase<word64, MessageAuthenticationCode>;
template class IteratedHashBase<word32, HashTransformation>;
template class IteratedHashBase<word32, MessageAuthenticationCode>;
#endif
NAMESPACE_END