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
NAMESPACE_BEGIN(CryptoPP)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
CreateUpdateSpace(size_t & size)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
HashMultipleBlocks(const T * input,size_t length)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
PadLastBlock(unsigned int lastBlockSize,byte padFirst)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 memset(data+num, 0, lastBlockSize-num);
151 else
152 {
153 memset(data+num, 0, blockSize-num);
154 HashBlock(dataBuf);
155 memset(data, 0, lastBlockSize);
156 }
157 }
158
Restart()159 template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
160 {
161 m_countLo = m_countHi = 0;
162 Init();
163 }
164
TruncatedFinal(byte * digest,size_t size)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__)
193 template class IteratedHashBase<word64, HashTransformation>;
194 template class IteratedHashBase<word64, MessageAuthenticationCode>;
195
196 template class IteratedHashBase<word32, HashTransformation>;
197 template class IteratedHashBase<word32, MessageAuthenticationCode>;
198 #endif
199
200 NAMESPACE_END
201