Crypto++
iterhash.cpp
1 // iterhash.cpp - 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  unsigned int blockSize = this->BlockSize();
22  unsigned int num = ModPowerOf2(oldCountLo, blockSize);
23  T* dataBuf = this->DataBuf();
24  byte* data = (byte *)dataBuf;
25 
26  if (num != 0) // process left over data
27  {
28  if (num+len >= blockSize)
29  {
30  memcpy(data+num, input, blockSize-num);
31  HashBlock(dataBuf);
32  input += (blockSize-num);
33  len -= (blockSize-num);
34  num = 0;
35  // drop through and do the rest
36  }
37  else
38  {
39  memcpy(data+num, input, len);
40  return;
41  }
42  }
43 
44  // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
45  if (len >= blockSize)
46  {
47  if (input == data)
48  {
49  assert(len == blockSize);
50  HashBlock(dataBuf);
51  return;
52  }
53  else if (IsAligned<T>(input))
54  {
55  size_t leftOver = HashMultipleBlocks((T *)input, len);
56  input += (len - leftOver);
57  len = leftOver;
58  }
59  else
60  do
61  { // copy input first if it's not aligned correctly
62  memcpy(data, input, blockSize);
63  HashBlock(dataBuf);
64  input+=blockSize;
65  len-=blockSize;
66  } while (len >= blockSize);
67  }
68 
69  if (len && data != input)
70  memcpy(data, input, len);
71 }
72 
73 template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
74 {
75  unsigned int blockSize = this->BlockSize();
76  unsigned int num = ModPowerOf2(m_countLo, blockSize);
77  size = blockSize - num;
78  return (byte *)DataBuf() + num;
79 }
80 
81 template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
82 {
83  unsigned int blockSize = this->BlockSize();
84  bool noReverse = NativeByteOrderIs(this->GetByteOrder());
85  T* dataBuf = this->DataBuf();
86  do
87  {
88  if (noReverse)
89  this->HashEndianCorrectedBlock(input);
90  else
91  {
92  ByteReverse(dataBuf, input, this->BlockSize());
93  this->HashEndianCorrectedBlock(dataBuf);
94  }
95 
96  input += blockSize/sizeof(T);
97  length -= blockSize;
98  }
99  while (length >= blockSize);
100  return length;
101 }
102 
103 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
104 {
105  unsigned int blockSize = this->BlockSize();
106  unsigned int num = ModPowerOf2(m_countLo, blockSize);
107  T* dataBuf = this->DataBuf();
108  byte* data = (byte *)dataBuf;
109  data[num++] = padFirst;
110  if (num <= lastBlockSize)
111  memset(data+num, 0, lastBlockSize-num);
112  else
113  {
114  memset(data+num, 0, blockSize-num);
115  HashBlock(dataBuf);
116  memset(data, 0, lastBlockSize);
117  }
118 }
119 
120 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
121 {
122  m_countLo = m_countHi = 0;
123  Init();
124 }
125 
126 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
127 {
128  this->ThrowIfInvalidTruncatedSize(size);
129 
130  T* dataBuf = this->DataBuf();
131  T* stateBuf = this->StateBuf();
132  unsigned int blockSize = this->BlockSize();
133  ByteOrder order = this->GetByteOrder();
134 
135  PadLastBlock(blockSize - 2*sizeof(HashWordType));
136  dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
137  dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
138 
139  HashBlock(dataBuf);
140 
141  if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
142  ConditionalByteReverse<HashWordType>(order, (HashWordType *)digest, stateBuf, size);
143  else
144  {
145  ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
146  memcpy(digest, stateBuf, size);
147  }
148 
149  this->Restart(); // reinit for next use
150 }
151 
152 #ifdef __GNUC__
155 
158 #endif
159 
160 NAMESPACE_END
const char * DigestSize()
int, in bytes
Definition: argnames.h:73
exception thrown when trying to hash more data than is allowed by a hash function ...
Definition: iterhash.h:12
const char * BlockSize()
int, in bytes
Definition: argnames.h:21