Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/ccm.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// CCM.c    implementation of the CCM block cipher mode
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
7
#include "precomp.h"
8
9
0
#define CCM_MIN_NONCE_SIZE  (7)
10
0
#define CCM_MAX_NONCE_SIZE  (13)
11
0
#define CCM_MIN_TAG_SIZE    (4)
12
0
#define CCM_MAX_TAG_SIZE    (16)
13
14
#define CCM_MAX_COUNTER_SIZE    (SYMCRYPT_CCM_BLOCK_SIZE - 1 - CCM_MIN_NONCE_SIZE)
15
16
0
#define AUTHDATA_16BIT_LIMIT    ((1<<16) - (1<<8))
17
0
#define AUTHDATA_32BIT_LIMIT    (1ull << 32)
18
19
// Compile time BOOL statically determines if we need to check cbAuthData < AUTHDATA_32BIT_LIMIT
20
// Used to suppress MSVC C4127 and clang Wtautological-constant-out-of-range-compare on 32b platforms
21
const BOOL fcbAuthDataLt32bitLimitStatic = SIZE_T_MAX < AUTHDATA_32BIT_LIMIT;
22
23
0
#define CCM_BLOCK_MOD_MASK      (SYMCRYPT_CCM_BLOCK_SIZE - 1)
24
0
#define CCM_BLOCK_ROUND_MASK    (~CCM_BLOCK_MOD_MASK)
25
26
SYMCRYPT_ERROR
27
SYMCRYPT_CALL
28
SymCryptCcmValidateParameters(
29
    _In_    PCSYMCRYPT_BLOCKCIPHER  pBlockCipher,
30
    _In_    SIZE_T                  cbNonce,
31
    _In_    SIZE_T                  cbAssociatedData,
32
    _In_    UINT64                  cbData,
33
    _In_    SIZE_T                  cbTag
34
   )
35
0
{
36
0
    SIZE_T cbCounter;
37
38
0
    UNREFERENCED_PARAMETER( cbAssociatedData );
39
40
0
    if( pBlockCipher->blockSize != SYMCRYPT_CCM_BLOCK_SIZE )
41
0
    {
42
0
        return SYMCRYPT_WRONG_BLOCK_SIZE;
43
0
    }
44
45
    //
46
    // Test against limits in SP800-38C appendix A
47
    //
48
0
    if( cbNonce < CCM_MIN_NONCE_SIZE || cbNonce > CCM_MAX_NONCE_SIZE )
49
0
    {
50
0
        return SYMCRYPT_WRONG_NONCE_SIZE;
51
0
    }
52
53
    //
54
    // cbAssociatedData is limited to <2^64
55
    // We don't test for this. None of our platforms has a SIZE_T that is
56
    // large enough to violate this condition. And the test
57
    // is of a form that the compiler cannot optimize away.
58
    //
59
60
    //
61
    // The counter block consists of a single flag byte, the nonce, and the counter field.
62
    //
63
0
    cbCounter = SYMCRYPT_CCM_BLOCK_SIZE - cbNonce - 1;
64
65
    //
66
    // per SP800-38C cbData is limited to 2^{8*cbCounter}
67
    // There is no way to do this test in a single comparison.
68
    // We don't have to worry about side-channels in the && because
69
    // cbCounter depends only on the length of the nonce, and we do not
70
    // try to hide any lengths.
71
    //
72
0
    if( cbCounter < sizeof( UINT64 ) &&
73
0
        cbData >= ((UINT64)1 << (8*cbCounter)) )
74
0
    {
75
0
        return SYMCRYPT_WRONG_DATA_SIZE;
76
0
    }
77
78
0
    if( cbTag < CCM_MIN_TAG_SIZE ||
79
0
        cbTag > CCM_MAX_TAG_SIZE ||
80
0
        (cbTag & 1) == 1        // valid tag lengths are [4, 6, 8, ..., 16]
81
0
        )
82
0
    {
83
0
        return SYMCRYPT_WRONG_TAG_SIZE;
84
0
    }
85
86
0
    return SYMCRYPT_NO_ERROR;
87
0
}
88
89
90
91
VOID
92
SYMCRYPT_CALL
93
SymCryptCcmEncryptDecryptPart(
94
    _Inout_                     PSYMCRYPT_CCM_STATE pState,
95
    _In_reads_( cbData )        PCBYTE              pbSrc,
96
    _Out_writes_( cbData )      PBYTE               pbDst,
97
                                SIZE_T              cbData )
