crypto_hkdf.c (6877B)
1 /* Copyright (c) 2001, Matej Pfajfar. 2 * Copyright (c) 2001-2004, Roger Dingledine. 3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. 4 * Copyright (c) 2007-2021, The Tor Project, Inc. */ 5 /* See LICENSE for licensing information */ 6 7 /** 8 * \file crypto_hkdf.c 9 * \brief Block of functions related with HKDF utilities and operations. 10 **/ 11 12 #include "lib/crypt_ops/crypto_hkdf.h" 13 #include "lib/crypt_ops/crypto_util.h" 14 #include "lib/crypt_ops/crypto_digest.h" 15 16 #include "lib/crypt_ops/crypto_openssl_mgt.h" 17 #include "lib/intmath/cmp.h" 18 #include "lib/log/util_bug.h" 19 20 #ifdef ENABLE_OPENSSL 21 #include <openssl/evp.h> 22 #include <openssl/opensslv.h> 23 #include <openssl/kdf.h> 24 #define HAVE_OPENSSL_HKDF 25 #endif /* defined(ENABLE_OPENSSL) */ 26 27 #include <string.h> 28 29 /** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> 30 * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in 31 * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of 32 * H(K | [00]) | H(K | [01]) | .... 33 * 34 * This is the key expansion algorithm used in the "TAP" circuit extension 35 * mechanism; it shouldn't be used for new protocols. 36 * 37 * Return 0 on success, -1 on failure. 38 */ 39 int 40 crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, 41 uint8_t *key_out, size_t key_out_len) 42 { 43 int i, r = -1; 44 uint8_t *cp, *tmp = tor_malloc(key_in_len+1); 45 uint8_t digest[DIGEST_LEN]; 46 47 /* If we try to get more than this amount of key data, we'll repeat blocks.*/ 48 tor_assert(key_out_len <= DIGEST_LEN*256); 49 50 memcpy(tmp, key_in, key_in_len); 51 for (cp = key_out, i=0; cp < key_out+key_out_len; 52 ++i, cp += DIGEST_LEN) { 53 tmp[key_in_len] = i; 54 if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) 55 goto exit; 56 memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); 57 } 58 59 r = 0; 60 exit: 61 memwipe(tmp, 0, key_in_len+1); 62 tor_free(tmp); 63 memwipe(digest, 0, sizeof(digest)); 64 return r; 65 } 66 67 #ifdef HAVE_OPENSSL_HKDF 68 /** 69 * Perform RFC5869 HKDF computation using OpenSSL (only to be called from 70 * crypto_expand_key_material_rfc5869_sha256_openssl). Note that OpenSSL 71 * requires input key to be nonempty and salt length to be equal or less 72 * than 1024. 73 */ 74 static int 75 crypto_expand_key_material_rfc5869_sha256_openssl( 76 const uint8_t *key_in, size_t key_in_len, 77 const uint8_t *salt_in, size_t salt_in_len, 78 const uint8_t *info_in, size_t info_in_len, 79 uint8_t *key_out, size_t key_out_len) 80 { 81 int r; 82 EVP_PKEY_CTX *evp_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); 83 tor_assert(evp_pkey_ctx); 84 tor_assert(key_in_len != 0); 85 tor_assert(salt_in_len <= 1024); 86 87 r = EVP_PKEY_derive_init(evp_pkey_ctx); 88 tor_assert(r == 1); 89 90 r = EVP_PKEY_CTX_set_hkdf_md(evp_pkey_ctx, EVP_sha256()); 91 tor_assert(r == 1); 92 93 r = EVP_PKEY_CTX_set1_hkdf_salt(evp_pkey_ctx, salt_in, (int)salt_in_len); 94 tor_assert(r == 1); 95 96 r = EVP_PKEY_CTX_set1_hkdf_key(evp_pkey_ctx, key_in, (int)key_in_len); 97 tor_assert(r == 1); 98 99 r = EVP_PKEY_CTX_add1_hkdf_info(evp_pkey_ctx, info_in, (int)info_in_len); 100 tor_assert(r == 1); 101 102 r = EVP_PKEY_derive(evp_pkey_ctx, key_out, &key_out_len); 103 tor_assert(r == 1); 104 105 EVP_PKEY_CTX_free(evp_pkey_ctx); 106 return 0; 107 } 108 109 #else /* !defined(HAVE_OPENSSL_HKDF) */ 110 111 /** 112 * Perform RFC5869 HKDF computation using our own legacy implementation. 113 * Only to be called from crypto_expand_key_material_rfc5869_sha256_openssl. 114 */ 115 static int 116 crypto_expand_key_material_rfc5869_sha256_legacy( 117 const uint8_t *key_in, size_t key_in_len, 118 const uint8_t *salt_in, size_t salt_in_len, 119 const uint8_t *info_in, size_t info_in_len, 120 uint8_t *key_out, size_t key_out_len) 121 { 122 uint8_t prk[DIGEST256_LEN]; 123 uint8_t tmp[DIGEST256_LEN + 128 + 1]; 124 uint8_t mac[DIGEST256_LEN]; 125 int i; 126 uint8_t *outp; 127 size_t tmp_len; 128 129 crypto_hmac_sha256((char*)prk, 130 (const char*)salt_in, salt_in_len, 131 (const char*)key_in, key_in_len); 132 133 /* If we try to get more than this amount of key data, we'll repeat blocks.*/ 134 tor_assert(key_out_len <= DIGEST256_LEN * 256); 135 tor_assert(info_in_len <= 128); 136 memset(tmp, 0, sizeof(tmp)); 137 outp = key_out; 138 i = 1; 139 140 while (key_out_len) { 141 size_t n; 142 if (i > 1) { 143 memcpy(tmp, mac, DIGEST256_LEN); 144 memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); 145 tmp[DIGEST256_LEN+info_in_len] = i; 146 tmp_len = DIGEST256_LEN + info_in_len + 1; 147 } else { 148 memcpy(tmp, info_in, info_in_len); 149 tmp[info_in_len] = i; 150 tmp_len = info_in_len + 1; 151 } 152 crypto_hmac_sha256((char*)mac, 153 (const char*)prk, DIGEST256_LEN, 154 (const char*)tmp, tmp_len); 155 n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; 156 memcpy(outp, mac, n); 157 key_out_len -= n; 158 outp += n; 159 ++i; 160 } 161 162 memwipe(tmp, 0, sizeof(tmp)); 163 memwipe(mac, 0, sizeof(mac)); 164 return 0; 165 } 166 #endif /* defined(HAVE_OPENSSL_HKDF) */ 167 168 /** Expand some secret key material according to RFC5869, using SHA256 as the 169 * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the 170 * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the 171 * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" 172 * and "info" parameters respectively. On success, write <b>key_out_len</b> 173 * bytes to <b>key_out</b> and return 0. Assert on failure. 174 */ 175 int 176 crypto_expand_key_material_rfc5869_sha256( 177 const uint8_t *key_in, size_t key_in_len, 178 const uint8_t *salt_in, size_t salt_in_len, 179 const uint8_t *info_in, size_t info_in_len, 180 uint8_t *key_out, size_t key_out_len) 181 { 182 tor_assert(key_in); 183 tor_assert(key_in_len > 0); 184 185 #ifdef HAVE_OPENSSL_HKDF 186 return crypto_expand_key_material_rfc5869_sha256_openssl(key_in, 187 key_in_len, salt_in, 188 salt_in_len, info_in, 189 info_in_len, 190 key_out, key_out_len); 191 #else /* !defined(HAVE_OPENSSL_HKDF) */ 192 return crypto_expand_key_material_rfc5869_sha256_legacy(key_in, 193 key_in_len, salt_in, 194 salt_in_len, info_in, 195 info_in_len, 196 key_out, key_out_len); 197 #endif /* defined(HAVE_OPENSSL_HKDF) */ 198 }