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 | | |