98
99
0
{
100
0
    SIZE_T  cbToDo = cbData;
101
0
    SIZE_T  bytesToProcess;
102
103
    //
104
    // Use any left-over key stream
105
    //
106
0
    while( (pState->bytesProcessed & CCM_BLOCK_MOD_MASK) != 0 && cbToDo > 0 )
107
0
    {
108
0
        *pbDst = *pbSrc ^ pState->keystreamBlock[ pState->bytesProcessed & CCM_BLOCK_MOD_MASK ];
109
0
        pbDst++;
110
0
        pbSrc++;
111
0
        cbToDo--;
112
0
        pState->bytesProcessed++;
113
0
    }
114
115
    //
116
    // Bulk process the main part of the input and output
117
    //
118
0
    if( cbToDo >= SYMCRYPT_CCM_BLOCK_SIZE )
119
0
    {
120
0
        bytesToProcess = cbToDo & CCM_BLOCK_ROUND_MASK;
121
0
        SYMCRYPT_ASSERT( bytesToProcess <= cbToDo );
122
123
0
        SYMCRYPT_ASSERT( pState->pBlockCipher->blockSize == SYMCRYPT_CCM_BLOCK_SIZE );
124
0
        SymCryptCtrMsb64(   pState->pBlockCipher,
125
0
                            pState->pExpandedKey,
126
0
                            &pState->counterBlock[0],
127
0
                            pbSrc,
128
0
                            pbDst,
129
0
                            bytesToProcess );
130
0
        pbSrc += bytesToProcess;
131
0
        pbDst += bytesToProcess;
132
0
        pState->bytesProcessed += bytesToProcess;
133
0
        cbToDo -= bytesToProcess;
134
0
    }
135
136
0
    if( cbToDo > 0 )
137
0
    {
138
        //
139
        // Encrypt an all-zero key stream block to get the key stream.
140
        //
141
0
        SymCryptWipeKnownSize( &pState->keystreamBlock[0], SYMCRYPT_CCM_BLOCK_SIZE );
142
143
0
        SYMCRYPT_ASSERT( pState->pBlockCipher->blockSize == SYMCRYPT_CCM_BLOCK_SIZE );
144
0
        SymCryptCtrMsb64(   pState->pBlockCipher,
145
0
                            pState->pExpandedKey,
146
0
                            &pState->counterBlock[0],
147
0
                            &pState->keystreamBlock[0],
148
0
                            &pState->keystreamBlock[0],
149
0
                            SYMCRYPT_CCM_BLOCK_SIZE );
150
0
        while( cbToDo > 0 )
151
0
        {
152
0
            *pbDst = *pbSrc ^ pState->keystreamBlock[ pState->bytesProcessed & CCM_BLOCK_MOD_MASK ];
153
0
            pbDst++;
154
0
            pbSrc++;
155
0
            cbToDo--;
156
0
            pState->bytesProcessed++;
157
0
        }
158
0
    }
159
0
}
160
161
162
VOID
163
SYMCRYPT_CALL
164
SymCryptCcmAddMacData(
165
    _Inout_                 PSYMCRYPT_CCM_STATE pState,
166
    _In_reads_( cbData )    PCBYTE              pbData,
167
                            SIZE_T              cbData )
