• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 OR GPL-2.0-or-later
7  */
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 
18 #include "common.h"
19 
20 #if defined(MBEDTLS_NIST_KW_C)
21 
22 #include "mbedtls/nist_kw.h"
23 #include "mbedtls/platform_util.h"
24 #include "mbedtls/error.h"
25 #include "mbedtls/constant_time.h"
26 #include "constant_time_internal.h"
27 
28 #include <stdint.h>
29 #include <string.h>
30 
31 #include "mbedtls/platform.h"
32 
33 #if !defined(MBEDTLS_NIST_KW_ALT)
34 
35 #define KW_SEMIBLOCK_LENGTH    8
36 #define MIN_SEMIBLOCKS_COUNT   3
37 
38 /*! The 64-bit default integrity check value (ICV) for KW mode. */
39 static const unsigned char NIST_KW_ICV1[] = { 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 };
40 /*! The 32-bit default integrity check value (ICV) for KWP mode. */
41 static const  unsigned char NIST_KW_ICV2[] = { 0xA6, 0x59, 0x59, 0xA6 };
42 
43 /*
44  * Initialize context
45  */
mbedtls_nist_kw_init(mbedtls_nist_kw_context * ctx)46 void mbedtls_nist_kw_init(mbedtls_nist_kw_context *ctx)
47 {
48     memset(ctx, 0, sizeof(mbedtls_nist_kw_context));
49 }
50 
mbedtls_nist_kw_setkey(mbedtls_nist_kw_context * ctx,mbedtls_cipher_id_t cipher,const unsigned char * key,unsigned int keybits,const int is_wrap)51 int 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)
56 {
57     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
58     const mbedtls_cipher_info_t *cipher_info;
59 
60     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     }
66 
67     if (cipher_info->block_size != 16) {
68         return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
69     }
70 
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      */
80     if (cipher != MBEDTLS_CIPHER_ID_AES) {
81         return MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
82     }
83 
84     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;
98 }
99 
100 /*
101  * Free context
102  */
mbedtls_nist_kw_free(mbedtls_nist_kw_context * ctx)103 void mbedtls_nist_kw_free(mbedtls_nist_kw_context *ctx)
104 {
105     mbedtls_cipher_free(&ctx->cipher_ctx);
106     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_nist_kw_context));
107 }
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  */
calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH],uint64_t t)113 static void calc_a_xor_t(unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t)
114 {
115     size_t i = 0;
116     for (i = 0; i < sizeof(t); i++) {
117         A[i] ^= (t >> ((sizeof(t) - 1 - i) * 8)) & 0xff;
118     }
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  */
mbedtls_nist_kw_wrap(mbedtls_nist_kw_context * ctx,mbedtls_nist_kw_mode_t mode,const unsigned char * input,size_t in_len,unsigned char * output,size_t * out_len,size_t out_size)125 int 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)
129 {
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];
137 
138     *out_len = 0;
139     /*
140      * Generate the String to work on
141      */
142     if (mode == MBEDTLS_KW_MODE_KW) {
143         if (out_size < in_len + KW_SEMIBLOCK_LENGTH) {
144             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
145         }
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          */
151         if (in_len < 16 ||
152 #if SIZE_MAX > 0x1FFFFFFFFFFFFF8
153             in_len > 0x1FFFFFFFFFFFFF8 ||
154 #endif
155             in_len % KW_SEMIBLOCK_LENGTH != 0) {
156             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
157         }
158 
159         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));
164         }
165 
166         if (out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen) {
167             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
168         }
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          */
174         if (in_len < 1
175 #if SIZE_MAX > 0xFFFFFFFF
176             || in_len > 0xFFFFFFFF
177 #endif
178             ) {
179             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
180         }
181 
182         memcpy(output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2);
183         MBEDTLS_PUT_UINT32_BE((in_len & 0xffffffff), output,
184                               KW_SEMIBLOCK_LENGTH / 2);
185 
186         memcpy(output + KW_SEMIBLOCK_LENGTH, input, in_len);
187         memset(output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen);
188     }
189     semiblocks = ((in_len + padlen) / KW_SEMIBLOCK_LENGTH) + 1;
190 
191     s = 6 * (semiblocks - 1);
192 
193     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) {
199             goto cleanup;
200         }
201     } else {
202         unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
203         unsigned char *A = output;
204 
205         /*
206          * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
207          */
208         if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
209             ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
210             goto cleanup;
211         }
212 
213         /* Calculate intermediate values */
214         for (t = 1; t <= s; t++) {
215             memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
216             memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH);
217 
218             ret = mbedtls_cipher_update(&ctx->cipher_ctx,
219                                         inbuff, 16, outbuff, &olen);
220             if (ret != 0) {
221                 goto cleanup;
222             }
223 
224             memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
225             calc_a_xor_t(A, t);
226 
227             memcpy(R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
228             R2 += KW_SEMIBLOCK_LENGTH;
229             if (R2 >= output + (semiblocks * KW_SEMIBLOCK_LENGTH)) {
230                 R2 = output + KW_SEMIBLOCK_LENGTH;
231             }
232         }
233     }
234 
235     *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
236 
237 cleanup:
238 
239     if (ret != 0) {
240         memset(output, 0, semiblocks * KW_SEMIBLOCK_LENGTH);
241     }
242     mbedtls_platform_zeroize(inbuff, KW_SEMIBLOCK_LENGTH * 2);
243     mbedtls_platform_zeroize(outbuff, KW_SEMIBLOCK_LENGTH * 2);
244 
245     return ret;
246 }
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  */
unwrap(mbedtls_nist_kw_context * ctx,const unsigned char * input,size_t semiblocks,unsigned char A[KW_SEMIBLOCK_LENGTH],unsigned char * output,size_t * out_len)256 static 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)
260 {
261     int ret = 0;
262     const size_t s = 6 * (semiblocks - 1);
263     size_t olen;
264     uint64_t t = 0;
265     unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
266     unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
267     unsigned char *R = NULL;
268     *out_len = 0;
269 
270     if (semiblocks < MIN_SEMIBLOCKS_COUNT) {
271         return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
272     }
273 
274     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;
277 
278     /* Calculate intermediate values */
279     for (t = s; t >= 1; t--) {
280         calc_a_xor_t(A, t);
281 
282         memcpy(inbuff, A, KW_SEMIBLOCK_LENGTH);
283         memcpy(inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH);
284 
285         ret = mbedtls_cipher_update(&ctx->cipher_ctx,
286                                     inbuff, 16, outbuff, &olen);
287         if (ret != 0) {
288             goto cleanup;
289         }
290 
291         memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
292 
293         /* Set R as LSB64 of outbuff */
294         memcpy(R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
295 
296         if (R == output) {
297             R = output + (semiblocks - 2) * KW_SEMIBLOCK_LENGTH;
298         } else {
299             R -= KW_SEMIBLOCK_LENGTH;
300         }
301     }
302 
303     *out_len = (semiblocks - 1) * KW_SEMIBLOCK_LENGTH;
304 
305 cleanup:
306     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));
311 
312     return ret;
313 }
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  */
mbedtls_nist_kw_unwrap(mbedtls_nist_kw_context * ctx,mbedtls_nist_kw_mode_t mode,const unsigned char * input,size_t in_len,unsigned char * output,size_t * out_len,size_t out_size)319 int 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)
323 {
324     int ret = 0;
325     size_t i, olen;
326     unsigned char A[KW_SEMIBLOCK_LENGTH];
327     unsigned char diff;
328 
329     *out_len = 0;
330     if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
331         return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
332     }
333 
334     if (mode == MBEDTLS_KW_MODE_KW) {
335         /*
336          * According to SP 800-38F Table 1, the ciphertext length for KW
337          * must be between 3 to 2^54 semiblocks inclusive.
338          */
339         if (in_len < 24 ||
340 #if SIZE_MAX > 0x200000000000000
341             in_len > 0x200000000000000 ||
342 #endif
343             in_len % KW_SEMIBLOCK_LENGTH != 0) {
344             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
345         }
346 
347         ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
348                      A, output, out_len);
349         if (ret != 0) {
350             goto cleanup;
351         }
352 
353         /* Check ICV in "constant-time" */
354         diff = mbedtls_ct_memcmp(NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH);
355 
356         if (diff != 0) {
357             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
358             goto cleanup;
359         }
360 
361     } else if (mode == MBEDTLS_KW_MODE_KWP) {
362         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          */
368         if (in_len < KW_SEMIBLOCK_LENGTH * 2 ||
369 #if SIZE_MAX > 0x100000000
370             in_len > 0x100000000 ||
371 #endif
372             in_len % KW_SEMIBLOCK_LENGTH != 0) {
373             return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
374         }
375 
376         if (in_len == KW_SEMIBLOCK_LENGTH * 2) {
377             unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
378             ret = mbedtls_cipher_update(&ctx->cipher_ctx,
379                                         input, 16, outbuff, &olen);
380             if (ret != 0) {
381                 goto cleanup;
382             }
383 
384             memcpy(A, outbuff, KW_SEMIBLOCK_LENGTH);
385             memcpy(output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH);
386             mbedtls_platform_zeroize(outbuff, sizeof(outbuff));
387             *out_len = KW_SEMIBLOCK_LENGTH;
388         } else {
389             /* in_len >=  KW_SEMIBLOCK_LENGTH * 3 */
390             ret = unwrap(ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
391                          A, output, out_len);
392             if (ret != 0) {
393                 goto cleanup;
394             }
395         }
396 
397         /* Check ICV in "constant-time" */
398         diff = mbedtls_ct_memcmp(NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2);
399 
400         if (diff != 0) {
401             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
402         }
403 
404         Plen = MBEDTLS_GET_UINT32_BE(A, KW_SEMIBLOCK_LENGTH / 2);
405 
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;
412         ret = -(int) mbedtls_ct_uint_if(padlen & ~7, -MBEDTLS_ERR_CIPHER_AUTH_FAILED, -ret);
413         padlen &= 7;
414 
415         /* Check padding in "constant-time" */
416         for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) {
417             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]);
419         }
420 
421         if (diff != 0) {
422             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
423         }
424 
425         if (ret != 0) {
426             goto cleanup;
427         }
428         memset(output + Plen, 0, padlen);
429         *out_len = Plen;
430     } else {
431         ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
432         goto cleanup;
433     }
434 
435 cleanup:
436     if (ret != 0) {
437         memset(output, 0, *out_len);
438         *out_len = 0;
439     }
440 
441     mbedtls_platform_zeroize(&diff, sizeof(diff));
442     mbedtls_platform_zeroize(A, sizeof(A));
443 
444     return ret;
445 }
446 
447 #endif /* !MBEDTLS_NIST_KW_ALT */
448 
449 #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  */
457 static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
458 
459 static 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 
471 static 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 
484 static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
485 static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
486 static 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 
502 static 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 
514 static 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 };
523 static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
524 
525 static 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 };
537 static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
538 
mbedtls_nist_kw_self_test(int verbose)539 int mbedtls_nist_kw_self_test(int verbose)
540 {
541     mbedtls_nist_kw_context ctx;
542     unsigned char out[48];
543     size_t olen;
544     int i;
545     int ret = 0;
546     mbedtls_nist_kw_init(&ctx);
547 
548     for (i = 0; i < KW_TESTS; i++) {
549         if (verbose != 0) {
550             mbedtls_printf("  KW-AES-%u ", (unsigned int) key_len[i] * 8);
551         }
552 
553         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             }
559 
560             goto end;
561         }
562 
563         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             }
570 
571             ret = 1;
572             goto end;
573         }
574 
575         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             }
581 
582             goto end;
583         }
584 
585         ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW,
586                                      out, olen, out, &olen, sizeof(out));
587 
588         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             }
593 
594             ret = 1;
595             goto end;
596         }
597 
598         if (verbose != 0) {
599             mbedtls_printf(" passed\n");
600         }
601     }
602 
603     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         }
608 
609         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             }
615 
616             goto end;
617         }
618         ret = mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
619                                    kwp_msg_len[i], out, &olen, sizeof(out));
620 
621         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             }
626 
627             ret = 1;
628             goto end;
629         }
630 
631         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             }
637 
638             goto end;
639         }
640 
641         ret = mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KWP, out,
642                                      olen, out, &olen, sizeof(out));
643 
644         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             }
649 
650             ret = 1;
651             goto end;
652         }
653 
654         if (verbose != 0) {
655             mbedtls_printf(" passed\n");
656         }
657     }
658 end:
659     mbedtls_nist_kw_free(&ctx);
660 
661     if (verbose != 0) {
662         mbedtls_printf("\n");
663     }
664 
665     return ret;
666 }
667 
668 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
669 
670 #endif /* MBEDTLS_NIST_KW_C */
671