blob: 5a5b995c1674949af957aed07b23149841cf18a3 [file] [log] [blame]
Ron Eldorcb349ac2018-07-15 09:29:47 +03001/*
2 * Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
3 * only
4 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02005 * Copyright The Mbed TLS Contributors
Dave Rodgman7ff79652023-11-03 12:04:52 +00006 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Ron Eldorcb349ac2018-07-15 09:29:47 +03007 */
8/*
9 * Definition of Key Wrapping:
10 * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
11 * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
12 * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
13 *
14 * Note: RFC 3394 defines different methodology for intermediate operations for
15 * the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
16 */
17
Gilles Peskinedb09ef62020-06-03 01:43:33 +020018#include "common.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030019
20#if defined(MBEDTLS_NIST_KW_C)
21
22#include "mbedtls/nist_kw.h"
23#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000024#include "mbedtls/error.h"
Gabor Mezeie24dea82021-10-19 12:22:25 +020025#include "mbedtls/constant_time.h"
Dave Rodgman40dc3b32023-09-20 14:23:29 +010026#include "constant_time_internal.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030027
28#include <stdint.h>
29#include <string.h>
30
Ron Eldorcb349ac2018-07-15 09:29:47 +030031#include "mbedtls/platform.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030032
33#if !defined(MBEDTLS_NIST_KW_ALT)
34
35#define KW_SEMIBLOCK_LENGTH 8
36#define MIN_SEMIBLOCKS_COUNT 3
37
Ron Eldorcb349ac2018-07-15 09:29:47 +030038/*! The 64-bit default integrity check value (ICV) for KW mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010039static const unsigned char NIST_KW_ICV1[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030040/*! The 32-bit default integrity check value (ICV) for KWP mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010041static const unsigned char NIST_KW_ICV2[] = { 0xA6, 0x59, 0x59, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030042
Ron Eldorcb349ac2018-07-15 09:29:47 +030043/*
44 * Initialize context
45 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010046void mbedtls_nist_kw_init(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +030047{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010048 memset(ctx, 0, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +030049}
50
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051int mbedtls_nist_kw_setkey(mbedtls_nist_kw_context *ctx,
52 mbedtls_cipher_id_t cipher,
53 const unsigned char *key,
54 unsigned int keybits,
55 const int is_wrap)
Ron Eldorcb349ac2018-07-15 09:29:47 +030056{
Janos Follath24eed8d2019-11-22 13:21:35 +000057 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Ron Eldorcb349ac2018-07-15 09:29:47 +030058 const mbedtls_cipher_info_t *cipher_info;
59
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060 cipher_info = mbedtls_cipher_info_from_values(cipher,
61 keybits,
62 MBEDTLS_MODE_ECB);
63 if (cipher_info == NULL) {
64 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
65 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030066
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010067 if (cipher_info->block_size != 16) {
68 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
69 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030070
71 /*
72 * SP 800-38F currently defines AES cipher as the only block cipher allowed:
73 * "For KW and KWP, the underlying block cipher shall be approved, and the
74 * block size shall be 128 bits. Currently, the AES block cipher, with key
75 * lengths of 128, 192, or 256 bits, is the only block cipher that fits
76 * this profile."
77 * Currently we don't support other 128 bit block ciphers for key wrapping,
78 * such as Camellia and Aria.
79 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010080 if (cipher != MBEDTLS_CIPHER_ID_AES) {
81 return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
Ron Eldorcb349ac2018-07-15 09:29:47 +030082 }
83
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010084 mbedtls_cipher_free(&ctx->cipher_ctx);
85
86 if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
87 return ret;
88 }
89
90 if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
91 is_wrap ? MBEDTLS_ENCRYPT :
92 MBEDTLS_DECRYPT)
93 ) != 0) {
94 return ret;
95 }
96
97 return 0;
Ron Eldorcb349ac2018-07-15 09:29:47 +030098}
99
100/*
101 * Free context
102 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100103void mbedtls_nist_kw_free(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300104{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100105 mbedtls_cipher_free(&ctx->cipher_ctx);
106 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300107}
108
109/*
110 * Helper function for Xoring the uint64_t "t" with the encrypted A.
111 * Defined in NIST SP 800-38F section 6.1
112 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100113static void calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300114{
115 size_t i = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100116 for (i = 0; i < sizeof(t); i++) {
117 A[i] ^= (t >> ((sizeof(t) - 1 - i) * 8)) & 0xff;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300118 }
119}
120
121/*
122 * KW-AE as defined in SP 800-38F section 6.2
123 * KWP-AE as defined in SP 800-38F section 6.3
124 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100125int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx,
126 mbedtls_nist_kw_mode_t mode,
127 const unsigned char *input, size_t in_len,
128 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300129{
130 int ret = 0;
131 size_t semiblocks = 0;
132 size_t s;
133 size_t olen, padlen = 0;
134 uint64_t t = 0;
135 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
136 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Ron Eldorcb349ac2018-07-15 09:29:47 +0300137
138 *out_len = 0;
139 /*
140 * Generate the String to work on
141 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100142 if (mode == MBEDTLS_KW_MODE_KW) {
143 if (out_size < in_len + KW_SEMIBLOCK_LENGTH) {
144 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300145 }
146
147 /*
148 * According to SP 800-38F Table 1, the plaintext length for KW
149 * must be between 2 to 2^54-1 semiblocks inclusive.
150 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100151 if (in_len < 16 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300152#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
153 in_len > 0x1FFFFFFFFFFFFF8 ||
154#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100155 in_len % KW_SEMIBLOCK_LENGTH != 0) {
156 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300157 }
158
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100159 memcpy(output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH);
160 memmove(output + KW_SEMIBLOCK_LENGTH, input, in_len);
161 } else {
162 if (in_len % 8 != 0) {
163 padlen = (8 - (in_len % 8));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300164 }
165
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100166 if (out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen) {
167 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300168 }
169
170 /*
171 * According to SP 800-38F Table 1, the plaintext length for KWP
172 * must be between 1 and 2^32-1 octets inclusive.
173 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100174 if (in_len < 1
Ron Eldorcb349ac2018-07-15 09:29:47 +0300175#if SIZE_MAX > 0xFFFFFFFF
176 || in_len > 0xFFFFFFFF
177#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100178 ) {
179 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300180 }
181
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100182 memcpy(output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2);
183 MBEDTLS_PUT_UINT32_BE((in_len & 0xffffffff), output,
184 KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300185
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100186 memcpy(output + KW_SEMIBLOCK_LENGTH, input, in_len);
187 memset(output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300188 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100189 semiblocks = ((in_len + padlen) / KW_SEMIBLOCK_LENGTH) + 1;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300190
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100191 s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300192
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100193 if (mode == MBEDTLS_KW_MODE_KWP
194 && in_len <= KW_SEMIBLOCK_LENGTH) {
195 memcpy(inbuff, output, 16);
196 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
197 inbuff, 16, output, &olen);
198 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300199 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 }
201 } else {
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200202 unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
203 unsigned char *A = output;
204
Ron Eldorcb349ac2018-07-15 09:29:47 +0300205 /*
206 * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
207 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100208 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300209 ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
210 goto cleanup;
211 }
212
213 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100214 for (t = 1; t <= s; t++) {
215 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
216 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300217
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100218 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
219 inbuff, 16, outbuff, &olen);
220 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300221 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100222 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300223
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100224 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
225 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300226
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100227 memcpy(R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300228 R2 += KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100229 if (R2 >= output + (semiblocks * KW_SEMIBLOCK_LENGTH)) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300230 R2 = output + KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100231 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300232 }
233 }
234
235 *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
236
237cleanup:
238
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100239 if (ret != 0) {
240 memset(output, 0, semiblocks * KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300241 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100242 mbedtls_platform_zeroize(inbuff, KW_SEMIBLOCK_LENGTH * 2);
243 mbedtls_platform_zeroize(outbuff, KW_SEMIBLOCK_LENGTH * 2);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500244
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100245 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300246}
247
248/*
249 * W-1 function as defined in RFC 3394 section 2.2.2
250 * This function assumes the following:
251 * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
252 * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
253 * 3. Minimal number of semiblocks is 3.
254 * 4. A is a buffer to hold the first semiblock of the input buffer.
255 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256static int unwrap(mbedtls_nist_kw_context *ctx,
257 const unsigned char *input, size_t semiblocks,
258 unsigned char A[KW_SEMIBLOCK_LENGTH],
259 unsigned char *output, size_t *out_len)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300260{
261 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100262 const size_t s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300263 size_t olen;
264 uint64_t t = 0;
265 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
266 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200267 unsigned char *R = NULL;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300268 *out_len = 0;
269
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100270 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
271 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300272 }
273
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100274 memcpy(A, input, KW_SEMIBLOCK_LENGTH);
275 memmove(output, input + KW_SEMIBLOCK_LENGTH, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
276 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300277
278 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100279 for (t = s; t >= 1; t--) {
280 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300281
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
283 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300284
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100285 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
286 inbuff, 16, outbuff, &olen);
287 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300288 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100289 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300290
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100291 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300292
293 /* Set R as LSB64 of outbuff */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100294 memcpy(R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300295
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100296 if (R == output) {
297 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
298 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300299 R -= KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100300 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300301 }
302
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100303 *out_len = (semiblocks - 1) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300304
305cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100306 if (ret != 0) {
307 memset(output, 0, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
308 }
309 mbedtls_platform_zeroize(inbuff, sizeof(inbuff));
310 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300311
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100312 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300313}
314
315/*
316 * KW-AD as defined in SP 800-38F section 6.2
317 * KWP-AD as defined in SP 800-38F section 6.3
318 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100319int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx,
320 mbedtls_nist_kw_mode_t mode,
321 const unsigned char *input, size_t in_len,
322 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300323{
324 int ret = 0;
325 size_t i, olen;
326 unsigned char A[KW_SEMIBLOCK_LENGTH];
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100327 unsigned char diff;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300328
329 *out_len = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100330 if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
331 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300332 }
333
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100334 if (mode == MBEDTLS_KW_MODE_KW) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300335 /*
336 * According to SP 800-38F Table 1, the ciphertext length for KW
337 * must be between 3 to 2^54 semiblocks inclusive.
338 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100339 if (in_len < 24 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300340#if SIZE_MAX > 0x200000000000000
341 in_len > 0x200000000000000 ||
342#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100343 in_len % KW_SEMIBLOCK_LENGTH != 0) {
344 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300345 }
346
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100347 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
348 A, output, out_len);
349 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300350 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300352
353 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100354 diff = mbedtls_ct_memcmp(NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300355
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100356 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300357 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
358 goto cleanup;
359 }
360
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100361 } else if (mode == MBEDTLS_KW_MODE_KWP) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300362 size_t padlen = 0;
363 uint32_t Plen;
364 /*
365 * According to SP 800-38F Table 1, the ciphertext length for KWP
366 * must be between 2 to 2^29 semiblocks inclusive.
367 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 if (in_len < KW_SEMIBLOCK_LENGTH * 2 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300369#if SIZE_MAX > 0x100000000
370 in_len > 0x100000000 ||
371#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100372 in_len % KW_SEMIBLOCK_LENGTH != 0) {
373 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300374 }
375
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100376 if (in_len == KW_SEMIBLOCK_LENGTH * 2) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300377 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100378 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
379 input, 16, outbuff, &olen);
380 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300381 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100382 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300383
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100384 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
385 memcpy(output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
386 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300387 *out_len = KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300389 /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100390 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
391 A, output, out_len);
392 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300393 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100394 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300395 }
396
397 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100398 diff = mbedtls_ct_memcmp(NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300399
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100400 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300401 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
402 }
403
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100404 Plen = MBEDTLS_GET_UINT32_BE(A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300405
406 /*
407 * Plen is the length of the plaintext, when the input is valid.
408 * If Plen is larger than the plaintext and padding, padlen will be
409 * larger than 8, because of the type wrap around.
410 */
411 padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
Dave Rodgman5ea6bb02023-09-20 20:14:15 +0100412 ret = -(int) mbedtls_ct_uint_if(padlen & ~7, -MBEDTLS_ERR_CIPHER_AUTH_FAILED, -ret);
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100413 padlen &= 7;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300414
415 /* Check padding in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100416 for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) {
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100417 size_t mask = mbedtls_ct_size_mask_ge(i, KW_SEMIBLOCK_LENGTH - padlen);
418 diff |= (unsigned char) (mask & output[*out_len - KW_SEMIBLOCK_LENGTH + i]);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300419 }
420
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100421 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300422 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
423 }
424
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100425 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300426 goto cleanup;
427 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100428 memset(output + Plen, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300429 *out_len = Plen;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100430 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300431 ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
432 goto cleanup;
433 }
434
435cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100436 if (ret != 0) {
437 memset(output, 0, *out_len);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300438 *out_len = 0;
439 }
440
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100441 mbedtls_platform_zeroize(&diff, sizeof(diff));
442 mbedtls_platform_zeroize(A, sizeof(A));
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500443
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100444 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300445}
446
447#endif /* !MBEDTLS_NIST_KW_ALT */
448
Ron Eldor9ab746c2018-07-15 09:33:07 +0300449#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
450
451#define KW_TESTS 3
452
453/*
454 * Test vectors taken from NIST
455 * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
456 */
457static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
458
459static const unsigned char kw_key[KW_TESTS][32] = {
460 { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
461 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
462 { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
463 0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
464 0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
465 { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
466 0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
467 0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
468 0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
469};
470
471static const unsigned char kw_msg[KW_TESTS][40] = {
472 { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
473 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
474 { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
475 0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
476 0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
477 0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
478 0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
479 { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
480 0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
481 0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
482};
483
484static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
485static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
486static const unsigned char kw_res[KW_TESTS][48] = {
487 { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
488 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
489 0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
490 { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
491 0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
492 0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
493 0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
494 0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
495 0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
496 { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
497 0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
498 0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
499 0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
500};
501
502static const unsigned char kwp_key[KW_TESTS][32] = {
503 { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
504 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
505 { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
506 0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
507 0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
508 { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
509 0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
510 0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
511 0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
512};
513
514static const unsigned char kwp_msg[KW_TESTS][31] = {
515 { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
516 0x96 },
517 { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
518 0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
519 0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
520 0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
521 { 0xd1 }
522};
523static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
524
525static const unsigned char kwp_res[KW_TESTS][48] = {
526 { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
527 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
528 0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
529 { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
530 0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
531 0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
532 0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
533 0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
534 { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
535 0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 }
536};
537static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
538
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100539int mbedtls_nist_kw_self_test(int verbose)
Ron Eldor9ab746c2018-07-15 09:33:07 +0300540{
541 mbedtls_nist_kw_context ctx;
542 unsigned char out[48];
543 size_t olen;
544 int i;
545 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100546 mbedtls_nist_kw_init(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300547
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100548 for (i = 0; i < KW_TESTS; i++) {
549 if (verbose != 0) {
550 mbedtls_printf(" KW-AES-%u ", (unsigned int) key_len[i] * 8);
551 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300552
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100553 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
554 kw_key[i], key_len[i] * 8, 1);
555 if (ret != 0) {
556 if (verbose != 0) {
557 mbedtls_printf(" KW: setup failed ");
558 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300559
560 goto end;
561 }
562
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100563 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
564 kw_msg_len[i], out, &olen, sizeof(out));
565 if (ret != 0 || kw_out_len[i] != olen ||
566 memcmp(out, kw_res[i], kw_out_len[i]) != 0) {
567 if (verbose != 0) {
568 mbedtls_printf("failed. ");
569 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300570
571 ret = 1;
572 goto end;
573 }
574
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100575 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
576 kw_key[i], key_len[i] * 8, 0))
577 != 0) {
578 if (verbose != 0) {
579 mbedtls_printf(" KW: setup failed ");
580 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300581
582 goto end;
583 }
584
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100585 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW,
586 out, olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300587
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100588 if (ret != 0 || olen != kw_msg_len[i] ||
589 memcmp(out, kw_msg[i], kw_msg_len[i]) != 0) {
590 if (verbose != 0) {
591 mbedtls_printf("failed\n");
592 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300593
594 ret = 1;
595 goto end;
596 }
597
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100598 if (verbose != 0) {
599 mbedtls_printf(" passed\n");
600 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300601 }
602
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100603 for (i = 0; i < KW_TESTS; i++) {
604 olen = sizeof(out);
605 if (verbose != 0) {
606 mbedtls_printf(" KWP-AES-%u ", (unsigned int) key_len[i] * 8);
607 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300608
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100609 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
610 key_len[i] * 8, 1);
611 if (ret != 0) {
612 if (verbose != 0) {
613 mbedtls_printf(" KWP: setup failed ");
614 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300615
616 goto end;
617 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100618 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
619 kwp_msg_len[i], out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300620
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100621 if (ret != 0 || kwp_out_len[i] != olen ||
622 memcmp(out, kwp_res[i], kwp_out_len[i]) != 0) {
623 if (verbose != 0) {
624 mbedtls_printf("failed. ");
625 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300626
627 ret = 1;
628 goto end;
629 }
630
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100631 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
632 kwp_key[i], key_len[i] * 8, 0))
633 != 0) {
634 if (verbose != 0) {
635 mbedtls_printf(" KWP: setup failed ");
636 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300637
638 goto end;
639 }
640
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100641 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KWP, out,
642 olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300643
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100644 if (ret != 0 || olen != kwp_msg_len[i] ||
645 memcmp(out, kwp_msg[i], kwp_msg_len[i]) != 0) {
646 if (verbose != 0) {
647 mbedtls_printf("failed. ");
648 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300649
650 ret = 1;
651 goto end;
652 }
653
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100654 if (verbose != 0) {
655 mbedtls_printf(" passed\n");
656 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300657 }
658end:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100659 mbedtls_nist_kw_free(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300660
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100661 if (verbose != 0) {
662 mbedtls_printf("\n");
663 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300664
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100665 return ret;
Ron Eldor9ab746c2018-07-15 09:33:07 +0300666}
667
668#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
669
Ron Eldorcb349ac2018-07-15 09:29:47 +0300670#endif /* MBEDTLS_NIST_KW_C */