168
0
{
169
0
    SIZE_T bytesToProcess;
170
0
    if( pState->bytesInMacBlock > 0 )
171
0
    {
172
0
        bytesToProcess = SYMCRYPT_MIN( cbData, SYMCRYPT_CCM_BLOCK_SIZE - pState->bytesInMacBlock );
173
0
        SymCryptXorBytes( &pState->macBlock[pState->bytesInMacBlock], pbData, &pState->macBlock[pState->bytesInMacBlock], bytesToProcess );
174
0
        pbData += bytesToProcess;
175
0
        cbData -= bytesToProcess;
176
0
        pState->bytesInMacBlock += bytesToProcess;
177
178
0
        if( pState->bytesInMacBlock == SYMCRYPT_CCM_BLOCK_SIZE )
179
0
        {
180
0
            pState->pBlockCipher->encryptFunc( pState->pExpandedKey, &pState->macBlock[0], &pState->macBlock[0] );
181
0
            pState->bytesInMacBlock = 0;
182
0
        }
183
0
    }
184
185
0
    if( cbData >= SYMCRYPT_CCM_BLOCK_SIZE )
186
0
    {
187
0
        bytesToProcess = cbData & CCM_BLOCK_ROUND_MASK;
188
0
        SYMCRYPT_ASSERT( pState->pBlockCipher->blockSize == SYMCRYPT_CCM_BLOCK_SIZE );
189
190
0
        SymCryptCbcMac( pState->pBlockCipher,
191
0
                        pState->pExpandedKey,
192
0
                        &pState->macBlock[0],
193
0
                        pbData,
194
0
                        bytesToProcess );
195
196
0
        pbData += bytesToProcess;
197
0
        cbData -= bytesToProcess;
198
0
    }
199
200
0
    if( cbData > 0 )
201
0
    {
202
0
        SymCryptXorBytes( &pState->macBlock[0], pbData, &pState->macBlock[0], cbData );
203
0
        pState->bytesInMacBlock = cbData;
204
0
    }
205
0
}
206
207
VOID
208
SYMCRYPT_CALL
209
SymCryptCcmPadMacData( _Inout_ PSYMCRYPT_CCM_STATE  pState )
210
0
{
211
    //
212
    // Pad the MAC data with zeroes until we hit the block size.
213
    // The data is xorred into macBlock, so we don't have to update that.
214
    // All we do is apply the block cipher if there was any data remaining in the macBlock.
215
    //
216
0
    if( pState->bytesInMacBlock > 0 )
217
0
    {
218
0
        pState->pBlockCipher->encryptFunc( pState->pExpandedKey, &pState->macBlock[0], &pState->macBlock[0] );
219
0
        pState->bytesInMacBlock = 0;
220
0
    }
221
0
}
222
223
224
SYMCRYPT_NOINLINE
225
VOID
226
SYMCRYPT_CALL
227
SymCryptCcmEncrypt(
228
    _In_                            PCSYMCRYPT_BLOCKCIPHER  pBlockCipher,
229
    _In_                            PCVOID                  pExpandedKey,
230
    _In_reads_( cbNonce )           PCBYTE                  pbNonce,
231
                                    SIZE_T                  cbNonce,
232
    _In_reads_opt_( cbAuthData )    PCBYTE                  pbAuthData,
233
                                    SIZE_T                  cbAuthData,
234
    _In_reads_( cbData )            PCBYTE                  pbSrc,
235
    _Out_writes_( cbData )          PBYTE                   pbDst,
236
                                    SIZE_T                  cbData,
237
    _Out_writes_( cbTag )           PBYTE                   pbTag,
238
                                    SIZE_T                  cbTag )
239
0
{
240
0
    SYMCRYPT_CCM_STATE  state;
241
242
0
    SymCryptCcmInit(    &state,
243
0
                        pBlockCipher,
244
0
                        pExpandedKey,
245
0
                        pbNonce, cbNonce,
246
0
                        pbAuthData, cbAuthData,
247
0
                        cbData, cbTag );
248
249
0
    SymCryptCcmEncryptPart( &state, pbSrc, pbDst, cbData );
250
251
0
    SymCryptCcmEncryptFinal( &state, pbTag, cbTag );
252
0
}
253
254
SYMCRYPT_NOINLINE
255
SYMCRYPT_ERROR
256
SYMCRYPT_CALL
257
SymCryptCcmDecrypt(
258
    _In_                            PCSYMCRYPT_BLOCKCIPHER  pBlockCipher,
259
    _In_                            PCVOID                  pExpandedKey,
260
    _In_reads_( cbNonce )           PCBYTE                  pbNonce,
261
                                    SIZE_T                  cbNonce,
262
    _In_reads_opt_( cbAuthData )    PCBYTE                  pbAuthData,
263
                                    SIZE_T                  cbAuthData,
264
    _In_reads_( cbData )            PCBYTE                  pbSrc,
265
    _Out_writes_( cbData )          PBYTE                   pbDst,
266
                                    SIZE_T                  cbData,
267
    _In_reads_( cbTag )             PCBYTE                  pbTag,
268
                                    SIZE_T                  cbTag )
