"Fossies" - the Fresh Open Source Software Archive

Member "tor-0.4.1.6/src/lib/crypt_ops/crypto_hkdf.c" (10 Jun 2019, 6930 Bytes) of package /linux/misc/tor-0.4.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "crypto_hkdf.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.4.0.5_vs_0.4.1.5.

    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-2019, 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 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   int i, r = -1;
   47   uint8_t *cp, *tmp = tor_malloc(key_in_len+1);
   48   uint8_t digest[DIGEST_LEN];
   49 
   50   /* If we try to get more than this amount of key data, we'll repeat blocks.*/
   51   tor_assert(key_out_len <= DIGEST_LEN*256);
   52 
   53   memcpy(tmp, key_in, key_in_len);
   54   for (cp = key_out, i=0; cp < key_out+key_out_len;
   55        ++i, cp += DIGEST_LEN) {
   56     tmp[key_in_len] = i;
   57     if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0)
   58       goto exit;
   59     memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out)));
   60   }
   61 
   62   r = 0;
   63  exit:
   64   memwipe(tmp, 0, key_in_len+1);
   65   tor_free(tmp);
   66   memwipe(digest, 0, sizeof(digest));
   67   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 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   int r;
   85   EVP_PKEY_CTX *evp_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
   86   tor_assert(evp_pkey_ctx);
   87   tor_assert(key_in_len != 0);
   88   tor_assert(salt_in_len <= 1024);
   89 
   90   r = EVP_PKEY_derive_init(evp_pkey_ctx);
   91   tor_assert(r == 1);
   92 
   93   r = EVP_PKEY_CTX_set_hkdf_md(evp_pkey_ctx, EVP_sha256());
   94   tor_assert(r == 1);
   95 
   96   r = EVP_PKEY_CTX_set1_hkdf_salt(evp_pkey_ctx, salt_in, (int)salt_in_len);
   97   tor_assert(r == 1);
   98 
   99   r = EVP_PKEY_CTX_set1_hkdf_key(evp_pkey_ctx, key_in, (int)key_in_len);
  100   tor_assert(r == 1);
  101 
  102   r = EVP_PKEY_CTX_add1_hkdf_info(evp_pkey_ctx, info_in, (int)info_in_len);
  103   tor_assert(r == 1);
  104 
  105   r = EVP_PKEY_derive(evp_pkey_ctx, key_out, &key_out_len);
  106   tor_assert(r == 1);
  107 
  108   EVP_PKEY_CTX_free(evp_pkey_ctx);
  109   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 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   tor_assert(key_in);
  186   tor_assert(key_in_len > 0);
  187 
  188 #ifdef HAVE_OPENSSL_HKDF
  189   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 }