LCOV - code coverage report
Current view: top level - lib/crypt_ops - crypto_hkdf.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 40 41 97.6 %
Date: 2021-11-24 03:28:48 Functions: 3 3 100.0 %

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

Generated by: LCOV version 1.14