/* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file crypto_hkdf.c * \brief Block of functions related with HKDF utilities and operations. **/ #include "common/crypto_hkdf.h" #include "common/crypto_util.h" #include "common/crypto_digest.h" /** Given key_in_len bytes of negotiated randomness in key_in * ("K"), expand it into key_out_len bytes of negotiated key material in * key_out by taking the first key_out_len bytes of * H(K | [00]) | H(K | [01]) | .... * * This is the key expansion algorithm used in the "TAP" circuit extension * mechanism; it shouldn't be used for new protocols. * * Return 0 on success, -1 on failure. */ int crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, uint8_t *key_out, size_t key_out_len) { int i, r = -1; uint8_t *cp, *tmp = tor_malloc(key_in_len+1); uint8_t digest[DIGEST_LEN]; /* If we try to get more than this amount of key data, we'll repeat blocks.*/ tor_assert(key_out_len <= DIGEST_LEN*256); memcpy(tmp, key_in, key_in_len); for (cp = key_out, i=0; cp < key_out+key_out_len; ++i, cp += DIGEST_LEN) { tmp[key_in_len] = i; if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) goto exit; memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); } r = 0; exit: memwipe(tmp, 0, key_in_len+1); tor_free(tmp); memwipe(digest, 0, sizeof(digest)); return r; } /** Expand some secret key material according to RFC5869, using SHA256 as the * underlying hash. The key_in_len bytes at key_in are the * secret key material; the salt_in_len bytes at salt_in and the * info_in_len bytes in info_in_len are the algorithm's "salt" * and "info" parameters respectively. On success, write key_out_len * bytes to key_out and return 0. Assert on failure. */ int crypto_expand_key_material_rfc5869_sha256( const uint8_t *key_in, size_t key_in_len, const uint8_t *salt_in, size_t salt_in_len, const uint8_t *info_in, size_t info_in_len, uint8_t *key_out, size_t key_out_len) { uint8_t prk[DIGEST256_LEN]; uint8_t tmp[DIGEST256_LEN + 128 + 1]; uint8_t mac[DIGEST256_LEN]; int i; uint8_t *outp; size_t tmp_len; crypto_hmac_sha256((char*)prk, (const char*)salt_in, salt_in_len, (const char*)key_in, key_in_len); /* If we try to get more than this amount of key data, we'll repeat blocks.*/ tor_assert(key_out_len <= DIGEST256_LEN * 256); tor_assert(info_in_len <= 128); memset(tmp, 0, sizeof(tmp)); outp = key_out; i = 1; while (key_out_len) { size_t n; if (i > 1) { memcpy(tmp, mac, DIGEST256_LEN); memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); tmp[DIGEST256_LEN+info_in_len] = i; tmp_len = DIGEST256_LEN + info_in_len + 1; } else { memcpy(tmp, info_in, info_in_len); tmp[info_in_len] = i; tmp_len = info_in_len + 1; } crypto_hmac_sha256((char*)mac, (const char*)prk, DIGEST256_LEN, (const char*)tmp, tmp_len); n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; memcpy(outp, mac, n); key_out_len -= n; outp += n; ++i; } memwipe(tmp, 0, sizeof(tmp)); memwipe(mac, 0, sizeof(mac)); return 0; }