| 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 | static void fromBytesToWords(UInt64 *stateAsWords, const unsigned char *state) | 
|---|
| 220 | { | 
|---|
| 221 | unsigned int i, j; | 
|---|
| 222 | for (i = 0; i < 25; i++) { | 
|---|
| 223 | stateAsWords[i] = 0; | 
|---|
| 224 | for (j = 0; j < (64 / 8); j++) | 
|---|
| 225 | stateAsWords[i] |= (UInt64)(state[i*(64 / 8) + j]) << (8 * j); | 
|---|
| 226 | } | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | void KeccakP1600OnWords(UInt64 *state, unsigned int nrRounds) | 
|---|
| 230 | { | 
|---|
| 231 | for (unsigned int i = (24 - nrRounds); i < 24; i++) KeccakP1600Round(state, i); | 
|---|
| 232 | } | 
|---|
| 233 |  | 
|---|
| 234 | static void fromWordsToBytes(unsigned char *state, const UInt64 *stateAsWords) | 
|---|
| 235 | { | 
|---|
| 236 | unsigned int i, j; | 
|---|
| 237 | for (i = 0; i < 25; i++) | 
|---|
| 238 | for (j = 0; j < (64 / 8); j++) | 
|---|
| 239 | state[i*(64 / 8) + j] = (unsigned char)((stateAsWords[i] >> (8 * j)) & 0xFF); | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | void KeccakP1600_Permute_24rounds(void *state) | 
|---|
| 243 | { | 
|---|
| 244 | #ifndef POCO_ARCH_LITTLE_ENDIAN | 
|---|
| 245 | UInt64 stateAsWords[1600 / 64]; | 
|---|
| 246 | #endif | 
|---|
| 247 | #ifdef POCO_ARCH_LITTLE_ENDIAN | 
|---|
| 248 | KeccakP1600OnWords((UInt64*)state, 24); | 
|---|
| 249 | #else | 
|---|
| 250 | fromBytesToWords(stateAsWords, (const unsigned char *)state); | 
|---|
| 251 | KeccakP1600OnWords(stateAsWords, 24); | 
|---|
| 252 | fromWordsToBytes((unsigned char *)state, stateAsWords); | 
|---|
| 253 | #endif | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | void (const void *state, unsigned char *data, unsigned int offset, unsigned int length) | 
|---|
| 257 | { | 
|---|
| 258 | assert(offset < 200); | 
|---|
| 259 | assert(offset + length <= 200); | 
|---|
| 260 | memcpy(data, (unsigned char*)state + offset, length); | 
|---|
| 261 | } | 
|---|
| 262 | #else | 
|---|
| 263 | void toBitInterleaving(UInt32 low, UInt32 high, UInt32 *even, UInt32 *odd) | 
|---|
| 264 | { | 
|---|
| 265 | unsigned int i; | 
|---|
| 266 |  | 
|---|
| 267 | *even = 0; | 
|---|
| 268 | *odd = 0; | 
|---|
| 269 | for (i = 0; i<64; i++) { | 
|---|
| 270 | unsigned int inBit; | 
|---|
| 271 | if (i < 32) | 
|---|
| 272 | inBit = (low >> i) & 1; | 
|---|
| 273 | else | 
|---|
| 274 | inBit = (high >> (i - 32)) & 1; | 
|---|
| 275 | if ((i % 2) == 0) | 
|---|
| 276 | *even |= inBit << (i / 2); | 
|---|
| 277 | else | 
|---|
| 278 | *odd |= inBit << ((i - 1) / 2); | 
|---|
| 279 | } | 
|---|
| 280 | } | 
|---|
| 281 |  | 
|---|
| 282 | void fromBitInterleaving(UInt32 even, UInt32 odd, UInt32 *low, UInt32 *high) | 
|---|
| 283 | { | 
|---|
| 284 | unsigned int i; | 
|---|
| 285 |  | 
|---|
| 286 | *low = 0; | 
|---|
| 287 | *high = 0; | 
|---|
| 288 | for (i = 0; i<64; i++) { | 
|---|
| 289 | unsigned int inBit; | 
|---|
| 290 | if ((i % 2) == 0) | 
|---|
| 291 | inBit = (even >> (i / 2)) & 1; | 
|---|
| 292 | else | 
|---|
| 293 | inBit = (odd >> ((i - 1) / 2)) & 1; | 
|---|
| 294 | if (i < 32) | 
|---|
| 295 | *low |= inBit << i; | 
|---|
| 296 | else | 
|---|
| 297 | *high |= inBit << (i - 32); | 
|---|
| 298 | } | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length) | 
|---|
| 302 | { | 
|---|
| 303 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { | 
|---|
| 304 | UInt8 laneAsBytes[8]; | 
|---|
| 305 | UInt32 low, high; | 
|---|
| 306 | UInt32 lane[2]; | 
|---|
| 307 | UInt32 *stateAsHalfLanes; | 
|---|
| 308 |  | 
|---|
| 309 | memset(laneAsBytes, 0, 8); | 
|---|
| 310 | memcpy(laneAsBytes + offset, data, length); | 
|---|
| 311 | low = laneAsBytes[0] | 
|---|
| 312 | | ((UInt32)(laneAsBytes[1]) << 8) | 
|---|
| 313 | | ((UInt32)(laneAsBytes[2]) << 16) | 
|---|
| 314 | | ((UInt32)(laneAsBytes[3]) << 24); | 
|---|
| 315 | high = laneAsBytes[4] | 
|---|
| 316 | | ((UInt32)(laneAsBytes[5]) << 8) | 
|---|
| 317 | | ((UInt32)(laneAsBytes[6]) << 16) | 
|---|
| 318 | | ((UInt32)(laneAsBytes[7]) << 24); | 
|---|
| 319 | toBitInterleaving(low, high, lane, lane + 1); | 
|---|
| 320 | stateAsHalfLanes = (UInt32*)state; | 
|---|
| 321 | stateAsHalfLanes[lanePosition * 2 + 0] ^= lane[0]; | 
|---|
| 322 | stateAsHalfLanes[lanePosition * 2 + 1] ^= lane[1]; | 
|---|
| 323 | } | 
|---|
| 324 | } | 
|---|
| 325 |  | 
|---|
| 326 | void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length) | 
|---|
| 327 | { | 
|---|
| 328 | unsigned int lanePosition = offset / 8; | 
|---|
| 329 | unsigned int offsetInLane = offset % 8; | 
|---|
| 330 |  | 
|---|
| 331 | assert(offset < 200); | 
|---|
| 332 | assert(offset + length <= 200); | 
|---|
| 333 | while (length > 0) { | 
|---|
| 334 | unsigned int bytesInLane = 8 - offsetInLane; | 
|---|
| 335 | if (bytesInLane > length) | 
|---|
| 336 | bytesInLane = length; | 
|---|
| 337 | KeccakP1600_AddBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); | 
|---|
| 338 | length -= bytesInLane; | 
|---|
| 339 | lanePosition++; | 
|---|
| 340 | offsetInLane = 0; | 
|---|
| 341 | data += bytesInLane; | 
|---|
| 342 | } | 
|---|
| 343 | } | 
|---|
| 344 |  | 
|---|
| 345 | void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset) | 
|---|
| 346 | { | 
|---|
| 347 | unsigned char data[1]; | 
|---|
| 348 | assert(offset < 200); | 
|---|
| 349 | data[0] = byte; | 
|---|
| 350 | KeccakP1600_AddBytes(state, data, offset, 1); | 
|---|
| 351 | } | 
|---|
| 352 |  | 
|---|
| 353 | #define ROL32(a, offset) ((offset != 0) ? ((((UInt32)a) << offset) ^ (((UInt32)a) >> (32-offset))) : a) | 
|---|
| 354 | #define index(x, y,z) ((((x)%5)+5*((y)%5))*2 + z) | 
|---|
| 355 | void ROL64(UInt32 inEven, UInt32 inOdd, UInt32 *outEven, UInt32 *outOdd, unsigned int offset) | 
|---|
| 356 | { | 
|---|
| 357 | if ((offset % 2) == 0) { | 
|---|
| 358 | *outEven = ROL32(inEven, offset / 2); | 
|---|
| 359 | *outOdd = ROL32(inOdd, offset / 2); | 
|---|
| 360 | } | 
|---|
| 361 | else { | 
|---|
| 362 | *outEven = ROL32(inOdd, (offset + 1) / 2); | 
|---|
| 363 | *outOdd = ROL32(inEven, (offset - 1) / 2); | 
|---|
| 364 | } | 
|---|
| 365 | } | 
|---|
| 366 |  | 
|---|
| 367 | static void theta(UInt32 *A) | 
|---|
| 368 | { | 
|---|
| 369 | unsigned int x, y, z; | 
|---|
| 370 | UInt32 C[5][2], D[5][2]; | 
|---|
| 371 | for (x = 0; x<5; x++) { | 
|---|
| 372 | for (z = 0; z<2; z++) { | 
|---|
| 373 | C[x][z] = 0; | 
|---|
| 374 | for (y = 0; y<5; y++) | 
|---|
| 375 | C[x][z] ^= A[index(x, y, z)]; | 
|---|
| 376 | } | 
|---|
| 377 | } | 
|---|
| 378 | for (x = 0; x<5; x++) { | 
|---|
| 379 | ROL64(C[(x + 1) % 5][0], C[(x + 1) % 5][1], &(D[x][0]), &(D[x][1]), 1); | 
|---|
| 380 | for (z = 0; z<2; z++) | 
|---|
| 381 | D[x][z] ^= C[(x + 4) % 5][z]; | 
|---|
| 382 | } | 
|---|
| 383 | for (x = 0; x<5; x++) | 
|---|
| 384 | for (y = 0; y<5; y++) | 
|---|
| 385 | for (z = 0; z<2; z++) | 
|---|
| 386 | A[index(x, y, z)] ^= D[x][z]; | 
|---|
| 387 | } | 
|---|
| 388 |  | 
|---|
| 389 | static void rho(UInt32 *A) | 
|---|
| 390 | { | 
|---|
| 391 | unsigned int x, y; | 
|---|
| 392 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) | 
|---|
| 393 | 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]); | 
|---|
| 394 | } | 
|---|
| 395 |  | 
|---|
| 396 | static void pi(UInt32 *A) | 
|---|
| 397 | { | 
|---|
| 398 | unsigned int x, y, z; | 
|---|
| 399 | UInt32 tempA[50]; | 
|---|
| 400 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) | 
|---|
| 401 | tempA[index(x, y, z)] = A[index(x, y, z)]; | 
|---|
| 402 | for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++) | 
|---|
| 403 | A[index(0 * x + 1 * y, 2 * x + 3 * y, z)] = tempA[index(x, y, z)]; | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 | static void chi(UInt32 *A) | 
|---|
| 407 | { | 
|---|
| 408 | unsigned int x, y, z; | 
|---|
| 409 | UInt32 C[5][2]; | 
|---|
| 410 | for (y = 0; y<5; y++) { | 
|---|
| 411 | for (x = 0; x<5; x++) | 
|---|
| 412 | for (z = 0; z<2; z++) | 
|---|
| 413 | C[x][z] = A[index(x, y, z)] ^ ((~A[index(x + 1, y, z)]) & A[index(x + 2, y, z)]); | 
|---|
| 414 | for (x = 0; x<5; x++) | 
|---|
| 415 | for (z = 0; z<2; z++) | 
|---|
| 416 | A[index(x, y, z)] = C[x][z]; | 
|---|
| 417 | } | 
|---|
| 418 | } | 
|---|
| 419 |  | 
|---|
| 420 | static void iota(UInt32 *A, unsigned int indexRound) | 
|---|
| 421 | { | 
|---|
| 422 | A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0]; | 
|---|
| 423 | A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1]; | 
|---|
| 424 | } | 
|---|
| 425 |  | 
|---|
| 426 | void KeccakP1600_PermutationOnWords(UInt32 *state, unsigned int nrRounds) | 
|---|
| 427 | { | 
|---|
| 428 | for (unsigned int i = (24 - nrRounds); i < 24; i++) | 
|---|
| 429 | { | 
|---|
| 430 | theta(state); | 
|---|
| 431 | rho(state); | 
|---|
| 432 | pi(state); | 
|---|
| 433 | chi(state); | 
|---|
| 434 | iota(state, i); | 
|---|
| 435 | } | 
|---|
| 436 | } | 
|---|
| 437 |  | 
|---|
| 438 | void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length) | 
|---|
| 439 | { | 
|---|
| 440 | if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) { | 
|---|
| 441 | UInt32 *stateAsHalfLanes = (UInt32*)state; | 
|---|
| 442 | UInt32 lane[2]; | 
|---|
| 443 | UInt8 laneAsBytes[8]; | 
|---|
| 444 | fromBitInterleaving(stateAsHalfLanes[lanePosition * 2], stateAsHalfLanes[lanePosition * 2 + 1], lane, lane + 1); | 
|---|
| 445 | laneAsBytes[0] = lane[0] & 0xFF; | 
|---|
| 446 | laneAsBytes[1] = (lane[0] >> 8) & 0xFF; | 
|---|
| 447 | laneAsBytes[2] = (lane[0] >> 16) & 0xFF; | 
|---|
| 448 | laneAsBytes[3] = (lane[0] >> 24) & 0xFF; | 
|---|
| 449 | laneAsBytes[4] = lane[1] & 0xFF; | 
|---|
| 450 | laneAsBytes[5] = (lane[1] >> 8) & 0xFF; | 
|---|
| 451 | laneAsBytes[6] = (lane[1] >> 16) & 0xFF; | 
|---|
| 452 | laneAsBytes[7] = (lane[1] >> 24) & 0xFF; | 
|---|
| 453 | memcpy(data, laneAsBytes + offset, length); | 
|---|
| 454 | } | 
|---|
| 455 | } | 
|---|
| 456 |  | 
|---|
| 457 | void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length) | 
|---|
| 458 | { | 
|---|
| 459 | unsigned int lanePosition = offset / 8; | 
|---|
| 460 | unsigned int offsetInLane = offset % 8; | 
|---|
| 461 |  | 
|---|
| 462 | assert(offset < 200); | 
|---|
| 463 | assert(offset + length <= 200); | 
|---|
| 464 | while (length > 0) { | 
|---|
| 465 | unsigned int bytesInLane = 8 - offsetInLane; | 
|---|
| 466 | if (bytesInLane > length) | 
|---|
| 467 | bytesInLane = length; | 
|---|
| 468 | KeccakP1600_ExtractBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane); | 
|---|
| 469 | length -= bytesInLane; | 
|---|
| 470 | lanePosition++; | 
|---|
| 471 | offsetInLane = 0; | 
|---|
| 472 | data += bytesInLane; | 
|---|
| 473 | } | 
|---|
| 474 | } | 
|---|
| 475 |  | 
|---|
| 476 | void KeccakP1600_Permute_24rounds(void *state) | 
|---|
| 477 | { | 
|---|
| 478 | UInt32 *stateAsHalfLanes = (UInt32*)state; | 
|---|
| 479 | { | 
|---|
| 480 | UInt8 stateAsBytes[1600 / 8]; | 
|---|
| 481 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); | 
|---|
| 482 | } | 
|---|
| 483 | KeccakP1600_PermutationOnWords(stateAsHalfLanes, 24); | 
|---|
| 484 | { | 
|---|
| 485 | UInt8 stateAsBytes[1600 / 8]; | 
|---|
| 486 | KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8); | 
|---|
| 487 | } | 
|---|
| 488 | } | 
|---|
| 489 | #endif | 
|---|
| 490 |  | 
|---|
| 491 | void SHA3Engine::updateImpl(const void* buffer_, std::size_t count) | 
|---|
| 492 | { | 
|---|
| 493 | if (_context == NULL || buffer_ == NULL || count == 0) return; | 
|---|
| 494 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; | 
|---|
| 495 | size_t j; | 
|---|
| 496 | unsigned int partialBlock; | 
|---|
| 497 | unsigned int rateInBytes = (&pContext->sponge)->rate / 8; | 
|---|
| 498 | if ((&pContext->sponge)->squeezing) return; | 
|---|
| 499 | size_t i = 0; | 
|---|
| 500 | const unsigned char *curData = (const unsigned char *)buffer_; | 
|---|
| 501 | while (i < count) { | 
|---|
| 502 | if (((&pContext->sponge)->byteIOIndex == 0) && (count >= (i + rateInBytes))) { | 
|---|
| 503 | for (j = count - i; j >= rateInBytes; j -= rateInBytes) { | 
|---|
| 504 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, 0, rateInBytes); | 
|---|
| 505 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); | 
|---|
| 506 | curData += rateInBytes; | 
|---|
| 507 | } | 
|---|
| 508 | i = count - j; | 
|---|
| 509 | } | 
|---|
| 510 | else { | 
|---|
| 511 | partialBlock = (unsigned int)(count - i); | 
|---|
| 512 | if (partialBlock + (&pContext->sponge)->byteIOIndex > rateInBytes) | 
|---|
| 513 | partialBlock = rateInBytes - (&pContext->sponge)->byteIOIndex; | 
|---|
| 514 | i += partialBlock; | 
|---|
| 515 |  | 
|---|
| 516 | KeccakP1600_AddBytes((&pContext->sponge)->state, curData, (&pContext->sponge)->byteIOIndex, partialBlock); | 
|---|
| 517 | curData += partialBlock; | 
|---|
| 518 | (&pContext->sponge)->byteIOIndex += partialBlock; | 
|---|
| 519 | if ((&pContext->sponge)->byteIOIndex == rateInBytes) { | 
|---|
| 520 | KeccakP1600_Permute_24rounds((&pContext->sponge)->state); | 
|---|
| 521 | (&pContext->sponge)->byteIOIndex = 0; | 
|---|
| 522 | } | 
|---|
| 523 | } | 
|---|
| 524 | } | 
|---|
| 525 | } | 
|---|
| 526 |  | 
|---|
| 527 | std::size_t SHA3Engine::digestLength() const | 
|---|
| 528 | { | 
|---|
| 529 | return (size_t)((int)_algorithm / 8); | 
|---|
| 530 | } | 
|---|
| 531 |  | 
|---|
| 532 | int KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance *instance, unsigned int rate, unsigned int capacity) | 
|---|
| 533 | { | 
|---|
| 534 | if (rate + capacity != 1600) return 1; | 
|---|
| 535 | if ((rate <= 0) || (rate > 1600) || ((rate % 8) != 0)) return 1; | 
|---|
| 536 | memset(instance->state, 0, 1600 / 8); | 
|---|
| 537 | instance->rate = rate; | 
|---|
| 538 | instance->byteIOIndex = 0; | 
|---|
| 539 | instance->squeezing = 0; | 
|---|
| 540 | return 0; | 
|---|
| 541 | } | 
|---|
| 542 |  | 
|---|
| 543 | void SHA3Engine::reset() | 
|---|
| 544 | { | 
|---|
| 545 | if (_context != NULL) free(_context); | 
|---|
| 546 | _context = calloc(1, sizeof(HASHCONTEXT)); | 
|---|
| 547 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; | 
|---|
| 548 | switch (_algorithm) | 
|---|
| 549 | { | 
|---|
| 550 | case SHA3_224: | 
|---|
| 551 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1152, 448); | 
|---|
| 552 | pContext->fixedOutputLength = 224; | 
|---|
| 553 | pContext->delimitedSuffix = 0x06; | 
|---|
| 554 | break; | 
|---|
| 555 | case SHA3_256: | 
|---|
| 556 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1088, 512); | 
|---|
| 557 | pContext->fixedOutputLength = 256; | 
|---|
| 558 | pContext->delimitedSuffix = 0x06; | 
|---|
| 559 | break; | 
|---|
| 560 | case SHA3_384: | 
|---|
| 561 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 832, 768); | 
|---|
| 562 | pContext->fixedOutputLength = 384; | 
|---|
| 563 | pContext->delimitedSuffix = 0x06; | 
|---|
| 564 | break; | 
|---|
| 565 | default: | 
|---|
| 566 | case SHA3_512: | 
|---|
| 567 | KeccakWidth1600_SpongeInitialize(&pContext->sponge, 576, 1024); | 
|---|
| 568 | pContext->fixedOutputLength = 512; | 
|---|
| 569 | pContext->delimitedSuffix = 0x06; | 
|---|
| 570 | break; | 
|---|
| 571 | } | 
|---|
| 572 | } | 
|---|
| 573 |  | 
|---|
| 574 | int KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) | 
|---|
| 575 | { | 
|---|
| 576 | unsigned int rateInBytes = instance->rate / 8; | 
|---|
| 577 |  | 
|---|
| 578 | if (delimitedData == 0) | 
|---|
| 579 | return 1; | 
|---|
| 580 | if (instance->squeezing) | 
|---|
| 581 | return 1; /* Too late for additional input */ | 
|---|
| 582 |  | 
|---|
| 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 SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData) | 
|---|
| 597 | { | 
|---|
| 598 | unsigned int rateInBytes = instance->rate / 8; | 
|---|
| 599 | if (delimitedData == 0) return 1; | 
|---|
| 600 | if (instance->squeezing) return 1; /* Too late for additional input */ | 
|---|
| 601 | /* Last few bits, whose delimiter coincides with first bit of padding */ | 
|---|
| 602 | KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex); | 
|---|
| 603 | /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */ | 
|---|
| 604 | if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1))) | 
|---|
| 605 | KeccakP1600_Permute_24rounds(instance->state); | 
|---|
| 606 | /* Second bit of padding */ | 
|---|
| 607 | KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1); | 
|---|
| 608 | KeccakP1600_Permute_24rounds(instance->state); | 
|---|
| 609 | instance->byteIOIndex = 0; | 
|---|
| 610 | instance->squeezing = 1; | 
|---|
| 611 | return 0; | 
|---|
| 612 | } | 
|---|
| 613 |  | 
|---|
| 614 | int KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance *instance, unsigned char *data, size_t dataByteLen) | 
|---|
| 615 | { | 
|---|
| 616 | size_t i, j; | 
|---|
| 617 | unsigned int partialBlock; | 
|---|
| 618 | unsigned int rateInBytes = instance->rate / 8; | 
|---|
| 619 | unsigned char *curData; | 
|---|
| 620 |  | 
|---|
| 621 | if (!instance->squeezing) | 
|---|
| 622 | SpongeAbsorbLastFewBits(instance, 0x01); | 
|---|
| 623 |  | 
|---|
| 624 | i = 0; | 
|---|
| 625 | curData = data; | 
|---|
| 626 | while (i < dataByteLen) { | 
|---|
| 627 | if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) { | 
|---|
| 628 | for (j = dataByteLen - i; j >= rateInBytes; j -= rateInBytes) { | 
|---|
| 629 | KeccakP1600_Permute_24rounds(instance->state); | 
|---|
| 630 | KeccakP1600_ExtractBytes(instance->state, curData, 0, rateInBytes); | 
|---|
| 631 | curData += rateInBytes; | 
|---|
| 632 | } | 
|---|
| 633 | i = dataByteLen - j; | 
|---|
| 634 | } | 
|---|
| 635 | else { | 
|---|
| 636 | /* normal lane: using the message queue */ | 
|---|
| 637 | if (instance->byteIOIndex == rateInBytes) { | 
|---|
| 638 | KeccakP1600_Permute_24rounds(instance->state); | 
|---|
| 639 | instance->byteIOIndex = 0; | 
|---|
| 640 | } | 
|---|
| 641 | partialBlock = (unsigned int)(dataByteLen - i); | 
|---|
| 642 | if (partialBlock + instance->byteIOIndex > rateInBytes) | 
|---|
| 643 | partialBlock = rateInBytes - instance->byteIOIndex; | 
|---|
| 644 | i += partialBlock; | 
|---|
| 645 |  | 
|---|
| 646 | KeccakP1600_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock); | 
|---|
| 647 | curData += partialBlock; | 
|---|
| 648 | instance->byteIOIndex += partialBlock; | 
|---|
| 649 | } | 
|---|
| 650 | } | 
|---|
| 651 | return 0; | 
|---|
| 652 | } | 
|---|
| 653 |  | 
|---|
| 654 | const DigestEngine::Digest& SHA3Engine::digest() | 
|---|
| 655 | { | 
|---|
| 656 | _digest.clear(); | 
|---|
| 657 | HASHCONTEXT* pContext = (HASHCONTEXT*)_context; | 
|---|
| 658 | unsigned char hash[64]; | 
|---|
| 659 | memset(hash, 0, 64); | 
|---|
| 660 | if (KeccakWidth1600_SpongeAbsorbLastFewBits(&pContext->sponge, pContext->delimitedSuffix) == 0) | 
|---|
| 661 | KeccakWidth1600_SpongeSqueeze(&pContext->sponge, hash, pContext->fixedOutputLength / 8); | 
|---|
| 662 | _digest.insert(_digest.begin(), hash, hash + digestLength()); | 
|---|
| 663 | reset(); | 
|---|
| 664 | return _digest; | 
|---|
| 665 | } | 
|---|
| 666 |  | 
|---|
| 667 | } // namespace Poco | 
|---|
| 668 |  | 
|---|