Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.4 KiB

  1. // iterhash.cpp - written and placed in the public domain by Wei Dai
  2. #ifndef __GNUC__
  3. #define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
  4. #endif
  5. #include "iterhash.h"
  6. #include "misc.h"
  7. NAMESPACE_BEGIN(CryptoPP)
  8. template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, size_t len)
  9. {
  10. HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
  11. if ((m_countLo = oldCountLo + HashWordType(len)) < oldCountLo)
  12. m_countHi++; // carry from low to high
  13. m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(len);
  14. if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(len) != 0)
  15. throw HashInputTooLong(this->AlgorithmName());
  16. const unsigned int blockSize = this->BlockSize();
  17. unsigned int num = ModPowerOf2(oldCountLo, blockSize);
  18. T* dataBuf = this->DataBuf();
  19. byte* data = (byte *)dataBuf;
  20. assert(dataBuf && data);
  21. if (num != 0) // process left over data
  22. {
  23. if (num+len >= blockSize)
  24. {
  25. if (data && input) {memcpy(data+num, input, blockSize-num);}
  26. HashBlock(dataBuf);
  27. input += (blockSize-num);
  28. len -= (blockSize-num);
  29. num = 0;
  30. // drop through and do the rest
  31. }
  32. else
  33. {
  34. if (data && input && len) {memcpy(data+num, input, len);}
  35. return;
  36. }
  37. }
  38. // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
  39. if (len >= blockSize)
  40. {
  41. if (input == data)
  42. {
  43. assert(len == blockSize);
  44. HashBlock(dataBuf);
  45. return;
  46. }
  47. else if (IsAligned<T>(input))
  48. {
  49. size_t leftOver = HashMultipleBlocks((T *)input, len);
  50. input += (len - leftOver);
  51. len = leftOver;
  52. }
  53. else
  54. do
  55. { // copy input first if it's not aligned correctly
  56. if (data && input) memcpy(data, input, blockSize);
  57. HashBlock(dataBuf);
  58. input+=blockSize;
  59. len-=blockSize;
  60. } while (len >= blockSize);
  61. }
  62. if (data && input && len && data != input)
  63. memcpy(data, input, len);
  64. }
  65. template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
  66. {
  67. unsigned int blockSize = this->BlockSize();
  68. unsigned int num = ModPowerOf2(m_countLo, blockSize);
  69. size = blockSize - num;
  70. return (byte *)DataBuf() + num;
  71. }
  72. template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
  73. {
  74. unsigned int blockSize = this->BlockSize();
  75. bool noReverse = NativeByteOrderIs(this->GetByteOrder());
  76. T* dataBuf = this->DataBuf();
  77. do
  78. {
  79. if (noReverse)
  80. this->HashEndianCorrectedBlock(input);
  81. else
  82. {
  83. ByteReverse(dataBuf, input, this->BlockSize());
  84. this->HashEndianCorrectedBlock(dataBuf);
  85. }
  86. input += blockSize/sizeof(T);
  87. length -= blockSize;
  88. }
  89. while (length >= blockSize);
  90. return length;
  91. }
  92. template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
  93. {
  94. unsigned int blockSize = this->BlockSize();
  95. unsigned int num = ModPowerOf2(m_countLo, blockSize);
  96. T* dataBuf = this->DataBuf();
  97. byte* data = (byte *)dataBuf;
  98. data[num++] = padFirst;
  99. if (num <= lastBlockSize)
  100. memset(data+num, 0, lastBlockSize-num);
  101. else
  102. {
  103. memset(data+num, 0, blockSize-num);
  104. HashBlock(dataBuf);
  105. memset(data, 0, lastBlockSize);
  106. }
  107. }
  108. template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
  109. {
  110. m_countLo = m_countHi = 0;
  111. Init();
  112. }
  113. template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
  114. {
  115. this->ThrowIfInvalidTruncatedSize(size);
  116. T* dataBuf = this->DataBuf();
  117. T* stateBuf = this->StateBuf();
  118. unsigned int blockSize = this->BlockSize();
  119. ByteOrder order = this->GetByteOrder();
  120. PadLastBlock(blockSize - 2*sizeof(HashWordType));
  121. dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
  122. dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
  123. HashBlock(dataBuf);
  124. if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
  125. ConditionalByteReverse<HashWordType>(order, (HashWordType *)digest, stateBuf, size);
  126. else
  127. {
  128. ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
  129. memcpy(digest, stateBuf, size);
  130. }
  131. this->Restart(); // reinit for next use
  132. }
  133. #ifdef __GNUC__
  134. template class IteratedHashBase<word64, HashTransformation>;
  135. template class IteratedHashBase<word64, MessageAuthenticationCode>;
  136. template class IteratedHashBase<word32, HashTransformation>;
  137. template class IteratedHashBase<word32, MessageAuthenticationCode>;
  138. #endif
  139. NAMESPACE_END