Crypto++  8.8
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 length)
14 {
15  CRYPTOPP_ASSERT(!(input == NULLPTR && length != 0));
16  if (length == 0) { return; }
17 
18  HashWordType oldCountLo = m_countLo, oldCountHi = m_countHi;
19  if ((m_countLo = oldCountLo + HashWordType(length)) < oldCountLo)
20  m_countHi++; // carry from low to high
21  m_countHi += (HashWordType)SafeRightShift<8*sizeof(HashWordType)>(length);
22  if (m_countHi < oldCountHi || SafeRightShift<2*8*sizeof(HashWordType)>(length) != 0)
23  throw HashInputTooLong(this->AlgorithmName());
24 
25  const unsigned int blockSize = this->BlockSize();
26  unsigned int num = ModPowerOf2(oldCountLo, blockSize);
27 
28  T* dataBuf = this->DataBuf();
29  byte* data = (byte *)dataBuf;
30 
31  if (num != 0) // process left over data
32  {
33  if (num+length >= blockSize)
34  {
35  if (input)
36  {std::memcpy(data+num, input, blockSize-num);}
37 
38  HashBlock(dataBuf);
39  input += (blockSize-num);
40  length -= (blockSize-num);
41  num = 0;
42  // drop through and do the rest
43  }
44  else
45  {
46  if (input && length)
47  {std::memcpy(data+num, input, length);}
48  return;
49  }
50  }
51 
52  // now process the input data in blocks of blockSize bytes and save the leftovers to m_data
53  if (length >= blockSize)
54  {
55  if (input == data)
56  {
57  CRYPTOPP_ASSERT(length == blockSize);
58  HashBlock(dataBuf);
59  return;
60  }
61  else if (IsAligned<T>(input))
62  {
63  size_t leftOver = HashMultipleBlocks((T *)(void*)input, length);
64  input += (length - leftOver);
65  length = leftOver;
66  }
67  else
68  {
69  do
70  { // copy input first if it's not aligned correctly
71  if (input)
72  { std::memcpy(data, input, blockSize); }
73 
74  HashBlock(dataBuf);
75  input+=blockSize;
76  length-=blockSize;
77  } while (length >= blockSize);
78  }
79  }
80 
81  if (input && data != input)
82  std::memcpy(data, input, length);
83 }
84 
85 template <class T, class BASE> byte * IteratedHashBase<T, BASE>::CreateUpdateSpace(size_t &size)
86 {
87  unsigned int blockSize = this->BlockSize();
88  unsigned int num = ModPowerOf2(m_countLo, blockSize);
89  size = blockSize - num;
90  return (byte *)DataBuf() + num;
91 }
92 
93 template <class T, class BASE> size_t IteratedHashBase<T, BASE>::HashMultipleBlocks(const T *input, size_t length)
94 {
95  const unsigned int blockSize = this->BlockSize();
96  bool noReverse = NativeByteOrderIs(this->GetByteOrder());
97  T* dataBuf = this->DataBuf();
98 
99  // Alignment checks due to http://github.com/weidai11/cryptopp/issues/690.
100  // Sparc requires 8-byte aligned buffer when HashWordType is word64.
101  // We also had to provide a GetAlignmentOf specialization for word64 on Sparc.
102 
103  do
104  {
105  if (noReverse)
106  {
107  if (IsAligned<HashWordType>(input))
108  {
109  // Sparc bus error with non-aligned input.
110  this->HashEndianCorrectedBlock(input);
111  }
112  else
113  {
114  std::memcpy(dataBuf, input, blockSize);
115  this->HashEndianCorrectedBlock(dataBuf);
116  }
117  }
118  else
119  {
120  if (IsAligned<HashWordType>(input))
121  {
122  // Sparc bus error with non-aligned input.
123  ByteReverse(dataBuf, input, blockSize);
124  this->HashEndianCorrectedBlock(dataBuf);
125  }
126  else
127  {
128  std::memcpy(dataBuf, input, blockSize);
129  ByteReverse(dataBuf, dataBuf, blockSize);
130  this->HashEndianCorrectedBlock(dataBuf);
131  }
132  }
133 
134  input += blockSize/sizeof(T);
135  length -= blockSize;
136  }
137  while (length >= blockSize);
138  return length;
139 }
140 
141 template <class T, class BASE> void IteratedHashBase<T, BASE>::PadLastBlock(unsigned int lastBlockSize, byte padFirst)
142 {
143  unsigned int blockSize = this->BlockSize();
144  unsigned int num = ModPowerOf2(m_countLo, blockSize);
145  T* dataBuf = this->DataBuf();
146  byte* data = (byte *)dataBuf;
147 
148  data[num++] = padFirst;
149  if (num <= lastBlockSize)
150  std::memset(data+num, 0, lastBlockSize-num);
151  else
152  {
153  std::memset(data+num, 0, blockSize-num);
154  HashBlock(dataBuf);
155  std::memset(data, 0, lastBlockSize);
156  }
157 }
158 
159 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
160 {
161  m_countLo = m_countHi = 0;
162  Init();
163 }
164 
165 template <class T, class BASE> void IteratedHashBase<T, BASE>::TruncatedFinal(byte *digest, size_t size)
166 {
167  CRYPTOPP_ASSERT(digest != NULLPTR);
168  this->ThrowIfInvalidTruncatedSize(size);
169 
170  T* dataBuf = this->DataBuf();
171  T* stateBuf = this->StateBuf();
172  unsigned int blockSize = this->BlockSize();
173  ByteOrder order = this->GetByteOrder();
174 
175  PadLastBlock(blockSize - 2*sizeof(HashWordType));
176  dataBuf[blockSize/sizeof(T)-2+order] = ConditionalByteReverse(order, this->GetBitCountLo());
177  dataBuf[blockSize/sizeof(T)-1-order] = ConditionalByteReverse(order, this->GetBitCountHi());
178 
179  HashBlock(dataBuf);
180 
181  if (IsAligned<HashWordType>(digest) && size%sizeof(HashWordType)==0)
182  ConditionalByteReverse<HashWordType>(order, (HashWordType *)(void*)digest, stateBuf, size);
183  else
184  {
185  ConditionalByteReverse<HashWordType>(order, stateBuf, stateBuf, this->DigestSize());
186  std::memcpy(digest, stateBuf, size);
187  }
188 
189  this->Restart(); // reinit for next use
190 }
191 
192 #if defined(__GNUC__) || defined(__clang__)
195 
198 #endif
199 
200 NAMESPACE_END
Exception thrown when trying to hash more data than is allowed by a hash function.
Definition: iterhash.h:26
Iterated hash base class.
Definition: iterhash.h:39
void TruncatedFinal(byte *digest, size_t digestSize)
Computes the hash of the current message.
Definition: iterhash.cpp:165
byte * CreateUpdateSpace(size_t &size)
Requests space which can be written into by the caller.
Definition: iterhash.cpp:85
void Restart()
Restart the hash.
Definition: iterhash.cpp:159
Functions for CPU features and intrinsics.
ByteOrder
Provides the byte ordering.
Definition: cryptlib.h:148
Base classes for iterated hashes.
Utility functions for the Crypto++ library.
byte ByteReverse(byte value)
Reverses bytes in a 8-bit value.
Definition: misc.h:2231
T2 ModPowerOf2(const T1 &a, const T2 &b)
Reduces a value to a power of 2.
Definition: misc.h:1334
bool NativeByteOrderIs(ByteOrder order)
Determines whether order follows native byte ordering.
Definition: misc.h:1481
T ConditionalByteReverse(ByteOrder order, T value)
Reverses bytes in a value depending upon endianness.
Definition: misc.h:2417
T SafeRightShift(T value)
Safely right shift values when undefined behavior could occur.
Definition: misc.h:3163
Crypto++ library namespace.
const char * BlockSize()
int, in bytes
Definition: argnames.h:27
const char * DigestSize()
int, in bytes
Definition: argnames.h:79
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68