Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/sha3.c
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
}