269
0
{
270
0
    SYMCRYPT_CCM_STATE  state;
271
0
    SYMCRYPT_ERROR      status;
272
273
0
    SymCryptCcmInit(    &state,
274
0
                        pBlockCipher,
275
0
                        pExpandedKey,
276
0
                        pbNonce, cbNonce,
277
0
                        pbAuthData, cbAuthData,
278
0
                        cbData, cbTag );
279
280
281
0
    SymCryptCcmDecryptPart( &state, pbSrc, pbDst, cbData );
282
283
0
    status = SymCryptCcmDecryptFinal( &state, pbTag, cbTag );
284
285
    //
286
    // If we failed for any reason we wipe our output buffer to avoid returning
287
    // decrypted but unauthenticated data.
288
    //
289
0
    if( status != SYMCRYPT_NO_ERROR )
290
0
    {
291
0
        SymCryptWipe( pbDst, cbData );
292
0
    }
293
294
0
    return status;
295
0
}
296
297
SYMCRYPT_NOINLINE
298
VOID
299
SYMCRYPT_CALL
300
SymCryptCcmInit(
301
    _Out_                           PSYMCRYPT_CCM_STATE     pState,
302
    _In_                            PCSYMCRYPT_BLOCKCIPHER  pBlockCipher,
303
    _In_                            PCVOID                  pExpandedKey,
304
    _In_reads_( cbNonce )           PCBYTE                  pbNonce,
305
                                    SIZE_T                  cbNonce,
306
    _In_reads_opt_( cbAuthData )    PCBYTE                  pbAuthData,
307
                                    SIZE_T                  cbAuthData,
308
                                    UINT64                  cbData,
309
                                    SIZE_T                  cbTag )
