xref: /optee_os/lib/libmbedtls/mbedtls/library/hkdf.c (revision 11fa71b9ddb429088f325cfda430183003ccd1db)
13d3b0591SJens Wiklander /*
23d3b0591SJens Wiklander  *  HKDF implementation -- RFC 5869
33d3b0591SJens Wiklander  *
43d3b0591SJens Wiklander  *  Copyright (C) 2016-2018, ARM Limited, All Rights Reserved
53d3b0591SJens Wiklander  *  SPDX-License-Identifier: Apache-2.0
63d3b0591SJens Wiklander  *
73d3b0591SJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
83d3b0591SJens Wiklander  *  not use this file except in compliance with the License.
93d3b0591SJens Wiklander  *  You may obtain a copy of the License at
103d3b0591SJens Wiklander  *
113d3b0591SJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
123d3b0591SJens Wiklander  *
133d3b0591SJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
143d3b0591SJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
153d3b0591SJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
163d3b0591SJens Wiklander  *  See the License for the specific language governing permissions and
173d3b0591SJens Wiklander  *  limitations under the License.
183d3b0591SJens Wiklander  *
193d3b0591SJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
203d3b0591SJens Wiklander  */
213d3b0591SJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
223d3b0591SJens Wiklander #include "mbedtls/config.h"
233d3b0591SJens Wiklander #else
243d3b0591SJens Wiklander #include MBEDTLS_CONFIG_FILE
253d3b0591SJens Wiklander #endif
263d3b0591SJens Wiklander 
273d3b0591SJens Wiklander #if defined(MBEDTLS_HKDF_C)
283d3b0591SJens Wiklander 
293d3b0591SJens Wiklander #include <string.h>
303d3b0591SJens Wiklander #include "mbedtls/hkdf.h"
313d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
32*11fa71b9SJerome Forissier #include "mbedtls/error.h"
333d3b0591SJens Wiklander 
343d3b0591SJens Wiklander int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt,
353d3b0591SJens Wiklander                   size_t salt_len, const unsigned char *ikm, size_t ikm_len,
363d3b0591SJens Wiklander                   const unsigned char *info, size_t info_len,
373d3b0591SJens Wiklander                   unsigned char *okm, size_t okm_len )
383d3b0591SJens Wiklander {
39*11fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
403d3b0591SJens Wiklander     unsigned char prk[MBEDTLS_MD_MAX_SIZE];
413d3b0591SJens Wiklander 
423d3b0591SJens Wiklander     ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk );
433d3b0591SJens Wiklander 
443d3b0591SJens Wiklander     if( ret == 0 )
453d3b0591SJens Wiklander     {
463d3b0591SJens Wiklander         ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ),
473d3b0591SJens Wiklander                                    info, info_len, okm, okm_len );
483d3b0591SJens Wiklander     }
493d3b0591SJens Wiklander 
503d3b0591SJens Wiklander     mbedtls_platform_zeroize( prk, sizeof( prk ) );
513d3b0591SJens Wiklander 
523d3b0591SJens Wiklander     return( ret );
533d3b0591SJens Wiklander }
543d3b0591SJens Wiklander 
553d3b0591SJens Wiklander int mbedtls_hkdf_extract( const mbedtls_md_info_t *md,
563d3b0591SJens Wiklander                           const unsigned char *salt, size_t salt_len,
573d3b0591SJens Wiklander                           const unsigned char *ikm, size_t ikm_len,
583d3b0591SJens Wiklander                           unsigned char *prk )
593d3b0591SJens Wiklander {
603d3b0591SJens Wiklander     unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' };
613d3b0591SJens Wiklander 
623d3b0591SJens Wiklander     if( salt == NULL )
633d3b0591SJens Wiklander     {
643d3b0591SJens Wiklander         size_t hash_len;
653d3b0591SJens Wiklander 
663d3b0591SJens Wiklander         if( salt_len != 0 )
673d3b0591SJens Wiklander         {
683d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
693d3b0591SJens Wiklander         }
703d3b0591SJens Wiklander 
713d3b0591SJens Wiklander         hash_len = mbedtls_md_get_size( md );
723d3b0591SJens Wiklander 
733d3b0591SJens Wiklander         if( hash_len == 0 )
743d3b0591SJens Wiklander         {
753d3b0591SJens Wiklander             return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA;
763d3b0591SJens Wiklander         }
773d3b0591SJens Wiklander 
783d3b0591SJens Wiklander         salt = null_salt;
793d3b0591SJens Wiklander         salt_len = hash_len;
803d3b0591SJens Wiklander     }
813d3b0591SJens Wiklander 
823d3b0591SJens Wiklander     return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) );
833d3b0591SJens Wiklander }
843d3b0591SJens Wiklander 
853d3b0591SJens Wiklander int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk,
863d3b0591SJens Wiklander                          size_t prk_len, const unsigned char *info,
873d3b0591SJens Wiklander                          size_t info_len, unsigned char *okm, size_t okm_len )
883d3b0591SJens Wiklander {
893d3b0591SJens Wiklander     size_t hash_len;
903d3b0591SJens Wiklander     size_t where = 0;
913d3b0591SJens Wiklander     size_t n;
923d3b0591SJens Wiklander     size_t t_len = 0;
933d3b0591SJens Wiklander     size_t i;
943d3b0591SJens Wiklander     int ret = 0;
953d3b0591SJens Wiklander     mbedtls_md_context_t ctx;
963d3b0591SJens Wiklander     unsigned char t[MBEDTLS_MD_MAX_SIZE];
973d3b0591SJens Wiklander 
983d3b0591SJens Wiklander     if( okm == NULL )
993d3b0591SJens Wiklander     {
1003d3b0591SJens Wiklander         return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
1013d3b0591SJens Wiklander     }
1023d3b0591SJens Wiklander 
1033d3b0591SJens Wiklander     hash_len = mbedtls_md_get_size( md );
1043d3b0591SJens Wiklander 
1053d3b0591SJens Wiklander     if( prk_len < hash_len || hash_len == 0 )
1063d3b0591SJens Wiklander     {
1073d3b0591SJens Wiklander         return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
1083d3b0591SJens Wiklander     }
1093d3b0591SJens Wiklander 
1103d3b0591SJens Wiklander     if( info == NULL )
1113d3b0591SJens Wiklander     {
1123d3b0591SJens Wiklander         info = (const unsigned char *) "";
1133d3b0591SJens Wiklander         info_len = 0;
1143d3b0591SJens Wiklander     }
1153d3b0591SJens Wiklander 
1163d3b0591SJens Wiklander     n = okm_len / hash_len;
1173d3b0591SJens Wiklander 
118*11fa71b9SJerome Forissier     if( okm_len % hash_len != 0 )
1193d3b0591SJens Wiklander     {
1203d3b0591SJens Wiklander         n++;
1213d3b0591SJens Wiklander     }
1223d3b0591SJens Wiklander 
1233d3b0591SJens Wiklander     /*
1243d3b0591SJens Wiklander      * Per RFC 5869 Section 2.3, okm_len must not exceed
1253d3b0591SJens Wiklander      * 255 times the hash length
1263d3b0591SJens Wiklander      */
1273d3b0591SJens Wiklander     if( n > 255 )
1283d3b0591SJens Wiklander     {
1293d3b0591SJens Wiklander         return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA );
1303d3b0591SJens Wiklander     }
1313d3b0591SJens Wiklander 
1323d3b0591SJens Wiklander     mbedtls_md_init( &ctx );
1333d3b0591SJens Wiklander 
1343d3b0591SJens Wiklander     if( ( ret = mbedtls_md_setup( &ctx, md, 1 ) ) != 0 )
1353d3b0591SJens Wiklander     {
1363d3b0591SJens Wiklander         goto exit;
1373d3b0591SJens Wiklander     }
1383d3b0591SJens Wiklander 
139*11fa71b9SJerome Forissier     memset( t, 0, hash_len );
140*11fa71b9SJerome Forissier 
1413d3b0591SJens Wiklander     /*
1423d3b0591SJens Wiklander      * Compute T = T(1) | T(2) | T(3) | ... | T(N)
1433d3b0591SJens Wiklander      * Where T(N) is defined in RFC 5869 Section 2.3
1443d3b0591SJens Wiklander      */
1453d3b0591SJens Wiklander     for( i = 1; i <= n; i++ )
1463d3b0591SJens Wiklander     {
1473d3b0591SJens Wiklander         size_t num_to_copy;
1483d3b0591SJens Wiklander         unsigned char c = i & 0xff;
1493d3b0591SJens Wiklander 
1503d3b0591SJens Wiklander         ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len );
1513d3b0591SJens Wiklander         if( ret != 0 )
1523d3b0591SJens Wiklander         {
1533d3b0591SJens Wiklander             goto exit;
1543d3b0591SJens Wiklander         }
1553d3b0591SJens Wiklander 
1563d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update( &ctx, t, t_len );
1573d3b0591SJens Wiklander         if( ret != 0 )
1583d3b0591SJens Wiklander         {
1593d3b0591SJens Wiklander             goto exit;
1603d3b0591SJens Wiklander         }
1613d3b0591SJens Wiklander 
1623d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update( &ctx, info, info_len );
1633d3b0591SJens Wiklander         if( ret != 0 )
1643d3b0591SJens Wiklander         {
1653d3b0591SJens Wiklander             goto exit;
1663d3b0591SJens Wiklander         }
1673d3b0591SJens Wiklander 
1683d3b0591SJens Wiklander         /* The constant concatenated to the end of each T(n) is a single octet.
1693d3b0591SJens Wiklander          * */
1703d3b0591SJens Wiklander         ret = mbedtls_md_hmac_update( &ctx, &c, 1 );
1713d3b0591SJens Wiklander         if( ret != 0 )
1723d3b0591SJens Wiklander         {
1733d3b0591SJens Wiklander             goto exit;
1743d3b0591SJens Wiklander         }
1753d3b0591SJens Wiklander 
1763d3b0591SJens Wiklander         ret = mbedtls_md_hmac_finish( &ctx, t );
1773d3b0591SJens Wiklander         if( ret != 0 )
1783d3b0591SJens Wiklander         {
1793d3b0591SJens Wiklander             goto exit;
1803d3b0591SJens Wiklander         }
1813d3b0591SJens Wiklander 
1823d3b0591SJens Wiklander         num_to_copy = i != n ? hash_len : okm_len - where;
1833d3b0591SJens Wiklander         memcpy( okm + where, t, num_to_copy );
1843d3b0591SJens Wiklander         where += hash_len;
1853d3b0591SJens Wiklander         t_len = hash_len;
1863d3b0591SJens Wiklander     }
1873d3b0591SJens Wiklander 
1883d3b0591SJens Wiklander exit:
1893d3b0591SJens Wiklander     mbedtls_md_free( &ctx );
1903d3b0591SJens Wiklander     mbedtls_platform_zeroize( t, sizeof( t ) );
1913d3b0591SJens Wiklander 
1923d3b0591SJens Wiklander     return( ret );
1933d3b0591SJens Wiklander }
1943d3b0591SJens Wiklander 
1953d3b0591SJens Wiklander #endif /* MBEDTLS_HKDF_C */
196