blob: c85545fc1a581d4002c87a2ce758f92dd2af5260 [file] [log] [blame]
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +02001/*
2 * NIST SP800-38C compliant CCM implementation
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +020018 */
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
Gilles Peskinedb09ef62020-06-03 01:43:33 +020029#include "common.h"
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +020030
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020031#if defined(MBEDTLS_CCM_C)
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +020032
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020033# include "mbedtls/ccm.h"
34# include "mbedtls/platform_util.h"
35# include "mbedtls/error.h"
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +020036
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020037# include <string.h>
Rich Evans00ab4702015-02-06 13:43:58 +000038
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020039# if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
40# if defined(MBEDTLS_PLATFORM_C)
41# include "mbedtls/platform.h"
42# else
43# include <stdio.h>
44# define mbedtls_printf printf
45# endif /* MBEDTLS_PLATFORM_C */
46# endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
Rich Evans00ab4702015-02-06 13:43:58 +000047
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020048# if !defined(MBEDTLS_CCM_ALT)
Steven Cooreman222e2ff2017-04-04 11:37:15 +020049
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020050# define CCM_VALIDATE_RET(cond) \
51 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_CCM_BAD_INPUT)
52# define CCM_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE(cond)
k-stachowiak26d365e2018-12-11 12:22:16 +010053
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020054# define CCM_ENCRYPT 0
55# define CCM_DECRYPT 1
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +020056
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020057/*
58 * Initialize context
59 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020060void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +020061{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020062 CCM_VALIDATE(ctx != NULL);
63 memset(ctx, 0, sizeof(mbedtls_ccm_context));
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +020064}
65
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020066int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
67 mbedtls_cipher_id_t cipher,
68 const unsigned char *key,
69 unsigned int keybits)
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020070{
Janos Follath24eed8d2019-11-22 13:21:35 +000071 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020072 const mbedtls_cipher_info_t *cipher_info;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020073
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020074 CCM_VALIDATE_RET(ctx != NULL);
75 CCM_VALIDATE_RET(key != NULL);
k-stachowiak26d365e2018-12-11 12:22:16 +010076
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020077 cipher_info =
78 mbedtls_cipher_info_from_values(cipher, keybits, MBEDTLS_MODE_ECB);
79 if (cipher_info == NULL)
80 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020081
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020082 if (cipher_info->block_size != 16)
83 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020084
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020085 mbedtls_cipher_free(&ctx->cipher_ctx);
Manuel Pégourié-Gonnard43b08572015-05-27 17:23:30 +020086
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020087 if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0)
88 return ret;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020089
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020090 if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
91 MBEDTLS_ENCRYPT)) != 0) {
92 return ret;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020093 }
94
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020095 return 0;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020096}
97
98/*
99 * Free context
100 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200101void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +0200102{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200103 if (ctx == NULL)
k-stachowiakfd42d532018-12-11 14:37:51 +0100104 return;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200105 mbedtls_cipher_free(&ctx->cipher_ctx);
106 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +0200107}
108
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200109/*
110 * Macros for common operations.
111 * Results in smaller compiled code than static inline functions.
112 */
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200113
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200114/*
115 * Update the CBC-MAC state in y using a block in b
116 * (Always using b as the source helps the compiler optimise a bit better.)
117 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200118# define UPDATE_CBC_MAC \
119 for (i = 0; i < 16; i++) \
120 y[i] ^= b[i]; \
121 \
122 if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, y, 16, y, \
123 &olen)) != 0) \
124 return ret;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200125
126/*
127 * Encrypt or decrypt a partial block with CTR
128 * Warning: using b for temporary storage! src and dst must not be b!
Manuel Pégourié-Gonnard0f6b66d2014-05-07 14:43:46 +0200129 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200130 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200131# define CTR_CRYPT(dst, src, len) \
132 do { \
133 if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctr, 16, b, \
134 &olen)) != 0) { \
135 return ret; \
136 } \
137 \
138 for (i = 0; i < (len); i++) \
139 (dst)[i] = (src)[i] ^ b[i]; \
140 } while (0)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200141
142/*
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200143 * Authenticated encryption or decryption
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200144 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200145static int ccm_auth_crypt(mbedtls_ccm_context *ctx,
146 int mode,
147 size_t length,
148 const unsigned char *iv,
149 size_t iv_len,
150 const unsigned char *add,
151 size_t add_len,
152 const unsigned char *input,
153 unsigned char *output,
154 unsigned char *tag,
155 size_t tag_len)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200156{
Janos Follath24eed8d2019-11-22 13:21:35 +0000157 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200158 unsigned char i;
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200159 unsigned char q;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200160 size_t len_left, olen;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200161 unsigned char b[16];
162 unsigned char y[16];
163 unsigned char ctr[16];
164 const unsigned char *src;
165 unsigned char *dst;
166
167 /*
168 * Check length requirements: SP800-38C A.1
169 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
170 * 'length' checked later (when writing it to the first block)
Janos Follath997e85c2018-05-29 11:33:45 +0100171 *
172 * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200173 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200174 if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0)
175 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200176
177 /* Also implies q is within bounds */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200178 if (iv_len < 7 || iv_len > 13)
179 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200180
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200181 if (add_len >= 0xFF00)
182 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200183
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200184 q = 16 - 1 - (unsigned char)iv_len;
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200185
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200186 /*
187 * First block B_0:
188 * 0 .. 0 flags
189 * 1 .. iv_len nonce (aka iv)
190 * iv_len+1 .. 15 length
191 *
192 * With flags as (bits):
193 * 7 0
194 * 6 add present?
195 * 5 .. 3 (t - 2) / 2
196 * 2 .. 0 q - 1
197 */
198 b[0] = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200199 b[0] |= (add_len > 0) << 6;
200 b[0] |= ((tag_len - 2) / 2) << 3;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200201 b[0] |= q - 1;
202
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200203 memcpy(b + 1, iv, iv_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200204
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200205 for (i = 0, len_left = length; i < q; i++, len_left >>= 8)
206 b[15 - i] = (unsigned char)(len_left & 0xFF);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200207
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200208 if (len_left > 0)
209 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200210
211 /* Start CBC-MAC with first block */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200212 memset(y, 0, 16);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200213 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200214
215 /*
216 * If there is additional data, update CBC-MAC with
217 * add_len, add, 0 (padding to a block boundary)
218 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200219 if (add_len > 0) {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200220 size_t use_len;
221 len_left = add_len;
222 src = add;
223
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200224 memset(b, 0, 16);
225 b[0] = (unsigned char)((add_len >> 8) & 0xFF);
226 b[1] = (unsigned char)((add_len)&0xFF);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200227
228 use_len = len_left < 16 - 2 ? len_left : 16 - 2;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200229 memcpy(b + 2, src, use_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200230 len_left -= use_len;
231 src += use_len;
232
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200233 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200234
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200235 while (len_left > 0) {
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200236 use_len = len_left > 16 ? 16 : len_left;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200237
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200238 memset(b, 0, 16);
239 memcpy(b, src, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200240 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200241
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200242 len_left -= use_len;
243 src += use_len;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200244 }
245 }
246
247 /*
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200248 * Prepare counter block for encryption:
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200249 * 0 .. 0 flags
250 * 1 .. iv_len nonce (aka iv)
251 * iv_len+1 .. 15 counter (initially 1)
252 *
253 * With flags as (bits):
254 * 7 .. 3 0
255 * 2 .. 0 q - 1
256 */
257 ctr[0] = q - 1;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200258 memcpy(ctr + 1, iv, iv_len);
259 memset(ctr + 1 + iv_len, 0, q);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200260 ctr[15] = 1;
261
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200262 /*
263 * Authenticate and {en,de}crypt the message.
264 *
265 * The only difference between encryption and decryption is
266 * the respective order of authentication and {en,de}cryption.
267 */
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200268 len_left = length;
269 src = input;
270 dst = output;
271
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200272 while (len_left > 0) {
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200273 size_t use_len = len_left > 16 ? 16 : len_left;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200274
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200275 if (mode == CCM_ENCRYPT) {
276 memset(b, 0, 16);
277 memcpy(b, src, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200278 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200279 }
280
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200281 CTR_CRYPT(dst, src, use_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200282
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200283 if (mode == CCM_DECRYPT) {
284 memset(b, 0, 16);
285 memcpy(b, dst, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200286 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200287 }
288
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200289 dst += use_len;
290 src += use_len;
291 len_left -= use_len;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200292
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200293 /*
294 * Increment counter.
295 * No need to check for overflow thanks to the length check above.
296 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200297 for (i = 0; i < q; i++)
298 if (++ctr[15 - i] != 0)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200299 break;
300 }
301
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200302 /*
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200303 * Authentication: reset counter and crypt/mask internal tag
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200304 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200305 for (i = 0; i < q; i++)
306 ctr[15 - i] = 0;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200307
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200308 CTR_CRYPT(y, y, 16);
309 memcpy(tag, y, tag_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200310
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200311 return 0;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200312}
313
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200314/*
315 * Authenticated encryption
316 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200317int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx,
318 size_t length,
319 const unsigned char *iv,
320 size_t iv_len,
321 const unsigned char *add,
322 size_t add_len,
323 const unsigned char *input,
324 unsigned char *output,
325 unsigned char *tag,
326 size_t tag_len)
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200327{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200328 CCM_VALIDATE_RET(ctx != NULL);
329 CCM_VALIDATE_RET(iv != NULL);
330 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
331 CCM_VALIDATE_RET(length == 0 || input != NULL);
332 CCM_VALIDATE_RET(length == 0 || output != NULL);
333 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
334 return (ccm_auth_crypt(ctx, CCM_ENCRYPT, length, iv, iv_len, add, add_len,
335 input, output, tag, tag_len));
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200336}
337
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200338int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx,
339 size_t length,
340 const unsigned char *iv,
341 size_t iv_len,
342 const unsigned char *add,
343 size_t add_len,
344 const unsigned char *input,
345 unsigned char *output,
346 unsigned char *tag,
347 size_t tag_len)
Janos Follathb5734a22018-05-14 14:31:49 +0100348{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200349 CCM_VALIDATE_RET(ctx != NULL);
350 CCM_VALIDATE_RET(iv != NULL);
351 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
352 CCM_VALIDATE_RET(length == 0 || input != NULL);
353 CCM_VALIDATE_RET(length == 0 || output != NULL);
354 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
355 if (tag_len == 0)
356 return MBEDTLS_ERR_CCM_BAD_INPUT;
Janos Follathb5734a22018-05-14 14:31:49 +0100357
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200358 return (mbedtls_ccm_star_encrypt_and_tag(
359 ctx, length, iv, iv_len, add, add_len, input, output, tag, tag_len));
Janos Follathb5734a22018-05-14 14:31:49 +0100360}
361
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200362/*
363 * Authenticated decryption
364 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200365int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx,
366 size_t length,
367 const unsigned char *iv,
368 size_t iv_len,
369 const unsigned char *add,
370 size_t add_len,
371 const unsigned char *input,
372 unsigned char *output,
373 const unsigned char *tag,
374 size_t tag_len)
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200375{
Janos Follath24eed8d2019-11-22 13:21:35 +0000376 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200377 unsigned char check_tag[16];
378 unsigned char i;
379 int diff;
380
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200381 CCM_VALIDATE_RET(ctx != NULL);
382 CCM_VALIDATE_RET(iv != NULL);
383 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
384 CCM_VALIDATE_RET(length == 0 || input != NULL);
385 CCM_VALIDATE_RET(length == 0 || output != NULL);
386 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
k-stachowiak26d365e2018-12-11 12:22:16 +0100387
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200388 if ((ret = ccm_auth_crypt(ctx, CCM_DECRYPT, length, iv, iv_len, add,
389 add_len, input, output, check_tag, tag_len)) !=
390 0) {
391 return ret;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200392 }
393
394 /* Check tag in "constant-time" */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200395 for (diff = 0, i = 0; i < tag_len; i++)
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200396 diff |= tag[i] ^ check_tag[i];
397
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200398 if (diff != 0) {
399 mbedtls_platform_zeroize(output, length);
400 return MBEDTLS_ERR_CCM_AUTH_FAILED;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200401 }
402
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200403 return 0;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200404}
405
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200406int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx,
407 size_t length,
408 const unsigned char *iv,
409 size_t iv_len,
410 const unsigned char *add,
411 size_t add_len,
412 const unsigned char *input,
413 unsigned char *output,
414 const unsigned char *tag,
415 size_t tag_len)
Janos Follathb5734a22018-05-14 14:31:49 +0100416{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200417 CCM_VALIDATE_RET(ctx != NULL);
418 CCM_VALIDATE_RET(iv != NULL);
419 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
420 CCM_VALIDATE_RET(length == 0 || input != NULL);
421 CCM_VALIDATE_RET(length == 0 || output != NULL);
422 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
k-stachowiakf7125342018-12-11 15:57:19 +0100423
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200424 if (tag_len == 0)
425 return MBEDTLS_ERR_CCM_BAD_INPUT;
Janos Follathb5734a22018-05-14 14:31:49 +0100426
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200427 return (mbedtls_ccm_star_auth_decrypt(ctx, length, iv, iv_len, add, add_len,
428 input, output, tag, tag_len));
Janos Follathb5734a22018-05-14 14:31:49 +0100429}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200430# endif /* !MBEDTLS_CCM_ALT */
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200431
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200432# if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200433/*
434 * Examples 1 to 3 from SP800-38C Appendix C
435 */
436
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200437# define NB_TESTS 3
438# define CCM_SELFTEST_PT_MAX_LEN 24
439# define CCM_SELFTEST_CT_MAX_LEN 32
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200440/*
441 * The data is the same for all tests, only the used length changes
442 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200443static const unsigned char key_test_data[] = { 0x40, 0x41, 0x42, 0x43,
444 0x44, 0x45, 0x46, 0x47,
445 0x48, 0x49, 0x4a, 0x4b,
446 0x4c, 0x4d, 0x4e, 0x4f };
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200447
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200448static const unsigned char iv_test_data[] = { 0x10, 0x11, 0x12, 0x13,
449 0x14, 0x15, 0x16, 0x17,
450 0x18, 0x19, 0x1a, 0x1b };
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200451
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200452static const unsigned char ad_test_data[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
453 0x05, 0x06, 0x07, 0x08, 0x09,
454 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
455 0x0f, 0x10, 0x11, 0x12, 0x13 };
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200456
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100457static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200458 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
459 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200460};
461
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200462static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 };
Michał Janiszewski9aeea932018-10-30 23:00:15 +0100463static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
464static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200465static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200466
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100467static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200468 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
469 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, 0x08, 0x1a, 0x77,
470 0x92, 0x07, 0x3d, 0x59, 0x3d, 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
471 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, 0x9b, 0x1c, 0xea,
472 0xec, 0xcd, 0x97, 0xe7, 0x0b, 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42,
473 0x8a, 0xa5, 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200474};
475
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200476int mbedtls_ccm_self_test(int verbose)
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200477{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200478 mbedtls_ccm_context ctx;
Ron Eldor1b9b2172018-04-26 14:15:01 +0300479 /*
480 * Some hardware accelerators require the input and output buffers
481 * would be in RAM, because the flash is not accessible.
482 * Use buffers on the stack to hold the test vectors data.
483 */
484 unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
485 unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200486 size_t i;
Janos Follath24eed8d2019-11-22 13:21:35 +0000487 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200488
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200489 mbedtls_ccm_init(&ctx);
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +0200490
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200491 if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
492 8 * sizeof(key_test_data)) != 0) {
493 if (verbose != 0)
494 mbedtls_printf(" CCM: setup failed");
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200495
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200496 return 1;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200497 }
498
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200499 for (i = 0; i < NB_TESTS; i++) {
500 if (verbose != 0)
501 mbedtls_printf(" CCM-AES #%u: ", (unsigned int)i + 1);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200502
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200503 memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
504 memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
505 memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
Ron Eldor1b9b2172018-04-26 14:15:01 +0300506
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200507 ret = mbedtls_ccm_encrypt_and_tag(
508 &ctx, msg_len_test_data[i], iv_test_data, iv_len_test_data[i],
509 ad_test_data, add_len_test_data[i], plaintext, ciphertext,
510 ciphertext + msg_len_test_data[i], tag_len_test_data[i]);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200511
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200512 if (ret != 0 ||
513 memcmp(ciphertext, res_test_data[i],
514 msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
515 if (verbose != 0)
516 mbedtls_printf("failed\n");
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200517
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200518 return 1;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200519 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200520 memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200521
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200522 ret = mbedtls_ccm_auth_decrypt(
523 &ctx, msg_len_test_data[i], iv_test_data, iv_len_test_data[i],
524 ad_test_data, add_len_test_data[i], ciphertext, plaintext,
525 ciphertext + msg_len_test_data[i], tag_len_test_data[i]);
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200526
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200527 if (ret != 0 ||
528 memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
529 if (verbose != 0)
530 mbedtls_printf("failed\n");
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200531
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200532 return 1;
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200533 }
534
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200535 if (verbose != 0)
536 mbedtls_printf("passed\n");
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200537 }
538
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200539 mbedtls_ccm_free(&ctx);
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200540
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200541 if (verbose != 0)
542 mbedtls_printf("\n");
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200543
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200544 return 0;
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200545}
546
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200547# endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200548
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200549#endif /* MBEDTLS_CCM_C */