310
0
{
311
0
    BYTE            flags;
312
0
    BYTE            tmpBuf[ SYMCRYPT_CCM_BLOCK_SIZE ];
313
0
    SIZE_T          cbCounter;
314
315
0
    SYMCRYPT_SET_MAGIC( pState );
316
317
    //
318
    // Validate parameters in checked builds
319
    //
320
0
    SYMCRYPT_ASSERT( SymCryptCcmValidateParameters( pBlockCipher, cbNonce, cbAuthData, cbData, cbTag ) == SYMCRYPT_NO_ERROR );
321
322
323
    //
324
    // compute # bytes in the counter field
325
    // We limit cbNonce to 15 so that cbCounter + cbNonce = 15 will always hold
326
    // This is much cheaper than full parameter validation, and it is enough to
327
    // avoid any buffer overflows.
328
    //
329
0
    cbNonce &= SYMCRYPT_CCM_BLOCK_SIZE - 1;
330
0
    cbCounter = SYMCRYPT_CCM_BLOCK_SIZE - 1 - cbNonce;
331
332
0
    pState->pBlockCipher = pBlockCipher;
333
0
    pState->pExpandedKey = pExpandedKey;
334
0
    pState->cbNonce = cbNonce;
335
0
    pState->cbData = cbData;
336
0
    pState->cbTag = cbTag;
337
0
    pState->cbCounter = cbCounter;
338
0
    pState->bytesProcessed = 0;
339
0
    pState->bytesInMacBlock = 0;
340
341
    //
342
    // Build the initial blocks for authentication and en/decryption
343
    //
344
    // Per Sp800-38c the flag byte is made up of four fields:
345
    // Bits 0-2 are cbCounter - 1
346
    // Bits 3-5 are (cbTag-2)/2
347
    // Bit 6 is 1 if cbAuthData > 0
348
    // Bit 7 is reserved and set to 0.
349
0
    flags = (BYTE) (pState->cbCounter - 1);
350
0
    flags |= ((cbTag-2)/2) << 3;
351
0
    if( cbAuthData > 0 )
352
0
    {
353
        //
354
        // No side-channel concerns with this if statements as we don't try to hide the
355
        // data length or presence of authdata.
356
        //
357
0
        flags |= (1 << 6);
358
0
    }
359
360
361
    //
362
    // The MAC starting block consists of three fields:
363
    // the flag byte, the nonce, and cbData encoded into cbCounter bytes.
364
    //
365
0
    pState->macBlock[0] = flags;
366
0
    memcpy( &pState->macBlock[1], pbNonce, cbNonce );
367
0
    SYMCRYPT_STORE_MSBFIRST64( &tmpBuf[0], cbData );
368
0
    memcpy( &pState->macBlock[1+cbNonce], &tmpBuf[ 8 - cbCounter ], cbCounter );
369
370
    //
371
    // The counter block is similar in layout, but with two changes:
372
    // Bits 3-7 of the flag bytes are set to 0.
373
    // The counter field is set to one (first counter value used for data encryption).
374
    // Wiping the whole block first is probably faster, as the size is known and the
375
    // block is aligned.
376
    // We also copy the nonce from the mac block to follow the read-once rule.
377
    //
378
0
    SymCryptWipeKnownSize( &pState->counterBlock[0], SYMCRYPT_CCM_BLOCK_SIZE );
379
0
    pState->counterBlock[0] = (BYTE)(flags & 0x7);
380
0
    memcpy( &pState->counterBlock[1], &pState->macBlock[1], cbNonce );
381
0
    pState->counterBlock[ SYMCRYPT_CCM_BLOCK_SIZE - 1] = 1;
382
383
    //
384
    // Encrypt the current MAC block; our CBC convention is to do the encryption
385
    // as soon as we have enough data.
386
    //
387
0
    pBlockCipher->encryptFunc( pExpandedKey, &pState->macBlock[0], &pState->macBlock[0] );
388
389
    //
390
    // Next we process the associated data
391
    // See the CCM specs for the details
392
    //
393
0
    if( cbAuthData <= 0 )
394
0
    {
395
        //
396
        // cbAuthData == 0, nothing needs to be done.
397
        //
398
0
    } else if( cbAuthData < AUTHDATA_16BIT_LIMIT )
399
0
    {
400
        //
401
        // 16-bit length encoding.
402
        //
403
0
        SYMCRYPT_STORE_MSBFIRST16( &tmpBuf[0], (UINT16) cbAuthData );
404
0
        SymCryptCcmAddMacData( pState, &tmpBuf[0], 2 );
405
0
    } else if( fcbAuthDataLt32bitLimitStatic || cbAuthData < AUTHDATA_32BIT_LIMIT )
406
0
    {
407
        //
408
        // 32-bit length
409
        //
410
0
        tmpBuf[0] = 0xff;
411
0
        tmpBuf[1] = 0xfe;       // Magic prefix as per SP 800-38c
412
0
        SYMCRYPT_STORE_MSBFIRST32( &tmpBuf[2], (UINT32) cbAuthData );
413
0
        SymCryptCcmAddMacData( pState, &tmpBuf[0], 2 + sizeof( UINT32 ) );
414
0
    } else
415
0
    {
416
        //
417
        // 64-bit length
418
        //
419
0
        tmpBuf[0] = 0xff;
420
0
        tmpBuf[1] = 0xff;       // Magic prefix as per SP 800-38c
421
0
        SYMCRYPT_STORE_MSBFIRST64( &tmpBuf[2], cbAuthData );
422
0
        SymCryptCcmAddMacData( pState, &tmpBuf[0], 2 + sizeof( UINT64 ) );
423
0
    }
424
425
0
    SymCryptCcmAddMacData( pState, pbAuthData, cbAuthData );
426
0
    SymCryptCcmPadMacData( pState );        // Pad MAC data with zeroes until the next block size boundary
427
428
0
}
429
430
SYMCRYPT_NOINLINE
431
VOID
432
SYMCRYPT_CALL
433
SymCryptCcmEncryptPart(
434
    _Inout_                   PSYMCRYPT_CCM_STATE pState,
435
    _In_reads_( cbData )      PCBYTE              pbSrc,
436
    _Out_writes_( cbData )    PBYTE               pbDst,
437
                              SIZE_T              cbData )
