tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 }