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