438
0
{
439
0
    UINT64 bytesProcessedAfterThisCall;
440
441
0
    SYMCRYPT_CHECK_MAGIC( pState );
442
443
0
    bytesProcessedAfterThisCall = cbData + pState->bytesProcessed;
444
445
0
    SYMCRYPT_ASSERT( bytesProcessedAfterThisCall >= cbData &&
446
0
                     bytesProcessedAfterThisCall <= pState->cbData );
447
448
    //
449
    // We are violating the read-once implementation rule here. We read the data twice:
450
    // once for MACing and once for encryption.
451
    // In this particular situation this is safe to do.
452
    // We consider the read for the MAC operation as reading the 'real' value.
453
    // The encryption code reads the data, but all it does is XOR the key stream into
454
    // it. (CCM encryption uses CTR mode for the encryption part.)
455
    // We don't care if the attacker modifies the data before the encryption.
456
    // We are revealing the key stream anyway (from the plaintext and ciphertext) and
457
    // the exact byte value that we xor the key stream into is irrelevant.
458
    //
459
0
    SymCryptCcmAddMacData( pState, pbSrc, cbData );
460
461
0
    SymCryptCcmEncryptDecryptPart( pState, pbSrc, pbDst, cbData );
462
463
0
}
464
465
SYMCRYPT_NOINLINE
466
VOID
467
SYMCRYPT_CALL
468
SymCryptCcmEncryptFinal(
469
    _Inout_                 PSYMCRYPT_CCM_STATE pState,
470
    _Out_writes_( cbTag )   PBYTE               pbTag,
471
                            SIZE_T              cbTag )
472
0
{
473
    //
474
    // Check invariants in checked builds
475
    //
476
0
    SYMCRYPT_CHECK_MAGIC( pState );
477
478
0
    SYMCRYPT_ASSERT( cbTag  == pState->cbTag && pState->bytesProcessed == pState->cbData );
479
480
481
0
    SymCryptCcmPadMacData( pState );
482
483
    //
484
    // Set the counter value to zero to get the counter value that encrypts the tag,
485
    // and then encrypt the tag.
486
    // We reset bytesProcessed so that the partial encrypt/decrypt function will do the right thing
487
    //
488
0
    SymCryptWipe( &pState->counterBlock[1 + pState->cbNonce], pState->cbCounter );
489
490
0
    pState->bytesProcessed = 0;
491
492
0
    SymCryptCcmEncryptDecryptPart( pState, &pState->macBlock[0], &pState->macBlock[0], SYMCRYPT_CCM_BLOCK_SIZE );
493
494
0
    memcpy( pbTag, &pState->macBlock[0], cbTag );
495
496
0
    SymCryptWipeKnownSize( pState, sizeof( *pState ) );
497
0
    SYMCRYPT_ASSERT( pState->bytesInMacBlock == 0 );
498
0
}
499
500
SYMCRYPT_NOINLINE
501
VOID
502
SYMCRYPT_CALL
503
SymCryptCcmDecryptPart(
504
    _Inout_                 PSYMCRYPT_CCM_STATE pState,
505
    _In_reads_( cbData )    PCBYTE              pbSrc,
506
    _Out_writes_( cbData )  PBYTE               pbDst,
507
                            SIZE_T              cbData )
508
0
{
509
0
    UINT64 bytesProcessedAfterThisCall;
510
511
0
    SYMCRYPT_CHECK_MAGIC( pState );
512
513
0
    bytesProcessedAfterThisCall = cbData + pState->bytesProcessed;
514
515
0
    SYMCRYPT_ASSERT( bytesProcessedAfterThisCall >= cbData &&
516
0
                     bytesProcessedAfterThisCall <= pState->cbData );
517
518
519
    //
520
    // We are violating the read-once/write-once implementation rule here.
521
    // We write the decrypted data and then read it back for the authentication function.
522
    // In this particular situation this is safe to do.
523
    //
524
    // Anyone who can access the memory space that contains the source and destination of this
525
    // function can recover the key stream used for this (key,nonce) combination.
526
    // We can think of the decryption function as merely exposing the key stream, and then the
527
    // caller picking the ciphertext (and by implication the plaintext) to be authenticated.
528
    // Thus the data we read during authentication is the 'real' plaintext, and the
529
    // decryption function merely made the key stream available.
530
    //
531
    // Note that this would not safe in general, it is only safe because CTR mode decryption already
532
    // reveals the key stream.
533
    //
534
0
    SymCryptCcmEncryptDecryptPart( pState, pbSrc, pbDst, cbData );
535
0
    SymCryptCcmAddMacData( pState, pbDst, cbData );
536
537
0
}
538
539
SYMCRYPT_NOINLINE
540
SYMCRYPT_ERROR
541
SYMCRYPT_CALL
542
SymCryptCcmDecryptFinal(
543
    _Inout_             PSYMCRYPT_CCM_STATE pState,
544
    _In_reads_( cbTag ) PCBYTE              pbTag,
545
                        SIZE_T              cbTag )
