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