1 /* 2 * HKDF implementation -- RFC 5869 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); you may 8 * not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 #include "common.h" 20 21 #if defined(MBEDTLS_HKDF_C) 22 23 #include <string.h> 24 #include "mbedtls/hkdf.h" 25 #include "mbedtls/platform_util.h" 26 #include "mbedtls/error.h" 27 28 int mbedtls_hkdf( const mbedtls_md_info_t *md, const unsigned char *salt, 29 size_t salt_len, const unsigned char *ikm, size_t ikm_len, 30 const unsigned char *info, size_t info_len, 31 unsigned char *okm, size_t okm_len ) 32 { 33 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 34 unsigned char prk[MBEDTLS_MD_MAX_SIZE]; 35 36 ret = mbedtls_hkdf_extract( md, salt, salt_len, ikm, ikm_len, prk ); 37 38 if( ret == 0 ) 39 { 40 ret = mbedtls_hkdf_expand( md, prk, mbedtls_md_get_size( md ), 41 info, info_len, okm, okm_len ); 42 } 43 44 mbedtls_platform_zeroize( prk, sizeof( prk ) ); 45 46 return( ret ); 47 } 48 49 int mbedtls_hkdf_extract( const mbedtls_md_info_t *md, 50 const unsigned char *salt, size_t salt_len, 51 const unsigned char *ikm, size_t ikm_len, 52 unsigned char *prk ) 53 { 54 unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; 55 56 if( salt == NULL ) 57 { 58 size_t hash_len; 59 60 if( salt_len != 0 ) 61 { 62 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 63 } 64 65 hash_len = mbedtls_md_get_size( md ); 66 67 if( hash_len == 0 ) 68 { 69 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 70 } 71 72 salt = null_salt; 73 salt_len = hash_len; 74 } 75 76 return( mbedtls_md_hmac( md, salt, salt_len, ikm, ikm_len, prk ) ); 77 } 78 79 int mbedtls_hkdf_expand( const mbedtls_md_info_t *md, const unsigned char *prk, 80 size_t prk_len, const unsigned char *info, 81 size_t info_len, unsigned char *okm, size_t okm_len ) 82 { 83 size_t hash_len; 84 size_t where = 0; 85 size_t n; 86 size_t t_len = 0; 87 size_t i; 88 int ret = 0; 89 mbedtls_md_context_t ctx; 90 unsigned char t[MBEDTLS_MD_MAX_SIZE]; 91 92 if( okm == NULL ) 93 { 94 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); 95 } 96 97 hash_len = mbedtls_md_get_size( md ); 98 99 if( prk_len < hash_len || hash_len == 0 ) 100 { 101 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); 102 } 103 104 if( info == NULL ) 105 { 106 info = (const unsigned char *) ""; 107 info_len = 0; 108 } 109 110 n = okm_len / hash_len; 111 112 if( okm_len % hash_len != 0 ) 113 { 114 n++; 115 } 116 117 /* 118 * Per RFC 5869 Section 2.3, okm_len must not exceed 119 * 255 times the hash length 120 */ 121 if( n > 255 ) 122 { 123 return( MBEDTLS_ERR_HKDF_BAD_INPUT_DATA ); 124 } 125 126 mbedtls_md_init( &ctx ); 127 128 if( ( ret = mbedtls_md_setup( &ctx, md, 1 ) ) != 0 ) 129 { 130 goto exit; 131 } 132 133 memset( t, 0, hash_len ); 134 135 /* 136 * Compute T = T(1) | T(2) | T(3) | ... | T(N) 137 * Where T(N) is defined in RFC 5869 Section 2.3 138 */ 139 for( i = 1; i <= n; i++ ) 140 { 141 size_t num_to_copy; 142 unsigned char c = i & 0xff; 143 144 ret = mbedtls_md_hmac_starts( &ctx, prk, prk_len ); 145 if( ret != 0 ) 146 { 147 goto exit; 148 } 149 150 ret = mbedtls_md_hmac_update( &ctx, t, t_len ); 151 if( ret != 0 ) 152 { 153 goto exit; 154 } 155 156 ret = mbedtls_md_hmac_update( &ctx, info, info_len ); 157 if( ret != 0 ) 158 { 159 goto exit; 160 } 161 162 /* The constant concatenated to the end of each T(n) is a single octet. 163 * */ 164 ret = mbedtls_md_hmac_update( &ctx, &c, 1 ); 165 if( ret != 0 ) 166 { 167 goto exit; 168 } 169 170 ret = mbedtls_md_hmac_finish( &ctx, t ); 171 if( ret != 0 ) 172 { 173 goto exit; 174 } 175 176 num_to_copy = i != n ? hash_len : okm_len - where; 177 memcpy( okm + where, t, num_to_copy ); 178 where += hash_len; 179 t_len = hash_len; 180 } 181 182 exit: 183 mbedtls_md_free( &ctx ); 184 mbedtls_platform_zeroize( t, sizeof( t ) ); 185 186 return( ret ); 187 } 188 189 #endif /* MBEDTLS_HKDF_C */ 190