// 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 void IteratedHashBase::Update(const byte *input, size_t length) { CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0)); if (length == 0) { return; } HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi; if ((m_countLo = oldCountLo + HashWordType(length)) < oldCountLo) 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) 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) { if (input) {std::memcpy(data+num, input, blockSize-num);} HashBlock(dataBuf); input += (blockSize-num); length -= (blockSize-num); num = 0; // drop through and do the rest } else { if (input && length) {std::memcpy(data+num, input, length);} return; } } // now process the input data in blocks of blockSize bytes and save the leftovers to m_data if (length >= blockSize) { if (input == data) { CRYPTOPP_ASSERT(length == blockSize); HashBlock(dataBuf); return; } else if (IsAligned(input)) { size_t leftOver = HashMultipleBlocks((T *)(void*)input, length); input += (length - leftOver); length = leftOver; } else { do { // copy input first if it's not aligned correctly if (input) { std::memcpy(data, input, blockSize); } HashBlock(dataBuf); input+=blockSize; length-=blockSize; } while (length >= blockSize); } } if (input && data != input) std::memcpy(data, input, length); } template byte * IteratedHashBase::CreateUpdateSpace(size_t &size) { unsigned int blockSize = this->BlockSize(); unsigned int num = ModPowerOf2(m_countLo, blockSize); size = blockSize - num; return (byte *)DataBuf() + num; } template size_t IteratedHashBase::HashMultipleBlocks(const T *input, size_t length) { const unsigned int blockSize = this->BlockSize(); 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. do { if (noReverse) { if (IsAligned(input)) { // Sparc bus error with non-aligned input. this->HashEndianCorrectedBlock(input); } else { std::memcpy(dataBuf, input, blockSize); this->HashEndianCorrectedBlock(dataBuf); } } else { if (IsAligned(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); } } input += blockSize/sizeof(T); length -= blockSize; } while (length >= blockSize); return length; } template void IteratedHashBase::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; data[num++] = padFirst; if (num <= lastBlockSize) std::memset(data+num, 0, lastBlockSize-num); else { std::memset(data+num, 0, blockSize-num); HashBlock(dataBuf); std::memset(data, 0, lastBlockSize); } } template void IteratedHashBase::Restart() { m_countLo = m_countHi = 0; Init(); } template void IteratedHashBase::TruncatedFinal(byte *digest, size_t size) { CRYPTOPP_ASSERT(digest != NULLPTR); 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(digest) && size%sizeof(HashWordType)==0) ConditionalByteReverse(order, (HashWordType *)(void*)digest, stateBuf, size); else { ConditionalByteReverse(order, stateBuf, stateBuf, this->DigestSize()); std::memcpy(digest, stateBuf, size); } this->Restart(); // reinit for next use } #if defined(__GNUC__) || defined(__clang__) template class IteratedHashBase; template class IteratedHashBase; template class IteratedHashBase; template class IteratedHashBase; #endif NAMESPACE_END