blob: 79a04a275aefc50f3aedad70e52402915de3dc11 [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
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000033#include "mbedtls/ccm.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050034#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000035#include "mbedtls/error.h"
Dave Rodgmanc2805202023-09-11 18:25:16 +010036#include "mbedtls/constant_time.h"
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +020037
Rich Evans00ab4702015-02-06 13:43:58 +000038#include <string.h>
39
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000040#include "mbedtls/platform.h"
Rich Evans00ab4702015-02-06 13:43:58 +000041
Steven Cooreman222e2ff2017-04-04 11:37:15 +020042#if !defined(MBEDTLS_CCM_ALT)
43
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010044#define CCM_VALIDATE_RET(cond) \
45 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_CCM_BAD_INPUT)
46#define CCM_VALIDATE(cond) \
47 MBEDTLS_INTERNAL_VALIDATE(cond)
k-stachowiak26d365e2018-12-11 12:22:16 +010048
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +020049#define CCM_ENCRYPT 0
50#define CCM_DECRYPT 1
51
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020052/*
53 * Initialize context
54 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010055void mbedtls_ccm_init(mbedtls_ccm_context *ctx)
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +020056{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010057 CCM_VALIDATE(ctx != NULL);
58 memset(ctx, 0, sizeof(mbedtls_ccm_context));
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +020059}
60
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010061int mbedtls_ccm_setkey(mbedtls_ccm_context *ctx,
62 mbedtls_cipher_id_t cipher,
63 const unsigned char *key,
64 unsigned int keybits)
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020065{
Janos Follath24eed8d2019-11-22 13:21:35 +000066 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020067 const mbedtls_cipher_info_t *cipher_info;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020068
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010069 CCM_VALIDATE_RET(ctx != NULL);
70 CCM_VALIDATE_RET(key != NULL);
k-stachowiak26d365e2018-12-11 12:22:16 +010071
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072 cipher_info = mbedtls_cipher_info_from_values(cipher, keybits,
73 MBEDTLS_MODE_ECB);
74 if (cipher_info == NULL) {
75 return MBEDTLS_ERR_CCM_BAD_INPUT;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020076 }
77
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010078 if (cipher_info->block_size != 16) {
79 return MBEDTLS_ERR_CCM_BAD_INPUT;
80 }
81
82 mbedtls_cipher_free(&ctx->cipher_ctx);
83
84 if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
85 return ret;
86 }
87
88 if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
89 MBEDTLS_ENCRYPT)) != 0) {
90 return ret;
91 }
92
93 return 0;
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +020094}
95
96/*
97 * Free context
98 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010099void mbedtls_ccm_free(mbedtls_ccm_context *ctx)
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +0200100{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100101 if (ctx == NULL) {
k-stachowiakfd42d532018-12-11 14:37:51 +0100102 return;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100103 }
104 mbedtls_cipher_free(&ctx->cipher_ctx);
105 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ccm_context));
Manuel Pégourié-Gonnard9fe0d132014-05-06 12:12:45 +0200106}
107
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200108/*
109 * Macros for common operations.
110 * Results in smaller compiled code than static inline functions.
111 */
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200112
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200113/*
114 * Update the CBC-MAC state in y using a block in b
115 * (Always using b as the source helps the compiler optimise a bit better.)
116 */
117#define UPDATE_CBC_MAC \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100118 for (i = 0; i < 16; i++) \
119 y[i] ^= b[i]; \
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200120 \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100121 if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, y, 16, y, &olen)) != 0) \
122 return ret;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200123
124/*
125 * Encrypt or decrypt a partial block with CTR
126 * Warning: using b for temporary storage! src and dst must not be b!
Manuel Pégourié-Gonnard0f6b66d2014-05-07 14:43:46 +0200127 * This avoids allocating one more 16 bytes buffer while allowing src == dst.
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200128 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100129#define CTR_CRYPT(dst, src, len) \
Hanno Becker1eeca412018-10-15 12:01:35 +0100130 do \
131 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100132 if ((ret = mbedtls_cipher_update(&ctx->cipher_ctx, ctr, \
133 16, b, &olen)) != 0) \
Hanno Becker1eeca412018-10-15 12:01:35 +0100134 { \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100135 return ret; \
Hanno Becker1eeca412018-10-15 12:01:35 +0100136 } \
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100137 \
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 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100145static int ccm_auth_crypt(mbedtls_ccm_context *ctx, int mode, size_t length,
146 const unsigned char *iv, size_t iv_len,
147 const unsigned char *add, size_t add_len,
148 const unsigned char *input, unsigned char *output,
149 unsigned char *tag, size_t tag_len)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200150{
Janos Follath24eed8d2019-11-22 13:21:35 +0000151 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200152 unsigned char i;
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200153 unsigned char q;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200154 size_t len_left, olen;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200155 unsigned char b[16];
156 unsigned char y[16];
157 unsigned char ctr[16];
158 const unsigned char *src;
159 unsigned char *dst;
160
161 /*
162 * Check length requirements: SP800-38C A.1
163 * Additional requirement: a < 2^16 - 2^8 to simplify the code.
164 * 'length' checked later (when writing it to the first block)
Janos Follath997e85c2018-05-29 11:33:45 +0100165 *
166 * Also, loosen the requirements to enable support for CCM* (IEEE 802.15.4).
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200167 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100168 if (tag_len == 2 || tag_len > 16 || tag_len % 2 != 0) {
169 return MBEDTLS_ERR_CCM_BAD_INPUT;
170 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200171
172 /* Also implies q is within bounds */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100173 if (iv_len < 7 || iv_len > 13) {
174 return MBEDTLS_ERR_CCM_BAD_INPUT;
175 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200176
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100177 if (add_len >= 0xFF00) {
178 return MBEDTLS_ERR_CCM_BAD_INPUT;
179 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200180
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200181 q = 16 - 1 - (unsigned char) iv_len;
182
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200183 /*
184 * First block B_0:
185 * 0 .. 0 flags
186 * 1 .. iv_len nonce (aka iv)
187 * iv_len+1 .. 15 length
188 *
189 * With flags as (bits):
190 * 7 0
191 * 6 add present?
192 * 5 .. 3 (t - 2) / 2
193 * 2 .. 0 q - 1
194 */
195 b[0] = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100196 b[0] |= (add_len > 0) << 6;
197 b[0] |= ((tag_len - 2) / 2) << 3;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200198 b[0] |= q - 1;
199
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 memcpy(b + 1, iv, iv_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200201
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 for (i = 0, len_left = length; i < q; i++, len_left >>= 8) {
203 b[15-i] = MBEDTLS_BYTE_0(len_left);
204 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200205
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100206 if (len_left > 0) {
207 return MBEDTLS_ERR_CCM_BAD_INPUT;
208 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200209
210
211 /* Start CBC-MAC with first block */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100212 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 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100219 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
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100224 memset(b, 0, 16);
225 MBEDTLS_PUT_UINT16_BE(add_len, b, 0);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200226
227 use_len = len_left < 16 - 2 ? len_left : 16 - 2;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100228 memcpy(b + 2, src, use_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200229 len_left -= use_len;
230 src += use_len;
231
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200232 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200233
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234 while (len_left > 0) {
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200235 use_len = len_left > 16 ? 16 : len_left;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200236
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100237 memset(b, 0, 16);
238 memcpy(b, src, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200239 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200240
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200241 len_left -= use_len;
242 src += use_len;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200243 }
244 }
245
246 /*
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200247 * Prepare counter block for encryption:
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200248 * 0 .. 0 flags
249 * 1 .. iv_len nonce (aka iv)
250 * iv_len+1 .. 15 counter (initially 1)
251 *
252 * With flags as (bits):
253 * 7 .. 3 0
254 * 2 .. 0 q - 1
255 */
256 ctr[0] = q - 1;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100257 memcpy(ctr + 1, iv, iv_len);
258 memset(ctr + 1 + iv_len, 0, q);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200259 ctr[15] = 1;
260
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200261 /*
262 * Authenticate and {en,de}crypt the message.
263 *
264 * The only difference between encryption and decryption is
265 * the respective order of authentication and {en,de}cryption.
266 */
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200267 len_left = length;
268 src = input;
269 dst = output;
270
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100271 while (len_left > 0) {
Manuel Pégourié-Gonnard9de64f52015-07-01 15:51:43 +0200272 size_t use_len = len_left > 16 ? 16 : len_left;
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200273
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100274 if (mode == CCM_ENCRYPT) {
275 memset(b, 0, 16);
276 memcpy(b, src, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200277 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200278 }
279
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100280 CTR_CRYPT(dst, src, use_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200281
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 if (mode == CCM_DECRYPT) {
283 memset(b, 0, 16);
284 memcpy(b, dst, use_len);
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200285 UPDATE_CBC_MAC;
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200286 }
287
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200288 dst += use_len;
289 src += use_len;
290 len_left -= use_len;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200291
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200292 /*
293 * Increment counter.
294 * No need to check for overflow thanks to the length check above.
295 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100296 for (i = 0; i < q; i++) {
297 if (++ctr[15-i] != 0) {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200298 break;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100299 }
300 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200301 }
302
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200303 /*
Manuel Pégourié-Gonnardaed60652014-05-07 13:14:42 +0200304 * Authentication: reset counter and crypt/mask internal tag
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200305 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100306 for (i = 0; i < q; i++) {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200307 ctr[15-i] = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100308 }
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200309
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100310 CTR_CRYPT(y, y, 16);
311 memcpy(tag, y, tag_len);
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200312
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100313 return 0;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200314}
315
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200316/*
317 * Authenticated encryption
318 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100319int mbedtls_ccm_star_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
320 const unsigned char *iv, size_t iv_len,
321 const unsigned char *add, size_t add_len,
322 const unsigned char *input, unsigned char *output,
323 unsigned char *tag, size_t tag_len)
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200324{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100325 CCM_VALIDATE_RET(ctx != NULL);
326 CCM_VALIDATE_RET(iv != NULL);
327 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
328 CCM_VALIDATE_RET(length == 0 || input != NULL);
329 CCM_VALIDATE_RET(length == 0 || output != NULL);
330 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
331 return ccm_auth_crypt(ctx, CCM_ENCRYPT, length, iv, iv_len,
332 add, add_len, input, output, tag, tag_len);
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200333}
334
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100335int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx, size_t length,
336 const unsigned char *iv, size_t iv_len,
337 const unsigned char *add, size_t add_len,
338 const unsigned char *input, unsigned char *output,
339 unsigned char *tag, size_t tag_len)
Janos Follathb5734a22018-05-14 14:31:49 +0100340{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100341 CCM_VALIDATE_RET(ctx != NULL);
342 CCM_VALIDATE_RET(iv != NULL);
343 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
344 CCM_VALIDATE_RET(length == 0 || input != NULL);
345 CCM_VALIDATE_RET(length == 0 || output != NULL);
346 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
347 if (tag_len == 0) {
348 return MBEDTLS_ERR_CCM_BAD_INPUT;
349 }
Janos Follathb5734a22018-05-14 14:31:49 +0100350
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351 return mbedtls_ccm_star_encrypt_and_tag(ctx, length, iv, iv_len, add,
352 add_len, input, output, tag, tag_len);
Janos Follathb5734a22018-05-14 14:31:49 +0100353}
354
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200355/*
356 * Authenticated decryption
357 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100358int mbedtls_ccm_star_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
359 const unsigned char *iv, size_t iv_len,
360 const unsigned char *add, size_t add_len,
361 const unsigned char *input, unsigned char *output,
362 const unsigned char *tag, size_t tag_len)
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200363{
Janos Follath24eed8d2019-11-22 13:21:35 +0000364 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200365 unsigned char check_tag[16];
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200366 int diff;
367
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 CCM_VALIDATE_RET(ctx != NULL);
369 CCM_VALIDATE_RET(iv != NULL);
370 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
371 CCM_VALIDATE_RET(length == 0 || input != NULL);
372 CCM_VALIDATE_RET(length == 0 || output != NULL);
373 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
k-stachowiak26d365e2018-12-11 12:22:16 +0100374
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100375 if ((ret = ccm_auth_crypt(ctx, CCM_DECRYPT, length,
376 iv, iv_len, add, add_len,
377 input, output, check_tag, tag_len)) != 0) {
378 return ret;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200379 }
380
381 /* Check tag in "constant-time" */
Dave Rodgmanc2805202023-09-11 18:25:16 +0100382 diff = mbedtls_ct_memcmp(tag, check_tag, tag_len);
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200383
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100384 if (diff != 0) {
385 mbedtls_platform_zeroize(output, length);
386 return MBEDTLS_ERR_CCM_AUTH_FAILED;
387 }
388
389 return 0;
Manuel Pégourié-Gonnard00232332014-05-06 15:56:07 +0200390}
391
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100392int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx, size_t length,
393 const unsigned char *iv, size_t iv_len,
394 const unsigned char *add, size_t add_len,
395 const unsigned char *input, unsigned char *output,
396 const unsigned char *tag, size_t tag_len)
Janos Follathb5734a22018-05-14 14:31:49 +0100397{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100398 CCM_VALIDATE_RET(ctx != NULL);
399 CCM_VALIDATE_RET(iv != NULL);
400 CCM_VALIDATE_RET(add_len == 0 || add != NULL);
401 CCM_VALIDATE_RET(length == 0 || input != NULL);
402 CCM_VALIDATE_RET(length == 0 || output != NULL);
403 CCM_VALIDATE_RET(tag_len == 0 || tag != NULL);
k-stachowiakf7125342018-12-11 15:57:19 +0100404
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100405 if (tag_len == 0) {
406 return MBEDTLS_ERR_CCM_BAD_INPUT;
407 }
Janos Follathb5734a22018-05-14 14:31:49 +0100408
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100409 return mbedtls_ccm_star_auth_decrypt(ctx, length, iv, iv_len, add,
410 add_len, input, output, tag, tag_len);
Janos Follathb5734a22018-05-14 14:31:49 +0100411}
Steven Cooreman222e2ff2017-04-04 11:37:15 +0200412#endif /* !MBEDTLS_CCM_ALT */
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200413
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200414#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200415/*
416 * Examples 1 to 3 from SP800-38C Appendix C
417 */
418
419#define NB_TESTS 3
Ron Eldor1b9b2172018-04-26 14:15:01 +0300420#define CCM_SELFTEST_PT_MAX_LEN 24
421#define CCM_SELFTEST_CT_MAX_LEN 32
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200422/*
423 * The data is the same for all tests, only the used length changes
424 */
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100425static const unsigned char key_test_data[] = {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200426 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
427 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
428};
429
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100430static const unsigned char iv_test_data[] = {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200431 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
432 0x18, 0x19, 0x1a, 0x1b
433};
434
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100435static const unsigned char ad_test_data[] = {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200436 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
437 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
438 0x10, 0x11, 0x12, 0x13
439};
440
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100441static const unsigned char msg_test_data[CCM_SELFTEST_PT_MAX_LEN] = {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200442 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
443 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
444 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
445};
446
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100447static const size_t iv_len_test_data[NB_TESTS] = { 7, 8, 12 };
Michał Janiszewski9aeea932018-10-30 23:00:15 +0100448static const size_t add_len_test_data[NB_TESTS] = { 8, 16, 20 };
449static const size_t msg_len_test_data[NB_TESTS] = { 4, 16, 24 };
450static const size_t tag_len_test_data[NB_TESTS] = { 4, 6, 8 };
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200451
Michał Janiszewskic79e92b2018-10-31 20:43:05 +0100452static const unsigned char res_test_data[NB_TESTS][CCM_SELFTEST_CT_MAX_LEN] = {
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200453 { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
454 { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
455 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
456 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
457 { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
458 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
459 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
460 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
461};
462
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100463int mbedtls_ccm_self_test(int verbose)
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200464{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200465 mbedtls_ccm_context ctx;
Ron Eldor1b9b2172018-04-26 14:15:01 +0300466 /*
467 * Some hardware accelerators require the input and output buffers
468 * would be in RAM, because the flash is not accessible.
469 * Use buffers on the stack to hold the test vectors data.
470 */
471 unsigned char plaintext[CCM_SELFTEST_PT_MAX_LEN];
472 unsigned char ciphertext[CCM_SELFTEST_CT_MAX_LEN];
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200473 size_t i;
Janos Follath24eed8d2019-11-22 13:21:35 +0000474 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200475
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100476 mbedtls_ccm_init(&ctx);
Manuel Pégourié-Gonnard6963ff02015-04-28 18:02:54 +0200477
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100478 if (mbedtls_ccm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key_test_data,
Dave Rodgman18688702023-02-02 12:40:50 +0000479 8 * sizeof(key_test_data)) != 0) {
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100480 if (verbose != 0) {
481 mbedtls_printf(" CCM: setup failed");
Manuel Pégourié-Gonnardce77d552014-05-06 18:06:52 +0200482 }
483
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100484 return 1;
Manuel Pégourié-Gonnard637eb3d2014-05-06 12:13:09 +0200485 }
486
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100487 for (i = 0; i < NB_TESTS; i++) {
488 if (verbose != 0) {
489 mbedtls_printf(" CCM-AES #%u: ", (unsigned int) i + 1);
490 }
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200491
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100492 memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
493 memset(ciphertext, 0, CCM_SELFTEST_CT_MAX_LEN);
494 memcpy(plaintext, msg_test_data, msg_len_test_data[i]);
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200495
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100496 ret = mbedtls_ccm_encrypt_and_tag(&ctx, msg_len_test_data[i],
497 iv_test_data, iv_len_test_data[i],
498 ad_test_data, add_len_test_data[i],
499 plaintext, ciphertext,
500 ciphertext + msg_len_test_data[i],
501 tag_len_test_data[i]);
502
503 if (ret != 0 ||
504 memcmp(ciphertext, res_test_data[i],
505 msg_len_test_data[i] + tag_len_test_data[i]) != 0) {
506 if (verbose != 0) {
507 mbedtls_printf("failed\n");
508 }
509
510 return 1;
511 }
512 memset(plaintext, 0, CCM_SELFTEST_PT_MAX_LEN);
513
514 ret = mbedtls_ccm_auth_decrypt(&ctx, msg_len_test_data[i],
515 iv_test_data, iv_len_test_data[i],
516 ad_test_data, add_len_test_data[i],
517 ciphertext, plaintext,
518 ciphertext + msg_len_test_data[i],
519 tag_len_test_data[i]);
520
521 if (ret != 0 ||
522 memcmp(plaintext, msg_test_data, msg_len_test_data[i]) != 0) {
523 if (verbose != 0) {
524 mbedtls_printf("failed\n");
525 }
526
527 return 1;
528 }
529
530 if (verbose != 0) {
531 mbedtls_printf("passed\n");
532 }
533 }
534
535 mbedtls_ccm_free(&ctx);
536
537 if (verbose != 0) {
538 mbedtls_printf("\n");
539 }
540
541 return 0;
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200542}
543
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200544#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
Manuel Pégourié-Gonnarda6916fa2014-05-02 15:17:29 +0200545
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200546#endif /* MBEDTLS_CCM_C */