1/*
2 * Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
3 * only
4 *
5 * Copyright The Mbed TLS Contributors
6 * 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.
19 */
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
30#include "common.h"
31
32#if defined(MBEDTLS_NIST_KW_C)
33
34#include "mbedtls/nist_kw.h"
35#include "mbedtls/platform_util.h"
36#include "mbedtls/error.h"
37#include "mbedtls/constant_time.h"
38
39#include <stdint.h>
40#include <string.h>
41
42#include "mbedtls/platform.h"
43
44#if !defined(MBEDTLS_NIST_KW_ALT)
45
46#define KW_SEMIBLOCK_LENGTH 8
47#define MIN_SEMIBLOCKS_COUNT 3
48
49/*! The 64-bit default integrity check value (ICV) for KW mode. */
50static const unsigned char NIST_KW_ICV1[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
51/*! The 32-bit default integrity check value (ICV) for KWP mode. */
52static const unsigned char NIST_KW_ICV2[] = { 0xA6, 0x59, 0x59, 0xA6 };
53
54/*
55 * Initialize context
56 */
57void mbedtls_nist_kw_init(mbedtls_nist_kw_context *ctx)
58{
59 memset(ctx, 0, sizeof(mbedtls_nist_kw_context));
60}
61
62int 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)
67{
68 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
69 const mbedtls_cipher_info_t *cipher_info;
70
71 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 }
77
78 if (cipher_info->block_size != 16) {
79 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
80 }
81
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 */
91 if (cipher != MBEDTLS_CIPHER_ID_AES) {
92 return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
93 }
94
95 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;
109}
110
111/*
112 * Free context
113 */
114void mbedtls_nist_kw_free(mbedtls_nist_kw_context *ctx)
115{
116 mbedtls_cipher_free(&ctx->cipher_ctx);
117 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_nist_kw_context));
118}
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 */
124static void calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t)
125{
126 size_t i = 0;
127 for (i = 0; i < sizeof(t); i++) {
128 A[i] ^= (t >> ((sizeof(t) - 1 - i) * 8)) & 0xff;
129 }
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 */
136int 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)
140{
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];
148
149 *out_len = 0;
150 /*
151 * Generate the String to work on
152 */
153 if (mode == MBEDTLS_KW_MODE_KW) {
154 if (out_size < in_len + KW_SEMIBLOCK_LENGTH) {
155 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
156 }
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 */
162 if (in_len < 16 ||
163#if SIZE_MAX > 0x1FFFFFFFFFFFFF8
164 in_len > 0x1FFFFFFFFFFFFF8 ||
165#endif
166 in_len % KW_SEMIBLOCK_LENGTH != 0) {
167 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
168 }
169
170 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));
175 }
176
177 if (out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen) {
178 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
179 }
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 */
185 if (in_len < 1
186#if SIZE_MAX > 0xFFFFFFFF
187 || in_len > 0xFFFFFFFF
188#endif
189 ) {
190 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
191 }
192
193 memcpy(output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2);
194 MBEDTLS_PUT_UINT32_BE((in_len & 0xffffffff), output,
195 KW_SEMIBLOCK_LENGTH / 2);
196
197 memcpy(output + KW_SEMIBLOCK_LENGTH, input, in_len);
198 memset(output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen);
199 }
200 semiblocks = ((in_len + padlen) / KW_SEMIBLOCK_LENGTH) + 1;
201
202 s = 6 * (semiblocks - 1);
203
204 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) {
210 goto cleanup;
211 }
212 } else {
213 unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
214 unsigned char *A = output;
215
216 /*
217 * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
218 */
219 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
220 ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
221 goto cleanup;
222 }
223
224 /* Calculate intermediate values */
225 for (t = 1; t <= s; t++) {
226 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
227 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH);
228
229 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
230 inbuff, 16, outbuff, &olen);
231 if (ret != 0) {
232 goto cleanup;
233 }
234
235 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
236 calc_a_xor_t(A, t);
237
238 memcpy(R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
239 R2 += KW_SEMIBLOCK_LENGTH;
240 if (R2 >= output + (semiblocks * KW_SEMIBLOCK_LENGTH)) {
241 R2 = output + KW_SEMIBLOCK_LENGTH;
242 }
243 }
244 }
245
246 *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
247
248cleanup:
249
250 if (ret != 0) {
251 memset(output, 0, semiblocks * KW_SEMIBLOCK_LENGTH);
252 }
253 mbedtls_platform_zeroize(inbuff, KW_SEMIBLOCK_LENGTH * 2);
254 mbedtls_platform_zeroize(outbuff, KW_SEMIBLOCK_LENGTH * 2);
255
256 return ret;
257}
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 */
267static 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)
271{
272 int ret = 0;
273 const size_t s = 6 * (semiblocks - 1);
274 size_t olen;
275 uint64_t t = 0;
276 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
277 unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
278 unsigned char *R = NULL;
279 *out_len = 0;
280
281 if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
282 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
283 }
284
285 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;
288
289 /* Calculate intermediate values */
290 for (t = s; t >= 1; t--) {
291 calc_a_xor_t(A, t);
292
293 memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
294 memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH);
295
296 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
297 inbuff, 16, outbuff, &olen);
298 if (ret != 0) {
299 goto cleanup;
300 }
301
302 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
303
304 /* Set R as LSB64 of outbuff */
305 memcpy(R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
306
307 if (R == output) {
308 R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
309 } else {
310 R -= KW_SEMIBLOCK_LENGTH;
311 }
312 }
313
314 *out_len = (semiblocks - 1) * KW_SEMIBLOCK_LENGTH;
315
316cleanup:
317 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));
322
323 return ret;
324}
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 */
330int 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)
334{
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;
341 if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
342 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
343 }
344
345 if (mode == MBEDTLS_KW_MODE_KW) {
346 /*
347 * According to SP 800-38F Table 1, the ciphertext length for KW
348 * must be between 3 to 2^54 semiblocks inclusive.
349 */
350 if (in_len < 24 ||
351#if SIZE_MAX > 0x200000000000000
352 in_len > 0x200000000000000 ||
353#endif
354 in_len % KW_SEMIBLOCK_LENGTH != 0) {
355 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
356 }
357
358 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
359 A, output, out_len);
360 if (ret != 0) {
361 goto cleanup;
362 }
363
364 /* Check ICV in "constant-time" */
365 diff = mbedtls_ct_memcmp(NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH);
366
367 if (diff != 0) {
368 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
369 goto cleanup;
370 }
371
372 } else if (mode == MBEDTLS_KW_MODE_KWP) {
373 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 */
379 if (in_len < KW_SEMIBLOCK_LENGTH * 2 ||
380#if SIZE_MAX > 0x100000000
381 in_len > 0x100000000 ||
382#endif
383 in_len % KW_SEMIBLOCK_LENGTH != 0) {
384 return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
385 }
386
387 if (in_len == KW_SEMIBLOCK_LENGTH * 2) {
388 unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
389 ret = mbedtls_cipher_update(&ctx->cipher_ctx,
390 input, 16, outbuff, &olen);
391 if (ret != 0) {
392 goto cleanup;
393 }
394
395 memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
396 memcpy(output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
397 mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
398 *out_len = KW_SEMIBLOCK_LENGTH;
399 } else {
400 /* in_len >= KW_SEMIBLOCK_LENGTH * 3 */
401 ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
402 A, output, out_len);
403 if (ret != 0) {
404 goto cleanup;
405 }
406 }
407
408 /* Check ICV in "constant-time" */
409 diff = mbedtls_ct_memcmp(NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2);
410
411 if (diff != 0) {
412 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
413 }
414
415 Plen = MBEDTLS_GET_UINT32_BE(A, KW_SEMIBLOCK_LENGTH / 2);
416
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;
423 if (padlen > 7) {
424 padlen &= 7;
425 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
426 }
427
428 /* Check padding in "constant-time" */
429 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 }
435 }
436
437 if (diff != 0) {
438 ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
439 }
440
441 if (ret != 0) {
442 goto cleanup;
443 }
444 memset(output + Plen, 0, padlen);
445 *out_len = Plen;
446 } else {
447 ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
448 goto cleanup;
449 }
450
451cleanup:
452 if (ret != 0) {
453 memset(output, 0, *out_len);
454 *out_len = 0;
455 }
456
457 mbedtls_platform_zeroize(&bad_padding, sizeof(bad_padding));
458 mbedtls_platform_zeroize(&diff, sizeof(diff));
459 mbedtls_platform_zeroize(A, sizeof(A));
460
461 return ret;
462}
463
464#endif /* !MBEDTLS_NIST_KW_ALT */
465
466#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
556int mbedtls_nist_kw_self_test(int verbose)
557{
558 mbedtls_nist_kw_context ctx;
559 unsigned char out[48];
560 size_t olen;
561 int i;
562 int ret = 0;
563 mbedtls_nist_kw_init(&ctx);
564
565 for (i = 0; i < KW_TESTS; i++) {
566 if (verbose != 0) {
567 mbedtls_printf(" KW-AES-%u ", (unsigned int) key_len[i] * 8);
568 }
569
570 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 }
576
577 goto end;
578 }
579
580 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 }
587
588 ret = 1;
589 goto end;
590 }
591
592 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 }
598
599 goto end;
600 }
601
602 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW,
603 out, olen, out, &olen, sizeof(out));
604
605 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 }
610
611 ret = 1;
612 goto end;
613 }
614
615 if (verbose != 0) {
616 mbedtls_printf(" passed\n");
617 }
618 }
619
620 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 }
625
626 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 }
632
633 goto end;
634 }
635 ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
636 kwp_msg_len[i], out, &olen, sizeof(out));
637
638 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 }
643
644 ret = 1;
645 goto end;
646 }
647
648 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 }
654
655 goto end;
656 }
657
658 ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KWP, out,
659 olen, out, &olen, sizeof(out));
660
661 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 }
666
667 ret = 1;
668 goto end;
669 }
670
671 if (verbose != 0) {
672 mbedtls_printf(" passed\n");
673 }
674 }
675end:
676 mbedtls_nist_kw_free(&ctx);
677
678 if (verbose != 0) {
679 mbedtls_printf("\n");
680 }
681
682 return ret;
683}
684
685#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
686
687#endif /* MBEDTLS_NIST_KW_C */
688