1 | // |
2 | // SHA3Engine.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Crypt |
6 | // Module: SHA3Engine |
7 | // |
8 | // Code of class SHA3Engine. |
9 | // |
10 | /// This class implements the SHA-3 message digest algorithm. |
11 | /// (FIPS 202, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf) |
12 | // |
13 | // Based on the Keccak Code Package (public domain) |
14 | // https://github.com/gvanas/KeccakCodePackage |
15 | // |
16 | // Copyright (c) 2017, Applied Informatics Software Engineering GmbH |
17 | // and Contributors. |
18 | // |
19 | // SPDX-License-Identifier: BSL-1.0 |
20 | // |
21 | |
22 | #include "Poco/SHA3Engine.h" |
23 | #include <string.h> |
24 | #include <assert.h> |
25 | |
26 | namespace Poco { |
27 | |
28 | #ifdef _MSC_VER |
29 | #pragma intrinsic(memcpy) |
30 | #endif |
31 | |
32 | #if defined(__GNUC__) |
33 | #define ALIGN(x) __attribute__ ((aligned(x))) |
34 | #elif defined(_MSC_VER) |
35 | #define ALIGN(x) __declspec(align(x)) |
36 | #elif defined(__ARMCC_VERSION) |
37 | #define ALIGN(x) __align(x) |
38 | #else |
39 | #define ALIGN(x) |
40 | #endif |
41 | |
42 | #ifdef POCO_PTR_IS_64_BIT |
43 | static const UInt64 KeccakRoundConstants[24] = |
44 | { |
45 | 0x0000000000000001, |
46 | 0x0000000000008082, |
47 | 0x800000000000808a, |
48 | 0x8000000080008000, |
49 | 0x000000000000808b, |
50 | 0x0000000080000001, |
51 | 0x8000000080008081, |
52 | 0x8000000000008009, |
53 | 0x000000000000008a, |
54 | 0x0000000000000088, |
55 | 0x0000000080008009, |
56 | 0x000000008000000a, |
57 | 0x000000008000808b, |
58 | 0x800000000000008b, |
59 | 0x8000000000008089, |
60 | 0x8000000000008003, |
61 | 0x8000000000008002, |
62 | 0x8000000000000080, |
63 | 0x000000000000800a, |
64 | 0x800000008000000a, |
65 | 0x8000000080008081, |
66 | 0x8000000000008080, |
67 | 0x0000000080000001, |
68 | 0x8000000080008008, |
69 | }; |
70 | static const unsigned int KeccakRhoOffsets[25] = |
71 | { |
72 | 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 |
73 | }; |
74 | #define KeccakP1600_stateAlignment 8 |
75 | #else |
76 | static const UInt32 KeccakRoundConstants[24][2] = |
77 | { |
78 | 0x00000001, 0x00000000, |
79 | 0x00000000, 0x00000089, |
80 | 0x00000000, 0x8000008B, |
81 | 0x00000000, 0x80008080, |
82 | 0x00000001, 0x0000008B, |
83 | 0x00000001, 0x00008000, |
84 | 0x00000001, 0x80008088, |
85 | 0x00000001, 0x80000082, |
86 | 0x00000000, 0x0000000B, |
87 | 0x00000000, 0x0000000A, |
88 | 0x00000001, 0x00008082, |
89 | 0x00000000, 0x00008003, |
90 | 0x00000001, 0x0000808B, |
91 | 0x00000001, 0x8000000B, |
92 | 0x00000001, 0x8000008A, |
93 | 0x00000001, 0x80000081, |
94 | 0x00000000, 0x80000081, |
95 | 0x00000000, 0x80000008, |
96 | 0x00000000, 0x00000083, |
97 | 0x00000000, 0x80008003, |
98 | 0x00000001, 0x80008088, |
99 | 0x00000000, 0x80000088, |
100 | 0x00000001, 0x00008000, |
101 | 0x00000000, 0x80008082 |
102 | }; |
103 | |
104 | static const unsigned int KeccakRhoOffsets[25] = |
105 | { |
106 | 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14 |
107 | }; |
108 | #define KeccakP1600_stateAlignment 4 |
109 | #endif |
110 | |
111 | ALIGN(KeccakP1600_stateAlignment) typedef struct KeccakWidth1600_SpongeInstanceStruct |
112 | { |
113 | unsigned char state[200]; |
114 | unsigned int rate; |
115 | unsigned int byteIOIndex; |
116 | int squeezing; |
117 | } KeccakWidth1600_SpongeInstance; |
118 | |
119 | typedef struct |
120 | { |
121 | KeccakWidth1600_SpongeInstance sponge; |
122 | unsigned int fixedOutputLength; |
123 | unsigned char delimitedSuffix; |
124 | } HASHCONTEXT; |
125 | |
126 | SHA3Engine::SHA3Engine(ALGORITHM algorithm): _context(NULL), |
127 | _algorithm(algorithm) |
128 | { |
129 | _digest.reserve(digestLength()); |
130 | reset(); |
131 | } |
132 | |
133 | SHA3Engine::~SHA3Engine() |
134 | { |
135 | reset(); |
136 | free(_context); |
137 | } |
138 | |
139 | #ifdef POCO_PTR_IS_64_BIT |
140 | void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length) |
141 | { |
142 | assert(offset < 200); |
143 | assert(offset + length <= 200); |
144 | for (unsigned int i = 0; i<length; i++) ((unsigned char *)state)[offset + i] ^= data[i]; |
145 | } |
146 | |
147 | void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset) |
148 | { |
149 | assert(offset < 200); |
150 | ((unsigned char *)state)[offset] ^= byte; |
151 | } |
152 | |
153 | #define ROL64(a, offset) ((offset != 0) ? ((((UInt64)a) << offset) ^ (((UInt64)a) >> (64-offset))) : a) |
154 | #define index(x, y) (((x)%5)+5*((y)%5)) |
155 | |
156 | static void theta(UInt64 *A) |
157 | { |
158 | unsigned int x, y; |
159 | UInt64 C[5], D[5]; |
160 | |
161 | for (x = 0; x<5; x++) { |
162 | C[x] = 0; |
163 | for (y = 0; y<5; y++) |
164 | C[x] ^= A[index(x, y)]; |
165 | } |
166 | for (x = 0; x<5; x++) |
167 | D[x] = ROL64(C[(x + 1) % 5], 1) ^ C[(x + 4) % 5]; |
168 | for (x = 0; x<5; x++) |
169 | for (y = 0; y<5; y++) |
170 | A[index(x, y)] ^= D[x]; |
171 | } |
172 | |
173 | static void rho(UInt64 *A) |
174 | { |
175 | unsigned int x, y; |
176 | |
177 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
178 | A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]); |
179 | } |
180 | |
181 | static void pi(UInt64 *A) |
182 | { |
183 | unsigned int x, y; |
184 | UInt64 tempA[25]; |
185 | |
186 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
187 | tempA[index(x, y)] = A[index(x, y)]; |
188 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
189 | A[index(0 * x + 1 * y, 2 * x + 3 * y)] = tempA[index(x, y)]; |
190 | } |
191 | |
192 | static void chi(UInt64 *A) |
193 | { |
194 | unsigned int x, y; |
195 | UInt64 C[5]; |
196 | |
197 | for (y = 0; y<5; y++) { |
198 | for (x = 0; x<5; x++) |
199 | C[x] = A[index(x, y)] ^ ((~A[index(x + 1, y)]) & A[index(x + 2, y)]); |
200 | for (x = 0; x<5; x++) |
201 | A[index(x, y)] = C[x]; |
202 | } |
203 | } |
204 | |
205 | static void iota(UInt64 *A, unsigned int indexRound) |
206 | { |
207 | A[index(0, 0)] ^= KeccakRoundConstants[indexRound]; |
208 | } |
209 | |
210 | void KeccakP1600Round(UInt64 *state, unsigned int indexRound) |
211 | { |
212 | theta(state); |
213 | rho(state); |
214 | pi(state); |
215 | chi(state); |
216 | iota(state, indexRound); |
217 | } |
218 | |
219 | void KeccakP1600OnWords(UInt64 *state, unsigned int nrRounds) |
220 | { |
221 | for (unsigned int i = (24 - nrRounds); i < 24; i++) KeccakP1600Round(state, i); |
222 | } |
223 | |
224 | void KeccakP1600_Permute_24rounds(void *state) |
225 | { |
226 | #ifndef POCO_ARCH_LITTLE_ENDIAN |
227 | UInt64 stateAsWords[1600 / 64]; |
228 | #endif |
229 | #ifdef POCO_ARCH_LITTLE_ENDIAN |
230 | KeccakP1600OnWords((UInt64*)state, 24); |
231 | #else |
232 | fromBytesToWords(stateAsWords, (const unsigned char *)state); |
233 | KeccakP1600OnWords(stateAsWords, 24); |
234 | fromWordsToBytes((unsigned char *)state, stateAsWords); |
235 | #endif |
236 | } |
237 | |
238 | void (const void *state, unsigned char *data, unsigned int offset, unsigned int length) |
239 | { |
240 | assert(offset < 200); |
241 | assert(offset + length <= 200); |
242 | memcpy(data, (unsigned char*)state + offset, length); |
243 | } |
244 | #else |
245 | void toBitInterleaving(UInt32 low, UInt32 high, UInt32 *even, UInt32 *odd) |
246 | { |
247 | unsigned int i; |
248 | |
249 | *even = 0; |
250 | *odd = 0; |
251 | for (i = 0; i<64; i++) { |
252 | unsigned int inBit; |
253 | if (i < 32) |
254 | inBit = (low >> i) & 1; |
255 | else |
256 | inBit = (high >> (i - 32)) & 1; |
257 | if ((i % 2) == 0) |
258 | *even |= inBit << (i / 2); |
259 | else |
260 | *odd |= inBit << ((i - 1) / 2); |
261 | } |
262 | } |
263 | |
264 | void fromBitInterleaving(UInt32 even, UInt32 odd, UInt32 *low, UInt32 *high) |
265 | { |
266 | unsigned int i; |
267 | |
268 | *low = 0; |
269 | *high = 0; |
270 | for (i = 0; i<64; i++) { |
271 | unsigned int inBit; |
272 | if ((i % 2) == 0) |
273 | inBit = (even >> (i / 2)) & 1; |
274 | else |
275 | inBit = (odd >> ((i - 1) / 2)) & 1; |
276 | if (i < 32) |
277 | *low |= inBit << i; |
278 | else |
279 | *high |= inBit << (i - 32); |
280 | } |
281 | } |
282 | |
283 | void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length) |
284 | { |
285 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { |
286 | UInt8 laneAsBytes[8]; |
287 | UInt32 low, high; |
288 | UInt32 lane[2]; |
289 | UInt32 *stateAsHalfLanes; |
290 | |
291 | memset(laneAsBytes, 0, 8); |
292 | memcpy(laneAsBytes + offset, data, length); |
293 | low = laneAsBytes[0] |
294 | | ((UInt32)(laneAsBytes[1]) << 8) |
295 | | ((UInt32)(laneAsBytes[2]) << 16) |
296 | | ((UInt32)(laneAsBytes[3]) << 24); |
297 | high = laneAsBytes[4] |
298 | | ((UInt32)(laneAsBytes[5]) << 8) |
299 | | ((UInt32)(laneAsBytes[6]) << 16) |
300 | | ((UInt32)(laneAsBytes[7]) << 24); |
301 | toBitInterleaving(low, high, lane, lane + 1); |
302 | stateAsHalfLanes = (UInt32*)state; |
303 | stateAsHalfLanes[lanePosition * 2 + 0] ^= lane[0]; |
304 | stateAsHalfLanes[lanePosition * 2 + 1] ^= lane[1]; |
305 | } |
306 | } |
307 | |
308 | void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length) |
309 | { |
310 | unsigned int lanePosition = offset / 8; |
311 | unsigned int offsetInLane = offset % 8; |
312 | |
313 | assert(offset < 200); |
314 | assert(offset + length <= 200); |
315 | while (length > 0) { |
316 | unsigned int bytesInLane = 8 - offsetInLane; |
317 | if (bytesInLane > length) |
318 | bytesInLane = length; |
319 | KeccakP1600_AddBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); |
320 | length -= bytesInLane; |
321 | lanePosition++; |
322 | offsetInLane = 0; |
323 | data += bytesInLane; |
324 | } |
325 | } |
326 | |
327 | void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset) |
328 | { |
329 | unsigned char data[1]; |
330 | assert(offset < 200); |
331 | data[0] = byte; |
332 | KeccakP1600_AddBytes(state, data, offset, 1); |
333 | } |
334 | |
335 | #define ROL32(a, offset) ((offset != 0) ? ((((UInt32)a) << offset) ^ (((UInt32)a) >> (32-offset))) : a) |
336 | #define index(x, y,z) ((((x)%5)+5*((y)%5))*2 + z) |
337 | void ROL64(UInt32 inEven, UInt32 inOdd, UInt32 *outEven, UInt32 *outOdd, unsigned int offset) |
338 | { |
339 | if ((offset % 2) == 0) { |
340 | *outEven = ROL32(inEven, offset / 2); |
341 | *outOdd = ROL32(inOdd, offset / 2); |
342 | } |
343 | else { |
344 | *outEven = ROL32(inOdd, (offset + 1) / 2); |
345 | *outOdd = ROL32(inEven, (offset - 1) / 2); |
346 | } |
347 | } |
348 | |
349 | static void theta(UInt32 *A) |
350 | { |
351 | unsigned int x, y, z; |
352 | UInt32 C[5][2], D[5][2]; |
353 | for (x = 0; x<5; x++) { |
354 | for (z = 0; z<2; z++) { |
355 | C[x][z] = 0; |
356 | for (y = 0; y<5; y++) |
357 | C[x][z] ^= A[index(x, y, z)]; |
358 | } |
359 | } |
360 | for (x = 0; x<5; x++) { |
361 | ROL64(C[(x + 1) % 5][0], C[(x + 1) % 5][1], &(D[x][0]), &(D[x][1]), 1); |
362 | for (z = 0; z<2; z++) |
363 | D[x][z] ^= C[(x + 4) % 5][z]; |
364 | } |
365 | for (x = 0; x<5; x++) |
366 | for (y = 0; y<5; y++) |
367 | for (z = 0; z<2; z++) |
368 | A[index(x, y, z)] ^= D[x][z]; |
369 | } |
370 | |
371 | static void rho(UInt32 *A) |
372 | { |
373 | unsigned int x, y; |
374 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) |
375 | ROL64(A[index(x, y, 0)], A[index(x, y, 1)], &(A[index(x, y, 0)]), &(A[index(x, y, 1)]), KeccakRhoOffsets[5 * y + x]); |
376 | } |
377 | |
378 | static void pi(UInt32 *A) |
379 | { |
380 | unsigned int x, y, z; |
381 | UInt32 tempA[50]; |
382 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) |
383 | tempA[index(x, y, z)] = A[index(x, y, z)]; |
384 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) |
385 | A[index(0 * x + 1 * y, 2 * x + 3 * y, z)] = tempA[index(x, y, z)]; |
386 | } |
387 | |
388 | static void chi(UInt32 *A) |
389 | { |
390 | unsigned int x, y, z; |
391 | UInt32 C[5][2]; |
392 | for (y = 0; y<5; y++) { |
393 | for (x = 0; x<5; x++) |
394 | for (z = 0; z<2; z++) |
395 | C[x][z] = A[index(x, y, z)] ^ ((~A[index(x + 1, y, z)]) & A[index(x + 2, y, z)]); |
396 | for (x = 0; x<5; x++) |
397 | for (z = 0; z<2; z++) |
398 | A[index(x, y, z)] = C[x][z]; |
399 | } |
400 | } |
401 | |
402 | static void iota(UInt32 *A, unsigned int indexRound) |
403 | { |
404 | A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0]; |
405 | A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1]; |
406 | } |
407 | |
408 | void KeccakP1600_PermutationOnWords(UInt32 *state, unsigned int nrRounds) |
409 | { |
410 | for (unsigned int i = (24 - nrRounds); i < 24; i++) |
411 | { |
412 | theta(state); |
413 | rho(state); |
414 | pi(state); |
415 | chi(state); |
416 | iota(state, i); |
417 | } |
418 | } |
419 | |
420 | void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length) |
421 | { |
422 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { |
423 | UInt32 *stateAsHalfLanes = (UInt32*)state; |
424 | UInt32 lane[2]; |
425 | UInt8 laneAsBytes[8]; |
426 | fromBitInterleaving(stateAsHalfLanes[lanePosition * 2], stateAsHalfLanes[lanePosition * 2 + 1], lane, lane + 1); |
427 | laneAsBytes[0] = lane[0] & 0xFF; |
428 | laneAsBytes[1] = (lane[0] >> 8) & 0xFF; |
429 | laneAsBytes[2] = (lane[0] >> 16) & 0xFF; |
430 | laneAsBytes[3] = (lane[0] >> 24) & 0xFF; |
431 | laneAsBytes[4] = lane[1] & 0xFF; |
432 | laneAsBytes[5] = (lane[1] >> 8) & 0xFF; |
433 | laneAsBytes[6] = (lane[1] >> 16) & 0xFF; |
434 | laneAsBytes[7] = (lane[1] >> 24) & 0xFF; |
435 | memcpy(data, laneAsBytes + offset, length); |
436 | } |
437 | } |
438 | |
439 | void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length) |
440 | { |
441 | unsigned int lanePosition = offset / 8; |
442 | unsigned int offsetInLane = offset % 8; |
443 | |
444 | assert(offset < 200); |
445 | assert(offset + length <= 200); |
446 | while (length > 0) { |
447 | unsigned int bytesInLane = 8 - offsetInLane; |
448 | if (bytesInLane > length) |
449 | bytesInLane = length; |
450 | KeccakP1600_ExtractBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); |
451 | length -= bytesInLane; |
452 | lanePosition++; |
453 | offsetInLane = 0; |
454 | data += bytesInLane; |
455 | } |
456 | } |
457 | |
458 | void KeccakP1600_Permute_24rounds(void *state) |
459 | { |
460 | UInt32 *stateAsHalfLanes = (UInt32*)state; |
461 | { |
462 | UInt8 stateAsBytes[1600 / 8]; |
463 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); |
464 | } |
465 | KeccakP1600_PermutationOnWords(stateAsHalfLanes, 24); |
466 | { |
467 | UInt8 stateAsBytes[1600 / 8]; |
468 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); |
469 | } |
470 | } |
471 | #endif |
472 | |
473 | void SHA3Engine::updateImpl(const void* buffer_, std::size_t count) |
474 | { |
475 | if (_context == NULL || buffer_ == NULL || count == 0) return; |
476 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
477 | size_t j; |
478 | unsigned int partialBlock; |
479 | unsigned int rateInBytes = (&pContext->sponge)->rate / 8; |
480 | if ((&pContext->sponge)->squeezing) return; |
481 | size_t i = 0; |
482 | const unsigned char *curData = (const unsigned char *)buffer_; |
483 | while (i < count) { |
484 | if (((&pContext->sponge)->byteIOIndex == 0) && (count >= (i + rateInBytes))) { |
485 | for (j = count - i; j >= rateInBytes; j -= rateInBytes) { |
486 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, 0, rateInBytes); |
487 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); |
488 | curData += rateInBytes; |
489 | } |
490 | i = count - j; |
491 | } |
492 | else { |
493 | partialBlock = (unsigned int)(count - i); |
494 | if (partialBlock + (&pContext->sponge)->byteIOIndex > rateInBytes) |
495 | partialBlock = rateInBytes - (&pContext->sponge)->byteIOIndex; |
496 | i += partialBlock; |
497 | |
498 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, (&pContext->sponge)->byteIOIndex, partialBlock); |
499 | curData += partialBlock; |
500 | (&pContext->sponge)->byteIOIndex += partialBlock; |
501 | if ((&pContext->sponge)->byteIOIndex == rateInBytes) { |
502 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); |
503 | (&pContext->sponge)->byteIOIndex = 0; |
504 | } |
505 | } |
506 | } |
507 | } |
508 | |
509 | std::size_t SHA3Engine::digestLength() const |
510 | { |
511 | return (size_t)((int)_algorithm / 8); |
512 | } |
513 | |
514 | int KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance *instance, unsigned int rate, unsigned int capacity) |
515 | { |
516 | if (rate + capacity != 1600) return 1; |
517 | if ((rate <= 0) || (rate > 1600) || ((rate % 8) != 0)) return 1; |
518 | memset(instance->state, 0, 1600 / 8); |
519 | instance->rate = rate; |
520 | instance->byteIOIndex = 0; |
521 | instance->squeezing = 0; |
522 | return 0; |
523 | } |
524 | |
525 | void SHA3Engine::reset() |
526 | { |
527 | if (_context != NULL) free(_context); |
528 | _context = calloc(1, sizeof(HASHCONTEXT)); |
529 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
530 | switch (_algorithm) |
531 | { |
532 | case SHA3_224: |
533 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1152, 448); |
534 | pContext->fixedOutputLength = 224; |
535 | pContext->delimitedSuffix = 0x06; |
536 | break; |
537 | case SHA3_256: |
538 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1088, 512); |
539 | pContext->fixedOutputLength = 256; |
540 | pContext->delimitedSuffix = 0x06; |
541 | break; |
542 | case SHA3_384: |
543 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 832, 768); |
544 | pContext->fixedOutputLength = 384; |
545 | pContext->delimitedSuffix = 0x06; |
546 | break; |
547 | default: |
548 | case SHA3_512: |
549 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 576, 1024); |
550 | pContext->fixedOutputLength = 512; |
551 | pContext->delimitedSuffix = 0x06; |
552 | break; |
553 | } |
554 | } |
555 | |
556 | int KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) |
557 | { |
558 | unsigned int rateInBytes = instance->rate / 8; |
559 | |
560 | if (delimitedData == 0) |
561 | return 1; |
562 | if (instance->squeezing) |
563 | return 1; /* Too late for additional input */ |
564 | |
565 | /* Last few bits, whose delimiter coincides with first bit of padding */ |
566 | KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex); |
567 | /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ |
568 | if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1))) |
569 | KeccakP1600_Permute_24rounds(instance->state); |
570 | /* Second bit of padding */ |
571 | KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1); |
572 | KeccakP1600_Permute_24rounds(instance->state); |
573 | instance->byteIOIndex = 0; |
574 | instance->squeezing = 1; |
575 | return 0; |
576 | } |
577 | |
578 | int SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) |
579 | { |
580 | unsigned int rateInBytes = instance->rate / 8; |
581 | if (delimitedData == 0) return 1; |
582 | if (instance->squeezing) return 1; /* Too late for additional input */ |
583 | /* Last few bits, whose delimiter coincides with first bit of padding */ |
584 | KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex); |
585 | /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ |
586 | if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1))) |
587 | KeccakP1600_Permute_24rounds(instance->state); |
588 | /* Second bit of padding */ |
589 | KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1); |
590 | KeccakP1600_Permute_24rounds(instance->state); |
591 | instance->byteIOIndex = 0; |
592 | instance->squeezing = 1; |
593 | return 0; |
594 | } |
595 | |
596 | int KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance *instance, unsigned char *data, size_t dataByteLen) |
597 | { |
598 | size_t i, j; |
599 | unsigned int partialBlock; |
600 | unsigned int rateInBytes = instance->rate / 8; |
601 | unsigned char *curData; |
602 | |
603 | if (!instance->squeezing) |
604 | SpongeAbsorbLastFewBits(instance, 0x01); |
605 | |
606 | i = 0; |
607 | curData = data; |
608 | while (i < dataByteLen) { |
609 | if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { |
610 | for (j = dataByteLen - i; j >= rateInBytes; j -= rateInBytes) { |
611 | KeccakP1600_Permute_24rounds(instance->state); |
612 | KeccakP1600_ExtractBytes(instance->state, curData, 0, rateInBytes); |
613 | curData += rateInBytes; |
614 | } |
615 | i = dataByteLen - j; |
616 | } |
617 | else { |
618 | /* normal lane: using the message queue */ |
619 | if (instance->byteIOIndex == rateInBytes) { |
620 | KeccakP1600_Permute_24rounds(instance->state); |
621 | instance->byteIOIndex = 0; |
622 | } |
623 | partialBlock = (unsigned int)(dataByteLen - i); |
624 | if (partialBlock + instance->byteIOIndex > rateInBytes) |
625 | partialBlock = rateInBytes - instance->byteIOIndex; |
626 | i += partialBlock; |
627 | |
628 | KeccakP1600_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); |
629 | curData += partialBlock; |
630 | instance->byteIOIndex += partialBlock; |
631 | } |
632 | } |
633 | return 0; |
634 | } |
635 | |
636 | const DigestEngine::Digest& SHA3Engine::digest() |
637 | { |
638 | _digest.clear(); |
639 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; |
640 | unsigned char hash[64]; |
641 | memset(hash, 0, 64); |
642 | if (KeccakWidth1600_SpongeAbsorbLastFewBits(&pContext->sponge, pContext->delimitedSuffix) == 0) |
643 | KeccakWidth1600_SpongeSqueeze(&pContext->sponge, hash, pContext->fixedOutputLength / 8); |
644 | _digest.insert(_digest.begin(), hash, hash + digestLength()); |
645 | reset(); |
646 | return _digest; |
647 | } |
648 | |
649 | } // namespace Poco |
650 | |