546
0
{
547
0
    SYMCRYPT_ERROR status;
548
549
    //
550
    // Check invariants in checked builds
551
    //
552
0
    SYMCRYPT_CHECK_MAGIC( pState );
553
554
0
    SYMCRYPT_ASSERT( cbTag  == pState->cbTag && pState->bytesProcessed == pState->cbData );
555
556
0
    SymCryptCcmPadMacData( pState );
557
558
    //
559
    // Set the counter value to zero to get the counter value that encrypts the tag,
560
    // and then encrypt the tag
561
    // We reset bytesProcessed so that the partial encrypt/decrypt function will do the right thing
562
    //
563
0
    SymCryptWipe( &pState->counterBlock[1 + pState->cbNonce], pState->cbCounter );
564
565
0
    pState->bytesProcessed = 0;
566
567
0
    SymCryptCcmEncryptDecryptPart( pState, &pState->macBlock[0], &pState->macBlock[0], SYMCRYPT_CCM_BLOCK_SIZE );
568
569
0
    if( !SymCryptEqual( pbTag, &pState->macBlock[0], cbTag ) )
570
0
    {
571
0
        status = SYMCRYPT_AUTHENTICATION_FAILURE;
572
0
    }
573
0
    else
574
0
    {
575
0
        status = SYMCRYPT_NO_ERROR;
576
0
    }
577
578
0
    SymCryptWipeKnownSize( pState, sizeof( *pState ) );
579
0
    SYMCRYPT_ASSERT( pState->bytesInMacBlock == 0 );
580
581
0
    return status;
582
0
}
583
584
585
static const BYTE SymCryptCcmSelftestResult[3 + SYMCRYPT_AES_BLOCK_SIZE ] =
586
{
587
    0x42, 0xd7, 0xda,
588
    0x3d, 0x9e, 0x95, 0x82, 0x29, 0x3c, 0x10, 0x9c, 0xa3, 0x39, 0x31, 0x3f, 0x18, 0xf3, 0x10, 0xf6
589
};
590
591
VOID
592
SYMCRYPT_CALL
593
SymCryptCcmSelftest(void)
594
0
{
595
0
    BYTE    buf[ 3 + SYMCRYPT_AES_BLOCK_SIZE ];
596
0
    SYMCRYPT_AES_EXPANDED_KEY key;
597
0
    SYMCRYPT_ERROR err;
598
599
0
    if( SymCryptAesExpandKey( &key, SymCryptTestKey32, 16 ) != SYMCRYPT_NO_ERROR )
600
0
    {
601
0
        SymCryptFatal( 'ccm0' );
602
0
    }
603
604
0
    SymCryptCcmEncrypt( SymCryptAesBlockCipher,
605
0
                        &key,
606
0
                        &SymCryptTestKey32[16], 12,
607
0
                        NULL, 0,
608
0
                        &SymCryptTestMsg3[0], buf, 3,
609
0
                        &buf[3], SYMCRYPT_AES_BLOCK_SIZE );
610
611
0
    SymCryptInjectError( buf, sizeof( buf ) );
612
0
    if( memcmp( buf, SymCryptCcmSelftestResult, sizeof( buf ) ) != 0 )
613
0
    {
614
0
        SymCryptFatal( 'ccm1' );
615
0
    }
616
617
    // inject error into the ciphertext or tag
618
0
    SymCryptInjectError( buf, sizeof( buf ) );
619
620
0
    err = SymCryptCcmDecrypt(   SymCryptAesBlockCipher,
621
0
                                &key,
622
0
                                &SymCryptTestKey32[16], 12,
623
0
                                NULL, 0,
624
0
                                buf, buf, 3,
625
0
                                &buf[3], SYMCRYPT_AES_BLOCK_SIZE );
626
627
0
    SymCryptInjectError( buf, 3 );
628
629
0
    if( err != SYMCRYPT_NO_ERROR || memcmp( buf, SymCryptTestMsg3, 3 ) != 0 )
630
0
    {
631
0
        SymCryptFatal( 'ccm2' );
632
0
    }
633
634
0
}
635