Crypto++  5.6.3
Free C++ class library of cryptographic schemes
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  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  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  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  unsigned int blockSize = this->BlockSize();
86  bool noReverse = NativeByteOrderIs(this->GetByteOrder());
87  T* dataBuf = this->DataBuf();
88  do
89  {
90  if (noReverse)
91  this->HashEndianCorrectedBlock(input);
92  else
93  {
94  ByteReverse(dataBuf, input, this->BlockSize());
95  this->HashEndianCorrectedBlock(dataBuf);
96  }
97 
98  input += blockSize/sizeof(T);
99  length -= blockSize;
100  }
101  while (length >= blockSize);
102  return length;
103 }
104 
105 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
106 {
107  unsigned int blockSize = this->BlockSize();
108  unsigned int num = ModPowerOf2(m_countLo, blockSize);
109  T* dataBuf = this->DataBuf();
110  byte* data = (byte *)dataBuf;
111  data[num++] = padFirst;
112  if (num <= lastBlockSize)
113  memset(data+num, 0, lastBlockSize-num);
114  else
115  {
116  memset(data+num, 0, blockSize-num);
117  HashBlock(dataBuf);
118  memset(data, 0, lastBlockSize);
119  }
120 }
121 
122 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
123 {
124  m_countLo = m_countHi = 0;
125  Init();
126 }
127 
128 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
129 {
130  this->ThrowIfInvalidTruncatedSize(size);
131 
132  T* dataBuf = this->DataBuf();
133  T* stateBuf = this->StateBuf();
134  unsigned int blockSize = this->BlockSize();
135  ByteOrder order = this->GetByteOrder();
136 
137  PadLastBlock(blockSize - 2*sizeof(HashWordType));
138  dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
139  dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
140 
141  HashBlock(dataBuf);
142 
143  if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
144  ConditionalByteReverse<HashWordType>(order, (HashWordType *)(void*)digest, stateBuf, size);
145  else
146  {
147  ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
148  memcpy(digest, stateBuf, size);
149  }
150 
151  this->Restart(); // reinit for next use
152 }
153 
154 #ifdef __GNUC__
157 
160 #endif
161 
162 NAMESPACE_END
const char * DigestSize()
int, in bytes
Definition: argnames.h:78
bool NativeByteOrderIs(ByteOrder order)
Determines whether order follows native byte ordering.
Definition: misc.h:910
Utility functions for the Crypto++ library.
ByteOrder
Provides the byte ordering.
Definition: cryptlib.h:123
T2 ModPowerOf2(const T1 &a, const T2 &b)
Tests whether the residue of a value is a power of 2.
Definition: misc.h:798
exception thrown when trying to hash more data than is allowed by a hash function ...
Definition: iterhash.h:12
T ConditionalByteReverse(ByteOrder order, T value)
Reverses bytes in a value depending upon endianess.
Definition: misc.h:1793
Safely right shift values when undefined behavior could occur.
const char * BlockSize()
int, in bytes
Definition: argnames.h:26
Crypto++ library namespace.
byte ByteReverse(byte value)
Reverses bytes in a 8-bit value.
Definition: misc.h:1649