Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Sha3.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | #include "precomp.h" |
8 | | |
9 | | // |
10 | | // See the symcrypt.h file for documentation on what the various functions do. |
11 | | // |
12 | | |
13 | | |
14 | | // |
15 | | // Keccak state |
16 | | // |
17 | | // Keccak-f[1600] state consists of 25 64-bit words. We represent this state as a single |
18 | | // dimensional array of 25 elements (Wi being the i^th element of the array for i=0..24) |
19 | | // with the following mapping to two dimensional coordinates. Note that in FIPS 202 Figure 2, |
20 | | // the element W0 at (x,y)=(0,0) is depicted in the middle of the 5x5 array. We set W0 |
21 | | // to be the first element so that the rate part of the permutation maps to the beginning |
22 | | // of the state. |
23 | | // |
24 | | // x=0 x=1 x=2 x=3 x=4 |
25 | | // ----------------------- |
26 | | // y=0 W0 W1 W2 W3 W4 |
27 | | // y=1 W5 W6 W7 W8 W9 |
28 | | // y=2 W10 W11 W12 W13 W14 |
29 | | // y=3 W15 W16 W17 W18 W19 |
30 | | // y=4 W20 W21 W22 W23 W24 |
31 | | |
32 | | |
33 | | |
34 | | // Rotation constants for Keccak Rho transformation |
35 | | static const UINT8 KeccakRhoK[25] = { |
36 | | 0, 1, 62, 28, 27, // y = 0 |
37 | | 36, 44, 6, 55, 20, // y = 1 |
38 | | 3, 10, 43, 25, 39, // y = 2 |
39 | | 41, 45, 15, 21, 8, // y = 3 |
40 | | 18, 2, 61, 56, 14, // y = 4 |
41 | | }; |
42 | | |
43 | | // Keccak round constants |
44 | | static UINT64 KeccakIotaK[24] = { |
45 | | 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, |
46 | | 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, |
47 | | 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, |
48 | | 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, |
49 | | 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, |
50 | | 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL |
51 | | }; |
52 | | |
53 | | // XOR sum of column c of the state |
54 | | #define KECCAK_COLUMN_SUM(state, c) \ |
55 | 9.64M | (state[0 + (c)] ^ state[5 + (c)] ^ state[10 + (c)] ^ state[15 + (c)] ^ state[20 + (c)]) |
56 | | |
57 | | // XOR w to all the lanes in column c of the state |
58 | | // |
59 | | // Note: The expression to be XORed is copied to a temporary variable to avoid reevaluation |
60 | 9.64M | #define KECCAK_COLUMN_UPDATE(state, c, w) { \ |
61 | 9.64M | UINT64 t = (w); \ |
62 | 9.64M | state[ 0 + (c)] ^= t; \ |
63 | 9.64M | state[ 5 + (c)] ^= t; \ |
64 | 9.64M | state[10 + (c)] ^= t; \ |
65 | 9.64M | state[15 + (c)] ^= t; \ |
66 | 9.64M | state[20 + (c)] ^= t; \ |
67 | 9.64M | } |
68 | | |
69 | | // Apply Theta transformation to the state |
70 | 1.92M | #define KECCAK_THETA(state) { \ |
71 | 1.92M | UINT64 colSum[5]; \ |
72 | 1.92M | colSum[0] = KECCAK_COLUMN_SUM(state, 0); \ |
73 | 1.92M | colSum[1] = KECCAK_COLUMN_SUM(state, 1); \ |
74 | 1.92M | colSum[2] = KECCAK_COLUMN_SUM(state, 2); \ |
75 | 1.92M | colSum[3] = KECCAK_COLUMN_SUM(state, 3); \ |
76 | 1.92M | colSum[4] = KECCAK_COLUMN_SUM(state, 4); \ |
77 | 1.92M | KECCAK_COLUMN_UPDATE(state, 0, colSum[4] ^ ROL64(colSum[1], 1)); \ |
78 | 1.92M | KECCAK_COLUMN_UPDATE(state, 1, colSum[0] ^ ROL64(colSum[2], 1)); \ |
79 | 1.92M | KECCAK_COLUMN_UPDATE(state, 2, colSum[1] ^ ROL64(colSum[3], 1)); \ |
80 | 1.92M | KECCAK_COLUMN_UPDATE(state, 3, colSum[2] ^ ROL64(colSum[4], 1)); \ |
81 | 1.92M | KECCAK_COLUMN_UPDATE(state, 4, colSum[3] ^ ROL64(colSum[0], 1)); \ |
82 | 1.92M | } |
83 | | |
84 | | // Apply Rho transformation to row r of the state |
85 | 7.71M | #define KECCAK_RHO_ROW(state, r) { \ |
86 | 7.71M | state[5 * (r) + 0] = ROL64(state[5 * (r) + 0], KeccakRhoK[5 * (r) + 0]); \ |
87 | 7.71M | state[5 * (r) + 1] = ROL64(state[5 * (r) + 1], KeccakRhoK[5 * (r) + 1]); \ |
88 | 7.71M | state[5 * (r) + 2] = ROL64(state[5 * (r) + 2], KeccakRhoK[5 * (r) + 2]); \ |
89 | 7.71M | state[5 * (r) + 3] = ROL64(state[5 * (r) + 3], KeccakRhoK[5 * (r) + 3]); \ |
90 | 7.71M | state[5 * (r) + 4] = ROL64(state[5 * (r) + 4], KeccakRhoK[5 * (r) + 4]); \ |
91 | 7.71M | } |
92 | | |
93 | | // Apply Rho transformation to row 0 of the state |
94 | | // |
95 | | // The first row contains a rotation by 0 on the first lane that uses a shift |
96 | | // by 64 which we want to avoid. Rho operation below omits the rotation on the first lane. |
97 | 1.92M | #define KECCAK_RHO_ROW0(state) { \ |
98 | 1.92M | state[1] = ROL64(state[1], KeccakRhoK[1]); \ |
99 | 1.92M | state[2] = ROL64(state[2], KeccakRhoK[2]); \ |
100 | 1.92M | state[3] = ROL64(state[3], KeccakRhoK[3]); \ |
101 | 1.92M | state[4] = ROL64(state[4], KeccakRhoK[4]); \ |
102 | 1.92M | } |
103 | | |
104 | | // Apply Rho transformation to the state |
105 | 1.92M | #define KECCAK_RHO(state) { \ |
106 | 1.92M | KECCAK_RHO_ROW0(state); \ |
107 | 1.92M | KECCAK_RHO_ROW(state, 1); \ |
108 | 1.92M | KECCAK_RHO_ROW(state, 2); \ |
109 | 1.92M | KECCAK_RHO_ROW(state, 3); \ |
110 | 1.92M | KECCAK_RHO_ROW(state, 4); \ |
111 | 1.92M | } |
112 | | |
113 | | // Apply Pi transformation to the state |
114 | 1.92M | #define KECCAK_PI(state) { \ |
115 | 1.92M | UINT64 t = state[ 1]; state[ 1] = state[ 6]; state[ 6] = state[ 9]; state[ 9] = state[22]; state[22] = state[14]; \ |
116 | 1.92M | state[14] = state[20]; state[20] = state[ 2]; state[ 2] = state[12]; state[12] = state[13]; state[13] = state[19]; \ |
117 | 1.92M | state[19] = state[23]; state[23] = state[15]; state[15] = state[ 4]; state[ 4] = state[24]; state[24] = state[21]; \ |
118 | 1.92M | state[21] = state[ 8]; state[ 8] = state[16]; state[16] = state[ 5]; state[ 5] = state[ 3]; state[ 3] = state[18]; \ |
119 | 1.92M | state[18] = state[17]; state[17] = state[11]; state[11] = state[ 7]; state[ 7] = state[10]; state[10] = t; \ |
120 | 1.92M | } |
121 | | |
122 | | // Apply Chi transformation on row r of state |
123 | 9.64M | #define KECCAK_CHI_ROW(state, r) { \ |
124 | 9.64M | UINT64 t1 = state[5 * (r) + 0] ^ (~state[5 * (r) + 1] & state[5 * (r) + 2]); \ |
125 | 9.64M | UINT64 t2 = state[5 * (r) + 1] ^ (~state[5 * (r) + 2] & state[5 * (r) + 3]); \ |
126 | 9.64M | state[5 * (r) + 2] = state[5 * (r) + 2] ^ (~state[5 * (r) + 3] & state[5 * (r) + 4]); \ |
127 | 9.64M | state[5 * (r) + 3] = state[5 * (r) + 3] ^ (~state[5 * (r) + 4] & state[5 * (r) + 0]); \ |
128 | 9.64M | state[5 * (r) + 4] = state[5 * (r) + 4] ^ (~state[5 * (r) + 0] & state[5 * (r) + 1]); \ |
129 | 9.64M | state[5 * (r) + 0] = t1; \ |
130 | 9.64M | state[5 * (r) + 1] = t2; \ |
131 | 9.64M | } |
132 | | |
133 | | // Apply Chi transformation to state |
134 | 1.92M | #define KECCAK_CHI(state) { \ |
135 | 1.92M | KECCAK_CHI_ROW(state, 0); \ |
136 | 1.92M | KECCAK_CHI_ROW(state, 1); \ |
137 | 1.92M | KECCAK_CHI_ROW(state, 2); \ |
138 | 1.92M | KECCAK_CHI_ROW(state, 3); \ |
139 | 1.92M | KECCAK_CHI_ROW(state, 4); \ |
140 | 1.92M | } |
141 | | |
142 | | // Add round constant to state |
143 | 1.92M | #define KECCAK_IOTA(state, rnd) state[0] ^= KeccakIotaK[rnd] |
144 | | |
145 | | // Perform one round of Keccak permutation on state |
146 | 1.92M | #define KECCAK_PERM_ROUND(state, rnd) { \ |
147 | 1.92M | KECCAK_THETA(state); \ |
148 | 1.92M | KECCAK_RHO(state); \ |
149 | 1.92M | KECCAK_PI(state); \ |
150 | 1.92M | KECCAK_CHI(state); \ |
151 | 1.92M | KECCAK_IOTA(state, rnd); \ |
152 | 1.92M | } |
153 | | |
154 | | |
155 | | // |
156 | | // SymCryptKeccakPermute |
157 | | // |
158 | | VOID |
159 | | SYMCRYPT_CALL |
160 | | SymCryptKeccakPermute(_Inout_updates_(25) UINT64* pState) |
161 | 80.4k | { |
162 | 2.01M | for (int r = 0; r < 24; r++) |
163 | 1.92M | { |
164 | 1.92M | KECCAK_PERM_ROUND(pState, r); |
165 | 1.92M | } |
166 | 80.4k | } |
167 | | |
168 | | |
169 | | // |
170 | | // SymCryptKeccakInit |
171 | | // |
172 | | VOID |
173 | | SYMCRYPT_CALL |
174 | | SymCryptKeccakInit(_Out_ PSYMCRYPT_KECCAK_STATE pState, UINT32 inputBlockSize, UINT8 paddingValue) |
175 | 263 | { |
176 | 263 | pState->inputBlockSize = inputBlockSize; |
177 | 263 | pState->paddingValue = paddingValue; |
178 | | |
179 | | // Initialize the Keccak permutation state and set mutable state variables |
180 | | // to their default values. |
181 | 263 | SymCryptKeccakReset(pState); |
182 | 263 | } |
183 | | |
184 | | VOID |
185 | | SYMCRYPT_CALL |
186 | | SymCryptKeccakReset(_Out_ PSYMCRYPT_KECCAK_STATE pState) |
187 | 526 | { |
188 | | // |
189 | | // Wipe & re-initialize |
190 | | // |
191 | | // Wipe the Keccak permutation state and set the mutable state variables to their |
192 | | // default values. Non-mutable state variables retain their values. State becomes |
193 | | // re-initialized after this call. |
194 | 526 | SymCryptWipeKnownSize(pState->state, sizeof(pState->state)); |
195 | 526 | pState->stateIndex = 0; |
196 | 526 | pState->squeezeMode = FALSE; |
197 | 526 | } |
198 | | |
199 | | // |
200 | | // SymCryptKeccakAppendByte |
201 | | // |
202 | | FORCEINLINE |
203 | | VOID |
204 | | SYMCRYPT_CALL |
205 | | SymCryptKeccakAppendByte(_Inout_ PSYMCRYPT_KECCAK_STATE pState, BYTE val) |
206 | 4.11k | { |
207 | 4.11k | SYMCRYPT_ASSERT(!pState->squeezeMode); |
208 | 4.11k | SYMCRYPT_ASSERT(pState->stateIndex < pState->inputBlockSize); |
209 | | |
210 | 4.11k | pState->state[pState->stateIndex / sizeof(UINT64)] ^= ((UINT64)val << (8 * (pState->stateIndex % 8))); |
211 | 4.11k | pState->stateIndex++; |
212 | 4.11k | } |
213 | | |
214 | | // |
215 | | // SymCryptKeccakAppendBytes |
216 | | // |
217 | | FORCEINLINE |
218 | | VOID |
219 | | SYMCRYPT_CALL |
220 | | SymCryptKeccakAppendBytes(_Inout_ PSYMCRYPT_KECCAK_STATE pState, PCBYTE pbBuffer, SIZE_T cbBuffer) |
221 | 41.7k | { |
222 | 41.7k | SYMCRYPT_ASSERT(!pState->squeezeMode); |
223 | 41.7k | SYMCRYPT_ASSERT((pState->stateIndex + cbBuffer) <= pState->inputBlockSize); |
224 | | |
225 | 46.3k | for (SIZE_T i = 0; i < cbBuffer; i++) |
226 | 4.57k | { |
227 | 4.57k | pState->state[(pState->stateIndex + i) / sizeof(UINT64)] ^= ((UINT64)pbBuffer[i] << (8 * ((pState->stateIndex + i) % 8))); |
228 | 4.57k | } |
229 | | |
230 | 41.7k | pState->stateIndex += (UINT32)cbBuffer; |
231 | 41.7k | } |
232 | | |
233 | | |
234 | | // |
235 | | // SymCryptKeccakAppendLanes |
236 | | // |
237 | | VOID |
238 | | SYMCRYPT_CALL |
239 | | SymCryptKeccakAppendLanes( |
240 | | _Inout_ PSYMCRYPT_KECCAK_STATE pState, |
241 | | _In_reads_(uLaneCount * sizeof(UINT64)) PCBYTE pbData, |
242 | | SIZE_T uLaneCount) |
243 | 1.11k | { |
244 | 1.11k | SYMCRYPT_ASSERT(!pState->squeezeMode); |
245 | 1.11k | SYMCRYPT_ASSERT((pState->inputBlockSize & 0x7) == 0); |
246 | 1.11k | SYMCRYPT_ASSERT((pState->stateIndex & 0x7) == 0); |
247 | 1.11k | SYMCRYPT_ASSERT(pState->stateIndex != pState->inputBlockSize); |
248 | | |
249 | | // Locate the lane in the state for next append. |
250 | | // Currently, pState->stateIndex/sizeof(UINT64) of the lanes are used. |
251 | 1.11k | UINT32 uLaneIndex = pState->stateIndex / sizeof(UINT64); |
252 | | |
253 | 1.00M | for (SIZE_T i = 0; i < uLaneCount; i++) |
254 | 1.00M | { |
255 | 1.00M | pState->state[uLaneIndex] ^= SYMCRYPT_LOAD_LSBFIRST64(pbData + i * sizeof(UINT64)); |
256 | 1.00M | pState->stateIndex += sizeof(UINT64); |
257 | 1.00M | uLaneIndex++; |
258 | | |
259 | 1.00M | if (pState->stateIndex == pState->inputBlockSize) |
260 | 80.0k | { |
261 | 80.0k | SymCryptKeccakPermute(pState->state); |
262 | 80.0k | pState->stateIndex = 0; |
263 | 80.0k | uLaneIndex = 0; |
264 | 80.0k | } |
265 | 1.00M | } |
266 | 1.11k | } |
267 | | |
268 | | // |
269 | | // SymCryptKeccakZeroAppendBlock |
270 | | // |
271 | | VOID |
272 | | SYMCRYPT_CALL |
273 | | SymCryptKeccakZeroAppendBlock(_Inout_ PSYMCRYPT_KECCAK_STATE pState) |
274 | 0 | { |
275 | 0 | SYMCRYPT_ASSERT(!pState->squeezeMode); |
276 | 0 | SymCryptKeccakPermute(pState->state); |
277 | 0 | pState->stateIndex = 0; |
278 | 0 | } |
279 | | |
280 | | // |
281 | | // SymCryptKeccakAppend |
282 | | // |
283 | | VOID |
284 | | SYMCRYPT_CALL |
285 | | SymCryptKeccakAppend( |
286 | | _Inout_ PSYMCRYPT_KECCAK_STATE pState, |
287 | | _In_reads_(cbData) PCBYTE pbData, |
288 | | SIZE_T cbData) |
289 | 41.7k | { |
290 | 41.7k | SYMCRYPT_ASSERT(pState->inputBlockSize % 8 == 0); |
291 | | |
292 | | // If we were in squeeze mode (Append is called after an Extract without wiping), |
293 | | // switch to absorb mode to start a new hash computation. |
294 | 41.7k | if (pState->squeezeMode) |
295 | 0 | { |
296 | 0 | SymCryptKeccakReset(pState); |
297 | 0 | } |
298 | | |
299 | 41.7k | SYMCRYPT_ASSERT(pState->stateIndex < pState->inputBlockSize); |
300 | | |
301 | | // Make pState->stateIndex a multiple of 8. |
302 | | // Message block boundary will not be crossed, check |
303 | | // if permutation is needed after this part. |
304 | 45.8k | while (cbData > 0 && (pState->stateIndex & 0x7)) |
305 | 4.11k | { |
306 | 4.11k | SymCryptKeccakAppendByte(pState, *pbData); |
307 | 4.11k | pbData++; |
308 | 4.11k | cbData--; |
309 | 4.11k | } |
310 | | |
311 | | // Permute if input message block is filled |
312 | 41.7k | if (pState->stateIndex == pState->inputBlockSize) |
313 | 98 | { |
314 | 98 | SymCryptKeccakPermute(pState->state); |
315 | 98 | pState->stateIndex = 0; |
316 | 98 | } |
317 | | |
318 | | // Append full lanes |
319 | 41.7k | SIZE_T uFullLanes = cbData / sizeof(UINT64); |
320 | 41.7k | if (uFullLanes > 0) |
321 | 1.11k | { |
322 | 1.11k | SymCryptKeccakAppendLanes(pState, pbData, uFullLanes); |
323 | 1.11k | pbData += uFullLanes * sizeof(UINT64); |
324 | 1.11k | cbData -= uFullLanes * sizeof(UINT64); |
325 | 1.11k | } |
326 | | |
327 | 41.7k | SYMCRYPT_ASSERT(cbData < sizeof(UINT64)); |
328 | 41.7k | SymCryptKeccakAppendBytes(pState, pbData, cbData); |
329 | | |
330 | 41.7k | SYMCRYPT_ASSERT(pState->stateIndex != pState->inputBlockSize); |
331 | 41.7k | } |
332 | | |
333 | | // |
334 | | // SymCryptKeccakApplyPadding |
335 | | // |
336 | | VOID |
337 | | SYMCRYPT_CALL |
338 | | SymCryptKeccakApplyPadding(_Inout_ PSYMCRYPT_KECCAK_STATE pState) |
339 | 263 | { |
340 | 263 | SYMCRYPT_ASSERT(!pState->squeezeMode); |
341 | | |
342 | | // Locate the lane and byte position for the padding byte |
343 | 263 | UINT32 uLanePos = pState->stateIndex / sizeof(UINT64); |
344 | 263 | UINT32 uBytePos = pState->stateIndex % sizeof(UINT64); |
345 | 263 | pState->state[uLanePos] ^= ((UINT64)pState->paddingValue << (8 * uBytePos)); |
346 | | |
347 | | // Pad the final 1 bit to the msb of the last lane in the rate portion of the state |
348 | 263 | pState->state[pState->inputBlockSize / sizeof(UINT64) - 1] ^= (1ULL << 63); |
349 | | |
350 | | // Process the padded block and switch to squeeze mode |
351 | 263 | SymCryptKeccakPermute(pState->state); |
352 | 263 | pState->stateIndex = 0; |
353 | 263 | pState->squeezeMode = TRUE; |
354 | 263 | } |
355 | | |
356 | | // |
357 | | // SymCryptKeccakExtractByte |
358 | | // |
359 | | FORCEINLINE |
360 | | BYTE |
361 | | SYMCRYPT_CALL |
362 | | SymCryptKeccakExtractByte(_Inout_ PSYMCRYPT_KECCAK_STATE pState) |
363 | 0 | { |
364 | 0 | SYMCRYPT_ASSERT(pState->squeezeMode); |
365 | 0 | SYMCRYPT_ASSERT(pState->stateIndex < pState->inputBlockSize); |
366 | |
|
367 | 0 | BYTE ret = (BYTE)((pState->state[pState->stateIndex / sizeof(UINT64)] >> (8 * (pState->stateIndex % 8))) & 0xff); |
368 | 0 | pState->stateIndex++; |
369 | 0 | return ret; |
370 | 0 | } |
371 | | |
372 | | // |
373 | | // SymCryptKeccakExtractLanes |
374 | | // |
375 | | VOID |
376 | | SYMCRYPT_CALL |
377 | | SymCryptKeccakExtractLanes( |
378 | | _Inout_ PSYMCRYPT_KECCAK_STATE pState, |
379 | | _Out_writes_(uLaneCount * sizeof(UINT64)) PBYTE pbResult, |
380 | | SIZE_T uLaneCount) |
381 | 263 | { |
382 | 263 | SYMCRYPT_ASSERT(pState->squeezeMode); |
383 | 263 | SYMCRYPT_ASSERT((pState->inputBlockSize & 0x7) == 0); |
384 | 263 | SYMCRYPT_ASSERT((pState->stateIndex & 0x7) == 0); |
385 | | |
386 | | // Locate the lane in the state for next extraction |
387 | 263 | UINT32 uLaneIndex = pState->stateIndex / sizeof(UINT64); |
388 | | |
389 | 1.82k | for (SIZE_T i = 0; i < uLaneCount; i++) |
390 | 1.55k | { |
391 | 1.55k | SYMCRYPT_ASSERT(pState->stateIndex <= pState->inputBlockSize); |
392 | | |
393 | 1.55k | if (pState->stateIndex == pState->inputBlockSize) |
394 | 0 | { |
395 | 0 | SymCryptKeccakPermute(pState->state); |
396 | 0 | pState->stateIndex = 0; |
397 | 0 | uLaneIndex = 0; |
398 | 0 | } |
399 | | |
400 | 1.55k | SYMCRYPT_STORE_LSBFIRST64(pbResult + i * sizeof(UINT64), pState->state[uLaneIndex]); |
401 | 1.55k | pState->stateIndex += sizeof(UINT64); |
402 | 1.55k | uLaneIndex++; |
403 | 1.55k | } |
404 | 263 | } |
405 | | |
406 | | // |
407 | | // SymCryptKeccakExtract |
408 | | // |
409 | | VOID |
410 | | SYMCRYPT_CALL |
411 | | SymCryptKeccakExtract( |
412 | | _Inout_ PSYMCRYPT_KECCAK_STATE pState, |
413 | | _Out_writes_(cbResult) PBYTE pbResult, |
414 | | SIZE_T cbResult, |
415 | | BOOLEAN bWipe) |
416 | 263 | { |
417 | | // Apply padding and switch to squeeze mode if this is the first call to Extract |
418 | 263 | if (!pState->squeezeMode) |
419 | 263 | { |
420 | 263 | SymCryptKeccakApplyPadding(pState); |
421 | 263 | } |
422 | | |
423 | | // Do the permutation if there are no bytes available in the state |
424 | 263 | if ( (cbResult > 0) && (pState->stateIndex == pState->inputBlockSize) ) |
425 | 0 | { |
426 | 0 | SymCryptKeccakPermute(pState->state); |
427 | 0 | pState->stateIndex= 0; |
428 | 0 | } |
429 | | |
430 | | // Make stateIndex a multiple of 8 so that the extraction can be performed in lanes. |
431 | | // We don't call the permutation as soon as the stateIndex reaches inputBlockSize, |
432 | | // cbResult must also be non-zero for that. This condition is checked |
433 | | // in ExtractLanes or in the 'remaining bytes' block that follows it. |
434 | 263 | while (cbResult > 0 && (pState->stateIndex & 0x7)) |
435 | 0 | { |
436 | 0 | *pbResult = SymCryptKeccakExtractByte(pState); |
437 | 0 | pbResult++; |
438 | 0 | cbResult--; |
439 | 0 | } |
440 | | |
441 | 263 | SYMCRYPT_ASSERT((cbResult == 0) || ((pState->stateIndex & 0x7) == 0)); |
442 | | |
443 | | // Extract full lanes |
444 | 263 | SIZE_T uFullLanes = cbResult / sizeof(UINT64); |
445 | 263 | if (uFullLanes > 0) |
446 | 263 | { |
447 | 263 | SymCryptKeccakExtractLanes(pState, pbResult, uFullLanes); |
448 | 263 | pbResult += uFullLanes * sizeof(UINT64); |
449 | 263 | cbResult -= uFullLanes * sizeof(UINT64); |
450 | 263 | } |
451 | | |
452 | | // Extract the remaining bytes |
453 | 263 | SYMCRYPT_ASSERT(cbResult < sizeof(UINT64)); |
454 | 263 | while (cbResult > 0) |
455 | 0 | { |
456 | 0 | if (pState->stateIndex == pState->inputBlockSize) |
457 | 0 | { |
458 | 0 | SymCryptKeccakPermute(pState->state); |
459 | 0 | pState->stateIndex = 0; |
460 | 0 | } |
461 | |
|
462 | 0 | *pbResult = SymCryptKeccakExtractByte(pState); |
463 | 0 | pbResult++; |
464 | 0 | cbResult--; |
465 | 0 | } |
466 | | |
467 | 263 | if (bWipe) |
468 | 263 | { |
469 | | // Wipe the Keccak state and make it ready for a new hash computation |
470 | 263 | SymCryptKeccakReset(pState); |
471 | 263 | } |
472 | 263 | } |
473 | | |
474 | | // |
475 | | // SymCryptKeccakStateExport |
476 | | // |
477 | | VOID |
478 | | SYMCRYPT_CALL |
479 | | SymCryptKeccakStateExport( |
480 | | SYMCRYPT_BLOB_TYPE type, |
481 | | _In_ PCSYMCRYPT_KECCAK_STATE pState, |
482 | | _Out_writes_bytes_(SYMCRYPT_KECCAK_STATE_EXPORT_SIZE) PBYTE pbBlob) |
483 | 0 | { |
484 | |
|
485 | 0 | SYMCRYPT_ALIGN SYMCRYPT_KECCAK_STATE_EXPORT_BLOB blob; // local copy to have proper alignment. |
486 | 0 | C_ASSERT(sizeof(blob) == SYMCRYPT_KECCAK_STATE_EXPORT_SIZE); |
487 | |
|
488 | 0 | SymCryptWipeKnownSize(&blob, sizeof(blob)); // wipe to avoid any data leakage |
489 | |
|
490 | 0 | blob.header.magic = SYMCRYPT_BLOB_MAGIC; |
491 | 0 | blob.header.size = SYMCRYPT_KECCAK_STATE_EXPORT_SIZE; |
492 | 0 | blob.header.type = type; |
493 | | |
494 | | // |
495 | | // Copy the relevant data. Buffer will be 0-padded. |
496 | | // |
497 | |
|
498 | 0 | SymCryptUint64ToLsbFirst(&pState->state[0], &blob.state[0], 25); |
499 | 0 | blob.stateIndex = pState->stateIndex; |
500 | 0 | blob.paddingValue = pState->paddingValue; |
501 | 0 | blob.squeezeMode = pState->squeezeMode; |
502 | |
|
503 | 0 | SYMCRYPT_ASSERT((PCBYTE)&blob + sizeof(blob) - sizeof(SYMCRYPT_BLOB_TRAILER) == (PCBYTE)&blob.trailer); |
504 | 0 | SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&blob, sizeof(blob) - sizeof(SYMCRYPT_BLOB_TRAILER), &blob.trailer.checksum[0]); |
505 | |
|
506 | 0 | memcpy(pbBlob, &blob, sizeof(blob)); |
507 | |
|
508 | 0 | SymCryptWipeKnownSize(&blob, sizeof(blob)); |
509 | 0 | return; |
510 | 0 | } |
511 | | |
512 | | |
513 | | // |
514 | | // SymCryptKeccakStateImport |
515 | | // |
516 | | SYMCRYPT_ERROR |
517 | | SYMCRYPT_CALL |
518 | | SymCryptKeccakStateImport( |
519 | | SYMCRYPT_BLOB_TYPE type, |
520 | | _Out_ PSYMCRYPT_KECCAK_STATE pState, |
521 | | _In_reads_bytes_(SYMCRYPT_KECCAK_STATE_EXPORT_SIZE) PCBYTE pbBlob) |
522 | 0 | { |
523 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
524 | |
|
525 | 0 | SYMCRYPT_ALIGN SYMCRYPT_KECCAK_STATE_EXPORT_BLOB blob; // local copy to have proper alignment. |
526 | 0 | BYTE checksum[8]; |
527 | |
|
528 | 0 | C_ASSERT(sizeof(blob) == SYMCRYPT_KECCAK_STATE_EXPORT_SIZE); |
529 | 0 | memcpy(&blob, pbBlob, sizeof(blob)); |
530 | |
|
531 | 0 | if (blob.header.magic != SYMCRYPT_BLOB_MAGIC || |
532 | 0 | blob.header.size != SYMCRYPT_KECCAK_STATE_EXPORT_SIZE || |
533 | 0 | blob.header.type != (UINT32)type) |
534 | 0 | { |
535 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
536 | 0 | goto cleanup; |
537 | 0 | } |
538 | | |
539 | 0 | SymCryptMarvin32(SymCryptMarvin32DefaultSeed, (PCBYTE)&blob, sizeof(blob) - sizeof(SYMCRYPT_BLOB_TRAILER), checksum); |
540 | 0 | if (memcmp(checksum, &blob.trailer.checksum[0], 8) != 0) |
541 | 0 | { |
542 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
543 | 0 | goto cleanup; |
544 | 0 | } |
545 | | |
546 | 0 | SymCryptLsbFirstToUint64(&blob.state[0], &pState->state[0], 25); |
547 | 0 | pState->stateIndex = blob.stateIndex; |
548 | 0 | pState->paddingValue = blob.paddingValue; |
549 | 0 | pState->squeezeMode = blob.squeezeMode; |
550 | | |
551 | | // |
552 | | // Set state fields based on the blob type and do validation |
553 | | // |
554 | | |
555 | | // default values indicate error |
556 | 0 | pState->inputBlockSize = 0; |
557 | 0 | pState->paddingValue = 0; |
558 | |
|
559 | 0 | switch (blob.header.type) |
560 | 0 | { |
561 | 0 | case SymCryptBlobTypeSha3_256State: |
562 | 0 | pState->inputBlockSize = SYMCRYPT_SHA3_256_INPUT_BLOCK_SIZE; |
563 | 0 | if (blob.paddingValue == SYMCRYPT_SHA3_PADDING_VALUE) |
564 | 0 | { |
565 | 0 | pState->paddingValue = blob.paddingValue; |
566 | 0 | } |
567 | 0 | break; |
568 | | |
569 | 0 | case SymCryptBlobTypeSha3_384State: |
570 | 0 | pState->inputBlockSize = SYMCRYPT_SHA3_384_INPUT_BLOCK_SIZE; |
571 | 0 | if (blob.paddingValue == SYMCRYPT_SHA3_PADDING_VALUE) |
572 | 0 | { |
573 | 0 | pState->paddingValue = blob.paddingValue; |
574 | 0 | } |
575 | 0 | break; |
576 | | |
577 | 0 | case SymCryptBlobTypeSha3_512State: |
578 | 0 | pState->inputBlockSize = SYMCRYPT_SHA3_512_INPUT_BLOCK_SIZE; |
579 | 0 | if (blob.paddingValue == SYMCRYPT_SHA3_PADDING_VALUE) |
580 | 0 | { |
581 | 0 | pState->paddingValue = blob.paddingValue; |
582 | 0 | } |
583 | 0 | break; |
584 | 0 | default: |
585 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
586 | 0 | goto cleanup; |
587 | 0 | } |
588 | | |
589 | 0 | if (pState->inputBlockSize == 0 || pState->paddingValue == 0) |
590 | 0 | { |
591 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
592 | 0 | goto cleanup; |
593 | 0 | } |
594 | | |
595 | 0 | if (pState->stateIndex > pState->inputBlockSize) |
596 | 0 | { |
597 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
598 | 0 | goto cleanup; |
599 | 0 | } |
600 | | |
601 | | // Allow stateIndex = inputBlockSize only in squeeze mode |
602 | 0 | if ((pState->stateIndex == pState->inputBlockSize) && !pState->squeezeMode) |
603 | 0 | { |
604 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
605 | 0 | goto cleanup; |
606 | 0 | } |
607 | | |
608 | 0 | cleanup: |
609 | 0 | SymCryptWipeKnownSize(&blob, sizeof(blob)); |
610 | |
|
611 | 0 | return scError; |
612 | 0 | } |