blob: 4ff5e41b46d71247d78096ac0c02330ec460498c [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
Ron Eldorcb349ac2018-07-15 09:29:47 +03006 * SPDX-License-Identifier: Apache-2.0
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License"); you may
9 * not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
Ron Eldorcb349ac2018-07-15 09:29:47 +030019 */
20/*
21 * Definition of Key Wrapping:
22 * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
23 * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
24 * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
25 *
26 * Note: RFC 3394 defines different methodology for intermediate operations for
27 * the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
28 */
29
Gilles Peskinedb09ef62020-06-03 01:43:33 +020030#include "common.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030031
32#if defined(MBEDTLS_NIST_KW_C)
33
34#include "mbedtls/nist_kw.h"
35#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000036#include "mbedtls/error.h"
Gabor Mezeie24dea82021-10-19 12:22:25 +020037#include "mbedtls/constant_time.h"
Dave Rodgman40dc3b32023-09-20 14:23:29 +010038#include "constant_time_internal.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030039
40#include <stdint.h>
41#include <string.h>
42
Ron Eldorcb349ac2018-07-15 09:29:47 +030043#include "mbedtls/platform.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030044
45#if !defined(MBEDTLS_NIST_KW_ALT)
46
47#define KW_SEMIBLOCK_LENGTH 8
48#define MIN_SEMIBLOCKS_COUNT 3
49
Ron Eldorcb349ac2018-07-15 09:29:47 +030050/*! The 64-bit default integrity check value (ICV) for KW mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010051static const unsigned char NIST_KW_ICV1[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030052/*! The 32-bit default integrity check value (ICV) for KWP mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010053static const unsigned char NIST_KW_ICV2[] = { 0xA6, 0x59, 0x59, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030054
Ron Eldorcb349ac2018-07-15 09:29:47 +030055/*
56 * Initialize context
57 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010058void mbedtls_nist_kw_init(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +030059{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010060 memset(ctx, 0, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +030061}
62
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010063int mbedtls_nist_kw_setkey(mbedtls_nist_kw_context *ctx,
64 mbedtls_cipher_id_t cipher,
65 const unsigned char *key,
66 unsigned int keybits,
67 const int is_wrap)
Ron Eldorcb349ac2018-07-15 09:29:47 +030068{
Janos Follath24eed8d2019-11-22 13:21:35 +000069 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Ron Eldorcb349ac2018-07-15 09:29:47 +030070 const mbedtls_cipher_info_t *cipher_info;
71
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010072 cipher_info = mbedtls_cipher_info_from_values(cipher,
73 keybits,
74 MBEDTLS_MODE_ECB);
75 if (cipher_info == NULL) {
76 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
77 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030078
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010079 if (cipher_info->block_size != 16) {
80 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
81 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030082
83 /*
84 * SP 800-38F currently defines AES cipher as the only block cipher allowed:
85 * "For KW and KWP, the underlying block cipher shall be approved, and the
86 * block size shall be 128 bits. Currently, the AES block cipher, with key
87 * lengths of 128, 192, or 256 bits, is the only block cipher that fits
88 * this profile."
89 * Currently we don't support other 128 bit block ciphers for key wrapping,
90 * such as Camellia and Aria.
91 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010092 if (cipher != MBEDTLS_CIPHER_ID_AES) {
93 return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
Ron Eldorcb349ac2018-07-15 09:29:47 +030094 }
95
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010096 mbedtls_cipher_free(&ctx->cipher_ctx);
97
98 if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
99 return ret;
100 }
101
102 if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
103 is_wrap ? MBEDTLS_ENCRYPT :
104 MBEDTLS_DECRYPT)
105 ) != 0) {
106 return ret;
107 }
108
109 return 0;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300110}
111
112/*
113 * Free context
114 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100115void mbedtls_nist_kw_free(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300116{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100117 mbedtls_cipher_free(&ctx->cipher_ctx);
118 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300119}
120
121/*
122 * Helper function for Xoring the uint64_t "t" with the encrypted A.
123 * Defined in NIST SP 800-38F section 6.1
124 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100125static void calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300126{
127 size_t i = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100128 for (i = 0; i < sizeof(t); i++) {
129 A[i] ^= (t >> ((sizeof(t) - 1 - i) * 8)) & 0xff;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300130 }
131}
132
133/*
134 * KW-AE as defined in SP 800-38F section 6.2
135 * KWP-AE as defined in SP 800-38F section 6.3
136 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100137int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx,
138 mbedtls_nist_kw_mode_t mode,
139 const unsigned char *input, size_t in_len,
140 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300141{
142 int ret = 0;
143 size_t semiblocks = 0;
144 size_t s;
145 size_t olen, padlen = 0;
146 uint64_t t = 0;
147 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
148 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Ron Eldorcb349ac2018-07-15 09:29:47 +0300149
150 *out_len = 0;
151 /*
152 * Generate the String to work on
153 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100154 if (mode == MBEDTLS_KW_MODE_KW) {
155 if (out_size < in_len + KW_SEMIBLOCK_LENGTH) {
156 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300157 }
158
159 /*
160 * According to SP 800-38F Table 1, the plaintext length for KW
161 * must be between 2 to 2^54-1 semiblocks inclusive.
162 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100163 if (in_len < 16 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300164#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
165 in_len > 0x1FFFFFFFFFFFFF8 ||
166#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100167 in_len % KW_SEMIBLOCK_LENGTH != 0) {
168 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300169 }
170
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100171 memcpy(output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH);
172 memmove(output + KW_SEMIBLOCK_LENGTH, input, in_len);
173 } else {
174 if (in_len % 8 != 0) {
175 padlen = (8 - (in_len % 8));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300176 }
177
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100178 if (out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen) {
179 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300180 }
181
182 /*
183 * According to SP 800-38F Table 1, the plaintext length for KWP
184 * must be between 1 and 2^32-1 octets inclusive.
185 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100186 if (in_len < 1
Ron Eldorcb349ac2018-07-15 09:29:47 +0300187#if SIZE_MAX > 0xFFFFFFFF
188 || in_len > 0xFFFFFFFF
189#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100190 ) {
191 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300192 }
193
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100194 memcpy(output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2);
195 MBEDTLS_PUT_UINT32_BE((in_len & 0xffffffff), output,
196 KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300197
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100198 memcpy(output + KW_SEMIBLOCK_LENGTH, input, in_len);
199 memset(output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300200 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100201 semiblocks = ((in_len + padlen) / KW_SEMIBLOCK_LENGTH) + 1;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300202
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100203 s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300204
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100205 if (mode == MBEDTLS_KW_MODE_KWP
206 && in_len <= KW_SEMIBLOCK_LENGTH) {
207 memcpy(inbuff, output, 16);
208 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
209 inbuff, 16, output, &olen);
210 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300211 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100212 }
213 } else {
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200214 unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
215 unsigned char *A = output;
216
Ron Eldorcb349ac2018-07-15 09:29:47 +0300217 /*
218 * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
219 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100220 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300221 ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
222 goto cleanup;
223 }
224
225 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100226 for (t = 1; t <= s; t++) {
227 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
228 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300229
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100230 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
231 inbuff, 16, outbuff, &olen);
232 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300233 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100234 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300235
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100236 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
237 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300238
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100239 memcpy(R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300240 R2 += KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100241 if (R2 >= output + (semiblocks * KW_SEMIBLOCK_LENGTH)) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300242 R2 = output + KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100243 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300244 }
245 }
246
247 *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
248
249cleanup:
250
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100251 if (ret != 0) {
252 memset(output, 0, semiblocks * KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300253 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100254 mbedtls_platform_zeroize(inbuff, KW_SEMIBLOCK_LENGTH * 2);
255 mbedtls_platform_zeroize(outbuff, KW_SEMIBLOCK_LENGTH * 2);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500256
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100257 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300258}
259
260/*
261 * W-1 function as defined in RFC 3394 section 2.2.2
262 * This function assumes the following:
263 * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
264 * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
265 * 3. Minimal number of semiblocks is 3.
266 * 4. A is a buffer to hold the first semiblock of the input buffer.
267 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100268static int unwrap(mbedtls_nist_kw_context *ctx,
269 const unsigned char *input, size_t semiblocks,
270 unsigned char A[KW_SEMIBLOCK_LENGTH],
271 unsigned char *output, size_t *out_len)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300272{
273 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100274 const size_t s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300275 size_t olen;
276 uint64_t t = 0;
277 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
278 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200279 unsigned char *R = NULL;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300280 *out_len = 0;
281
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100282 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
283 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300284 }
285
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100286 memcpy(A, input, KW_SEMIBLOCK_LENGTH);
287 memmove(output, input + KW_SEMIBLOCK_LENGTH, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
288 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300289
290 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100291 for (t = s; t >= 1; t--) {
292 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300293
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100294 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
295 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300296
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100297 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
298 inbuff, 16, outbuff, &olen);
299 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300300 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100301 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300302
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100303 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300304
305 /* Set R as LSB64 of outbuff */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100306 memcpy(R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300307
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100308 if (R == output) {
309 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
310 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300311 R -= KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100312 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300313 }
314
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100315 *out_len = (semiblocks - 1) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300316
317cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100318 if (ret != 0) {
319 memset(output, 0, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
320 }
321 mbedtls_platform_zeroize(inbuff, sizeof(inbuff));
322 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300323
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100324 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300325}
326
327/*
328 * KW-AD as defined in SP 800-38F section 6.2
329 * KWP-AD as defined in SP 800-38F section 6.3
330 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100331int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx,
332 mbedtls_nist_kw_mode_t mode,
333 const unsigned char *input, size_t in_len,
334 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300335{
336 int ret = 0;
337 size_t i, olen;
338 unsigned char A[KW_SEMIBLOCK_LENGTH];
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100339 unsigned char diff;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300340
341 *out_len = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100342 if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
343 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300344 }
345
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100346 if (mode == MBEDTLS_KW_MODE_KW) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300347 /*
348 * According to SP 800-38F Table 1, the ciphertext length for KW
349 * must be between 3 to 2^54 semiblocks inclusive.
350 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100351 if (in_len < 24 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300352#if SIZE_MAX > 0x200000000000000
353 in_len > 0x200000000000000 ||
354#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100355 in_len % KW_SEMIBLOCK_LENGTH != 0) {
356 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300357 }
358
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100359 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
360 A, output, out_len);
361 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300362 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100363 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300364
365 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100366 diff = mbedtls_ct_memcmp(NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300367
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100368 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300369 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
370 goto cleanup;
371 }
372
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100373 } else if (mode == MBEDTLS_KW_MODE_KWP) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300374 size_t padlen = 0;
375 uint32_t Plen;
376 /*
377 * According to SP 800-38F Table 1, the ciphertext length for KWP
378 * must be between 2 to 2^29 semiblocks inclusive.
379 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100380 if (in_len < KW_SEMIBLOCK_LENGTH * 2 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300381#if SIZE_MAX > 0x100000000
382 in_len > 0x100000000 ||
383#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100384 in_len % KW_SEMIBLOCK_LENGTH != 0) {
385 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300386 }
387
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100388 if (in_len == KW_SEMIBLOCK_LENGTH * 2) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300389 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100390 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
391 input, 16, outbuff, &olen);
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
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100396 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
397 memcpy(output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
398 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300399 *out_len = KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100400 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300401 /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100402 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
403 A, output, out_len);
404 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300405 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100406 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300407 }
408
409 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100410 diff = mbedtls_ct_memcmp(NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300411
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100412 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300413 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
414 }
415
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100416 Plen = MBEDTLS_GET_UINT32_BE(A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300417
418 /*
419 * Plen is the length of the plaintext, when the input is valid.
420 * If Plen is larger than the plaintext and padding, padlen will be
421 * larger than 8, because of the type wrap around.
422 */
423 padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
Dave Rodgman5ea6bb02023-09-20 20:14:15 +0100424 ret = -(int) mbedtls_ct_uint_if(padlen & ~7, -MBEDTLS_ERR_CIPHER_AUTH_FAILED, -ret);
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100425 padlen &= 7;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300426
427 /* Check padding in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100428 for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) {
Dave Rodgman40dc3b32023-09-20 14:23:29 +0100429 size_t mask = mbedtls_ct_size_mask_ge(i, KW_SEMIBLOCK_LENGTH - padlen);
430 diff |= (unsigned char) (mask & output[*out_len - KW_SEMIBLOCK_LENGTH + i]);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300431 }
432
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100433 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300434 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
435 }
436
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100437 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300438 goto cleanup;
439 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100440 memset(output + Plen, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300441 *out_len = Plen;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100442 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300443 ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
444 goto cleanup;
445 }
446
447cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100448 if (ret != 0) {
449 memset(output, 0, *out_len);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300450 *out_len = 0;
451 }
452
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100453 mbedtls_platform_zeroize(&diff, sizeof(diff));
454 mbedtls_platform_zeroize(A, sizeof(A));
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500455
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100456 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300457}
458
459#endif /* !MBEDTLS_NIST_KW_ALT */
460
Ron Eldor9ab746c2018-07-15 09:33:07 +0300461#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
462
463#define KW_TESTS 3
464
465/*
466 * Test vectors taken from NIST
467 * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
468 */
469static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
470
471static const unsigned char kw_key[KW_TESTS][32] = {
472 { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
473 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
474 { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
475 0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
476 0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
477 { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
478 0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
479 0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
480 0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
481};
482
483static const unsigned char kw_msg[KW_TESTS][40] = {
484 { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
485 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
486 { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
487 0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
488 0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
489 0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
490 0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
491 { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
492 0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
493 0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
494};
495
496static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
497static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
498static const unsigned char kw_res[KW_TESTS][48] = {
499 { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
500 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
501 0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
502 { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
503 0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
504 0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
505 0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
506 0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
507 0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
508 { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
509 0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
510 0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
511 0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
512};
513
514static const unsigned char kwp_key[KW_TESTS][32] = {
515 { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
516 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
517 { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
518 0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
519 0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
520 { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
521 0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
522 0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
523 0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
524};
525
526static const unsigned char kwp_msg[KW_TESTS][31] = {
527 { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
528 0x96 },
529 { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
530 0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
531 0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
532 0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
533 { 0xd1 }
534};
535static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
536
537static const unsigned char kwp_res[KW_TESTS][48] = {
538 { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
539 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
540 0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
541 { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
542 0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
543 0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
544 0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
545 0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
546 { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
547 0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 }
548};
549static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
550
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100551int mbedtls_nist_kw_self_test(int verbose)
Ron Eldor9ab746c2018-07-15 09:33:07 +0300552{
553 mbedtls_nist_kw_context ctx;
554 unsigned char out[48];
555 size_t olen;
556 int i;
557 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100558 mbedtls_nist_kw_init(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300559
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100560 for (i = 0; i < KW_TESTS; i++) {
561 if (verbose != 0) {
562 mbedtls_printf(" KW-AES-%u ", (unsigned int) key_len[i] * 8);
563 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300564
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100565 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
566 kw_key[i], key_len[i] * 8, 1);
567 if (ret != 0) {
568 if (verbose != 0) {
569 mbedtls_printf(" KW: setup failed ");
570 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300571
572 goto end;
573 }
574
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100575 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
576 kw_msg_len[i], out, &olen, sizeof(out));
577 if (ret != 0 || kw_out_len[i] != olen ||
578 memcmp(out, kw_res[i], kw_out_len[i]) != 0) {
579 if (verbose != 0) {
580 mbedtls_printf("failed. ");
581 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300582
583 ret = 1;
584 goto end;
585 }
586
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100587 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
588 kw_key[i], key_len[i] * 8, 0))
589 != 0) {
590 if (verbose != 0) {
591 mbedtls_printf(" KW: setup failed ");
592 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300593
594 goto end;
595 }
596
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100597 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW,
598 out, olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300599
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100600 if (ret != 0 || olen != kw_msg_len[i] ||
601 memcmp(out, kw_msg[i], kw_msg_len[i]) != 0) {
602 if (verbose != 0) {
603 mbedtls_printf("failed\n");
604 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300605
606 ret = 1;
607 goto end;
608 }
609
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100610 if (verbose != 0) {
611 mbedtls_printf(" passed\n");
612 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300613 }
614
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100615 for (i = 0; i < KW_TESTS; i++) {
616 olen = sizeof(out);
617 if (verbose != 0) {
618 mbedtls_printf(" KWP-AES-%u ", (unsigned int) key_len[i] * 8);
619 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300620
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100621 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
622 key_len[i] * 8, 1);
623 if (ret != 0) {
624 if (verbose != 0) {
625 mbedtls_printf(" KWP: setup failed ");
626 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300627
628 goto end;
629 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100630 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
631 kwp_msg_len[i], out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300632
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100633 if (ret != 0 || kwp_out_len[i] != olen ||
634 memcmp(out, kwp_res[i], kwp_out_len[i]) != 0) {
635 if (verbose != 0) {
636 mbedtls_printf("failed. ");
637 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300638
639 ret = 1;
640 goto end;
641 }
642
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100643 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
644 kwp_key[i], key_len[i] * 8, 0))
645 != 0) {
646 if (verbose != 0) {
647 mbedtls_printf(" KWP: setup failed ");
648 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300649
650 goto end;
651 }
652
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100653 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KWP, out,
654 olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300655
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100656 if (ret != 0 || olen != kwp_msg_len[i] ||
657 memcmp(out, kwp_msg[i], kwp_msg_len[i]) != 0) {
658 if (verbose != 0) {
659 mbedtls_printf("failed. ");
660 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300661
662 ret = 1;
663 goto end;
664 }
665
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100666 if (verbose != 0) {
667 mbedtls_printf(" passed\n");
668 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300669 }
670end:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100671 mbedtls_nist_kw_free(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300672
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100673 if (verbose != 0) {
674 mbedtls_printf("\n");
675 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300676
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100677 return ret;
Ron Eldor9ab746c2018-07-15 09:33:07 +0300678}
679
680#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
681
Ron Eldorcb349ac2018-07-15 09:29:47 +0300682#endif /* MBEDTLS_NIST_KW_C */