xref: /optee_os/lib/libmbedtls/mbedtls/library/nist_kw.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
13d3b0591SJens Wiklander /*  SPDX-License-Identifier: Apache-2.0 */
23d3b0591SJens Wiklander /*
33d3b0591SJens Wiklander  *  Implementation of NIST SP 800-38F key wrapping, supporting KW and KWP modes
43d3b0591SJens Wiklander  *  only
53d3b0591SJens Wiklander  *
63d3b0591SJens Wiklander  *  Copyright (C) 2018, Arm Limited (or its affiliates), All Rights Reserved
73d3b0591SJens Wiklander  *
83d3b0591SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
93d3b0591SJens Wiklander  *  not use this file except in compliance with the License.
103d3b0591SJens Wiklander  *  You may obtain a copy of the License at
113d3b0591SJens Wiklander  *
123d3b0591SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
133d3b0591SJens Wiklander  *
143d3b0591SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
153d3b0591SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
163d3b0591SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
173d3b0591SJens Wiklander  *  See the License for the specific language governing permissions and
183d3b0591SJens Wiklander  *  limitations under the License.
193d3b0591SJens Wiklander  *
203d3b0591SJens Wiklander  *  This file is part of Mbed TLS (https://tls.mbed.org)
213d3b0591SJens Wiklander  */
223d3b0591SJens Wiklander /*
233d3b0591SJens Wiklander  * Definition of Key Wrapping:
243d3b0591SJens Wiklander  * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38F.pdf
253d3b0591SJens Wiklander  * RFC 3394 "Advanced Encryption Standard (AES) Key Wrap Algorithm"
263d3b0591SJens Wiklander  * RFC 5649 "Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm"
273d3b0591SJens Wiklander  *
283d3b0591SJens Wiklander  * Note: RFC 3394 defines different methodology for intermediate operations for
293d3b0591SJens Wiklander  * the wrapping and unwrapping operation than the definition in NIST SP 800-38F.
303d3b0591SJens Wiklander  */
313d3b0591SJens Wiklander 
323d3b0591SJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
333d3b0591SJens Wiklander #include "mbedtls/config.h"
343d3b0591SJens Wiklander #else
353d3b0591SJens Wiklander #include MBEDTLS_CONFIG_FILE
363d3b0591SJens Wiklander #endif
373d3b0591SJens Wiklander 
383d3b0591SJens Wiklander #if defined(MBEDTLS_NIST_KW_C)
393d3b0591SJens Wiklander 
403d3b0591SJens Wiklander #include "mbedtls/nist_kw.h"
413d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
42*11fa71b9SJerome Forissier #include "mbedtls/error.h"
433d3b0591SJens Wiklander 
443d3b0591SJens Wiklander #include <stdint.h>
453d3b0591SJens Wiklander #include <string.h>
463d3b0591SJens Wiklander 
473d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
483d3b0591SJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
493d3b0591SJens Wiklander #include "mbedtls/platform.h"
503d3b0591SJens Wiklander #else
513d3b0591SJens Wiklander #include <stdio.h>
523d3b0591SJens Wiklander #define mbedtls_printf printf
533d3b0591SJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
543d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
553d3b0591SJens Wiklander 
563d3b0591SJens Wiklander #if !defined(MBEDTLS_NIST_KW_ALT)
573d3b0591SJens Wiklander 
583d3b0591SJens Wiklander #define KW_SEMIBLOCK_LENGTH    8
593d3b0591SJens Wiklander #define MIN_SEMIBLOCKS_COUNT   3
603d3b0591SJens Wiklander 
613d3b0591SJens Wiklander /* constant-time buffer comparison */
623d3b0591SJens Wiklander static inline unsigned char mbedtls_nist_kw_safer_memcmp( const void *a, const void *b, size_t n )
633d3b0591SJens Wiklander {
643d3b0591SJens Wiklander     size_t i;
653d3b0591SJens Wiklander     volatile const unsigned char *A = (volatile const unsigned char *) a;
663d3b0591SJens Wiklander     volatile const unsigned char *B = (volatile const unsigned char *) b;
673d3b0591SJens Wiklander     volatile unsigned char diff = 0;
683d3b0591SJens Wiklander 
693d3b0591SJens Wiklander     for( i = 0; i < n; i++ )
703d3b0591SJens Wiklander     {
713d3b0591SJens Wiklander         /* Read volatile data in order before computing diff.
723d3b0591SJens Wiklander          * This avoids IAR compiler warning:
733d3b0591SJens Wiklander          * 'the order of volatile accesses is undefined ..' */
743d3b0591SJens Wiklander         unsigned char x = A[i], y = B[i];
753d3b0591SJens Wiklander         diff |= x ^ y;
763d3b0591SJens Wiklander     }
773d3b0591SJens Wiklander 
783d3b0591SJens Wiklander     return( diff );
793d3b0591SJens Wiklander }
803d3b0591SJens Wiklander 
813d3b0591SJens Wiklander /*! The 64-bit default integrity check value (ICV) for KW mode. */
823d3b0591SJens Wiklander static const unsigned char NIST_KW_ICV1[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
833d3b0591SJens Wiklander /*! The 32-bit default integrity check value (ICV) for KWP mode. */
843d3b0591SJens Wiklander static const  unsigned char NIST_KW_ICV2[] = {0xA6, 0x59, 0x59, 0xA6};
853d3b0591SJens Wiklander 
863d3b0591SJens Wiklander #ifndef GET_UINT32_BE
873d3b0591SJens Wiklander #define GET_UINT32_BE(n,b,i)                            \
883d3b0591SJens Wiklander do {                                                    \
893d3b0591SJens Wiklander     (n) = ( (uint32_t) (b)[(i)    ] << 24 )             \
903d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 1] << 16 )             \
913d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 2] <<  8 )             \
923d3b0591SJens Wiklander         | ( (uint32_t) (b)[(i) + 3]       );            \
933d3b0591SJens Wiklander } while( 0 )
943d3b0591SJens Wiklander #endif
953d3b0591SJens Wiklander 
963d3b0591SJens Wiklander #ifndef PUT_UINT32_BE
973d3b0591SJens Wiklander #define PUT_UINT32_BE(n,b,i)                            \
983d3b0591SJens Wiklander do {                                                    \
993d3b0591SJens Wiklander     (b)[(i)    ] = (unsigned char) ( (n) >> 24 );       \
1003d3b0591SJens Wiklander     (b)[(i) + 1] = (unsigned char) ( (n) >> 16 );       \
1013d3b0591SJens Wiklander     (b)[(i) + 2] = (unsigned char) ( (n) >>  8 );       \
1023d3b0591SJens Wiklander     (b)[(i) + 3] = (unsigned char) ( (n)       );       \
1033d3b0591SJens Wiklander } while( 0 )
1043d3b0591SJens Wiklander #endif
1053d3b0591SJens Wiklander 
1063d3b0591SJens Wiklander /*
1073d3b0591SJens Wiklander  * Initialize context
1083d3b0591SJens Wiklander  */
1093d3b0591SJens Wiklander void mbedtls_nist_kw_init( mbedtls_nist_kw_context *ctx )
1103d3b0591SJens Wiklander {
1113d3b0591SJens Wiklander     memset( ctx, 0, sizeof( mbedtls_nist_kw_context ) );
1123d3b0591SJens Wiklander }
1133d3b0591SJens Wiklander 
1143d3b0591SJens Wiklander int mbedtls_nist_kw_setkey( mbedtls_nist_kw_context *ctx,
1153d3b0591SJens Wiklander                             mbedtls_cipher_id_t cipher,
1163d3b0591SJens Wiklander                             const unsigned char *key,
1173d3b0591SJens Wiklander                             unsigned int keybits,
1183d3b0591SJens Wiklander                             const int is_wrap )
1193d3b0591SJens Wiklander {
120*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1213d3b0591SJens Wiklander     const mbedtls_cipher_info_t *cipher_info;
1223d3b0591SJens Wiklander 
1233d3b0591SJens Wiklander     cipher_info = mbedtls_cipher_info_from_values( cipher,
1243d3b0591SJens Wiklander                                                    keybits,
1253d3b0591SJens Wiklander                                                    MBEDTLS_MODE_ECB );
1263d3b0591SJens Wiklander     if( cipher_info == NULL )
1273d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
1283d3b0591SJens Wiklander 
1293d3b0591SJens Wiklander     if( cipher_info->block_size != 16 )
1303d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
1313d3b0591SJens Wiklander 
1323d3b0591SJens Wiklander     /*
1333d3b0591SJens Wiklander      * SP 800-38F currently defines AES cipher as the only block cipher allowed:
1343d3b0591SJens Wiklander      * "For KW and KWP, the underlying block cipher shall be approved, and the
1353d3b0591SJens Wiklander      *  block size shall be 128 bits. Currently, the AES block cipher, with key
1363d3b0591SJens Wiklander      *  lengths of 128, 192, or 256 bits, is the only block cipher that fits
1373d3b0591SJens Wiklander      *  this profile."
1383d3b0591SJens Wiklander      *  Currently we don't support other 128 bit block ciphers for key wrapping,
1393d3b0591SJens Wiklander      *  such as Camellia and Aria.
1403d3b0591SJens Wiklander      */
1413d3b0591SJens Wiklander     if( cipher != MBEDTLS_CIPHER_ID_AES )
1423d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
1433d3b0591SJens Wiklander 
1443d3b0591SJens Wiklander     mbedtls_cipher_free( &ctx->cipher_ctx );
1453d3b0591SJens Wiklander 
1463d3b0591SJens Wiklander     if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
1473d3b0591SJens Wiklander         return( ret );
1483d3b0591SJens Wiklander 
1493d3b0591SJens Wiklander     if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
1503d3b0591SJens Wiklander                                        is_wrap ? MBEDTLS_ENCRYPT :
1513d3b0591SJens Wiklander                                                  MBEDTLS_DECRYPT )
1523d3b0591SJens Wiklander                                                                    ) != 0 )
1533d3b0591SJens Wiklander     {
1543d3b0591SJens Wiklander         return( ret );
1553d3b0591SJens Wiklander     }
1563d3b0591SJens Wiklander 
1573d3b0591SJens Wiklander     return( 0 );
1583d3b0591SJens Wiklander }
1593d3b0591SJens Wiklander 
1603d3b0591SJens Wiklander /*
1613d3b0591SJens Wiklander  * Free context
1623d3b0591SJens Wiklander  */
1633d3b0591SJens Wiklander void mbedtls_nist_kw_free( mbedtls_nist_kw_context *ctx )
1643d3b0591SJens Wiklander {
1653d3b0591SJens Wiklander     mbedtls_cipher_free( &ctx->cipher_ctx );
1663d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_nist_kw_context ) );
1673d3b0591SJens Wiklander }
1683d3b0591SJens Wiklander 
1693d3b0591SJens Wiklander /*
1703d3b0591SJens Wiklander  * Helper function for Xoring the uint64_t "t" with the encrypted A.
1713d3b0591SJens Wiklander  * Defined in NIST SP 800-38F section 6.1
1723d3b0591SJens Wiklander  */
1733d3b0591SJens Wiklander static void calc_a_xor_t( unsigned char A[KW_SEMIBLOCK_LENGTH], uint64_t t )
1743d3b0591SJens Wiklander {
1753d3b0591SJens Wiklander     size_t i = 0;
1763d3b0591SJens Wiklander     for( i = 0; i < sizeof( t ); i++ )
1773d3b0591SJens Wiklander     {
1783d3b0591SJens Wiklander         A[i] ^= ( t >> ( ( sizeof( t ) - 1 - i ) * 8 ) ) & 0xff;
1793d3b0591SJens Wiklander     }
1803d3b0591SJens Wiklander }
1813d3b0591SJens Wiklander 
1823d3b0591SJens Wiklander /*
1833d3b0591SJens Wiklander  * KW-AE as defined in SP 800-38F section 6.2
1843d3b0591SJens Wiklander  * KWP-AE as defined in SP 800-38F section 6.3
1853d3b0591SJens Wiklander  */
1863d3b0591SJens Wiklander int mbedtls_nist_kw_wrap( mbedtls_nist_kw_context *ctx,
1873d3b0591SJens Wiklander                           mbedtls_nist_kw_mode_t mode,
1883d3b0591SJens Wiklander                           const unsigned char *input, size_t in_len,
1893d3b0591SJens Wiklander                           unsigned char *output, size_t *out_len, size_t out_size )
1903d3b0591SJens Wiklander {
1913d3b0591SJens Wiklander     int ret = 0;
1923d3b0591SJens Wiklander     size_t semiblocks = 0;
1933d3b0591SJens Wiklander     size_t s;
1943d3b0591SJens Wiklander     size_t olen, padlen = 0;
1953d3b0591SJens Wiklander     uint64_t t = 0;
1963d3b0591SJens Wiklander     unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
1973d3b0591SJens Wiklander     unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
1983d3b0591SJens Wiklander     unsigned char *R2 = output + KW_SEMIBLOCK_LENGTH;
1993d3b0591SJens Wiklander     unsigned char *A = output;
2003d3b0591SJens Wiklander 
2013d3b0591SJens Wiklander     *out_len = 0;
2023d3b0591SJens Wiklander     /*
2033d3b0591SJens Wiklander      * Generate the String to work on
2043d3b0591SJens Wiklander      */
2053d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KW )
2063d3b0591SJens Wiklander     {
2073d3b0591SJens Wiklander         if( out_size < in_len + KW_SEMIBLOCK_LENGTH )
2083d3b0591SJens Wiklander         {
2093d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2103d3b0591SJens Wiklander         }
2113d3b0591SJens Wiklander 
2123d3b0591SJens Wiklander         /*
2133d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the plaintext length for KW
2143d3b0591SJens Wiklander          * must be between 2 to 2^54-1 semiblocks inclusive.
2153d3b0591SJens Wiklander          */
2163d3b0591SJens Wiklander         if( in_len < 16 ||
2173d3b0591SJens Wiklander #if SIZE_MAX > 0x1FFFFFFFFFFFFF8
2183d3b0591SJens Wiklander             in_len > 0x1FFFFFFFFFFFFF8 ||
2193d3b0591SJens Wiklander #endif
2203d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
2213d3b0591SJens Wiklander         {
2223d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2233d3b0591SJens Wiklander         }
2243d3b0591SJens Wiklander 
2253d3b0591SJens Wiklander         memcpy( output, NIST_KW_ICV1, KW_SEMIBLOCK_LENGTH );
2263d3b0591SJens Wiklander         memmove( output + KW_SEMIBLOCK_LENGTH, input, in_len );
2273d3b0591SJens Wiklander     }
2283d3b0591SJens Wiklander     else
2293d3b0591SJens Wiklander     {
2303d3b0591SJens Wiklander         if( in_len % 8 != 0 )
2313d3b0591SJens Wiklander         {
2323d3b0591SJens Wiklander             padlen = ( 8 - ( in_len % 8 ) );
2333d3b0591SJens Wiklander         }
2343d3b0591SJens Wiklander 
2353d3b0591SJens Wiklander         if( out_size < in_len + KW_SEMIBLOCK_LENGTH + padlen )
2363d3b0591SJens Wiklander         {
2373d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2383d3b0591SJens Wiklander         }
2393d3b0591SJens Wiklander 
2403d3b0591SJens Wiklander         /*
2413d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the plaintext length for KWP
2423d3b0591SJens Wiklander          * must be between 1 and 2^32-1 octets inclusive.
2433d3b0591SJens Wiklander          */
2443d3b0591SJens Wiklander         if( in_len < 1
2453d3b0591SJens Wiklander #if SIZE_MAX > 0xFFFFFFFF
2463d3b0591SJens Wiklander             || in_len > 0xFFFFFFFF
2473d3b0591SJens Wiklander #endif
2483d3b0591SJens Wiklander           )
2493d3b0591SJens Wiklander         {
2503d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
2513d3b0591SJens Wiklander         }
2523d3b0591SJens Wiklander 
2533d3b0591SJens Wiklander         memcpy( output, NIST_KW_ICV2, KW_SEMIBLOCK_LENGTH / 2 );
2543d3b0591SJens Wiklander         PUT_UINT32_BE( ( in_len & 0xffffffff ), output,
2553d3b0591SJens Wiklander                        KW_SEMIBLOCK_LENGTH / 2 );
2563d3b0591SJens Wiklander 
2573d3b0591SJens Wiklander         memcpy( output + KW_SEMIBLOCK_LENGTH, input, in_len );
2583d3b0591SJens Wiklander         memset( output + KW_SEMIBLOCK_LENGTH + in_len, 0, padlen );
2593d3b0591SJens Wiklander     }
2603d3b0591SJens Wiklander     semiblocks = ( ( in_len + padlen ) / KW_SEMIBLOCK_LENGTH ) + 1;
2613d3b0591SJens Wiklander 
2623d3b0591SJens Wiklander     s = 6 * ( semiblocks - 1 );
2633d3b0591SJens Wiklander 
2643d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KWP
2653d3b0591SJens Wiklander         && in_len <= KW_SEMIBLOCK_LENGTH )
2663d3b0591SJens Wiklander     {
2673d3b0591SJens Wiklander         memcpy( inbuff, output, 16 );
2683d3b0591SJens Wiklander         ret = mbedtls_cipher_update( &ctx->cipher_ctx,
2693d3b0591SJens Wiklander                                      inbuff, 16, output, &olen );
2703d3b0591SJens Wiklander         if( ret != 0 )
2713d3b0591SJens Wiklander             goto cleanup;
2723d3b0591SJens Wiklander     }
2733d3b0591SJens Wiklander     else
2743d3b0591SJens Wiklander     {
2753d3b0591SJens Wiklander         /*
2763d3b0591SJens Wiklander          * Do the wrapping function W, as defined in RFC 3394 section 2.2.1
2773d3b0591SJens Wiklander          */
2783d3b0591SJens Wiklander         if( semiblocks < MIN_SEMIBLOCKS_COUNT )
2793d3b0591SJens Wiklander         {
2803d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
2813d3b0591SJens Wiklander             goto cleanup;
2823d3b0591SJens Wiklander         }
2833d3b0591SJens Wiklander 
2843d3b0591SJens Wiklander         /* Calculate intermediate values */
2853d3b0591SJens Wiklander         for( t = 1; t <= s; t++ )
2863d3b0591SJens Wiklander         {
2873d3b0591SJens Wiklander             memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
2883d3b0591SJens Wiklander             memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R2, KW_SEMIBLOCK_LENGTH );
2893d3b0591SJens Wiklander 
2903d3b0591SJens Wiklander             ret = mbedtls_cipher_update( &ctx->cipher_ctx,
2913d3b0591SJens Wiklander                                          inbuff, 16, outbuff, &olen );
2923d3b0591SJens Wiklander             if( ret != 0 )
2933d3b0591SJens Wiklander                 goto cleanup;
2943d3b0591SJens Wiklander 
2953d3b0591SJens Wiklander             memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
2963d3b0591SJens Wiklander             calc_a_xor_t( A, t );
2973d3b0591SJens Wiklander 
2983d3b0591SJens Wiklander             memcpy( R2, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
2993d3b0591SJens Wiklander             R2 += KW_SEMIBLOCK_LENGTH;
3003d3b0591SJens Wiklander             if( R2 >= output + ( semiblocks * KW_SEMIBLOCK_LENGTH ) )
3013d3b0591SJens Wiklander                 R2 = output + KW_SEMIBLOCK_LENGTH;
3023d3b0591SJens Wiklander         }
3033d3b0591SJens Wiklander     }
3043d3b0591SJens Wiklander 
3053d3b0591SJens Wiklander     *out_len = semiblocks * KW_SEMIBLOCK_LENGTH;
3063d3b0591SJens Wiklander 
3073d3b0591SJens Wiklander cleanup:
3083d3b0591SJens Wiklander 
3093d3b0591SJens Wiklander     if( ret != 0)
3103d3b0591SJens Wiklander     {
3113d3b0591SJens Wiklander         memset( output, 0, semiblocks * KW_SEMIBLOCK_LENGTH );
3123d3b0591SJens Wiklander     }
3133d3b0591SJens Wiklander     mbedtls_platform_zeroize( inbuff, KW_SEMIBLOCK_LENGTH * 2 );
3143d3b0591SJens Wiklander     mbedtls_platform_zeroize( outbuff, KW_SEMIBLOCK_LENGTH * 2 );
3153d3b0591SJens Wiklander 
3163d3b0591SJens Wiklander     return( ret );
3173d3b0591SJens Wiklander }
3183d3b0591SJens Wiklander 
3193d3b0591SJens Wiklander /*
3203d3b0591SJens Wiklander  * W-1 function as defined in RFC 3394 section 2.2.2
3213d3b0591SJens Wiklander  * This function assumes the following:
3223d3b0591SJens Wiklander  * 1. Output buffer is at least of size ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH.
3233d3b0591SJens Wiklander  * 2. The input buffer is of size semiblocks * KW_SEMIBLOCK_LENGTH.
3243d3b0591SJens Wiklander  * 3. Minimal number of semiblocks is 3.
3253d3b0591SJens Wiklander  * 4. A is a buffer to hold the first semiblock of the input buffer.
3263d3b0591SJens Wiklander  */
3273d3b0591SJens Wiklander static int unwrap( mbedtls_nist_kw_context *ctx,
3283d3b0591SJens Wiklander                    const unsigned char *input, size_t semiblocks,
3293d3b0591SJens Wiklander                    unsigned char A[KW_SEMIBLOCK_LENGTH],
3303d3b0591SJens Wiklander                    unsigned char *output, size_t* out_len )
3313d3b0591SJens Wiklander {
3323d3b0591SJens Wiklander     int ret = 0;
3333d3b0591SJens Wiklander     const size_t s = 6 * ( semiblocks - 1 );
3343d3b0591SJens Wiklander     size_t olen;
3353d3b0591SJens Wiklander     uint64_t t = 0;
3363d3b0591SJens Wiklander     unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
3373d3b0591SJens Wiklander     unsigned char inbuff[KW_SEMIBLOCK_LENGTH * 2];
3383d3b0591SJens Wiklander     unsigned char *R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
3393d3b0591SJens Wiklander     *out_len = 0;
3403d3b0591SJens Wiklander 
3413d3b0591SJens Wiklander     if( semiblocks < MIN_SEMIBLOCKS_COUNT )
3423d3b0591SJens Wiklander     {
3433d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
3443d3b0591SJens Wiklander     }
3453d3b0591SJens Wiklander 
3463d3b0591SJens Wiklander     memcpy( A, input, KW_SEMIBLOCK_LENGTH );
3473d3b0591SJens Wiklander     memmove( output, input + KW_SEMIBLOCK_LENGTH, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
3483d3b0591SJens Wiklander 
3493d3b0591SJens Wiklander     /* Calculate intermediate values */
3503d3b0591SJens Wiklander     for( t = s; t >= 1; t-- )
3513d3b0591SJens Wiklander     {
3523d3b0591SJens Wiklander         calc_a_xor_t( A, t );
3533d3b0591SJens Wiklander 
3543d3b0591SJens Wiklander         memcpy( inbuff, A, KW_SEMIBLOCK_LENGTH );
3553d3b0591SJens Wiklander         memcpy( inbuff + KW_SEMIBLOCK_LENGTH, R, KW_SEMIBLOCK_LENGTH );
3563d3b0591SJens Wiklander 
3573d3b0591SJens Wiklander         ret = mbedtls_cipher_update( &ctx->cipher_ctx,
3583d3b0591SJens Wiklander                                      inbuff, 16, outbuff, &olen );
3593d3b0591SJens Wiklander         if( ret != 0 )
3603d3b0591SJens Wiklander             goto cleanup;
3613d3b0591SJens Wiklander 
3623d3b0591SJens Wiklander         memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
3633d3b0591SJens Wiklander 
3643d3b0591SJens Wiklander         /* Set R as LSB64 of outbuff */
3653d3b0591SJens Wiklander         memcpy( R, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
3663d3b0591SJens Wiklander 
3673d3b0591SJens Wiklander         if( R == output )
3683d3b0591SJens Wiklander             R = output + ( semiblocks - 2 ) * KW_SEMIBLOCK_LENGTH;
3693d3b0591SJens Wiklander         else
3703d3b0591SJens Wiklander             R -= KW_SEMIBLOCK_LENGTH;
3713d3b0591SJens Wiklander     }
3723d3b0591SJens Wiklander 
3733d3b0591SJens Wiklander     *out_len = ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH;
3743d3b0591SJens Wiklander 
3753d3b0591SJens Wiklander cleanup:
3763d3b0591SJens Wiklander     if( ret != 0)
3773d3b0591SJens Wiklander         memset( output, 0, ( semiblocks - 1 ) * KW_SEMIBLOCK_LENGTH );
3783d3b0591SJens Wiklander     mbedtls_platform_zeroize( inbuff, sizeof( inbuff )  );
3793d3b0591SJens Wiklander     mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
3803d3b0591SJens Wiklander 
3813d3b0591SJens Wiklander     return( ret );
3823d3b0591SJens Wiklander }
3833d3b0591SJens Wiklander 
3843d3b0591SJens Wiklander /*
3853d3b0591SJens Wiklander  * KW-AD as defined in SP 800-38F section 6.2
3863d3b0591SJens Wiklander  * KWP-AD as defined in SP 800-38F section 6.3
3873d3b0591SJens Wiklander  */
3883d3b0591SJens Wiklander int mbedtls_nist_kw_unwrap( mbedtls_nist_kw_context *ctx,
3893d3b0591SJens Wiklander                             mbedtls_nist_kw_mode_t mode,
3903d3b0591SJens Wiklander                             const unsigned char *input, size_t in_len,
3913d3b0591SJens Wiklander                             unsigned char *output, size_t *out_len, size_t out_size )
3923d3b0591SJens Wiklander {
3933d3b0591SJens Wiklander     int ret = 0;
3943d3b0591SJens Wiklander     size_t i, olen;
3953d3b0591SJens Wiklander     unsigned char A[KW_SEMIBLOCK_LENGTH];
3963d3b0591SJens Wiklander     unsigned char diff, bad_padding = 0;
3973d3b0591SJens Wiklander 
3983d3b0591SJens Wiklander     *out_len = 0;
3993d3b0591SJens Wiklander     if( out_size < in_len - KW_SEMIBLOCK_LENGTH )
4003d3b0591SJens Wiklander     {
4013d3b0591SJens Wiklander         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
4023d3b0591SJens Wiklander     }
4033d3b0591SJens Wiklander 
4043d3b0591SJens Wiklander     if( mode == MBEDTLS_KW_MODE_KW )
4053d3b0591SJens Wiklander     {
4063d3b0591SJens Wiklander         /*
4073d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the ciphertext length for KW
4083d3b0591SJens Wiklander          * must be between 3 to 2^54 semiblocks inclusive.
4093d3b0591SJens Wiklander          */
4103d3b0591SJens Wiklander         if( in_len < 24 ||
4113d3b0591SJens Wiklander #if SIZE_MAX > 0x200000000000000
4123d3b0591SJens Wiklander             in_len > 0x200000000000000 ||
4133d3b0591SJens Wiklander #endif
4143d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
4153d3b0591SJens Wiklander         {
4163d3b0591SJens Wiklander             return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
4173d3b0591SJens Wiklander         }
4183d3b0591SJens Wiklander 
4193d3b0591SJens Wiklander         ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
4203d3b0591SJens Wiklander                       A, output, out_len );
4213d3b0591SJens Wiklander         if( ret != 0 )
4223d3b0591SJens Wiklander             goto cleanup;
4233d3b0591SJens Wiklander 
4243d3b0591SJens Wiklander         /* Check ICV in "constant-time" */
4253d3b0591SJens Wiklander         diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV1, A, KW_SEMIBLOCK_LENGTH );
4263d3b0591SJens Wiklander 
4273d3b0591SJens Wiklander         if( diff != 0 )
4283d3b0591SJens Wiklander         {
4293d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
4303d3b0591SJens Wiklander             goto cleanup;
4313d3b0591SJens Wiklander         }
4323d3b0591SJens Wiklander 
4333d3b0591SJens Wiklander     }
4343d3b0591SJens Wiklander     else if( mode == MBEDTLS_KW_MODE_KWP )
4353d3b0591SJens Wiklander     {
4363d3b0591SJens Wiklander         size_t padlen = 0;
4373d3b0591SJens Wiklander         uint32_t Plen;
4383d3b0591SJens Wiklander         /*
4393d3b0591SJens Wiklander          * According to SP 800-38F Table 1, the ciphertext length for KWP
4403d3b0591SJens Wiklander          * must be between 2 to 2^29 semiblocks inclusive.
4413d3b0591SJens Wiklander          */
4423d3b0591SJens Wiklander         if( in_len < KW_SEMIBLOCK_LENGTH * 2 ||
4433d3b0591SJens Wiklander #if SIZE_MAX > 0x100000000
4443d3b0591SJens Wiklander             in_len > 0x100000000 ||
4453d3b0591SJens Wiklander #endif
4463d3b0591SJens Wiklander             in_len % KW_SEMIBLOCK_LENGTH != 0 )
4473d3b0591SJens Wiklander         {
4483d3b0591SJens Wiklander             return(  MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
4493d3b0591SJens Wiklander         }
4503d3b0591SJens Wiklander 
4513d3b0591SJens Wiklander         if( in_len == KW_SEMIBLOCK_LENGTH * 2 )
4523d3b0591SJens Wiklander         {
4533d3b0591SJens Wiklander             unsigned char outbuff[KW_SEMIBLOCK_LENGTH * 2];
4543d3b0591SJens Wiklander             ret = mbedtls_cipher_update( &ctx->cipher_ctx,
4553d3b0591SJens Wiklander                                          input, 16, outbuff, &olen );
4563d3b0591SJens Wiklander             if( ret != 0 )
4573d3b0591SJens Wiklander                 goto cleanup;
4583d3b0591SJens Wiklander 
4593d3b0591SJens Wiklander             memcpy( A, outbuff, KW_SEMIBLOCK_LENGTH );
4603d3b0591SJens Wiklander             memcpy( output, outbuff + KW_SEMIBLOCK_LENGTH, KW_SEMIBLOCK_LENGTH );
4613d3b0591SJens Wiklander             mbedtls_platform_zeroize( outbuff, sizeof( outbuff ) );
4623d3b0591SJens Wiklander             *out_len = KW_SEMIBLOCK_LENGTH;
4633d3b0591SJens Wiklander         }
4643d3b0591SJens Wiklander         else
4653d3b0591SJens Wiklander         {
4663d3b0591SJens Wiklander             /* in_len >=  KW_SEMIBLOCK_LENGTH * 3 */
4673d3b0591SJens Wiklander             ret = unwrap( ctx, input, in_len / KW_SEMIBLOCK_LENGTH,
4683d3b0591SJens Wiklander                           A, output, out_len );
4693d3b0591SJens Wiklander             if( ret != 0 )
4703d3b0591SJens Wiklander                 goto cleanup;
4713d3b0591SJens Wiklander         }
4723d3b0591SJens Wiklander 
4733d3b0591SJens Wiklander         /* Check ICV in "constant-time" */
4743d3b0591SJens Wiklander         diff = mbedtls_nist_kw_safer_memcmp( NIST_KW_ICV2, A, KW_SEMIBLOCK_LENGTH / 2 );
4753d3b0591SJens Wiklander 
4763d3b0591SJens Wiklander         if( diff != 0 )
4773d3b0591SJens Wiklander         {
4783d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
4793d3b0591SJens Wiklander         }
4803d3b0591SJens Wiklander 
4813d3b0591SJens Wiklander         GET_UINT32_BE( Plen, A, KW_SEMIBLOCK_LENGTH / 2 );
4823d3b0591SJens Wiklander 
4833d3b0591SJens Wiklander         /*
4843d3b0591SJens Wiklander          * Plen is the length of the plaintext, when the input is valid.
4853d3b0591SJens Wiklander          * If Plen is larger than the plaintext and padding, padlen will be
4863d3b0591SJens Wiklander          * larger than 8, because of the type wrap around.
4873d3b0591SJens Wiklander          */
4883d3b0591SJens Wiklander         padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
4893d3b0591SJens Wiklander         if ( padlen > 7 )
4903d3b0591SJens Wiklander         {
4913d3b0591SJens Wiklander             padlen &= 7;
4923d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
4933d3b0591SJens Wiklander         }
4943d3b0591SJens Wiklander 
4953d3b0591SJens Wiklander         /* Check padding in "constant-time" */
4963d3b0591SJens Wiklander         for( diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++ )
4973d3b0591SJens Wiklander         {
4983d3b0591SJens Wiklander              if( i >= KW_SEMIBLOCK_LENGTH - padlen )
4993d3b0591SJens Wiklander                  diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
5003d3b0591SJens Wiklander              else
5013d3b0591SJens Wiklander                  bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
5023d3b0591SJens Wiklander         }
5033d3b0591SJens Wiklander 
5043d3b0591SJens Wiklander         if( diff != 0 )
5053d3b0591SJens Wiklander         {
5063d3b0591SJens Wiklander             ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
5073d3b0591SJens Wiklander         }
5083d3b0591SJens Wiklander 
5093d3b0591SJens Wiklander         if( ret != 0 )
5103d3b0591SJens Wiklander         {
5113d3b0591SJens Wiklander             goto cleanup;
5123d3b0591SJens Wiklander         }
5133d3b0591SJens Wiklander         memset( output + Plen, 0, padlen );
5143d3b0591SJens Wiklander         *out_len = Plen;
5153d3b0591SJens Wiklander     }
5163d3b0591SJens Wiklander     else
5173d3b0591SJens Wiklander     {
5183d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE;
5193d3b0591SJens Wiklander         goto cleanup;
5203d3b0591SJens Wiklander     }
5213d3b0591SJens Wiklander 
5223d3b0591SJens Wiklander cleanup:
5233d3b0591SJens Wiklander     if( ret != 0 )
5243d3b0591SJens Wiklander     {
5253d3b0591SJens Wiklander         memset( output, 0, *out_len );
5263d3b0591SJens Wiklander         *out_len = 0;
5273d3b0591SJens Wiklander     }
5283d3b0591SJens Wiklander 
5293d3b0591SJens Wiklander     mbedtls_platform_zeroize( &bad_padding, sizeof( bad_padding) );
5303d3b0591SJens Wiklander     mbedtls_platform_zeroize( &diff, sizeof( diff ) );
5313d3b0591SJens Wiklander     mbedtls_platform_zeroize( A, sizeof( A ) );
5323d3b0591SJens Wiklander 
5333d3b0591SJens Wiklander     return( ret );
5343d3b0591SJens Wiklander }
5353d3b0591SJens Wiklander 
5363d3b0591SJens Wiklander #endif /* !MBEDTLS_NIST_KW_ALT */
5373d3b0591SJens Wiklander 
5383d3b0591SJens Wiklander #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
5393d3b0591SJens Wiklander 
5403d3b0591SJens Wiklander #define KW_TESTS 3
5413d3b0591SJens Wiklander 
5423d3b0591SJens Wiklander /*
5433d3b0591SJens Wiklander  * Test vectors taken from NIST
5443d3b0591SJens Wiklander  * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/CAVP-TESTING-BLOCK-CIPHER-MODES#KW
5453d3b0591SJens Wiklander  */
5463d3b0591SJens Wiklander static const unsigned int key_len[KW_TESTS] = { 16, 24, 32 };
5473d3b0591SJens Wiklander 
5483d3b0591SJens Wiklander static const unsigned char kw_key[KW_TESTS][32] = {
5493d3b0591SJens Wiklander     { 0x75, 0x75, 0xda, 0x3a, 0x93, 0x60, 0x7c, 0xc2,
5503d3b0591SJens Wiklander       0xbf, 0xd8, 0xce, 0xc7, 0xaa, 0xdf, 0xd9, 0xa6 },
5513d3b0591SJens Wiklander     { 0x2d, 0x85, 0x26, 0x08, 0x1d, 0x02, 0xfb, 0x5b,
5523d3b0591SJens Wiklander       0x85, 0xf6, 0x9a, 0xc2, 0x86, 0xec, 0xd5, 0x7d,
5533d3b0591SJens Wiklander       0x40, 0xdf, 0x5d, 0xf3, 0x49, 0x47, 0x44, 0xd3 },
5543d3b0591SJens Wiklander     { 0x11, 0x2a, 0xd4, 0x1b, 0x48, 0x56, 0xc7, 0x25,
5553d3b0591SJens Wiklander       0x4a, 0x98, 0x48, 0xd3, 0x0f, 0xdd, 0x78, 0x33,
5563d3b0591SJens Wiklander       0x5b, 0x03, 0x9a, 0x48, 0xa8, 0x96, 0x2c, 0x4d,
5573d3b0591SJens Wiklander       0x1c, 0xb7, 0x8e, 0xab, 0xd5, 0xda, 0xd7, 0x88 }
5583d3b0591SJens Wiklander };
5593d3b0591SJens Wiklander 
5603d3b0591SJens Wiklander static const unsigned char kw_msg[KW_TESTS][40] = {
5613d3b0591SJens Wiklander     { 0x42, 0x13, 0x6d, 0x3c, 0x38, 0x4a, 0x3e, 0xea,
5623d3b0591SJens Wiklander       0xc9, 0x5a, 0x06, 0x6f, 0xd2, 0x8f, 0xed, 0x3f },
5633d3b0591SJens Wiklander     { 0x95, 0xc1, 0x1b, 0xf5, 0x35, 0x3a, 0xfe, 0xdb,
5643d3b0591SJens Wiklander       0x98, 0xfd, 0xd6, 0xc8, 0xca, 0x6f, 0xdb, 0x6d,
5653d3b0591SJens Wiklander       0xa5, 0x4b, 0x74, 0xb4, 0x99, 0x0f, 0xdc, 0x45,
5663d3b0591SJens Wiklander       0xc0, 0x9d, 0x15, 0x8f, 0x51, 0xce, 0x62, 0x9d,
5673d3b0591SJens Wiklander       0xe2, 0xaf, 0x26, 0xe3, 0x25, 0x0e, 0x6b, 0x4c },
5683d3b0591SJens Wiklander     { 0x1b, 0x20, 0xbf, 0x19, 0x90, 0xb0, 0x65, 0xd7,
5693d3b0591SJens Wiklander       0x98, 0xe1, 0xb3, 0x22, 0x64, 0xad, 0x50, 0xa8,
5703d3b0591SJens Wiklander       0x74, 0x74, 0x92, 0xba, 0x09, 0xa0, 0x4d, 0xd1 }
5713d3b0591SJens Wiklander };
5723d3b0591SJens Wiklander 
5733d3b0591SJens Wiklander static const size_t kw_msg_len[KW_TESTS] = { 16, 40, 24 };
5743d3b0591SJens Wiklander static const size_t kw_out_len[KW_TESTS] = { 24, 48, 32 };
5753d3b0591SJens Wiklander static const unsigned char kw_res[KW_TESTS][48] = {
5763d3b0591SJens Wiklander     { 0x03, 0x1f, 0x6b, 0xd7, 0xe6, 0x1e, 0x64, 0x3d,
5773d3b0591SJens Wiklander       0xf6, 0x85, 0x94, 0x81, 0x6f, 0x64, 0xca, 0xa3,
5783d3b0591SJens Wiklander       0xf5, 0x6f, 0xab, 0xea, 0x25, 0x48, 0xf5, 0xfb },
5793d3b0591SJens Wiklander     { 0x44, 0x3c, 0x6f, 0x15, 0x09, 0x83, 0x71, 0x91,
5803d3b0591SJens Wiklander       0x3e, 0x5c, 0x81, 0x4c, 0xa1, 0xa0, 0x42, 0xec,
5813d3b0591SJens Wiklander       0x68, 0x2f, 0x7b, 0x13, 0x6d, 0x24, 0x3a, 0x4d,
5823d3b0591SJens Wiklander       0x6c, 0x42, 0x6f, 0xc6, 0x97, 0x15, 0x63, 0xe8,
5833d3b0591SJens Wiklander       0xa1, 0x4a, 0x55, 0x8e, 0x09, 0x64, 0x16, 0x19,
5843d3b0591SJens Wiklander       0xbf, 0x03, 0xfc, 0xaf, 0x90, 0xb1, 0xfc, 0x2d },
5853d3b0591SJens Wiklander     { 0xba, 0x8a, 0x25, 0x9a, 0x47, 0x1b, 0x78, 0x7d,
5863d3b0591SJens Wiklander       0xd5, 0xd5, 0x40, 0xec, 0x25, 0xd4, 0x3d, 0x87,
5873d3b0591SJens Wiklander       0x20, 0x0f, 0xda, 0xdc, 0x6d, 0x1f, 0x05, 0xd9,
5883d3b0591SJens Wiklander       0x16, 0x58, 0x4f, 0xa9, 0xf6, 0xcb, 0xf5, 0x12 }
5893d3b0591SJens Wiklander };
5903d3b0591SJens Wiklander 
5913d3b0591SJens Wiklander static const unsigned char kwp_key[KW_TESTS][32] = {
5923d3b0591SJens Wiklander     { 0x78, 0x65, 0xe2, 0x0f, 0x3c, 0x21, 0x65, 0x9a,
5933d3b0591SJens Wiklander       0xb4, 0x69, 0x0b, 0x62, 0x9c, 0xdf, 0x3c, 0xc4 },
5943d3b0591SJens Wiklander     { 0xf5, 0xf8, 0x96, 0xa3, 0xbd, 0x2f, 0x4a, 0x98,
5953d3b0591SJens Wiklander       0x23, 0xef, 0x16, 0x2b, 0x00, 0xb8, 0x05, 0xd7,
5963d3b0591SJens Wiklander       0xde, 0x1e, 0xa4, 0x66, 0x26, 0x96, 0xa2, 0x58 },
5973d3b0591SJens Wiklander     { 0x95, 0xda, 0x27, 0x00, 0xca, 0x6f, 0xd9, 0xa5,
5983d3b0591SJens Wiklander       0x25, 0x54, 0xee, 0x2a, 0x8d, 0xf1, 0x38, 0x6f,
5993d3b0591SJens Wiklander       0x5b, 0x94, 0xa1, 0xa6, 0x0e, 0xd8, 0xa4, 0xae,
6003d3b0591SJens Wiklander       0xf6, 0x0a, 0x8d, 0x61, 0xab, 0x5f, 0x22, 0x5a }
6013d3b0591SJens Wiklander };
6023d3b0591SJens Wiklander 
6033d3b0591SJens Wiklander static const unsigned char kwp_msg[KW_TESTS][31] = {
6043d3b0591SJens Wiklander     { 0xbd, 0x68, 0x43, 0xd4, 0x20, 0x37, 0x8d, 0xc8,
6053d3b0591SJens Wiklander       0x96 },
6063d3b0591SJens Wiklander     { 0x6c, 0xcd, 0xd5, 0x85, 0x18, 0x40, 0x97, 0xeb,
6073d3b0591SJens Wiklander       0xd5, 0xc3, 0xaf, 0x3e, 0x47, 0xd0, 0x2c, 0x19,
6083d3b0591SJens Wiklander       0x14, 0x7b, 0x4d, 0x99, 0x5f, 0x96, 0x43, 0x66,
6093d3b0591SJens Wiklander       0x91, 0x56, 0x75, 0x8c, 0x13, 0x16, 0x8f },
6103d3b0591SJens Wiklander     { 0xd1 }
6113d3b0591SJens Wiklander };
6123d3b0591SJens Wiklander static const size_t kwp_msg_len[KW_TESTS] = { 9, 31, 1 };
6133d3b0591SJens Wiklander 
6143d3b0591SJens Wiklander static const unsigned char kwp_res[KW_TESTS][48] = {
6153d3b0591SJens Wiklander     { 0x41, 0xec, 0xa9, 0x56, 0xd4, 0xaa, 0x04, 0x7e,
6163d3b0591SJens Wiklander       0xb5, 0xcf, 0x4e, 0xfe, 0x65, 0x96, 0x61, 0xe7,
6173d3b0591SJens Wiklander       0x4d, 0xb6, 0xf8, 0xc5, 0x64, 0xe2, 0x35, 0x00 },
6183d3b0591SJens Wiklander     { 0x4e, 0x9b, 0xc2, 0xbc, 0xbc, 0x6c, 0x1e, 0x13,
6193d3b0591SJens Wiklander       0xd3, 0x35, 0xbc, 0xc0, 0xf7, 0x73, 0x6a, 0x88,
6203d3b0591SJens Wiklander       0xfa, 0x87, 0x53, 0x66, 0x15, 0xbb, 0x8e, 0x63,
6213d3b0591SJens Wiklander       0x8b, 0xcc, 0x81, 0x66, 0x84, 0x68, 0x17, 0x90,
6223d3b0591SJens Wiklander       0x67, 0xcf, 0xa9, 0x8a, 0x9d, 0x0e, 0x33, 0x26 },
6233d3b0591SJens Wiklander     { 0x06, 0xba, 0x7a, 0xe6, 0xf3, 0x24, 0x8c, 0xfd,
6243d3b0591SJens Wiklander       0xcf, 0x26, 0x75, 0x07, 0xfa, 0x00, 0x1b, 0xc4  }
6253d3b0591SJens Wiklander };
6263d3b0591SJens Wiklander static const size_t kwp_out_len[KW_TESTS] = { 24, 40, 16 };
6273d3b0591SJens Wiklander 
6283d3b0591SJens Wiklander int mbedtls_nist_kw_self_test( int verbose )
6293d3b0591SJens Wiklander {
6303d3b0591SJens Wiklander     mbedtls_nist_kw_context ctx;
6313d3b0591SJens Wiklander     unsigned char out[48];
6323d3b0591SJens Wiklander     size_t olen;
6333d3b0591SJens Wiklander     int i;
6343d3b0591SJens Wiklander     int ret = 0;
6353d3b0591SJens Wiklander     mbedtls_nist_kw_init( &ctx );
6363d3b0591SJens Wiklander 
6373d3b0591SJens Wiklander     for( i = 0; i < KW_TESTS; i++ )
6383d3b0591SJens Wiklander     {
6393d3b0591SJens Wiklander         if( verbose != 0 )
6403d3b0591SJens Wiklander             mbedtls_printf( "  KW-AES-%u ", (unsigned int) key_len[i] * 8 );
6413d3b0591SJens Wiklander 
6423d3b0591SJens Wiklander         ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
6433d3b0591SJens Wiklander                                       kw_key[i], key_len[i] * 8, 1 );
6443d3b0591SJens Wiklander         if( ret != 0 )
6453d3b0591SJens Wiklander         {
6463d3b0591SJens Wiklander             if( verbose != 0 )
6473d3b0591SJens Wiklander                 mbedtls_printf( "  KW: setup failed " );
6483d3b0591SJens Wiklander 
6493d3b0591SJens Wiklander             goto end;
6503d3b0591SJens Wiklander         }
6513d3b0591SJens Wiklander 
6523d3b0591SJens Wiklander         ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KW, kw_msg[i],
6533d3b0591SJens Wiklander                                     kw_msg_len[i], out, &olen, sizeof( out ) );
6543d3b0591SJens Wiklander         if( ret != 0 || kw_out_len[i] != olen ||
6553d3b0591SJens Wiklander             memcmp( out, kw_res[i], kw_out_len[i] ) != 0 )
6563d3b0591SJens Wiklander         {
6573d3b0591SJens Wiklander             if( verbose != 0 )
6583d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
6593d3b0591SJens Wiklander 
6603d3b0591SJens Wiklander             ret = 1;
6613d3b0591SJens Wiklander             goto end;
6623d3b0591SJens Wiklander         }
6633d3b0591SJens Wiklander 
6643d3b0591SJens Wiklander         if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
6653d3b0591SJens Wiklander                                             kw_key[i], key_len[i] * 8, 0 ) )
6663d3b0591SJens Wiklander               != 0 )
6673d3b0591SJens Wiklander         {
6683d3b0591SJens Wiklander             if( verbose != 0 )
6693d3b0591SJens Wiklander                 mbedtls_printf( "  KW: setup failed ");
6703d3b0591SJens Wiklander 
6713d3b0591SJens Wiklander             goto end;
6723d3b0591SJens Wiklander         }
6733d3b0591SJens Wiklander 
6743d3b0591SJens Wiklander         ret = mbedtls_nist_kw_unwrap( &ctx, MBEDTLS_KW_MODE_KW,
6753d3b0591SJens Wiklander                                       out, olen, out, &olen, sizeof( out ) );
6763d3b0591SJens Wiklander 
6773d3b0591SJens Wiklander         if( ret != 0 || olen != kw_msg_len[i] ||
6783d3b0591SJens Wiklander             memcmp( out, kw_msg[i], kw_msg_len[i] ) != 0 )
6793d3b0591SJens Wiklander         {
6803d3b0591SJens Wiklander             if( verbose != 0 )
6813d3b0591SJens Wiklander                 mbedtls_printf( "failed\n" );
6823d3b0591SJens Wiklander 
6833d3b0591SJens Wiklander             ret = 1;
6843d3b0591SJens Wiklander             goto end;
6853d3b0591SJens Wiklander         }
6863d3b0591SJens Wiklander 
6873d3b0591SJens Wiklander         if( verbose != 0 )
6883d3b0591SJens Wiklander             mbedtls_printf( " passed\n" );
6893d3b0591SJens Wiklander     }
6903d3b0591SJens Wiklander 
6913d3b0591SJens Wiklander     for( i = 0; i < KW_TESTS; i++ )
6923d3b0591SJens Wiklander     {
6933d3b0591SJens Wiklander         olen = sizeof( out );
6943d3b0591SJens Wiklander         if( verbose != 0 )
6953d3b0591SJens Wiklander             mbedtls_printf( "  KWP-AES-%u ", (unsigned int) key_len[i] * 8 );
6963d3b0591SJens Wiklander 
6973d3b0591SJens Wiklander         ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, kwp_key[i],
6983d3b0591SJens Wiklander                                       key_len[i] * 8, 1 );
6993d3b0591SJens Wiklander         if( ret  != 0 )
7003d3b0591SJens Wiklander         {
7013d3b0591SJens Wiklander             if( verbose != 0 )
7023d3b0591SJens Wiklander                 mbedtls_printf( "  KWP: setup failed " );
7033d3b0591SJens Wiklander 
7043d3b0591SJens Wiklander             goto end;
7053d3b0591SJens Wiklander         }
7063d3b0591SJens Wiklander         ret = mbedtls_nist_kw_wrap( &ctx, MBEDTLS_KW_MODE_KWP, kwp_msg[i],
7073d3b0591SJens Wiklander                                     kwp_msg_len[i], out, &olen, sizeof( out ) );
7083d3b0591SJens Wiklander 
7093d3b0591SJens Wiklander         if( ret != 0 || kwp_out_len[i] != olen ||
7103d3b0591SJens Wiklander             memcmp( out, kwp_res[i], kwp_out_len[i] ) != 0 )
7113d3b0591SJens Wiklander         {
7123d3b0591SJens Wiklander             if( verbose != 0 )
7133d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
7143d3b0591SJens Wiklander 
7153d3b0591SJens Wiklander             ret = 1;
7163d3b0591SJens Wiklander             goto end;
7173d3b0591SJens Wiklander         }
7183d3b0591SJens Wiklander 
7193d3b0591SJens Wiklander         if( ( ret = mbedtls_nist_kw_setkey( &ctx, MBEDTLS_CIPHER_ID_AES,
7203d3b0591SJens Wiklander                                             kwp_key[i], key_len[i] * 8, 0 ) )
7213d3b0591SJens Wiklander               != 0 )
7223d3b0591SJens Wiklander         {
7233d3b0591SJens Wiklander             if( verbose != 0 )
7243d3b0591SJens Wiklander                 mbedtls_printf( "  KWP: setup failed ");
7253d3b0591SJens Wiklander 
7263d3b0591SJens Wiklander             goto end;
7273d3b0591SJens Wiklander         }
7283d3b0591SJens Wiklander 
7293d3b0591SJens Wiklander         ret = mbedtls_nist_kw_unwrap(  &ctx, MBEDTLS_KW_MODE_KWP, out,
7303d3b0591SJens Wiklander                                        olen, out, &olen, sizeof( out ) );
7313d3b0591SJens Wiklander 
7323d3b0591SJens Wiklander         if( ret != 0 || olen != kwp_msg_len[i] ||
7333d3b0591SJens Wiklander             memcmp( out, kwp_msg[i], kwp_msg_len[i] ) != 0 )
7343d3b0591SJens Wiklander         {
7353d3b0591SJens Wiklander             if( verbose != 0 )
7363d3b0591SJens Wiklander                 mbedtls_printf( "failed. ");
7373d3b0591SJens Wiklander 
7383d3b0591SJens Wiklander             ret = 1;
7393d3b0591SJens Wiklander             goto end;
7403d3b0591SJens Wiklander         }
7413d3b0591SJens Wiklander 
7423d3b0591SJens Wiklander         if( verbose != 0 )
7433d3b0591SJens Wiklander             mbedtls_printf( " passed\n" );
7443d3b0591SJens Wiklander     }
7453d3b0591SJens Wiklander end:
7463d3b0591SJens Wiklander     mbedtls_nist_kw_free( &ctx );
7473d3b0591SJens Wiklander 
7483d3b0591SJens Wiklander     if( verbose != 0 )
7493d3b0591SJens Wiklander         mbedtls_printf( "\n" );
7503d3b0591SJens Wiklander 
7513d3b0591SJens Wiklander     return( ret );
7523d3b0591SJens Wiklander }
7533d3b0591SJens Wiklander 
7543d3b0591SJens Wiklander #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
7553d3b0591SJens Wiklander 
7563d3b0591SJens Wiklander #endif /* MBEDTLS_NIST_KW_C */
757