1 /* 2 * HKDF implementation -- RFC 5869 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6 */ 7 #include "common.h" 8 9 #if defined(MBEDTLS_HKDF_C) 10 11 #include <string.h> 12 #include "mbedtls/hkdf.h" 13 #include "mbedtls/platform_util.h" 14 #include "mbedtls/error.h" 15 16 int mbedtls_hkdf(const mbedtls_md_info_t *md, const unsigned char *salt, 17 size_t salt_len, const unsigned char *ikm, size_t ikm_len, 18 const unsigned char *info, size_t info_len, 19 unsigned char *okm, size_t okm_len) 20 { 21 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 22 unsigned char prk[MBEDTLS_MD_MAX_SIZE]; 23 24 ret = mbedtls_hkdf_extract(md, salt, salt_len, ikm, ikm_len, prk); 25 26 if (ret == 0) { 27 ret = mbedtls_hkdf_expand(md, prk, mbedtls_md_get_size(md), 28 info, info_len, okm, okm_len); 29 } 30 31 mbedtls_platform_zeroize(prk, sizeof(prk)); 32 33 return ret; 34 } 35 36 int mbedtls_hkdf_extract(const mbedtls_md_info_t *md, 37 const unsigned char *salt, size_t salt_len, 38 const unsigned char *ikm, size_t ikm_len, 39 unsigned char *prk) 40 { 41 unsigned char null_salt[MBEDTLS_MD_MAX_SIZE] = { '\0' }; 42 43 if (salt == NULL) { 44 size_t hash_len; 45 46 if (salt_len != 0) { 47 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 48 } 49 50 hash_len = mbedtls_md_get_size(md); 51 52 if (hash_len == 0) { 53 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 54 } 55 56 salt = null_salt; 57 salt_len = hash_len; 58 } 59 60 return mbedtls_md_hmac(md, salt, salt_len, ikm, ikm_len, prk); 61 } 62 63 int mbedtls_hkdf_expand(const mbedtls_md_info_t *md, const unsigned char *prk, 64 size_t prk_len, const unsigned char *info, 65 size_t info_len, unsigned char *okm, size_t okm_len) 66 { 67 size_t hash_len; 68 size_t where = 0; 69 size_t n; 70 size_t t_len = 0; 71 size_t i; 72 int ret = 0; 73 mbedtls_md_context_t ctx; 74 unsigned char t[MBEDTLS_MD_MAX_SIZE]; 75 76 if (okm == NULL) { 77 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 78 } 79 80 hash_len = mbedtls_md_get_size(md); 81 82 if (prk_len < hash_len || hash_len == 0) { 83 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 84 } 85 86 if (info == NULL) { 87 info = (const unsigned char *) ""; 88 info_len = 0; 89 } 90 91 n = okm_len / hash_len; 92 93 if (okm_len % hash_len != 0) { 94 n++; 95 } 96 97 /* 98 * Per RFC 5869 Section 2.3, okm_len must not exceed 99 * 255 times the hash length 100 */ 101 if (n > 255) { 102 return MBEDTLS_ERR_HKDF_BAD_INPUT_DATA; 103 } 104 105 mbedtls_md_init(&ctx); 106 107 if ((ret = mbedtls_md_setup(&ctx, md, 1)) != 0) { 108 goto exit; 109 } 110 111 memset(t, 0, hash_len); 112 113 /* 114 * Compute T = T(1) | T(2) | T(3) | ... | T(N) 115 * Where T(N) is defined in RFC 5869 Section 2.3 116 */ 117 for (i = 1; i <= n; i++) { 118 size_t num_to_copy; 119 unsigned char c = i & 0xff; 120 121 ret = mbedtls_md_hmac_starts(&ctx, prk, prk_len); 122 if (ret != 0) { 123 goto exit; 124 } 125 126 ret = mbedtls_md_hmac_update(&ctx, t, t_len); 127 if (ret != 0) { 128 goto exit; 129 } 130 131 ret = mbedtls_md_hmac_update(&ctx, info, info_len); 132 if (ret != 0) { 133 goto exit; 134 } 135 136 /* The constant concatenated to the end of each T(n) is a single octet. 137 * */ 138 ret = mbedtls_md_hmac_update(&ctx, &c, 1); 139 if (ret != 0) { 140 goto exit; 141 } 142 143 ret = mbedtls_md_hmac_finish(&ctx, t); 144 if (ret != 0) { 145 goto exit; 146 } 147 148 num_to_copy = i != n ? hash_len : okm_len - where; 149 memcpy(okm + where, t, num_to_copy); 150 where += hash_len; 151 t_len = hash_len; 152 } 153 154 exit: 155 mbedtls_md_free(&ctx); 156 mbedtls_platform_zeroize(t, sizeof(t)); 157 158 return ret; 159 } 160 161 #endif /* MBEDTLS_HKDF_C */ 162