Crypto++  5.6.5
Free C++ class library of cryptographic schemes
iterhash.cpp
1 // iterhash.cpp - originally written and placed in the public domain by Wei Dai
2 
3 #ifndef __GNUC__
4 #define CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
5 #endif
6 
7 #include "iterhash.h"
8 #include "misc.h"
9 
10 NAMESPACE_BEGIN(CryptoPP)
11 
12 template <class T, class BASE> void IteratedHashBase<T, BASE>::Update(const byte *input, size_t len)
13 {
14  HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
15  if ((m_countLo = oldCountLo + HashWordType(len)) < oldCountLo)
16  m_countHi++; // carry from low to high
17  m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(len);
18  if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(len) != 0)
19  throw HashInputTooLong(this->AlgorithmName());
20 
21  const unsigned int blockSize = this->BlockSize();
22  unsigned int num = ModPowerOf2(oldCountLo, blockSize);
23 
24  T* dataBuf = this->DataBuf();
25  byte* data = (byte *)dataBuf;
26  CRYPTOPP_ASSERT(dataBuf && data);
27 
28  if (num != 0) // process left over data
29  {
30  if (num+len >= blockSize)
31  {
32  if (data && input) {memcpy(data+num, input, blockSize-num);}
33  HashBlock(dataBuf);
34  input += (blockSize-num);
35  len -= (blockSize-num);
36  num = 0;
37  // drop through and do the rest
38  }
39  else
40  {
41  if (data && input && len) {memcpy(data+num, input, len);}
42  return;
43  }
44  }
45 
46  // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
47  if (len >= blockSize)
48  {
49  if (input == data)
50  {
51  CRYPTOPP_ASSERT(len == blockSize);
52  HashBlock(dataBuf);
53  return;
54  }
55  else if (IsAligned<T>(input))
56  {
57  size_t leftOver = HashMultipleBlocks((T *)(void*)input, len);
58  input += (len - leftOver);
59  len = leftOver;
60  }
61  else
62  do
63  { // copy input first if it's not aligned correctly
64  if (data && input) memcpy(data, input, blockSize);
65  HashBlock(dataBuf);
66  input+=blockSize;
67  len-=blockSize;
68  } while (len >= blockSize);
69  }
70 
71  if (data && input && len && data != input)
72  memcpy(data, input, len);
73 }
74 
75 template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
76 {
77  unsigned int blockSize = this->BlockSize();
78  unsigned int num = ModPowerOf2(m_countLo, blockSize);
79  size = blockSize - num;
80  return (byte *)DataBuf() + num;
81 }
82 
83 template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
84 {
85  // Hardware based SHA1 and SHA256 correct blocks themselves due to hardware requirements.
86  // For Intel, SHA1 will effectively call ByteReverse(). SHA256 formats data to Intel
87  // requirements, which means eight words ABCD EFGH are transformed to ABEF CDGH.
88  unsigned int blockSize = this->BlockSize();
89  bool noReverse = NativeByteOrderIs(this->GetByteOrder());
90  T* dataBuf = this->DataBuf();
91  do
92  {
93  if (noReverse)
94  this->HashEndianCorrectedBlock(input);
95  else
96  {
97  ByteReverse(dataBuf, input, this->BlockSize());
98  this->HashEndianCorrectedBlock(dataBuf);
99  }
100 
101  input += blockSize/sizeof(T);
102  length -= blockSize;
103  }
104  while (length >= blockSize);
105  return length;
106 }
107 
108 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
109 {
110  unsigned int blockSize = this->BlockSize();
111  unsigned int num = ModPowerOf2(m_countLo, blockSize);
112  T* dataBuf = this->DataBuf();
113  byte* data = (byte *)dataBuf;
114  data[num++] = padFirst;
115  if (num <= lastBlockSize)
116  memset(data+num, 0, lastBlockSize-num);
117  else
118  {
119  memset(data+num, 0, blockSize-num);
120  HashBlock(dataBuf);
121  memset(data, 0, lastBlockSize);
122  }
123 }
124 
125 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
126 {
127  m_countLo = m_countHi = 0;
128  Init();
129 }
130 
131 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
132 {
133  this->ThrowIfInvalidTruncatedSize(size);
134 
135  T* dataBuf = this->DataBuf();
136  T* stateBuf = this->StateBuf();
137  unsigned int blockSize = this->BlockSize();
138  ByteOrder order = this->GetByteOrder();
139 
140  PadLastBlock(blockSize - 2*sizeof(HashWordType));
141  dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
142  dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
143 
144  HashBlock(dataBuf);
145 
146  if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
147  ConditionalByteReverse<HashWordType>(order, (HashWordType *)(void*)digest, stateBuf, size);
148  else
149  {
150  ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
151  memcpy(digest, stateBuf, size);
152  }
153 
154  this->Restart(); // reinit for next use
155 }
156 
157 #ifdef __GNUC__
160 
163 #endif
164 
165 NAMESPACE_END
const char * DigestSize()
int, in bytes
Definition: argnames.h:79
bool NativeByteOrderIs(ByteOrder order)
Determines whether order follows native byte ordering.
Definition: misc.h:1077
Utility functions for the Crypto++ library.
ByteOrder
Provides the byte ordering.
Definition: cryptlib.h:134
T2 ModPowerOf2(const T1 &a, const T2 &b)
Reduces a value to a power of 2.
Definition: misc.h:928
Exception thrown when trying to hash more data than is allowed by a hash function.
Definition: iterhash.h:13
T ConditionalByteReverse(ByteOrder order, T value)
Reverses bytes in a value depending upon endianness.
Definition: misc.h:1919
void TruncatedFinal(byte *digest, size_t digestSize)
Computes the hash of the current message.
Definition: iterhash.cpp:131
Safely right shift values when undefined behavior could occur.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:61
const char * BlockSize()
int, in bytes
Definition: argnames.h:27
void Restart()
Restart the hash.
Definition: iterhash.cpp:125
Iterated hash base class.
Definition: iterhash.h:27
Crypto++ library namespace.
byte ByteReverse(byte value)
Reverses bytes in a 8-bit value.
Definition: misc.h:1766
byte * CreateUpdateSpace(size_t &size)
Requests space which can be written into by the caller.
Definition: iterhash.cpp:75