Crypto++ 8.7
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
11NAMESPACE_BEGIN(CryptoPP)
12
13template <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); }
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}
85template <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
93template <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
141template <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
159template <class T, class BASE> void IteratedHashBase<T, BASE>::Restart()
160{
161 m_countLo = m_countHi = 0;
162 Init();
163}
164
165template <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
200NAMESPACE_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:143
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:2022
T2 ModPowerOf2(const T1 &a, const T2 &b)
Reduces a value to a power of 2.
Definition: misc.h:1125
bool NativeByteOrderIs(ByteOrder order)
Determines whether order follows native byte ordering.
Definition: misc.h:1272
T ConditionalByteReverse(ByteOrder order, T value)
Reverses bytes in a value depending upon endianness.
Definition: misc.h:2208
T SafeRightShift(T value)
Safely right shift values when undefined behavior could occur.
Definition: misc.h:2954
Crypto++ library namespace.
const char * DigestSize()
int, in bytes
Definition: argnames.h:79
const char * BlockSize()
int, in bytes
Definition: argnames.h:27
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68