blob: 5817bf4f4c281ed7476a4428bd518f0db99e3fde [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"
Ron Eldorcb349ac2018-07-15 09:29:47 +030038
39#include <stdint.h>
40#include <string.h>
41
Ron Eldorcb349ac2018-07-15 09:29:47 +030042#include "mbedtls/platform.h"
Ron Eldorcb349ac2018-07-15 09:29:47 +030043
44#if !defined(MBEDTLS_NIST_KW_ALT)
45
46#define KW_SEMIBLOCK_LENGTH 8
47#define MIN_SEMIBLOCKS_COUNT 3
48
Ron Eldorcb349ac2018-07-15 09:29:47 +030049/*! The 64-bit default integrity check value (ICV) for KW mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010050static const unsigned char NIST_KW_ICV1[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030051/*! The 32-bit default integrity check value (ICV) for KWP mode. */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010052static const unsigned char NIST_KW_ICV2[] = { 0xA6, 0x59, 0x59, 0xA6 };
Ron Eldorcb349ac2018-07-15 09:29:47 +030053
Ron Eldorcb349ac2018-07-15 09:29:47 +030054/*
55 * Initialize context
56 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010057void mbedtls_nist_kw_init(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +030058{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010059 memset(ctx, 0, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +030060}
61
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010062int mbedtls_nist_kw_setkey(mbedtls_nist_kw_context *ctx,
63 mbedtls_cipher_id_t cipher,
64 const unsigned char *key,
65 unsigned int keybits,
66 const int is_wrap)
Ron Eldorcb349ac2018-07-15 09:29:47 +030067{
Janos Follath24eed8d2019-11-22 13:21:35 +000068 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Ron Eldorcb349ac2018-07-15 09:29:47 +030069 const mbedtls_cipher_info_t *cipher_info;
70
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010071 cipher_info = mbedtls_cipher_info_from_values(cipher,
72 keybits,
73 MBEDTLS_MODE_ECB);
74 if (cipher_info == NULL) {
75 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
76 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030077
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010078 if (cipher_info->block_size != 16) {
79 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
80 }
Ron Eldorcb349ac2018-07-15 09:29:47 +030081
82 /*
83 * SP 800-38F currently defines AES cipher as the only block cipher allowed:
84 * "For KW and KWP, the underlying block cipher shall be approved, and the
85 * block size shall be 128 bits. Currently, the AES block cipher, with key
86 * lengths of 128, 192, or 256 bits, is the only block cipher that fits
87 * this profile."
88 * Currently we don't support other 128 bit block ciphers for key wrapping,
89 * such as Camellia and Aria.
90 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010091 if (cipher != MBEDTLS_CIPHER_ID_AES) {
92 return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
Ron Eldorcb349ac2018-07-15 09:29:47 +030093 }
94
Gilles Peskine1b6c09a2023-01-11 14:52:35 +010095 mbedtls_cipher_free(&ctx->cipher_ctx);
96
97 if ((ret = mbedtls_cipher_setup(&ctx->cipher_ctx, cipher_info)) != 0) {
98 return ret;
99 }
100
101 if ((ret = mbedtls_cipher_setkey(&ctx->cipher_ctx, key, keybits,
102 is_wrap ? MBEDTLS_ENCRYPT :
103 MBEDTLS_DECRYPT)
104 ) != 0) {
105 return ret;
106 }
107
108 return 0;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300109}
110
111/*
112 * Free context
113 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100114void mbedtls_nist_kw_free(mbedtls_nist_kw_context *ctx)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300115{
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100116 mbedtls_cipher_free(&ctx->cipher_ctx);
117 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_nist_kw_context));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300118}
119
120/*
121 * Helper function for Xoring the uint64_t "t" with the encrypted A.
122 * Defined in NIST SP 800-38F section 6.1
123 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100124static void calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300125{
126 size_t i = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100127 for (i = 0; i < sizeof(t); i++) {
128 A[i] ^= (t >> ((sizeof(t) - 1 - i) * 8)) & 0xff;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300129 }
130}
131
132/*
133 * KW-AE as defined in SP 800-38F section 6.2
134 * KWP-AE as defined in SP 800-38F section 6.3
135 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100136int mbedtls_nist_kw_wrap(mbedtls_nist_kw_context *ctx,
137 mbedtls_nist_kw_mode_t mode,
138 const unsigned char *input, size_t in_len,
139 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300140{
141 int ret = 0;
142 size_t semiblocks = 0;
143 size_t s;
144 size_t olen, padlen = 0;
145 uint64_t t = 0;
146 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
147 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Ron Eldorcb349ac2018-07-15 09:29:47 +0300148
149 *out_len = 0;
150 /*
151 * Generate the String to work on
152 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100153 if (mode == MBEDTLS_KW_MODE_KW) {
154 if (out_size < in_len + KW_SEMIBLOCK_LENGTH) {
155 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300156 }
157
158 /*
159 * According to SP 800-38F Table 1, the plaintext length for KW
160 * must be between 2 to 2^54-1 semiblocks inclusive.
161 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100162 if (in_len < 16 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300163#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
164 in_len > 0x1FFFFFFFFFFFFF8 ||
165#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100166 in_len % KW_SEMIBLOCK_LENGTH != 0) {
167 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300168 }
169
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100170 memcpy(output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH);
171 memmove(output + KW_SEMIBLOCK_LENGTH, input, in_len);
172 } else {
173 if (in_len % 8 != 0) {
174 padlen = (8 - (in_len % 8));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300175 }
176
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100177 if (out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen) {
178 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300179 }
180
181 /*
182 * According to SP 800-38F Table 1, the plaintext length for KWP
183 * must be between 1 and 2^32-1 octets inclusive.
184 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100185 if (in_len < 1
Ron Eldorcb349ac2018-07-15 09:29:47 +0300186#if SIZE_MAX > 0xFFFFFFFF
187 || in_len > 0xFFFFFFFF
188#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100189 ) {
190 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300191 }
192
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100193 memcpy(output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2);
194 MBEDTLS_PUT_UINT32_BE((in_len & 0xffffffff), output,
195 KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300196
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100197 memcpy(output + KW_SEMIBLOCK_LENGTH, input, in_len);
198 memset(output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300199 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100200 semiblocks = ((in_len + padlen) / KW_SEMIBLOCK_LENGTH) + 1;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300201
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100202 s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300203
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100204 if (mode == MBEDTLS_KW_MODE_KWP
205 && in_len <= KW_SEMIBLOCK_LENGTH) {
206 memcpy(inbuff, output, 16);
207 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
208 inbuff, 16, output, &olen);
209 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300210 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100211 }
212 } else {
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200213 unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
214 unsigned char *A = output;
215
Ron Eldorcb349ac2018-07-15 09:29:47 +0300216 /*
217 * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
218 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100219 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300220 ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
221 goto cleanup;
222 }
223
224 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100225 for (t = 1; t <= s; t++) {
226 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
227 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300228
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100229 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
230 inbuff, 16, outbuff, &olen);
231 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300232 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100233 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300234
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100235 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
236 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300237
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100238 memcpy(R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300239 R2 += KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100240 if (R2 >= output + (semiblocks * KW_SEMIBLOCK_LENGTH)) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300241 R2 = output + KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100242 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300243 }
244 }
245
246 *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
247
248cleanup:
249
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100250 if (ret != 0) {
251 memset(output, 0, semiblocks * KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300252 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100253 mbedtls_platform_zeroize(inbuff, KW_SEMIBLOCK_LENGTH * 2);
254 mbedtls_platform_zeroize(outbuff, KW_SEMIBLOCK_LENGTH * 2);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500255
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100256 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300257}
258
259/*
260 * W-1 function as defined in RFC 3394 section 2.2.2
261 * This function assumes the following:
262 * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
263 * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
264 * 3. Minimal number of semiblocks is 3.
265 * 4. A is a buffer to hold the first semiblock of the input buffer.
266 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100267static int unwrap(mbedtls_nist_kw_context *ctx,
268 const unsigned char *input, size_t semiblocks,
269 unsigned char A[KW_SEMIBLOCK_LENGTH],
270 unsigned char *output, size_t *out_len)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300271{
272 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100273 const size_t s = 6 * (semiblocks - 1);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300274 size_t olen;
275 uint64_t t = 0;
276 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
277 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine570a8cd2021-06-01 11:22:56 +0200278 unsigned char *R = NULL;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300279 *out_len = 0;
280
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100281 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
282 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300283 }
284
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100285 memcpy(A, input, KW_SEMIBLOCK_LENGTH);
286 memmove(output, input + KW_SEMIBLOCK_LENGTH, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
287 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300288
289 /* Calculate intermediate values */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100290 for (t = s; t >= 1; t--) {
291 calc_a_xor_t(A, t);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300292
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100293 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
294 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300295
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100296 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
297 inbuff, 16, outbuff, &olen);
298 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300299 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100300 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300301
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100302 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300303
304 /* Set R as LSB64 of outbuff */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100305 memcpy(R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300306
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100307 if (R == output) {
308 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
309 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300310 R -= KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100311 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300312 }
313
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100314 *out_len = (semiblocks - 1) * KW_SEMIBLOCK_LENGTH;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300315
316cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100317 if (ret != 0) {
318 memset(output, 0, (semiblocks - 1) * KW_SEMIBLOCK_LENGTH);
319 }
320 mbedtls_platform_zeroize(inbuff, sizeof(inbuff));
321 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300322
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100323 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300324}
325
326/*
327 * KW-AD as defined in SP 800-38F section 6.2
328 * KWP-AD as defined in SP 800-38F section 6.3
329 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100330int mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context *ctx,
331 mbedtls_nist_kw_mode_t mode,
332 const unsigned char *input, size_t in_len,
333 unsigned char *output, size_t *out_len, size_t out_size)
Ron Eldorcb349ac2018-07-15 09:29:47 +0300334{
335 int ret = 0;
336 size_t i, olen;
337 unsigned char A[KW_SEMIBLOCK_LENGTH];
338 unsigned char diff, bad_padding = 0;
339
340 *out_len = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100341 if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
342 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300343 }
344
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100345 if (mode == MBEDTLS_KW_MODE_KW) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300346 /*
347 * According to SP 800-38F Table 1, the ciphertext length for KW
348 * must be between 3 to 2^54 semiblocks inclusive.
349 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100350 if (in_len < 24 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300351#if SIZE_MAX > 0x200000000000000
352 in_len > 0x200000000000000 ||
353#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100354 in_len % KW_SEMIBLOCK_LENGTH != 0) {
355 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300356 }
357
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100358 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
359 A, output, out_len);
360 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300361 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100362 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300363
364 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100365 diff = mbedtls_ct_memcmp(NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300366
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100367 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300368 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
369 goto cleanup;
370 }
371
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100372 } else if (mode == MBEDTLS_KW_MODE_KWP) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300373 size_t padlen = 0;
374 uint32_t Plen;
375 /*
376 * According to SP 800-38F Table 1, the ciphertext length for KWP
377 * must be between 2 to 2^29 semiblocks inclusive.
378 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100379 if (in_len < KW_SEMIBLOCK_LENGTH * 2 ||
Ron Eldorcb349ac2018-07-15 09:29:47 +0300380#if SIZE_MAX > 0x100000000
381 in_len > 0x100000000 ||
382#endif
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100383 in_len % KW_SEMIBLOCK_LENGTH != 0) {
384 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300385 }
386
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100387 if (in_len == KW_SEMIBLOCK_LENGTH * 2) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300388 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100389 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
390 input, 16, outbuff, &olen);
391 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300392 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100393 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300394
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100395 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
396 memcpy(output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
397 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
Ron Eldorcb349ac2018-07-15 09:29:47 +0300398 *out_len = KW_SEMIBLOCK_LENGTH;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100399 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300400 /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100401 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
402 A, output, out_len);
403 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300404 goto cleanup;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100405 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300406 }
407
408 /* Check ICV in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100409 diff = mbedtls_ct_memcmp(NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300410
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100411 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300412 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
413 }
414
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100415 Plen = MBEDTLS_GET_UINT32_BE(A, KW_SEMIBLOCK_LENGTH / 2);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300416
417 /*
418 * Plen is the length of the plaintext, when the input is valid.
419 * If Plen is larger than the plaintext and padding, padlen will be
420 * larger than 8, because of the type wrap around.
421 */
422 padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100423 if (padlen > 7) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300424 padlen &= 7;
425 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
426 }
427
428 /* Check padding in "constant-time" */
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100429 for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) {
430 if (i >= KW_SEMIBLOCK_LENGTH - padlen) {
431 diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
432 } else {
433 bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
434 }
Ron Eldorcb349ac2018-07-15 09:29:47 +0300435 }
436
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100437 if (diff != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300438 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
439 }
440
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100441 if (ret != 0) {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300442 goto cleanup;
443 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100444 memset(output + Plen, 0, padlen);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300445 *out_len = Plen;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100446 } else {
Ron Eldorcb349ac2018-07-15 09:29:47 +0300447 ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
448 goto cleanup;
449 }
450
451cleanup:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100452 if (ret != 0) {
453 memset(output, 0, *out_len);
Ron Eldorcb349ac2018-07-15 09:29:47 +0300454 *out_len = 0;
455 }
456
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100457 mbedtls_platform_zeroize(&bad_padding, sizeof(bad_padding));
458 mbedtls_platform_zeroize(&diff, sizeof(diff));
459 mbedtls_platform_zeroize(A, sizeof(A));
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500460
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100461 return ret;
Ron Eldorcb349ac2018-07-15 09:29:47 +0300462}
463
464#endif /* !MBEDTLS_NIST_KW_ALT */
465
Ron Eldor9ab746c2018-07-15 09:33:07 +0300466#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
467
468#define KW_TESTS 3
469
470/*
471 * Test vectors taken from NIST
472 * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
473 */
474static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
475
476static const unsigned char kw_key[KW_TESTS][32] = {
477 { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
478 0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
479 { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
480 0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
481 0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
482 { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
483 0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
484 0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
485 0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
486};
487
488static const unsigned char kw_msg[KW_TESTS][40] = {
489 { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
490 0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
491 { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
492 0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
493 0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
494 0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
495 0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
496 { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
497 0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
498 0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
499};
500
501static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
502static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
503static const unsigned char kw_res[KW_TESTS][48] = {
504 { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
505 0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
506 0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
507 { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
508 0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
509 0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
510 0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
511 0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
512 0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
513 { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
514 0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
515 0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
516 0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
517};
518
519static const unsigned char kwp_key[KW_TESTS][32] = {
520 { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
521 0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
522 { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
523 0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
524 0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
525 { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
526 0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
527 0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
528 0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
529};
530
531static const unsigned char kwp_msg[KW_TESTS][31] = {
532 { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
533 0x96 },
534 { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
535 0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
536 0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
537 0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
538 { 0xd1 }
539};
540static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
541
542static const unsigned char kwp_res[KW_TESTS][48] = {
543 { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
544 0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
545 0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
546 { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
547 0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
548 0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
549 0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
550 0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
551 { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
552 0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4 }
553};
554static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
555
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100556int mbedtls_nist_kw_self_test(int verbose)
Ron Eldor9ab746c2018-07-15 09:33:07 +0300557{
558 mbedtls_nist_kw_context ctx;
559 unsigned char out[48];
560 size_t olen;
561 int i;
562 int ret = 0;
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100563 mbedtls_nist_kw_init(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300564
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100565 for (i = 0; i < KW_TESTS; i++) {
566 if (verbose != 0) {
567 mbedtls_printf(" KW-AES-%u ", (unsigned int) key_len[i] * 8);
568 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300569
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100570 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
571 kw_key[i], key_len[i] * 8, 1);
572 if (ret != 0) {
573 if (verbose != 0) {
574 mbedtls_printf(" KW: setup failed ");
575 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300576
577 goto end;
578 }
579
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100580 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
581 kw_msg_len[i], out, &olen, sizeof(out));
582 if (ret != 0 || kw_out_len[i] != olen ||
583 memcmp(out, kw_res[i], kw_out_len[i]) != 0) {
584 if (verbose != 0) {
585 mbedtls_printf("failed. ");
586 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300587
588 ret = 1;
589 goto end;
590 }
591
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100592 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
593 kw_key[i], key_len[i] * 8, 0))
594 != 0) {
595 if (verbose != 0) {
596 mbedtls_printf(" KW: setup failed ");
597 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300598
599 goto end;
600 }
601
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100602 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW,
603 out, olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300604
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100605 if (ret != 0 || olen != kw_msg_len[i] ||
606 memcmp(out, kw_msg[i], kw_msg_len[i]) != 0) {
607 if (verbose != 0) {
608 mbedtls_printf("failed\n");
609 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300610
611 ret = 1;
612 goto end;
613 }
614
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100615 if (verbose != 0) {
616 mbedtls_printf(" passed\n");
617 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300618 }
619
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100620 for (i = 0; i < KW_TESTS; i++) {
621 olen = sizeof(out);
622 if (verbose != 0) {
623 mbedtls_printf(" KWP-AES-%u ", (unsigned int) key_len[i] * 8);
624 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300625
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100626 ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
627 key_len[i] * 8, 1);
628 if (ret != 0) {
629 if (verbose != 0) {
630 mbedtls_printf(" KWP: setup failed ");
631 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300632
633 goto end;
634 }
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100635 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
636 kwp_msg_len[i], out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300637
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100638 if (ret != 0 || kwp_out_len[i] != olen ||
639 memcmp(out, kwp_res[i], kwp_out_len[i]) != 0) {
640 if (verbose != 0) {
641 mbedtls_printf("failed. ");
642 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300643
644 ret = 1;
645 goto end;
646 }
647
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100648 if ((ret = mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES,
649 kwp_key[i], key_len[i] * 8, 0))
650 != 0) {
651 if (verbose != 0) {
652 mbedtls_printf(" KWP: setup failed ");
653 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300654
655 goto end;
656 }
657
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100658 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KWP, out,
659 olen, out, &olen, sizeof(out));
Ron Eldor9ab746c2018-07-15 09:33:07 +0300660
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100661 if (ret != 0 || olen != kwp_msg_len[i] ||
662 memcmp(out, kwp_msg[i], kwp_msg_len[i]) != 0) {
663 if (verbose != 0) {
664 mbedtls_printf("failed. ");
665 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300666
667 ret = 1;
668 goto end;
669 }
670
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100671 if (verbose != 0) {
672 mbedtls_printf(" passed\n");
673 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300674 }
675end:
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100676 mbedtls_nist_kw_free(&ctx);
Ron Eldor9ab746c2018-07-15 09:33:07 +0300677
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100678 if (verbose != 0) {
679 mbedtls_printf("\n");
680 }
Ron Eldor9ab746c2018-07-15 09:33:07 +0300681
Gilles Peskine1b6c09a2023-01-11 14:52:35 +0100682 return ret;
Ron Eldor9ab746c2018-07-15 09:33:07 +0300683}
684
685#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
686
Ron Eldorcb349ac2018-07-15 09:29:47 +0300687#endif /* MBEDTLS_NIST_KW_C */