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