xref: /optee_os/lib/libmbedtls/mbedtls/library/nist_kw.c (revision 3d3b05918ec9052ba13de82fbcaba204766eb636)
1*3d3b0591SJens Wiklander /*  SPDX-License-Identifier: Apache-2.0 */
2*3d3b0591SJens Wiklander /*
3*3d3b0591SJens Wiklander  *  Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
4*3d3b0591SJens Wiklander  *  only
5*3d3b0591SJens Wiklander  *
6*3d3b0591SJens Wiklander  *  Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved
7*3d3b0591SJens Wiklander  *
8*3d3b0591SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
9*3d3b0591SJens Wiklander  *  not use this file except in compliance with the License.
10*3d3b0591SJens Wiklander  *  You may obtain a copy of the License at
11*3d3b0591SJens Wiklander  *
12*3d3b0591SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
13*3d3b0591SJens Wiklander  *
14*3d3b0591SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
15*3d3b0591SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16*3d3b0591SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17*3d3b0591SJens Wiklander  *  See the License for the specific language governing permissions and
18*3d3b0591SJens Wiklander  *  limitations under the License.
19*3d3b0591SJens Wiklander  *
20*3d3b0591SJens Wiklander  *  This file is part of Mbed TLS (https://tls.mbed.org)
21*3d3b0591SJens Wiklander  */
22*3d3b0591SJens Wiklander /*
23*3d3b0591SJens Wiklander  * Definition of Key Wrapping:
24*3d3b0591SJens Wiklander  * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
25*3d3b0591SJens Wiklander  * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
26*3d3b0591SJens Wiklander  * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
27*3d3b0591SJens Wiklander  *
28*3d3b0591SJens Wiklander  * Note: RFC 3394 defines different methodology for intermediate operations for
29*3d3b0591SJens Wiklander  * the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
30*3d3b0591SJens Wiklander  */
31*3d3b0591SJens Wiklander 
32*3d3b0591SJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
33*3d3b0591SJens Wiklander #include "mbedtls/config.h"
34*3d3b0591SJens Wiklander #else
35*3d3b0591SJens Wiklander #include MBEDTLS_CONFIG_FILE
36*3d3b0591SJens Wiklander #endif
37*3d3b0591SJens Wiklander 
38*3d3b0591SJens Wiklander #if defined(MBEDTLS_NIST_KW_C)
39*3d3b0591SJens Wiklander 
40*3d3b0591SJens Wiklander #include "mbedtls/nist_kw.h"
41*3d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
42*3d3b0591SJens Wiklander 
43*3d3b0591SJens Wiklander #include <stdint.h>
44*3d3b0591SJens Wiklander #include <string.h>
45*3d3b0591SJens Wiklander 
46*3d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
47*3d3b0591SJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
48*3d3b0591SJens Wiklander #include "mbedtls/platform.h"
49*3d3b0591SJens Wiklander #else
50*3d3b0591SJens Wiklander #include <stdio.h>
51*3d3b0591SJens Wiklander #define mbedtls_printf printf
52*3d3b0591SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
53*3d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
54*3d3b0591SJens Wiklander 
55*3d3b0591SJens Wiklander #if !defined(MBEDTLS_NIST_KW_ALT)
56*3d3b0591SJens Wiklander 
57*3d3b0591SJens Wiklander #define KW_SEMIBLOCK_LENGTH    8
58*3d3b0591SJens Wiklander #define MIN_SEMIBLOCKS_COUNT   3
59*3d3b0591SJens Wiklander 
60*3d3b0591SJens Wiklander /* constant-time buffer comparison */
61*3d3b0591SJens Wiklander static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
62*3d3b0591SJens Wiklander {
63*3d3b0591SJens Wiklander     size_t i;
64*3d3b0591SJens Wiklander     volatile const unsigned char *A = (volatile const unsigned char *) a;
65*3d3b0591SJens Wiklander     volatile const unsigned char *B = (volatile const unsigned char *) b;
66*3d3b0591SJens Wiklander     volatile unsigned char diff = 0;
67*3d3b0591SJens Wiklander 
68*3d3b0591SJens Wiklander     for( i = 0; i < n; i++ )
69*3d3b0591SJens Wiklander     {
70*3d3b0591SJens Wiklander         /* Read volatile data in order before computing diff.
71*3d3b0591SJens Wiklander          * This avoids IAR compiler warning:
72*3d3b0591SJens Wiklander          * 'the order of volatile accesses is undefined ..' */
73*3d3b0591SJens Wiklander         unsigned char x = A[i], y = B[i];
74*3d3b0591SJens Wiklander         diff |= x ^ y;
75*3d3b0591SJens Wiklander     }
76*3d3b0591SJens Wiklander 
77*3d3b0591SJens Wiklander     return( diff );
78*3d3b0591SJens Wiklander }
79*3d3b0591SJens Wiklander 
80*3d3b0591SJens Wiklander /*! The 64-bit default integrity check value (ICV) for KW mode. */
81*3d3b0591SJens Wiklander static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
82*3d3b0591SJens Wiklander /*! The 32-bit default integrity check value (ICV) for KWP mode. */
83*3d3b0591SJens Wiklander static const  unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6};
84*3d3b0591SJens Wiklander 
85*3d3b0591SJens Wiklander #ifndef GET_UINT32_BE
86*3d3b0591SJens Wiklander #define GET_UINT32_BE(n,b,i)                            \
87*3d3b0591SJens Wiklander do {                                                    \
88*3d3b0591SJens Wiklander     (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
89*3d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 1] << 16 )             \
90*3d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
91*3d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 3]       );            \
92*3d3b0591SJens Wiklander } while( 0 )
93*3d3b0591SJens Wiklander #endif
94*3d3b0591SJens Wiklander 
95*3d3b0591SJens Wiklander #ifndef PUT_UINT32_BE
96*3d3b0591SJens Wiklander #define PUT_UINT32_BE(n,b,i)                            \
97*3d3b0591SJens Wiklander do {                                                    \
98*3d3b0591SJens Wiklander     (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
99*3d3b0591SJens Wiklander     (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
100*3d3b0591SJens Wiklander     (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
101*3d3b0591SJens Wiklander     (b)[(i) + 3] = (unsigned char) ( (n)       );       \
102*3d3b0591SJens Wiklander } while( 0 )
103*3d3b0591SJens Wiklander #endif
104*3d3b0591SJens Wiklander 
105*3d3b0591SJens Wiklander /*
106*3d3b0591SJens Wiklander  * Initialize context
107*3d3b0591SJens Wiklander  */
108*3d3b0591SJens Wiklander void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx )
109*3d3b0591SJens Wiklander {
110*3d3b0591SJens Wiklander     memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) );
111*3d3b0591SJens Wiklander }
112*3d3b0591SJens Wiklander 
113*3d3b0591SJens Wiklander int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx,
114*3d3b0591SJens Wiklander                             mbedtls_cipher_id_t cipher,
115*3d3b0591SJens Wiklander                             const unsigned char *key,
116*3d3b0591SJens Wiklander                             unsigned int keybits,
117*3d3b0591SJens Wiklander                             const int is_wrap )
118*3d3b0591SJens Wiklander {
119*3d3b0591SJens Wiklander     int ret;
120*3d3b0591SJens Wiklander     const mbedtls_cipher_info_t *cipher_info;
121*3d3b0591SJens Wiklander 
122*3d3b0591SJens Wiklander     cipher_info = mbedtls_cipher_info_from_values( cipher,
123*3d3b0591SJens Wiklander                                                    keybits,
124*3d3b0591SJens Wiklander                                                    MBEDTLS_MODE_ECB );
125*3d3b0591SJens Wiklander     if( cipher_info == NULL )
126*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
127*3d3b0591SJens Wiklander 
128*3d3b0591SJens Wiklander     if( cipher_info->block_size != 16 )
129*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
130*3d3b0591SJens Wiklander 
131*3d3b0591SJens Wiklander     /*
132*3d3b0591SJens Wiklander      * SP 800-38F currently defines AES cipher as the only block cipher allowed:
133*3d3b0591SJens Wiklander      * "For KW and KWP, the underlying block cipher shall be approved, and the
134*3d3b0591SJens Wiklander      *  block size shall be 128 bits. Currently, the AES block cipher, with key
135*3d3b0591SJens Wiklander      *  lengths of 128, 192, or 256 bits, is the only block cipher that fits
136*3d3b0591SJens Wiklander      *  this profile."
137*3d3b0591SJens Wiklander      *  Currently we don't support other 128 bit block ciphers for key wrapping,
138*3d3b0591SJens Wiklander      *  such as Camellia and Aria.
139*3d3b0591SJens Wiklander      */
140*3d3b0591SJens Wiklander     if( cipher != MBEDTLS_CIPHER_ID_AES )
141*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
142*3d3b0591SJens Wiklander 
143*3d3b0591SJens Wiklander     mbedtls_cipher_free( &ctx->cipher_ctx );
144*3d3b0591SJens Wiklander 
145*3d3b0591SJens Wiklander     if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
146*3d3b0591SJens Wiklander         return( ret );
147*3d3b0591SJens Wiklander 
148*3d3b0591SJens Wiklander     if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
149*3d3b0591SJens Wiklander                                        is_wrap ? MBEDTLS_ENCRYPT :
150*3d3b0591SJens Wiklander                                                  MBEDTLS_DECRYPT )
151*3d3b0591SJens Wiklander                                                                    ) != 0 )
152*3d3b0591SJens Wiklander     {
153*3d3b0591SJens Wiklander         return( ret );
154*3d3b0591SJens Wiklander     }
155*3d3b0591SJens Wiklander 
156*3d3b0591SJens Wiklander     return( 0 );
157*3d3b0591SJens Wiklander }
158*3d3b0591SJens Wiklander 
159*3d3b0591SJens Wiklander /*
160*3d3b0591SJens Wiklander  * Free context
161*3d3b0591SJens Wiklander  */
162*3d3b0591SJens Wiklander void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx )
163*3d3b0591SJens Wiklander {
164*3d3b0591SJens Wiklander     mbedtls_cipher_free( &ctx->cipher_ctx );
165*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) );
166*3d3b0591SJens Wiklander }
167*3d3b0591SJens Wiklander 
168*3d3b0591SJens Wiklander /*
169*3d3b0591SJens Wiklander  * Helper function for Xoring the uint64_t "t" with the encrypted A.
170*3d3b0591SJens Wiklander  * Defined in NIST SP 800-38F section 6.1
171*3d3b0591SJens Wiklander  */
172*3d3b0591SJens Wiklander static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t )
173*3d3b0591SJens Wiklander {
174*3d3b0591SJens Wiklander     size_t i = 0;
175*3d3b0591SJens Wiklander     for( i = 0; i < sizeof( t ); i++ )
176*3d3b0591SJens Wiklander     {
177*3d3b0591SJens Wiklander         A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff;
178*3d3b0591SJens Wiklander     }
179*3d3b0591SJens Wiklander }
180*3d3b0591SJens Wiklander 
181*3d3b0591SJens Wiklander /*
182*3d3b0591SJens Wiklander  * KW-AE as defined in SP 800-38F section 6.2
183*3d3b0591SJens Wiklander  * KWP-AE as defined in SP 800-38F section 6.3
184*3d3b0591SJens Wiklander  */
185*3d3b0591SJens Wiklander int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx,
186*3d3b0591SJens Wiklander                           mbedtls_nist_kw_mode_t mode,
187*3d3b0591SJens Wiklander                           const unsigned char *input, size_t in_len,
188*3d3b0591SJens Wiklander                           unsigned char *output, size_t *out_len, size_t out_size )
189*3d3b0591SJens Wiklander {
190*3d3b0591SJens Wiklander     int ret = 0;
191*3d3b0591SJens Wiklander     size_t semiblocks = 0;
192*3d3b0591SJens Wiklander     size_t s;
193*3d3b0591SJens Wiklander     size_t olen, padlen = 0;
194*3d3b0591SJens Wiklander     uint64_t t = 0;
195*3d3b0591SJens Wiklander     unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
196*3d3b0591SJens Wiklander     unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
197*3d3b0591SJens Wiklander     unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
198*3d3b0591SJens Wiklander     unsigned char *A = output;
199*3d3b0591SJens Wiklander 
200*3d3b0591SJens Wiklander     *out_len = 0;
201*3d3b0591SJens Wiklander     /*
202*3d3b0591SJens Wiklander      * Generate the String to work on
203*3d3b0591SJens Wiklander      */
204*3d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KW )
205*3d3b0591SJens Wiklander     {
206*3d3b0591SJens Wiklander         if( out_size < in_len + KW_SEMIBLOCK_LENGTH )
207*3d3b0591SJens Wiklander         {
208*3d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
209*3d3b0591SJens Wiklander         }
210*3d3b0591SJens Wiklander 
211*3d3b0591SJens Wiklander         /*
212*3d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the plaintext length for KW
213*3d3b0591SJens Wiklander          * must be between 2 to 2^54-1 semiblocks inclusive.
214*3d3b0591SJens Wiklander          */
215*3d3b0591SJens Wiklander         if( in_len < 16 ||
216*3d3b0591SJens Wiklander #if SIZE_MAX > 0x1FFFFFFFFFFFFF8
217*3d3b0591SJens Wiklander             in_len > 0x1FFFFFFFFFFFFF8 ||
218*3d3b0591SJens Wiklander #endif
219*3d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
220*3d3b0591SJens Wiklander         {
221*3d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
222*3d3b0591SJens Wiklander         }
223*3d3b0591SJens Wiklander 
224*3d3b0591SJens Wiklander         memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH );
225*3d3b0591SJens Wiklander         memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len );
226*3d3b0591SJens Wiklander     }
227*3d3b0591SJens Wiklander     else
228*3d3b0591SJens Wiklander     {
229*3d3b0591SJens Wiklander         if( in_len % 8 != 0 )
230*3d3b0591SJens Wiklander         {
231*3d3b0591SJens Wiklander             padlen = ( 8 - ( in_len % 8 ) );
232*3d3b0591SJens Wiklander         }
233*3d3b0591SJens Wiklander 
234*3d3b0591SJens Wiklander         if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen )
235*3d3b0591SJens Wiklander         {
236*3d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
237*3d3b0591SJens Wiklander         }
238*3d3b0591SJens Wiklander 
239*3d3b0591SJens Wiklander         /*
240*3d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the plaintext length for KWP
241*3d3b0591SJens Wiklander          * must be between 1 and 2^32-1 octets inclusive.
242*3d3b0591SJens Wiklander          */
243*3d3b0591SJens Wiklander         if( in_len < 1
244*3d3b0591SJens Wiklander #if SIZE_MAX > 0xFFFFFFFF
245*3d3b0591SJens Wiklander             || in_len > 0xFFFFFFFF
246*3d3b0591SJens Wiklander #endif
247*3d3b0591SJens Wiklander           )
248*3d3b0591SJens Wiklander         {
249*3d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
250*3d3b0591SJens Wiklander         }
251*3d3b0591SJens Wiklander 
252*3d3b0591SJens Wiklander         memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 );
253*3d3b0591SJens Wiklander         PUT_UINT32_BE( ( in_len & 0xffffffff ), output,
254*3d3b0591SJens Wiklander                        KW_SEMIBLOCK_LENGTH / 2 );
255*3d3b0591SJens Wiklander 
256*3d3b0591SJens Wiklander         memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len );
257*3d3b0591SJens Wiklander         memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen );
258*3d3b0591SJens Wiklander     }
259*3d3b0591SJens Wiklander     semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1;
260*3d3b0591SJens Wiklander 
261*3d3b0591SJens Wiklander     s = 6 * ( semiblocks - 1 );
262*3d3b0591SJens Wiklander 
263*3d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KWP
264*3d3b0591SJens Wiklander         && in_len <= KW_SEMIBLOCK_LENGTH )
265*3d3b0591SJens Wiklander     {
266*3d3b0591SJens Wiklander         memcpy( inbuff, output, 16 );
267*3d3b0591SJens Wiklander         ret = mbedtls_cipher_update( &ctx->cipher_ctx,
268*3d3b0591SJens Wiklander                                      inbuff, 16, output, &olen );
269*3d3b0591SJens Wiklander         if( ret != 0 )
270*3d3b0591SJens Wiklander             goto cleanup;
271*3d3b0591SJens Wiklander     }
272*3d3b0591SJens Wiklander     else
273*3d3b0591SJens Wiklander     {
274*3d3b0591SJens Wiklander         /*
275*3d3b0591SJens Wiklander          * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
276*3d3b0591SJens Wiklander          */
277*3d3b0591SJens Wiklander         if( semiblocks < MIN_SEMIBLOCKS_COUNT )
278*3d3b0591SJens Wiklander         {
279*3d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
280*3d3b0591SJens Wiklander             goto cleanup;
281*3d3b0591SJens Wiklander         }
282*3d3b0591SJens Wiklander 
283*3d3b0591SJens Wiklander         /* Calculate intermediate values */
284*3d3b0591SJens Wiklander         for( t = 1; t <= s; t++ )
285*3d3b0591SJens Wiklander         {
286*3d3b0591SJens Wiklander             memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
287*3d3b0591SJens Wiklander             memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH );
288*3d3b0591SJens Wiklander 
289*3d3b0591SJens Wiklander             ret = mbedtls_cipher_update( &ctx->cipher_ctx,
290*3d3b0591SJens Wiklander                                          inbuff, 16, outbuff, &olen );
291*3d3b0591SJens Wiklander             if( ret != 0 )
292*3d3b0591SJens Wiklander                 goto cleanup;
293*3d3b0591SJens Wiklander 
294*3d3b0591SJens Wiklander             memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
295*3d3b0591SJens Wiklander             calc_a_xor_t( A, t );
296*3d3b0591SJens Wiklander 
297*3d3b0591SJens Wiklander             memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
298*3d3b0591SJens Wiklander             R2 += KW_SEMIBLOCK_LENGTH;
299*3d3b0591SJens Wiklander             if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) )
300*3d3b0591SJens Wiklander                 R2 = output + KW_SEMIBLOCK_LENGTH;
301*3d3b0591SJens Wiklander         }
302*3d3b0591SJens Wiklander     }
303*3d3b0591SJens Wiklander 
304*3d3b0591SJens Wiklander     *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
305*3d3b0591SJens Wiklander 
306*3d3b0591SJens Wiklander cleanup:
307*3d3b0591SJens Wiklander 
308*3d3b0591SJens Wiklander     if( ret != 0)
309*3d3b0591SJens Wiklander     {
310*3d3b0591SJens Wiklander         memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH );
311*3d3b0591SJens Wiklander     }
312*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 );
313*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 );
314*3d3b0591SJens Wiklander 
315*3d3b0591SJens Wiklander     return( ret );
316*3d3b0591SJens Wiklander }
317*3d3b0591SJens Wiklander 
318*3d3b0591SJens Wiklander /*
319*3d3b0591SJens Wiklander  * W-1 function as defined in RFC 3394 section 2.2.2
320*3d3b0591SJens Wiklander  * This function assumes the following:
321*3d3b0591SJens Wiklander  * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
322*3d3b0591SJens Wiklander  * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
323*3d3b0591SJens Wiklander  * 3. Minimal number of semiblocks is 3.
324*3d3b0591SJens Wiklander  * 4. A is a buffer to hold the first semiblock of the input buffer.
325*3d3b0591SJens Wiklander  */
326*3d3b0591SJens Wiklander static int unwrap( mbedtls_nist_kw_context *ctx,
327*3d3b0591SJens Wiklander                    const unsigned char *input, size_t semiblocks,
328*3d3b0591SJens Wiklander                    unsigned char A[KW_SEMIBLOCK_LENGTH],
329*3d3b0591SJens Wiklander                    unsigned char *output, size_t* out_len )
330*3d3b0591SJens Wiklander {
331*3d3b0591SJens Wiklander     int ret = 0;
332*3d3b0591SJens Wiklander     const size_t s = 6 * ( semiblocks - 1 );
333*3d3b0591SJens Wiklander     size_t olen;
334*3d3b0591SJens Wiklander     uint64_t t = 0;
335*3d3b0591SJens Wiklander     unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
336*3d3b0591SJens Wiklander     unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
337*3d3b0591SJens Wiklander     unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
338*3d3b0591SJens Wiklander     *out_len = 0;
339*3d3b0591SJens Wiklander 
340*3d3b0591SJens Wiklander     if( semiblocks < MIN_SEMIBLOCKS_COUNT )
341*3d3b0591SJens Wiklander     {
342*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
343*3d3b0591SJens Wiklander     }
344*3d3b0591SJens Wiklander 
345*3d3b0591SJens Wiklander     memcpy( A, input, KW_SEMIBLOCK_LENGTH );
346*3d3b0591SJens Wiklander     memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
347*3d3b0591SJens Wiklander 
348*3d3b0591SJens Wiklander     /* Calculate intermediate values */
349*3d3b0591SJens Wiklander     for( t = s; t >= 1; t-- )
350*3d3b0591SJens Wiklander     {
351*3d3b0591SJens Wiklander         calc_a_xor_t( A, t );
352*3d3b0591SJens Wiklander 
353*3d3b0591SJens Wiklander         memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
354*3d3b0591SJens Wiklander         memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH );
355*3d3b0591SJens Wiklander 
356*3d3b0591SJens Wiklander         ret = mbedtls_cipher_update( &ctx->cipher_ctx,
357*3d3b0591SJens Wiklander                                      inbuff, 16, outbuff, &olen );
358*3d3b0591SJens Wiklander         if( ret != 0 )
359*3d3b0591SJens Wiklander             goto cleanup;
360*3d3b0591SJens Wiklander 
361*3d3b0591SJens Wiklander         memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
362*3d3b0591SJens Wiklander 
363*3d3b0591SJens Wiklander         /* Set R as LSB64 of outbuff */
364*3d3b0591SJens Wiklander         memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
365*3d3b0591SJens Wiklander 
366*3d3b0591SJens Wiklander         if( R == output )
367*3d3b0591SJens Wiklander             R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
368*3d3b0591SJens Wiklander         else
369*3d3b0591SJens Wiklander             R -= KW_SEMIBLOCK_LENGTH;
370*3d3b0591SJens Wiklander     }
371*3d3b0591SJens Wiklander 
372*3d3b0591SJens Wiklander     *out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH;
373*3d3b0591SJens Wiklander 
374*3d3b0591SJens Wiklander cleanup:
375*3d3b0591SJens Wiklander     if( ret != 0)
376*3d3b0591SJens Wiklander         memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
377*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( inbuff, sizeof( inbuff )  );
378*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
379*3d3b0591SJens Wiklander 
380*3d3b0591SJens Wiklander     return( ret );
381*3d3b0591SJens Wiklander }
382*3d3b0591SJens Wiklander 
383*3d3b0591SJens Wiklander /*
384*3d3b0591SJens Wiklander  * KW-AD as defined in SP 800-38F section 6.2
385*3d3b0591SJens Wiklander  * KWP-AD as defined in SP 800-38F section 6.3
386*3d3b0591SJens Wiklander  */
387*3d3b0591SJens Wiklander int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx,
388*3d3b0591SJens Wiklander                             mbedtls_nist_kw_mode_t mode,
389*3d3b0591SJens Wiklander                             const unsigned char *input, size_t in_len,
390*3d3b0591SJens Wiklander                             unsigned char *output, size_t *out_len, size_t out_size )
391*3d3b0591SJens Wiklander {
392*3d3b0591SJens Wiklander     int ret = 0;
393*3d3b0591SJens Wiklander     size_t i, olen;
394*3d3b0591SJens Wiklander     unsigned char A[KW_SEMIBLOCK_LENGTH];
395*3d3b0591SJens Wiklander     unsigned char diff, bad_padding = 0;
396*3d3b0591SJens Wiklander 
397*3d3b0591SJens Wiklander     *out_len = 0;
398*3d3b0591SJens Wiklander     if( out_size < in_len - KW_SEMIBLOCK_LENGTH )
399*3d3b0591SJens Wiklander     {
400*3d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
401*3d3b0591SJens Wiklander     }
402*3d3b0591SJens Wiklander 
403*3d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KW )
404*3d3b0591SJens Wiklander     {
405*3d3b0591SJens Wiklander         /*
406*3d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the ciphertext length for KW
407*3d3b0591SJens Wiklander          * must be between 3 to 2^54 semiblocks inclusive.
408*3d3b0591SJens Wiklander          */
409*3d3b0591SJens Wiklander         if( in_len < 24 ||
410*3d3b0591SJens Wiklander #if SIZE_MAX > 0x200000000000000
411*3d3b0591SJens Wiklander             in_len > 0x200000000000000 ||
412*3d3b0591SJens Wiklander #endif
413*3d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
414*3d3b0591SJens Wiklander         {
415*3d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
416*3d3b0591SJens Wiklander         }
417*3d3b0591SJens Wiklander 
418*3d3b0591SJens Wiklander         ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
419*3d3b0591SJens Wiklander                       A, output, out_len );
420*3d3b0591SJens Wiklander         if( ret != 0 )
421*3d3b0591SJens Wiklander             goto cleanup;
422*3d3b0591SJens Wiklander 
423*3d3b0591SJens Wiklander         /* Check ICV in "constant-time" */
424*3d3b0591SJens Wiklander         diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH );
425*3d3b0591SJens Wiklander 
426*3d3b0591SJens Wiklander         if( diff != 0 )
427*3d3b0591SJens Wiklander         {
428*3d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
429*3d3b0591SJens Wiklander             goto cleanup;
430*3d3b0591SJens Wiklander         }
431*3d3b0591SJens Wiklander 
432*3d3b0591SJens Wiklander     }
433*3d3b0591SJens Wiklander     else if( mode == MBEDTLS_KW_MODE_KWP )
434*3d3b0591SJens Wiklander     {
435*3d3b0591SJens Wiklander         size_t padlen = 0;
436*3d3b0591SJens Wiklander         uint32_t Plen;
437*3d3b0591SJens Wiklander         /*
438*3d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the ciphertext length for KWP
439*3d3b0591SJens Wiklander          * must be between 2 to 2^29 semiblocks inclusive.
440*3d3b0591SJens Wiklander          */
441*3d3b0591SJens Wiklander         if( in_len < KW_SEMIBLOCK_LENGTH * 2 ||
442*3d3b0591SJens Wiklander #if SIZE_MAX > 0x100000000
443*3d3b0591SJens Wiklander             in_len > 0x100000000 ||
444*3d3b0591SJens Wiklander #endif
445*3d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
446*3d3b0591SJens Wiklander         {
447*3d3b0591SJens Wiklander             return(  MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
448*3d3b0591SJens Wiklander         }
449*3d3b0591SJens Wiklander 
450*3d3b0591SJens Wiklander         if( in_len == KW_SEMIBLOCK_LENGTH * 2 )
451*3d3b0591SJens Wiklander         {
452*3d3b0591SJens Wiklander             unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
453*3d3b0591SJens Wiklander             ret = mbedtls_cipher_update( &ctx->cipher_ctx,
454*3d3b0591SJens Wiklander                                          input, 16, outbuff, &olen );
455*3d3b0591SJens Wiklander             if( ret != 0 )
456*3d3b0591SJens Wiklander                 goto cleanup;
457*3d3b0591SJens Wiklander 
458*3d3b0591SJens Wiklander             memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
459*3d3b0591SJens Wiklander             memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
460*3d3b0591SJens Wiklander             mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
461*3d3b0591SJens Wiklander             *out_len = KW_SEMIBLOCK_LENGTH;
462*3d3b0591SJens Wiklander         }
463*3d3b0591SJens Wiklander         else
464*3d3b0591SJens Wiklander         {
465*3d3b0591SJens Wiklander             /* in_len >=  KW_SEMIBLOCK_LENGTH * 3 */
466*3d3b0591SJens Wiklander             ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
467*3d3b0591SJens Wiklander                           A, output, out_len );
468*3d3b0591SJens Wiklander             if( ret != 0 )
469*3d3b0591SJens Wiklander                 goto cleanup;
470*3d3b0591SJens Wiklander         }
471*3d3b0591SJens Wiklander 
472*3d3b0591SJens Wiklander         /* Check ICV in "constant-time" */
473*3d3b0591SJens Wiklander         diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 );
474*3d3b0591SJens Wiklander 
475*3d3b0591SJens Wiklander         if( diff != 0 )
476*3d3b0591SJens Wiklander         {
477*3d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
478*3d3b0591SJens Wiklander         }
479*3d3b0591SJens Wiklander 
480*3d3b0591SJens Wiklander         GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 );
481*3d3b0591SJens Wiklander 
482*3d3b0591SJens Wiklander         /*
483*3d3b0591SJens Wiklander          * Plen is the length of the plaintext, when the input is valid.
484*3d3b0591SJens Wiklander          * If Plen is larger than the plaintext and padding, padlen will be
485*3d3b0591SJens Wiklander          * larger than 8, because of the type wrap around.
486*3d3b0591SJens Wiklander          */
487*3d3b0591SJens Wiklander         padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
488*3d3b0591SJens Wiklander         if ( padlen > 7 )
489*3d3b0591SJens Wiklander         {
490*3d3b0591SJens Wiklander             padlen &= 7;
491*3d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
492*3d3b0591SJens Wiklander         }
493*3d3b0591SJens Wiklander 
494*3d3b0591SJens Wiklander         /* Check padding in "constant-time" */
495*3d3b0591SJens Wiklander         for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ )
496*3d3b0591SJens Wiklander         {
497*3d3b0591SJens Wiklander              if( i >= KW_SEMIBLOCK_LENGTH - padlen )
498*3d3b0591SJens Wiklander                  diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
499*3d3b0591SJens Wiklander              else
500*3d3b0591SJens Wiklander                  bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
501*3d3b0591SJens Wiklander         }
502*3d3b0591SJens Wiklander 
503*3d3b0591SJens Wiklander         if( diff != 0 )
504*3d3b0591SJens Wiklander         {
505*3d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
506*3d3b0591SJens Wiklander         }
507*3d3b0591SJens Wiklander 
508*3d3b0591SJens Wiklander         if( ret != 0 )
509*3d3b0591SJens Wiklander         {
510*3d3b0591SJens Wiklander             goto cleanup;
511*3d3b0591SJens Wiklander         }
512*3d3b0591SJens Wiklander         memset( output + Plen, 0, padlen );
513*3d3b0591SJens Wiklander         *out_len = Plen;
514*3d3b0591SJens Wiklander     }
515*3d3b0591SJens Wiklander     else
516*3d3b0591SJens Wiklander     {
517*3d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
518*3d3b0591SJens Wiklander         goto cleanup;
519*3d3b0591SJens Wiklander     }
520*3d3b0591SJens Wiklander 
521*3d3b0591SJens Wiklander cleanup:
522*3d3b0591SJens Wiklander     if( ret != 0 )
523*3d3b0591SJens Wiklander     {
524*3d3b0591SJens Wiklander         memset( output, 0, *out_len );
525*3d3b0591SJens Wiklander         *out_len = 0;
526*3d3b0591SJens Wiklander     }
527*3d3b0591SJens Wiklander 
528*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) );
529*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( &diff, sizeof( diff ) );
530*3d3b0591SJens Wiklander     mbedtls_platform_zeroize( A, sizeof( A ) );
531*3d3b0591SJens Wiklander 
532*3d3b0591SJens Wiklander     return( ret );
533*3d3b0591SJens Wiklander }
534*3d3b0591SJens Wiklander 
535*3d3b0591SJens Wiklander #endif /* !MBEDTLS_NIST_KW_ALT */
536*3d3b0591SJens Wiklander 
537*3d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
538*3d3b0591SJens Wiklander 
539*3d3b0591SJens Wiklander #define KW_TESTS 3
540*3d3b0591SJens Wiklander 
541*3d3b0591SJens Wiklander /*
542*3d3b0591SJens Wiklander  * Test vectors taken from NIST
543*3d3b0591SJens Wiklander  * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
544*3d3b0591SJens Wiklander  */
545*3d3b0591SJens Wiklander static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
546*3d3b0591SJens Wiklander 
547*3d3b0591SJens Wiklander static const unsigned char kw_key[KW_TESTS][32] = {
548*3d3b0591SJens Wiklander     { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
549*3d3b0591SJens Wiklander       0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
550*3d3b0591SJens Wiklander     { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
551*3d3b0591SJens Wiklander       0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
552*3d3b0591SJens Wiklander       0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
553*3d3b0591SJens Wiklander     { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
554*3d3b0591SJens Wiklander       0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
555*3d3b0591SJens Wiklander       0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
556*3d3b0591SJens Wiklander       0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
557*3d3b0591SJens Wiklander };
558*3d3b0591SJens Wiklander 
559*3d3b0591SJens Wiklander static const unsigned char kw_msg[KW_TESTS][40] = {
560*3d3b0591SJens Wiklander     { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
561*3d3b0591SJens Wiklander       0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
562*3d3b0591SJens Wiklander     { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
563*3d3b0591SJens Wiklander       0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
564*3d3b0591SJens Wiklander       0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
565*3d3b0591SJens Wiklander       0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
566*3d3b0591SJens Wiklander       0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
567*3d3b0591SJens Wiklander     { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
568*3d3b0591SJens Wiklander       0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
569*3d3b0591SJens Wiklander       0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
570*3d3b0591SJens Wiklander };
571*3d3b0591SJens Wiklander 
572*3d3b0591SJens Wiklander static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
573*3d3b0591SJens Wiklander static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
574*3d3b0591SJens Wiklander static const unsigned char kw_res[KW_TESTS][48] = {
575*3d3b0591SJens Wiklander     { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
576*3d3b0591SJens Wiklander       0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
577*3d3b0591SJens Wiklander       0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
578*3d3b0591SJens Wiklander     { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
579*3d3b0591SJens Wiklander       0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
580*3d3b0591SJens Wiklander       0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
581*3d3b0591SJens Wiklander       0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
582*3d3b0591SJens Wiklander       0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
583*3d3b0591SJens Wiklander       0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
584*3d3b0591SJens Wiklander     { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
585*3d3b0591SJens Wiklander       0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
586*3d3b0591SJens Wiklander       0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
587*3d3b0591SJens Wiklander       0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
588*3d3b0591SJens Wiklander };
589*3d3b0591SJens Wiklander 
590*3d3b0591SJens Wiklander static const unsigned char kwp_key[KW_TESTS][32] = {
591*3d3b0591SJens Wiklander     { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
592*3d3b0591SJens Wiklander       0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
593*3d3b0591SJens Wiklander     { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
594*3d3b0591SJens Wiklander       0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
595*3d3b0591SJens Wiklander       0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
596*3d3b0591SJens Wiklander     { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
597*3d3b0591SJens Wiklander       0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
598*3d3b0591SJens Wiklander       0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
599*3d3b0591SJens Wiklander       0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
600*3d3b0591SJens Wiklander };
601*3d3b0591SJens Wiklander 
602*3d3b0591SJens Wiklander static const unsigned char kwp_msg[KW_TESTS][31] = {
603*3d3b0591SJens Wiklander     { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
604*3d3b0591SJens Wiklander       0x96 },
605*3d3b0591SJens Wiklander     { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
606*3d3b0591SJens Wiklander       0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
607*3d3b0591SJens Wiklander       0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
608*3d3b0591SJens Wiklander       0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
609*3d3b0591SJens Wiklander     { 0xd1 }
610*3d3b0591SJens Wiklander };
611*3d3b0591SJens Wiklander static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
612*3d3b0591SJens Wiklander 
613*3d3b0591SJens Wiklander static const unsigned char kwp_res[KW_TESTS][48] = {
614*3d3b0591SJens Wiklander     { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
615*3d3b0591SJens Wiklander       0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
616*3d3b0591SJens Wiklander       0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
617*3d3b0591SJens Wiklander     { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
618*3d3b0591SJens Wiklander       0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
619*3d3b0591SJens Wiklander       0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
620*3d3b0591SJens Wiklander       0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
621*3d3b0591SJens Wiklander       0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
622*3d3b0591SJens Wiklander     { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
623*3d3b0591SJens Wiklander       0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4  }
624*3d3b0591SJens Wiklander };
625*3d3b0591SJens Wiklander static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
626*3d3b0591SJens Wiklander 
627*3d3b0591SJens Wiklander int mbedtls_nist_kw_self_test( int verbose )
628*3d3b0591SJens Wiklander {
629*3d3b0591SJens Wiklander     mbedtls_nist_kw_context ctx;
630*3d3b0591SJens Wiklander     unsigned char out[48];
631*3d3b0591SJens Wiklander     size_t olen;
632*3d3b0591SJens Wiklander     int i;
633*3d3b0591SJens Wiklander     int ret = 0;
634*3d3b0591SJens Wiklander     mbedtls_nist_kw_init( &ctx );
635*3d3b0591SJens Wiklander 
636*3d3b0591SJens Wiklander     for( i = 0; i < KW_TESTS; i++ )
637*3d3b0591SJens Wiklander     {
638*3d3b0591SJens Wiklander         if( verbose != 0 )
639*3d3b0591SJens Wiklander             mbedtls_printf( "  KW-AES-%u ", (unsigned int) key_len[i] * 8 );
640*3d3b0591SJens Wiklander 
641*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
642*3d3b0591SJens Wiklander                                       kw_key[i], key_len[i] * 8, 1 );
643*3d3b0591SJens Wiklander         if( ret != 0 )
644*3d3b0591SJens Wiklander         {
645*3d3b0591SJens Wiklander             if( verbose != 0 )
646*3d3b0591SJens Wiklander                 mbedtls_printf( "  KW: setup failed " );
647*3d3b0591SJens Wiklander 
648*3d3b0591SJens Wiklander             goto end;
649*3d3b0591SJens Wiklander         }
650*3d3b0591SJens Wiklander 
651*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
652*3d3b0591SJens Wiklander                                     kw_msg_len[i], out, &olen, sizeof( out ) );
653*3d3b0591SJens Wiklander         if( ret != 0 || kw_out_len[i] != olen ||
654*3d3b0591SJens Wiklander             memcmp( out, kw_res[i], kw_out_len[i] ) != 0 )
655*3d3b0591SJens Wiklander         {
656*3d3b0591SJens Wiklander             if( verbose != 0 )
657*3d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
658*3d3b0591SJens Wiklander 
659*3d3b0591SJens Wiklander             ret = 1;
660*3d3b0591SJens Wiklander             goto end;
661*3d3b0591SJens Wiklander         }
662*3d3b0591SJens Wiklander 
663*3d3b0591SJens Wiklander         if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
664*3d3b0591SJens Wiklander                                             kw_key[i], key_len[i] * 8, 0 ) )
665*3d3b0591SJens Wiklander               != 0 )
666*3d3b0591SJens Wiklander         {
667*3d3b0591SJens Wiklander             if( verbose != 0 )
668*3d3b0591SJens Wiklander                 mbedtls_printf( "  KW: setup failed ");
669*3d3b0591SJens Wiklander 
670*3d3b0591SJens Wiklander             goto end;
671*3d3b0591SJens Wiklander         }
672*3d3b0591SJens Wiklander 
673*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW,
674*3d3b0591SJens Wiklander                                       out, olen, out, &olen, sizeof( out ) );
675*3d3b0591SJens Wiklander 
676*3d3b0591SJens Wiklander         if( ret != 0 || olen != kw_msg_len[i] ||
677*3d3b0591SJens Wiklander             memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 )
678*3d3b0591SJens Wiklander         {
679*3d3b0591SJens Wiklander             if( verbose != 0 )
680*3d3b0591SJens Wiklander                 mbedtls_printf( "failed\n" );
681*3d3b0591SJens Wiklander 
682*3d3b0591SJens Wiklander             ret = 1;
683*3d3b0591SJens Wiklander             goto end;
684*3d3b0591SJens Wiklander         }
685*3d3b0591SJens Wiklander 
686*3d3b0591SJens Wiklander         if( verbose != 0 )
687*3d3b0591SJens Wiklander             mbedtls_printf( " passed\n" );
688*3d3b0591SJens Wiklander     }
689*3d3b0591SJens Wiklander 
690*3d3b0591SJens Wiklander     for( i = 0; i < KW_TESTS; i++ )
691*3d3b0591SJens Wiklander     {
692*3d3b0591SJens Wiklander         olen = sizeof( out );
693*3d3b0591SJens Wiklander         if( verbose != 0 )
694*3d3b0591SJens Wiklander             mbedtls_printf( "  KWP-AES-%u ", (unsigned int) key_len[i] * 8 );
695*3d3b0591SJens Wiklander 
696*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
697*3d3b0591SJens Wiklander                                       key_len[i] * 8, 1 );
698*3d3b0591SJens Wiklander         if( ret  != 0 )
699*3d3b0591SJens Wiklander         {
700*3d3b0591SJens Wiklander             if( verbose != 0 )
701*3d3b0591SJens Wiklander                 mbedtls_printf( "  KWP: setup failed " );
702*3d3b0591SJens Wiklander 
703*3d3b0591SJens Wiklander             goto end;
704*3d3b0591SJens Wiklander         }
705*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
706*3d3b0591SJens Wiklander                                     kwp_msg_len[i], out, &olen, sizeof( out ) );
707*3d3b0591SJens Wiklander 
708*3d3b0591SJens Wiklander         if( ret != 0 || kwp_out_len[i] != olen ||
709*3d3b0591SJens Wiklander             memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 )
710*3d3b0591SJens Wiklander         {
711*3d3b0591SJens Wiklander             if( verbose != 0 )
712*3d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
713*3d3b0591SJens Wiklander 
714*3d3b0591SJens Wiklander             ret = 1;
715*3d3b0591SJens Wiklander             goto end;
716*3d3b0591SJens Wiklander         }
717*3d3b0591SJens Wiklander 
718*3d3b0591SJens Wiklander         if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
719*3d3b0591SJens Wiklander                                             kwp_key[i], key_len[i] * 8, 0 ) )
720*3d3b0591SJens Wiklander               != 0 )
721*3d3b0591SJens Wiklander         {
722*3d3b0591SJens Wiklander             if( verbose != 0 )
723*3d3b0591SJens Wiklander                 mbedtls_printf( "  KWP: setup failed ");
724*3d3b0591SJens Wiklander 
725*3d3b0591SJens Wiklander             goto end;
726*3d3b0591SJens Wiklander         }
727*3d3b0591SJens Wiklander 
728*3d3b0591SJens Wiklander         ret = mbedtls_nist_kw_unwrap(  &ctx, MBEDTLS_KW_MODE_KWP, out,
729*3d3b0591SJens Wiklander                                        olen, out, &olen, sizeof( out ) );
730*3d3b0591SJens Wiklander 
731*3d3b0591SJens Wiklander         if( ret != 0 || olen != kwp_msg_len[i] ||
732*3d3b0591SJens Wiklander             memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 )
733*3d3b0591SJens Wiklander         {
734*3d3b0591SJens Wiklander             if( verbose != 0 )
735*3d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
736*3d3b0591SJens Wiklander 
737*3d3b0591SJens Wiklander             ret = 1;
738*3d3b0591SJens Wiklander             goto end;
739*3d3b0591SJens Wiklander         }
740*3d3b0591SJens Wiklander 
741*3d3b0591SJens Wiklander         if( verbose != 0 )
742*3d3b0591SJens Wiklander             mbedtls_printf( " passed\n" );
743*3d3b0591SJens Wiklander     }
744*3d3b0591SJens Wiklander end:
745*3d3b0591SJens Wiklander     mbedtls_nist_kw_free( &ctx );
746*3d3b0591SJens Wiklander 
747*3d3b0591SJens Wiklander     if( verbose != 0 )
748*3d3b0591SJens Wiklander         mbedtls_printf( "\n" );
749*3d3b0591SJens Wiklander 
750*3d3b0591SJens Wiklander     return( ret );
751*3d3b0591SJens Wiklander }
752*3d3b0591SJens Wiklander 
753*3d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
754*3d3b0591SJens Wiklander 
755*3d3b0591SJens Wiklander #endif /* MBEDTLS_NIST_KW_C */
756