PolarSSL v1.3.9
ccm.c
Go to the documentation of this file.
1/*
2 * NIST SP800-38C compliant CCM implementation
3 *
4 * Copyright (C) 2014, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26/*
27 * Definition of CCM:
28 * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
29 * RFC 3610 "Counter with CBC-MAC (CCM)"
30 *
31 * Related:
32 * RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
33 */
34
35#if !defined(POLARSSL_CONFIG_FILE)
36#include "polarssl/config.h"
37#else
38#include POLARSSL_CONFIG_FILE
39#endif
40
41#if defined(POLARSSL_CCM_C)
42
43#include "polarssl/ccm.h"
44
45/* Implementation that should never be optimized out by the compiler */
46static void polarssl_zeroize( void *v, size_t n ) {
47 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
48}
49
50#define CCM_ENCRYPT 0
51#define CCM_DECRYPT 1
52
53/*
54 * Initialize context
55 */
56int ccm_init( ccm_context *ctx, cipher_id_t cipher,
57 const unsigned char *key, unsigned int keysize )
58{
59 int ret;
60 const cipher_info_t *cipher_info;
61
62 memset( ctx, 0, sizeof( ccm_context ) );
63
64 cipher_init( &ctx->cipher_ctx );
65
66 cipher_info = cipher_info_from_values( cipher, keysize, POLARSSL_MODE_ECB );
67 if( cipher_info == NULL )
69
70 if( cipher_info->block_size != 16 )
72
73 if( ( ret = cipher_init_ctx( &ctx->cipher_ctx, cipher_info ) ) != 0 )
74 return( ret );
75
76 if( ( ret = cipher_setkey( &ctx->cipher_ctx, key, keysize,
77 POLARSSL_ENCRYPT ) ) != 0 )
78 {
79 return( ret );
80 }
81
82 return( 0 );
83}
84
85/*
86 * Free context
87 */
88void ccm_free( ccm_context *ctx )
89{
90 cipher_free( &ctx->cipher_ctx );
91 polarssl_zeroize( ctx, sizeof( ccm_context ) );
92}
93
94/*
95 * Macros for common operations.
96 * Results in smaller compiled code than static inline functions.
97 */
98
99/*
100 * Update the CBC-MAC state in y using a block in b
101 * (Always using b as the source helps the compiler optimise a bit better.)
102 */
103#define UPDATE_CBC_MAC \
104 for( i = 0; i < 16; i++ ) \
105 y[i] ^= b[i]; \
106 \
107 if( ( ret = cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
108 return( ret );
109
110/*
111 * Encrypt or decrypt a partial block with CTR
112 * Warning: using b for temporary storage! src and dst must not be b!
113 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
114 */
115#define CTR_CRYPT( dst, src, len ) \
116 if( ( ret = cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
117 return( ret ); \
118 \
119 for( i = 0; i < len; i++ ) \
120 dst[i] = src[i] ^ b[i];
121
122/*
123 * Authenticated encryption or decryption
124 */
125static int ccm_auth_crypt( ccm_context *ctx, int mode, size_t length,
126 const unsigned char *iv, size_t iv_len,
127 const unsigned char *add, size_t add_len,
128 const unsigned char *input, unsigned char *output,
129 unsigned char *tag, size_t tag_len )
130{
131 int ret;
132 unsigned char i;
133 unsigned char q = 16 - 1 - iv_len;
134 size_t len_left, olen;
135 unsigned char b[16];
136 unsigned char y[16];
137 unsigned char ctr[16];
138 const unsigned char *src;
139 unsigned char *dst;
140
141 /*
142 * Check length requirements: SP800-38C A.1
143 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
144 * 'length' checked later (when writing it to the first block)
145 */
146 if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 )
148
149 /* Also implies q is within bounds */
150 if( iv_len < 7 || iv_len > 13 )
152
153 if( add_len > 0xFF00 )
155
156 /*
157 * First block B_0:
158 * 0 .. 0 flags
159 * 1 .. iv_len nonce (aka iv)
160 * iv_len+1 .. 15 length
161 *
162 * With flags as (bits):
163 * 7 0
164 * 6 add present?
165 * 5 .. 3 (t - 2) / 2
166 * 2 .. 0 q - 1
167 */
168 b[0] = 0;
169 b[0] |= ( add_len > 0 ) << 6;
170 b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
171 b[0] |= q - 1;
172
173 memcpy( b + 1, iv, iv_len );
174
175 for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
176 b[15-i] = (unsigned char)( len_left & 0xFF );
177
178 if( len_left > 0 )
180
181
182 /* Start CBC-MAC with first block */
183 memset( y, 0, 16 );
184 UPDATE_CBC_MAC;
185
186 /*
187 * If there is additional data, update CBC-MAC with
188 * add_len, add, 0 (padding to a block boundary)
189 */
190 if( add_len > 0 )
191 {
192 size_t use_len;
193 len_left = add_len;
194 src = add;
195
196 memset( b, 0, 16 );
197 b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
198 b[1] = (unsigned char)( ( add_len ) & 0xFF );
199
200 use_len = len_left < 16 - 2 ? len_left : 16 - 2;
201 memcpy( b + 2, src, use_len );
202 len_left -= use_len;
203 src += use_len;
204
205 UPDATE_CBC_MAC;
206
207 while( len_left > 0 )
208 {
209 use_len = len_left > 16 ? 16 : len_left;
210
211 memset( b, 0, 16 );
212 memcpy( b, src, use_len );
213 UPDATE_CBC_MAC;
214
215 len_left -= use_len;
216 src += use_len;
217 }
218 }
219
220 /*
221 * Prepare counter block for encryption:
222 * 0 .. 0 flags
223 * 1 .. iv_len nonce (aka iv)
224 * iv_len+1 .. 15 counter (initially 1)
225 *
226 * With flags as (bits):
227 * 7 .. 3 0
228 * 2 .. 0 q - 1
229 */
230 ctr[0] = q - 1;
231 memcpy( ctr + 1, iv, iv_len );
232 memset( ctr + 1 + iv_len, 0, q );
233 ctr[15] = 1;
234
235 /*
236 * Authenticate and {en,de}crypt the message.
237 *
238 * The only difference between encryption and decryption is
239 * the respective order of authentication and {en,de}cryption.
240 */
241 len_left = length;
242 src = input;
243 dst = output;
244
245 while( len_left > 0 )
246 {
247 unsigned char use_len = len_left > 16 ? 16 : len_left;
248
249 if( mode == CCM_ENCRYPT )
250 {
251 memset( b, 0, 16 );
252 memcpy( b, src, use_len );
253 UPDATE_CBC_MAC;
254 }
255
256 CTR_CRYPT( dst, src, use_len );
257
258 if( mode == CCM_DECRYPT )
259 {
260 memset( b, 0, 16 );
261 memcpy( b, dst, use_len );
262 UPDATE_CBC_MAC;
263 }
264
265 dst += use_len;
266 src += use_len;
267 len_left -= use_len;
268
269 /*
270 * Increment counter.
271 * No need to check for overflow thanks to the length check above.
272 */
273 for( i = 0; i < q; i++ )
274 if( ++ctr[15-i] != 0 )
275 break;
276 }
277
278 /*
279 * Authentication: reset counter and crypt/mask internal tag
280 */
281 for( i = 0; i < q; i++ )
282 ctr[15-i] = 0;
283
284 CTR_CRYPT( y, y, 16 );
285 memcpy( tag, y, tag_len );
286
287 return( 0 );
288}
289
290/*
291 * Authenticated encryption
292 */
293int ccm_encrypt_and_tag( ccm_context *ctx, size_t length,
294 const unsigned char *iv, size_t iv_len,
295 const unsigned char *add, size_t add_len,
296 const unsigned char *input, unsigned char *output,
297 unsigned char *tag, size_t tag_len )
298{
299 return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
300 add, add_len, input, output, tag, tag_len ) );
301}
302
303/*
304 * Authenticated decryption
305 */
306int ccm_auth_decrypt( ccm_context *ctx, size_t length,
307 const unsigned char *iv, size_t iv_len,
308 const unsigned char *add, size_t add_len,
309 const unsigned char *input, unsigned char *output,
310 const unsigned char *tag, size_t tag_len )
311{
312 int ret;
313 unsigned char check_tag[16];
314 unsigned char i;
315 int diff;
316
317 if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
318 iv, iv_len, add, add_len,
319 input, output, check_tag, tag_len ) ) != 0 )
320 {
321 return( ret );
322 }
323
324 /* Check tag in "constant-time" */
325 for( diff = 0, i = 0; i < tag_len; i++ )
326 diff |= tag[i] ^ check_tag[i];
327
328 if( diff != 0 )
329 {
330 polarssl_zeroize( output, length );
332 }
333
334 return( 0 );
335}
336
337
338#if defined(POLARSSL_SELF_TEST) && defined(POLARSSL_AES_C)
339
340#if defined(POLARSSL_PLATFORM_C)
341#include "polarssl/platform.h"
342#else
343#include <stdio.h>
344#define polarssl_printf printf
345#endif
346
347/*
348 * Examples 1 to 3 from SP800-38C Appendix C
349 */
350
351#define NB_TESTS 3
352
353/*
354 * The data is the same for all tests, only the used length changes
355 */
356static const unsigned char key[] = {
357 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
358 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
359};
360
361static const unsigned char iv[] = {
362 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
363 0x18, 0x19, 0x1a, 0x1b
364};
365
366static const unsigned char ad[] = {
367 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
368 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
369 0x10, 0x11, 0x12, 0x13
370};
371
372static const unsigned char msg[] = {
373 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
374 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
375 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
376};
377
378static const size_t iv_len [NB_TESTS] = { 7, 8, 12 };
379static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
380static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
381static const size_t tag_len[NB_TESTS] = { 4, 6, 8 };
382
383static const unsigned char res[NB_TESTS][32] = {
384 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
385 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
386 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
387 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
388 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
389 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
390 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
391 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
392};
393
394int ccm_self_test( int verbose )
395{
396 ccm_context ctx;
397 unsigned char out[32];
398 size_t i;
399 int ret;
400
401 if( ccm_init( &ctx, POLARSSL_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
402 {
403 if( verbose != 0 )
404 polarssl_printf( " CCM: setup failed" );
405
406 return( 1 );
407 }
408
409 for( i = 0; i < NB_TESTS; i++ )
410 {
411 if( verbose != 0 )
412 polarssl_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
413
414 ret = ccm_encrypt_and_tag( &ctx, msg_len[i],
415 iv, iv_len[i], ad, add_len[i],
416 msg, out,
417 out + msg_len[i], tag_len[i] );
418
419 if( ret != 0 ||
420 memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 )
421 {
422 if( verbose != 0 )
423 polarssl_printf( "failed\n" );
424
425 return( 1 );
426 }
427
428 ret = ccm_auth_decrypt( &ctx, msg_len[i],
429 iv, iv_len[i], ad, add_len[i],
430 res[i], out,
431 res[i] + msg_len[i], tag_len[i] );
432
433 if( ret != 0 ||
434 memcmp( out, msg, msg_len[i] ) != 0 )
435 {
436 if( verbose != 0 )
437 polarssl_printf( "failed\n" );
438
439 return( 1 );
440 }
441
442 if( verbose != 0 )
443 polarssl_printf( "passed\n" );
444 }
445
446 ccm_free( &ctx );
447
448 if( verbose != 0 )
449 polarssl_printf( "\n" );
450
451 return( 0 );
452}
453
454#endif /* POLARSSL_SELF_TEST && POLARSSL_AES_C */
455
456#endif /* POLARSSL_CCM_C */
Counter with CBC-MAC (CCM) for 128-bit block ciphers.
int ccm_auth_decrypt(ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, const unsigned char *tag, size_t tag_len)
CCM buffer authenticated decryption.
int ccm_encrypt_and_tag(ccm_context *ctx, size_t length, const unsigned char *iv, size_t iv_len, const unsigned char *add, size_t add_len, const unsigned char *input, unsigned char *output, unsigned char *tag, size_t tag_len)
CCM buffer encryption.
#define POLARSSL_ERR_CCM_BAD_INPUT
Bad input parameters to function.
Definition ccm.h:32
#define POLARSSL_ERR_CCM_AUTH_FAILED
Authenticated decryption failed.
Definition ccm.h:33
void ccm_free(ccm_context *ctx)
Free a CCM context and underlying cipher sub-context.
int ccm_self_test(int verbose)
Checkup routine.
int ccm_init(ccm_context *ctx, cipher_id_t cipher, const unsigned char *key, unsigned int keysize)
CCM initialization (encryption and decryption)
cipher_id_t
Definition cipher.h:71
@ POLARSSL_CIPHER_ID_AES
Definition cipher.h:74
void cipher_init(cipher_context_t *ctx)
Initialize a cipher_context (as NONE)
@ POLARSSL_ENCRYPT
Definition cipher.h:157
int cipher_setkey(cipher_context_t *ctx, const unsigned char *key, int key_length, const operation_t operation)
Set the key to use with the given context.
int cipher_init_ctx(cipher_context_t *ctx, const cipher_info_t *cipher_info)
Initialises and fills the cipher context structure with the appropriate values.
void cipher_free(cipher_context_t *ctx)
Free and clear the cipher-specific context of ctx.
@ POLARSSL_MODE_ECB
Definition cipher.h:136
const cipher_info_t * cipher_info_from_values(const cipher_id_t cipher_id, int key_length, const cipher_mode_t mode)
Returns the cipher information structure associated with the given cipher id, key size and mode.
Configuration options (set of defines)
PolarSSL Platform abstraction layer.
CCM context structure.
Definition ccm.h:42
cipher_context_t cipher_ctx
Definition ccm.h:43
Cipher information.
Definition cipher.h:226
unsigned int block_size
block size, in bytes
Definition cipher.h:248
#define polarssl_printf