1//
2// SHA1Engine.cpp
3//
4// Library: Foundation
5// Package: Crypt
6// Module: SHA1Engine
7//
8// Based on the public domain implementation by Peter C. Gutmann
9// on 2 Sep 1992, modified by Carl Ellison to be SHA-1.
10//
11// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
12// and Contributors.
13//
14// SPDX-License-Identifier: BSL-1.0
15//
16
17
18#include "Poco/SHA1Engine.h"
19#include "Poco/ByteOrder.h"
20#include <cstring>
21
22
23#ifdef POCO_ARCH_LITTLE_ENDIAN
24 #define SHA1_BYTE_REVERSE(x, y) byteReverse(x, y)
25#else
26 #define SHA1_BYTE_REVERSE(x, y)
27#endif
28
29
30namespace Poco {
31
32
33SHA1Engine::SHA1Engine()
34{
35 _digest.reserve(16);
36 reset();
37}
38
39
40SHA1Engine::~SHA1Engine()
41{
42 reset();
43}
44
45
46inline void SHA1Engine::byteReverse(UInt32* buffer, int byteCount)
47{
48#ifdef POCO_ARCH_LITTLE_ENDIAN
49 byteCount /= sizeof(UInt32);
50 for(int count = 0; count < byteCount; count++)
51 {
52 buffer[count] = Poco::ByteOrder::toBigEndian(buffer[ count ]);
53 }
54#endif // POCO_ARCH_LITTLE_ENDIAN
55}
56
57
58void SHA1Engine::updateImpl(const void* buffer_, std::size_t count)
59{
60 const BYTE* buffer = (const BYTE*) buffer_;
61 BYTE* db = (BYTE*) &_context.data[0];
62
63 /* Update bitcount */
64 if ((_context.countLo + ((UInt32) count << 3)) < _context.countLo)
65 _context.countHi++; /* Carry from low to high bitCount */
66 _context.countLo += ((UInt32) count << 3);
67 _context.countHi += ((UInt32 ) count >> 29);
68
69 /* Process data in BLOCK_SIZE chunks */
70 while (count-- > 0)
71 {
72 db[_context.slop++] = *(buffer++);
73 if (_context.slop == BLOCK_SIZE)
74 {
75 /* transform this one block */
76 SHA1_BYTE_REVERSE(_context.data, BLOCK_SIZE);
77 transform();
78 _context.slop = 0 ; /* no slop left */
79 }
80 }
81}
82
83
84std::size_t SHA1Engine::digestLength() const
85{
86 return DIGEST_SIZE;
87}
88
89
90void SHA1Engine::reset()
91{
92 _context.digest[0] = 0x67452301L;
93 _context.digest[1] = 0xEFCDAB89L;
94 _context.digest[2] = 0x98BADCFEL;
95 _context.digest[3] = 0x10325476L;
96 _context.digest[4] = 0xC3D2E1F0L;
97 _context.countLo = 0;
98 _context.countHi = 0;
99 _context.slop = 0;
100 std::memset(_context.data, 0, sizeof(_context.data));
101}
102
103
104const DigestEngine::Digest& SHA1Engine::digest()
105{
106 int count;
107 UInt32 lowBitcount = _context.countLo;
108 UInt32 highBitcount = _context.countHi;
109
110 /* Compute number of bytes mod 64 */
111 count = (int) ((_context.countLo >> 3) & 0x3F);
112
113 /* Set the first char of padding to 0x80. This is safe since there is
114 always at least one byte free */
115 ((BYTE*) _context.data)[count++] = 0x80;
116
117 /* Pad out to 56 mod 64 */
118 if (count > 56)
119 {
120 /* Two lots of padding: Pad the first block to 64 bytes */
121 std::memset((BYTE*) &_context.data + count, 0, 64 - count);
122 SHA1_BYTE_REVERSE(_context.data, BLOCK_SIZE);
123 transform();
124
125 /* Now fill the next block with 56 bytes */
126 std::memset(&_context.data, 0, 56);
127 }
128 else
129 {
130 /* Pad block to 56 bytes */
131 std::memset((BYTE*) &_context.data + count, 0, 56 - count);
132 }
133 SHA1_BYTE_REVERSE(_context.data, BLOCK_SIZE);
134
135 /* Append length in bits and transform */
136 _context.data[14] = highBitcount;
137 _context.data[15] = lowBitcount;
138
139 transform();
140 SHA1_BYTE_REVERSE(_context.data, DIGEST_SIZE);
141
142 unsigned char hash[DIGEST_SIZE];
143 for (count = 0; count < DIGEST_SIZE; count++)
144 hash[count] = (BYTE) ((_context.digest[count>>2]) >> (8*(3-(count & 0x3)))) & 0xff;
145 _digest.clear();
146 _digest.insert(_digest.begin(), hash, hash + DIGEST_SIZE);
147 reset();
148 return _digest;
149}
150
151
152/* The SHA f()-functions */
153#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) /* Rounds 0-19 */
154#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
155#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) /* Rounds 40-59 */
156#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
157
158
159/* The SHA Mysterious Constants */
160#define K1 0x5A827999L /* Rounds 0-19 */
161#define K2 0x6ED9EBA1L /* Rounds 20-39 */
162#define K3 0x8F1BBCDCL /* Rounds 40-59 */
163#define K4 0xCA62C1D6L /* Rounds 60-79 */
164
165
166/* 32-bit rotate - kludged with shifts */
167typedef UInt32 UL; /* to save space */
168
169
170#define S(n,X) ( ( ((UL)X) << n ) | ( ((UL)X) >> ( 32 - n ) ) )
171
172
173/* The initial expanding function */
174#define expand(count) W[ count ] = S(1,(W[ count - 3 ] ^ W[ count - 8 ] ^ W[ count - 14 ] ^ W[ count - 16 ])) /* to make this SHA-1 */
175
176
177/* The four SHA sub-rounds */
178#define subRound1(count) \
179{ \
180 temp = S( 5, A ) + f1( B, C, D ) + E + W[ count ] + K1; \
181 E = D; \
182 D = C; \
183 C = S( 30, B ); \
184 B = A; \
185 A = temp; \
186}
187
188#define subRound2(count) \
189{ \
190 temp = S( 5, A ) + f2( B, C, D ) + E + W[ count ] + K2; \
191 E = D; \
192 D = C; \
193 C = S( 30, B ); \
194 B = A; \
195 A = temp; \
196}
197
198#define subRound3(count) \
199{ \
200 temp = S( 5, A ) + f3( B, C, D ) + E + W[ count ] + K3; \
201 E = D; \
202 D = C; \
203 C = S( 30, B ); \
204 B = A; \
205 A = temp; \
206}
207
208#define subRound4(count) \
209{ \
210 temp = S( 5, A ) + f4( B, C, D ) + E + W[ count ] + K4; \
211 E = D; \
212 D = C; \
213 C = S( 30, B ); \
214 B = A; \
215 A = temp; \
216}
217
218
219void SHA1Engine::transform()
220{
221 UInt32 W[80];
222 UInt32 temp;
223 UInt32 A, B, C, D, E;
224 int i;
225
226 /* Step A. Copy the data buffer into the local work buffer */
227 for( i = 0; i < 16; i++ )
228 W[ i ] = _context.data[ i ];
229
230 /* Step B. Expand the 16 words into 64 temporary data words */
231 expand( 16 ); expand( 17 ); expand( 18 ); expand( 19 ); expand( 20 );
232 expand( 21 ); expand( 22 ); expand( 23 ); expand( 24 ); expand( 25 );
233 expand( 26 ); expand( 27 ); expand( 28 ); expand( 29 ); expand( 30 );
234 expand( 31 ); expand( 32 ); expand( 33 ); expand( 34 ); expand( 35 );
235 expand( 36 ); expand( 37 ); expand( 38 ); expand( 39 ); expand( 40 );
236 expand( 41 ); expand( 42 ); expand( 43 ); expand( 44 ); expand( 45 );
237 expand( 46 ); expand( 47 ); expand( 48 ); expand( 49 ); expand( 50 );
238 expand( 51 ); expand( 52 ); expand( 53 ); expand( 54 ); expand( 55 );
239 expand( 56 ); expand( 57 ); expand( 58 ); expand( 59 ); expand( 60 );
240 expand( 61 ); expand( 62 ); expand( 63 ); expand( 64 ); expand( 65 );
241 expand( 66 ); expand( 67 ); expand( 68 ); expand( 69 ); expand( 70 );
242 expand( 71 ); expand( 72 ); expand( 73 ); expand( 74 ); expand( 75 );
243 expand( 76 ); expand( 77 ); expand( 78 ); expand( 79 );
244
245 /* Step C. Set up first buffer */
246 A = _context.digest[ 0 ];
247 B = _context.digest[ 1 ];
248 C = _context.digest[ 2 ];
249 D = _context.digest[ 3 ];
250 E = _context.digest[ 4 ];
251
252 /* Step D. Serious mangling, divided into four sub-rounds */
253 subRound1( 0 ); subRound1( 1 ); subRound1( 2 ); subRound1( 3 );
254 subRound1( 4 ); subRound1( 5 ); subRound1( 6 ); subRound1( 7 );
255 subRound1( 8 ); subRound1( 9 ); subRound1( 10 ); subRound1( 11 );
256 subRound1( 12 ); subRound1( 13 ); subRound1( 14 ); subRound1( 15 );
257 subRound1( 16 ); subRound1( 17 ); subRound1( 18 ); subRound1( 19 );
258 subRound2( 20 ); subRound2( 21 ); subRound2( 22 ); subRound2( 23 );
259 subRound2( 24 ); subRound2( 25 ); subRound2( 26 ); subRound2( 27 );
260 subRound2( 28 ); subRound2( 29 ); subRound2( 30 ); subRound2( 31 );
261 subRound2( 32 ); subRound2( 33 ); subRound2( 34 ); subRound2( 35 );
262 subRound2( 36 ); subRound2( 37 ); subRound2( 38 ); subRound2( 39 );
263 subRound3( 40 ); subRound3( 41 ); subRound3( 42 ); subRound3( 43 );
264 subRound3( 44 ); subRound3( 45 ); subRound3( 46 ); subRound3( 47 );
265 subRound3( 48 ); subRound3( 49 ); subRound3( 50 ); subRound3( 51 );
266 subRound3( 52 ); subRound3( 53 ); subRound3( 54 ); subRound3( 55 );
267 subRound3( 56 ); subRound3( 57 ); subRound3( 58 ); subRound3( 59 );
268 subRound4( 60 ); subRound4( 61 ); subRound4( 62 ); subRound4( 63 );
269 subRound4( 64 ); subRound4( 65 ); subRound4( 66 ); subRound4( 67 );
270 subRound4( 68 ); subRound4( 69 ); subRound4( 70 ); subRound4( 71 );
271 subRound4( 72 ); subRound4( 73 ); subRound4( 74 ); subRound4( 75 );
272 subRound4( 76 ); subRound4( 77 ); subRound4( 78 ); subRound4( 79 );
273
274 /* Step E. Build message digest */
275 _context.digest[ 0 ] += A;
276 _context.digest[ 1 ] += B;
277 _context.digest[ 2 ] += C;
278 _context.digest[ 3 ] += D;
279 _context.digest[ 4 ] += E;
280}
281
282
283} // namespace Poco
284