Branch data Line data Source code
1 : : /*
2 : : * NIST SP800-38C compliant CCM implementation
3 : : *
4 : : * Copyright The Mbed TLS Contributors
5 : : * SPDX-License-Identifier: Apache-2.0
6 : : *
7 : : * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 : : * not use this file except in compliance with the License.
9 : : * You may obtain a copy of the License at
10 : : *
11 : : * http://www.apache.org/licenses/LICENSE-2.0
12 : : *
13 : : * Unless required by applicable law or agreed to in writing, software
14 : : * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 : : * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : : * See the License for the specific language governing permissions and
17 : : * limitations under the License.
18 : : */
19 : :
20 : : /*
21 : : * Definition of CCM:
22 : : * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
23 : : * RFC 3610 "Counter with CBC-MAC (CCM)"
24 : : *
25 : : * Related:
26 : : * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
27 : : */
28 : :
29 : : #include "common.h"
30 : :
31 : : #if defined(MBEDTLS_CCM_C)
32 : :
33 : : #include "mbedtls/ccm.h"
34 : : #include "mbedtls/platform_util.h"
35 : : #include "mbedtls/error.h"
36 : :
37 : : #include <string.h>
38 : :
39 : : #if defined(MBEDTLS_PLATFORM_C)
40 : : #include "mbedtls/platform.h"
41 : : #else
42 : : #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
43 : : #include <stdio.h>
44 : : #define mbedtls_printf printf
45 : : #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
46 : : #endif /* MBEDTLS_PLATFORM_C */
47 : :
48 : : #if !defined(MBEDTLS_CCM_ALT)
49 : :
50 : :
51 : : /*
52 : : * Initialize context
53 : : */
54 : 34 : void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
55 : : {
56 : 34 : memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
57 : 34 : }
58 : :
59 : 34 : int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
60 : : mbedtls_cipher_id_t cipher,
61 : : const unsigned char *key,
62 : : unsigned int keybits )
63 : : {
64 : 34 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
65 : 34 : const mbedtls_cipher_info_t *cipher_info;
66 : :
67 : 34 : cipher_info = mbedtls_cipher_info_from_values( cipher, keybits,
68 : : MBEDTLS_MODE_ECB );
69 [ + - ]: 34 : if( cipher_info == NULL )
70 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
71 : :
72 [ + - ]: 34 : if( cipher_info->block_size != 16 )
73 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
74 : :
75 : 34 : mbedtls_cipher_free( &ctx->cipher_ctx );
76 : :
77 [ + - ]: 34 : if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
78 : : return( ret );
79 : :
80 [ - + ]: 34 : if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
81 : : MBEDTLS_ENCRYPT ) ) != 0 )
82 : : {
83 : 0 : return( ret );
84 : : }
85 : :
86 : : return( 0 );
87 : : }
88 : :
89 : : /*
90 : : * Free context
91 : : */
92 : 34 : void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
93 : : {
94 [ + - ]: 34 : if( ctx == NULL )
95 : : return;
96 : 34 : mbedtls_cipher_free( &ctx->cipher_ctx );
97 : 34 : mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
98 : : }
99 : :
100 : : #define CCM_STATE__CLEAR 0
101 : : #define CCM_STATE__STARTED (1 << 0)
102 : : #define CCM_STATE__LENGHTS_SET (1 << 1)
103 : : #define CCM_STATE__AUTH_DATA_STARTED (1 << 2)
104 : : #define CCM_STATE__AUTH_DATA_FINISHED (1 << 3)
105 : : #define CCM_STATE__ERROR (1 << 4)
106 : :
107 : : /*
108 : : * Encrypt or decrypt a partial block with CTR
109 : : */
110 : 132 : static int mbedtls_ccm_crypt( mbedtls_ccm_context *ctx,
111 : : size_t offset, size_t use_len,
112 : : const unsigned char *input,
113 : : unsigned char *output )
114 : : {
115 : 132 : size_t i;
116 : 132 : size_t olen = 0;
117 : 132 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
118 : 132 : unsigned char tmp_buf[16] = {0};
119 : :
120 [ - + ]: 132 : if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->ctr, 16, tmp_buf,
121 : : &olen ) ) != 0 )
122 : : {
123 : 0 : ctx->state |= CCM_STATE__ERROR;
124 : 0 : mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
125 : 0 : return ret;
126 : : }
127 : :
128 [ + + ]: 2066 : for( i = 0; i < use_len; i++ )
129 : 1934 : output[i] = input[i] ^ tmp_buf[offset + i];
130 : :
131 : 132 : mbedtls_platform_zeroize(tmp_buf, sizeof(tmp_buf));
132 : 132 : return ret;
133 : : }
134 : :
135 : 34 : static void mbedtls_ccm_clear_state(mbedtls_ccm_context *ctx) {
136 : 34 : ctx->state = CCM_STATE__CLEAR;
137 : 34 : memset( ctx->y, 0, 16);
138 : 34 : memset( ctx->ctr, 0, 16);
139 : 34 : }
140 : :
141 : 68 : static int ccm_calculate_first_block_if_ready(mbedtls_ccm_context *ctx)
142 : : {
143 : 68 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
144 : 68 : unsigned char i;
145 : 68 : size_t len_left, olen;
146 : :
147 : : /* length calulcation can be done only after both
148 : : * mbedtls_ccm_starts() and mbedtls_ccm_set_lengths() have been executed
149 : : */
150 [ + + ]: 68 : if( !(ctx->state & CCM_STATE__STARTED) || !(ctx->state & CCM_STATE__LENGHTS_SET) )
151 : : return 0;
152 : :
153 : : /* CCM expects non-empty tag.
154 : : * CCM* allows empty tag. For CCM* without tag, ignore plaintext length.
155 : : */
156 [ - + ]: 34 : if( ctx->tag_len == 0 )
157 : : {
158 [ # # ]: 0 : if( ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT || ctx->mode == MBEDTLS_CCM_STAR_DECRYPT )
159 : : {
160 : 0 : ctx->plaintext_len = 0;
161 : : }
162 : : else
163 : : {
164 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
165 : : }
166 : : }
167 : :
168 : : /*
169 : : * First block:
170 : : * 0 .. 0 flags
171 : : * 1 .. iv_len nonce (aka iv) - set by: mbedtls_ccm_starts()
172 : : * iv_len+1 .. 15 length
173 : : *
174 : : * With flags as (bits):
175 : : * 7 0
176 : : * 6 add present?
177 : : * 5 .. 3 (t - 2) / 2
178 : : * 2 .. 0 q - 1
179 : : */
180 [ - + ]: 34 : ctx->y[0] |= ( ctx->add_len > 0 ) << 6;
181 : 34 : ctx->y[0] |= ( ( ctx->tag_len - 2 ) / 2 ) << 3;
182 : 34 : ctx->y[0] |= ctx->q - 1;
183 : :
184 [ + + ]: 102 : for( i = 0, len_left = ctx->plaintext_len; i < ctx->q; i++, len_left >>= 8 )
185 : 68 : ctx->y[15-i] = MBEDTLS_BYTE_0( len_left );
186 : :
187 [ - + ]: 34 : if( len_left > 0 )
188 : : {
189 : 0 : ctx->state |= CCM_STATE__ERROR;
190 : 0 : return( MBEDTLS_ERR_CCM_BAD_INPUT );
191 : : }
192 : :
193 : : /* Start CBC-MAC with first block*/
194 [ - + ]: 34 : if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
195 : : {
196 : 0 : ctx->state |= CCM_STATE__ERROR;
197 : 0 : return( ret );
198 : : }
199 : :
200 : : return (0);
201 : : }
202 : :
203 : 34 : int mbedtls_ccm_starts( mbedtls_ccm_context *ctx,
204 : : int mode,
205 : : const unsigned char *iv,
206 : : size_t iv_len )
207 : : {
208 : : /* Also implies q is within bounds */
209 [ + - ]: 34 : if( iv_len < 7 || iv_len > 13 )
210 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
211 : :
212 : 34 : ctx->mode = mode;
213 : 34 : ctx->q = 16 - 1 - (unsigned char) iv_len;
214 : :
215 : : /*
216 : : * Prepare counter block for encryption:
217 : : * 0 .. 0 flags
218 : : * 1 .. iv_len nonce (aka iv)
219 : : * iv_len+1 .. 15 counter (initially 1)
220 : : *
221 : : * With flags as (bits):
222 : : * 7 .. 3 0
223 : : * 2 .. 0 q - 1
224 : : */
225 : 34 : memset( ctx->ctr, 0, 16);
226 : 34 : ctx->ctr[0] = ctx->q - 1;
227 : 34 : memcpy( ctx->ctr + 1, iv, iv_len );
228 : 34 : memset( ctx->ctr + 1 + iv_len, 0, ctx->q );
229 : 34 : ctx->ctr[15] = 1;
230 : :
231 : : /*
232 : : * See ccm_calculate_first_block_if_ready() for block layout description
233 : : */
234 : 34 : memcpy( ctx->y + 1, iv, iv_len );
235 : :
236 : 34 : ctx->state |= CCM_STATE__STARTED;
237 : 34 : return ccm_calculate_first_block_if_ready(ctx);
238 : : }
239 : :
240 : 34 : int mbedtls_ccm_set_lengths( mbedtls_ccm_context *ctx,
241 : : size_t total_ad_len,
242 : : size_t plaintext_len,
243 : : size_t tag_len )
244 : : {
245 : : /*
246 : : * Check length requirements: SP800-38C A.1
247 : : * Additional requirement: a < 2^16 - 2^8 to simplify the code.
248 : : * 'length' checked later (when writing it to the first block)
249 : : *
250 : : * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
251 : : */
252 [ + - + - ]: 34 : if( tag_len == 2 || tag_len > 16 || tag_len % 2 != 0 )
253 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
254 : :
255 [ + - ]: 34 : if( total_ad_len >= 0xFF00 )
256 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
257 : :
258 : 34 : ctx->plaintext_len = plaintext_len;
259 : 34 : ctx->add_len = total_ad_len;
260 : 34 : ctx->tag_len = tag_len;
261 : 34 : ctx->processed = 0;
262 : :
263 : 34 : ctx->state |= CCM_STATE__LENGHTS_SET;
264 : 34 : return ccm_calculate_first_block_if_ready(ctx);
265 : : }
266 : :
267 : 34 : int mbedtls_ccm_update_ad( mbedtls_ccm_context *ctx,
268 : : const unsigned char *add,
269 : : size_t add_len )
270 : : {
271 : 34 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
272 : 34 : unsigned char i;
273 : 34 : size_t olen, use_len, offset;
274 : :
275 [ + - ]: 34 : if( ctx->state & CCM_STATE__ERROR )
276 : : {
277 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
278 : : }
279 : :
280 [ + - ]: 34 : if( add_len > 0 )
281 : : {
282 [ + - ]: 34 : if( ctx->state & CCM_STATE__AUTH_DATA_FINISHED )
283 : : {
284 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
285 : : }
286 : :
287 [ + - ]: 34 : if( !(ctx->state & CCM_STATE__AUTH_DATA_STARTED) )
288 : : {
289 [ + - ]: 34 : if ( add_len > ctx->add_len )
290 : : {
291 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
292 : : }
293 : :
294 : 34 : ctx->y[0] ^= (unsigned char)( ( ctx->add_len >> 8 ) & 0xFF );
295 : 34 : ctx->y[1] ^= (unsigned char)( ( ctx->add_len ) & 0xFF );
296 : :
297 : 34 : ctx->state |= CCM_STATE__AUTH_DATA_STARTED;
298 : : }
299 [ # # ]: 0 : else if ( ctx->processed + add_len > ctx->add_len )
300 : : {
301 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
302 : : }
303 : :
304 [ + + ]: 108 : while( add_len > 0 )
305 : : {
306 : 74 : offset = (ctx->processed + 2) % 16; /* account for y[0] and y[1]
307 : : * holding total auth data length */
308 : 74 : use_len = 16 - offset;
309 : :
310 : 74 : if( use_len > add_len )
311 : : use_len = add_len;
312 : :
313 [ + + ]: 905 : for( i = 0; i < use_len; i++ )
314 : 831 : ctx->y[i + offset] ^= add[i];
315 : :
316 : 74 : ctx->processed += use_len;
317 : 74 : add_len -= use_len;
318 : 74 : add += use_len;
319 : :
320 [ + + + - ]: 74 : if( use_len + offset == 16 || ctx->processed == ctx->add_len )
321 : : {
322 [ - + ]: 74 : if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
323 : : {
324 : 0 : ctx->state |= CCM_STATE__ERROR;
325 : 0 : return( ret );
326 : : }
327 : : }
328 : : }
329 : :
330 [ + - ]: 34 : if( ctx->processed == ctx->add_len )
331 : : {
332 : 34 : ctx->state |= CCM_STATE__AUTH_DATA_FINISHED;
333 : 34 : ctx->processed = 0; // prepare for mbedtls_ccm_update()
334 : : }
335 : : }
336 : :
337 : : return (0);
338 : : }
339 : :
340 : 34 : int mbedtls_ccm_update( mbedtls_ccm_context *ctx,
341 : : const unsigned char *input, size_t input_len,
342 : : unsigned char *output, size_t output_size,
343 : : size_t *output_len )
344 : : {
345 : 34 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
346 : 34 : unsigned char i;
347 : 34 : size_t use_len, offset, olen;
348 : :
349 : 34 : unsigned char local_output[16];
350 : :
351 [ + - ]: 34 : if( ctx->state & CCM_STATE__ERROR )
352 : : {
353 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
354 : : }
355 : :
356 : : /* Check against plaintext length only if performing operation with
357 : : * authentication
358 : : */
359 [ + - + - ]: 34 : if( ctx->tag_len != 0 && ctx->processed + input_len > ctx->plaintext_len )
360 : : {
361 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
362 : : }
363 : :
364 [ + - ]: 34 : if( output_size < input_len )
365 : : return( MBEDTLS_ERR_CCM_BAD_INPUT );
366 : 34 : *output_len = input_len;
367 : :
368 : 34 : ret = 0;
369 : :
370 [ + + ]: 132 : while ( input_len > 0 )
371 : : {
372 : 98 : offset = ctx->processed % 16;
373 : :
374 : 98 : use_len = 16 - offset;
375 : :
376 : 98 : if( use_len > input_len )
377 : : use_len = input_len;
378 : :
379 : 98 : ctx->processed += use_len;
380 : :
381 [ + + ]: 98 : if( ctx->mode == MBEDTLS_CCM_ENCRYPT || \
382 : : ctx->mode == MBEDTLS_CCM_STAR_ENCRYPT )
383 : : {
384 [ + + ]: 750 : for( i = 0; i < use_len; i++ )
385 : 700 : ctx->y[i + offset] ^= input[i];
386 : :
387 [ + + + - ]: 50 : if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
388 : : {
389 [ - + ]: 50 : if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
390 : : {
391 : 0 : ctx->state |= CCM_STATE__ERROR;
392 : 0 : goto exit;
393 : : }
394 : : }
395 : :
396 : 50 : ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, output );
397 [ - + ]: 50 : if( ret != 0 )
398 : 0 : goto exit;
399 : : }
400 : :
401 [ + + ]: 98 : if( ctx->mode == MBEDTLS_CCM_DECRYPT || \
402 : : ctx->mode == MBEDTLS_CCM_STAR_DECRYPT )
403 : : {
404 : : /* Since output may be in shared memory, we cannot be sure that
405 : : * it will contain what we wrote to it. Therefore, we should avoid using
406 : : * it as input to any operations.
407 : : * Write decrypted data to local_output to avoid using output variable as
408 : : * input in the XOR operation for Y.
409 : : */
410 : 48 : ret = mbedtls_ccm_crypt( ctx, offset, use_len, input, local_output );
411 [ - + ]: 48 : if( ret != 0 )
412 : 0 : goto exit;
413 : :
414 [ + + ]: 738 : for( i = 0; i < use_len; i++ )
415 : 690 : ctx->y[i + offset] ^= local_output[i];
416 : :
417 : 48 : memcpy( output, local_output, use_len );
418 : 48 : mbedtls_platform_zeroize( local_output, 16 );
419 : :
420 [ + + + - ]: 48 : if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
421 : : {
422 [ - + ]: 48 : if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->y, &olen ) ) != 0 )
423 : : {
424 : 0 : ctx->state |= CCM_STATE__ERROR;
425 : 0 : goto exit;
426 : : }
427 : : }
428 : : }
429 : :
430 [ + + + - ]: 98 : if( use_len + offset == 16 || ctx->processed == ctx->plaintext_len )
431 : : {
432 [ + - ]: 98 : for( i = 0; i < ctx->q; i++ )
433 [ - + ]: 98 : if( ++(ctx->ctr)[15-i] != 0 )
434 : : break;
435 : : }
436 : :
437 : 98 : input_len -= use_len;
438 : 98 : input += use_len;
439 : 98 : output += use_len;
440 : : }
441 : :
442 : 34 : exit:
443 : 34 : mbedtls_platform_zeroize( local_output, 16 );
444 : :
445 : 34 : return ret;
446 : : }
447 : :
448 : 34 : int mbedtls_ccm_finish( mbedtls_ccm_context *ctx,
449 : : unsigned char *tag, size_t tag_len )
450 : : {
451 : 34 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
452 : 34 : unsigned char i;
453 : :
454 [ + - ]: 34 : if( ctx->state & CCM_STATE__ERROR )
455 : : {
456 : : return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
457 : : }
458 : :
459 [ + - + - ]: 34 : if( ctx->add_len > 0 && !( ctx->state & CCM_STATE__AUTH_DATA_FINISHED ) )
460 : : {
461 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
462 : : }
463 : :
464 [ - + + - ]: 34 : if( ctx->plaintext_len > 0 && ctx->processed != ctx->plaintext_len )
465 : : {
466 : : return MBEDTLS_ERR_CCM_BAD_INPUT;
467 : : }
468 : :
469 : : /*
470 : : * Authentication: reset counter and crypt/mask internal tag
471 : : */
472 [ + + ]: 102 : for( i = 0; i < ctx->q; i++ )
473 : 68 : ctx->ctr[15-i] = 0;
474 : :
475 : 34 : ret = mbedtls_ccm_crypt( ctx, 0, 16, ctx->y, ctx->y );
476 [ + - ]: 34 : if( ret != 0 )
477 : : return ret;
478 [ + - ]: 34 : if( tag != NULL )
479 : 34 : memcpy( tag, ctx->y, tag_len );
480 : 34 : mbedtls_ccm_clear_state(ctx);
481 : :
482 : 34 : return( 0 );
483 : : }
484 : :
485 : : /*
486 : : * Authenticated encryption or decryption
487 : : */
488 : 34 : static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
489 : : const unsigned char *iv, size_t iv_len,
490 : : const unsigned char *add, size_t add_len,
491 : : const unsigned char *input, unsigned char *output,
492 : : unsigned char *tag, size_t tag_len )
493 : : {
494 : 34 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
495 : 34 : size_t olen;
496 : :
497 [ + - ]: 34 : if( ( ret = mbedtls_ccm_starts( ctx, mode, iv, iv_len ) ) != 0 )
498 : : return( ret );
499 : :
500 [ + - ]: 34 : if( ( ret = mbedtls_ccm_set_lengths( ctx, add_len, length, tag_len ) ) != 0 )
501 : : return( ret );
502 : :
503 [ + - ]: 34 : if( ( ret = mbedtls_ccm_update_ad( ctx, add, add_len ) ) != 0 )
504 : : return( ret );
505 : :
506 [ + - ]: 34 : if( ( ret = mbedtls_ccm_update( ctx, input, length,
507 : : output, length, &olen ) ) != 0 )
508 : : return( ret );
509 : :
510 [ - + ]: 34 : if( ( ret = mbedtls_ccm_finish( ctx, tag, tag_len ) ) != 0 )
511 : 0 : return( ret );
512 : :
513 : : return( 0 );
514 : : }
515 : :
516 : : /*
517 : : * Authenticated encryption
518 : : */
519 : 0 : int mbedtls_ccm_star_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
520 : : const unsigned char *iv, size_t iv_len,
521 : : const unsigned char *add, size_t add_len,
522 : : const unsigned char *input, unsigned char *output,
523 : : unsigned char *tag, size_t tag_len )
524 : : {
525 : 0 : return( ccm_auth_crypt( ctx, MBEDTLS_CCM_STAR_ENCRYPT, length, iv, iv_len,
526 : : add, add_len, input, output, tag, tag_len ) );
527 : : }
528 : :
529 : 18 : int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
530 : : const unsigned char *iv, size_t iv_len,
531 : : const unsigned char *add, size_t add_len,
532 : : const unsigned char *input, unsigned char *output,
533 : : unsigned char *tag, size_t tag_len )
534 : : {
535 : 18 : return( ccm_auth_crypt( ctx, MBEDTLS_CCM_ENCRYPT, length, iv, iv_len,
536 : : add, add_len, input, output, tag, tag_len ) );
537 : : }
538 : :
539 : : /*
540 : : * Authenticated decryption
541 : : */
542 : 16 : static int mbedtls_ccm_compare_tags(const unsigned char *tag1, const unsigned char *tag2, size_t tag_len)
543 : : {
544 : 16 : unsigned char i;
545 : 16 : int diff;
546 : :
547 : : /* Check tag in "constant-time" */
548 [ + + ]: 144 : for( diff = 0, i = 0; i < tag_len; i++ )
549 : 128 : diff |= tag1[i] ^ tag2[i];
550 : :
551 [ - + ]: 16 : if( diff != 0 )
552 : : {
553 : 0 : return( MBEDTLS_ERR_CCM_AUTH_FAILED );
554 : : }
555 : :
556 : : return( 0 );
557 : : }
558 : :
559 : 16 : static int ccm_auth_decrypt( mbedtls_ccm_context *ctx, int mode, size_t length,
560 : : const unsigned char *iv, size_t iv_len,
561 : : const unsigned char *add, size_t add_len,
562 : : const unsigned char *input, unsigned char *output,
563 : : const unsigned char *tag, size_t tag_len )
564 : : {
565 : 16 : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
566 : 16 : unsigned char check_tag[16];
567 : :
568 [ + - ]: 16 : if( ( ret = ccm_auth_crypt( ctx, mode, length,
569 : : iv, iv_len, add, add_len,
570 : : input, output, check_tag, tag_len ) ) != 0 )
571 : : {
572 : : return( ret );
573 : : }
574 : :
575 [ - + ]: 16 : if( ( ret = mbedtls_ccm_compare_tags( tag, check_tag, tag_len ) ) != 0 )
576 : : {
577 : 0 : mbedtls_platform_zeroize( output, length );
578 : 0 : return( ret );
579 : : }
580 : :
581 : : return( 0 );
582 : : }
583 : :
584 : 0 : int mbedtls_ccm_star_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
585 : : const unsigned char *iv, size_t iv_len,
586 : : const unsigned char *add, size_t add_len,
587 : : const unsigned char *input, unsigned char *output,
588 : : const unsigned char *tag, size_t tag_len )
589 : : {
590 : 0 : return ccm_auth_decrypt( ctx, MBEDTLS_CCM_STAR_DECRYPT, length,
591 : : iv, iv_len, add, add_len,
592 : : input, output, tag, tag_len );
593 : : }
594 : :
595 : 16 : int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
596 : : const unsigned char *iv, size_t iv_len,
597 : : const unsigned char *add, size_t add_len,
598 : : const unsigned char *input, unsigned char *output,
599 : : const unsigned char *tag, size_t tag_len )
600 : : {
601 : 16 : return ccm_auth_decrypt( ctx, MBEDTLS_CCM_DECRYPT, length,
602 : : iv, iv_len, add, add_len,
603 : : input, output, tag, tag_len );
604 : : }
605 : : #endif /* !MBEDTLS_CCM_ALT */
606 : :
607 : : #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
608 : : /*
609 : : * Examples 1 to 3 from SP800-38C Appendix C
610 : : */
611 : :
612 : : #define NB_TESTS 3
613 : : #define CCM_SELFTEST_PT_MAX_LEN 24
614 : : #define CCM_SELFTEST_CT_MAX_LEN 32
615 : : /*
616 : : * The data is the same for all tests, only the used length changes
617 : : */
618 : : static const unsigned char key_test_data[] = {
619 : : 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
620 : : 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
621 : : };
622 : :
623 : : static const unsigned char iv_test_data[] = {
624 : : 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
625 : : 0x18, 0x19, 0x1a, 0x1b
626 : : };
627 : :
628 : : static const unsigned char ad_test_data[] = {
629 : : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
630 : : 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
631 : : 0x10, 0x11, 0x12, 0x13
632 : : };
633 : :
634 : : static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
635 : : 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
636 : : 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
637 : : 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
638 : : };
639 : :
640 : : static const size_t iv_len_test_data [NB_TESTS] = { 7, 8, 12 };
641 : : static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
642 : : static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
643 : : static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
644 : :
645 : : static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
646 : : { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
647 : : { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
648 : : 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
649 : : 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
650 : : { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
651 : : 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
652 : : 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
653 : : 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
654 : : };
655 : :
656 : : int mbedtls_ccm_self_test( int verbose )
657 : : {
658 : : mbedtls_ccm_context ctx;
659 : : /*
660 : : * Some hardware accelerators require the input and output buffers
661 : : * would be in RAM, because the flash is not accessible.
662 : : * Use buffers on the stack to hold the test vectors data.
663 : : */
664 : : unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
665 : : unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
666 : : size_t i;
667 : : int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
668 : :
669 : : mbedtls_ccm_init( &ctx );
670 : :
671 : : if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
672 : : 8 * sizeof key_test_data ) != 0 )
673 : : {
674 : : if( verbose != 0 )
675 : : mbedtls_printf( " CCM: setup failed" );
676 : :
677 : : return( 1 );
678 : : }
679 : :
680 : : for( i = 0; i < NB_TESTS; i++ )
681 : : {
682 : : if( verbose != 0 )
683 : : mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
684 : :
685 : : memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
686 : : memset( ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN );
687 : : memcpy( plaintext, msg_test_data, msg_len_test_data[i] );
688 : :
689 : : ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len_test_data[i],
690 : : iv_test_data, iv_len_test_data[i],
691 : : ad_test_data, add_len_test_data[i],
692 : : plaintext, ciphertext,
693 : : ciphertext + msg_len_test_data[i],
694 : : tag_len_test_data[i] );
695 : :
696 : : if( ret != 0 ||
697 : : memcmp( ciphertext, res_test_data[i],
698 : : msg_len_test_data[i] + tag_len_test_data[i] ) != 0 )
699 : : {
700 : : if( verbose != 0 )
701 : : mbedtls_printf( "failed\n" );
702 : :
703 : : return( 1 );
704 : : }
705 : : memset( plaintext, 0, CCM_SELFTEST_PT_MAX_LEN );
706 : :
707 : : ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len_test_data[i],
708 : : iv_test_data, iv_len_test_data[i],
709 : : ad_test_data, add_len_test_data[i],
710 : : ciphertext, plaintext,
711 : : ciphertext + msg_len_test_data[i],
712 : : tag_len_test_data[i] );
713 : :
714 : : if( ret != 0 ||
715 : : memcmp( plaintext, msg_test_data, msg_len_test_data[i] ) != 0 )
716 : : {
717 : : if( verbose != 0 )
718 : : mbedtls_printf( "failed\n" );
719 : :
720 : : return( 1 );
721 : : }
722 : :
723 : : if( verbose != 0 )
724 : : mbedtls_printf( "passed\n" );
725 : : }
726 : :
727 : : mbedtls_ccm_free( &ctx );
728 : :
729 : : if( verbose != 0 )
730 : : mbedtls_printf( "\n" );
731 : :
732 : : return( 0 );
733 : : }
734 : :
735 : : #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
736 : :
737 : : #endif /* MBEDTLS_CCM_C */
|