diff --git a/src/common/crypto_dh.c b/src/common/crypto_dh.c index 625a270254..09e6ca5063 100644 --- a/src/common/crypto_dh.c +++ b/src/common/crypto_dh.c @@ -12,6 +12,7 @@ #include "compat_openssl.h" #include "crypto_dh.h" #include "crypto_digest.h" +#include "crypto_hkdf.h" #include "crypto_util.h" DISABLE_GCC_WARNING(redundant-decls) @@ -493,103 +494,6 @@ crypto_dh_free_(crypto_dh_t *dh) tor_free(dh); } -/** 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; -} - void crypto_dh_free_all(void) { diff --git a/src/common/crypto_dh.h b/src/common/crypto_dh.h index 7c78d8c907..111c199faa 100644 --- a/src/common/crypto_dh.h +++ b/src/common/crypto_dh.h @@ -37,15 +37,6 @@ ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, void crypto_dh_free_(crypto_dh_t *dh); #define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) -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 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); - /* Crypto DH free */ void crypto_dh_free_all(void); diff --git a/src/common/crypto_hkdf.c b/src/common/crypto_hkdf.c new file mode 100644 index 0000000000..6256f632dd --- /dev/null +++ b/src/common/crypto_hkdf.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.c + * \brief Block of functions related with HKDF utilities and operations. + **/ + +#include "crypto_hkdf.h" +#include "crypto_util.h" +#include "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; +} + diff --git a/src/common/crypto_hkdf.h b/src/common/crypto_hkdf.h new file mode 100644 index 0000000000..5b55172090 --- /dev/null +++ b/src/common/crypto_hkdf.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.h + * + * \brief Headers for crypto_hkdf.h + **/ + +#ifndef TOR_CRYPTO_HKDF_H +#define TOR_CRYPTO_HKDF_H + +#include "util.h" + +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 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); + +#endif /* !defined(TOR_CRYPTO_HKDF_H) */ + diff --git a/src/common/crypto_s2k.c b/src/common/crypto_s2k.c index 47cb62d076..2977a2d127 100644 --- a/src/common/crypto_s2k.c +++ b/src/common/crypto_s2k.c @@ -15,7 +15,7 @@ #include "compat.h" #include "crypto.h" #include "crypto_digest.h" -#include "crypto_dh.h" +#include "crypto_hkdf.h" #include "crypto_rand.h" #include "crypto_s2k.h" #include "crypto_util.h" diff --git a/src/common/crypto_util.c b/src/common/crypto_util.c index 1e1e7284e2..2933579cf9 100644 --- a/src/common/crypto_util.c +++ b/src/common/crypto_util.c @@ -106,6 +106,9 @@ memwipe(void *mem, uint8_t byte, size_t sz) memset(mem, byte, sz); } +/** Log all pending crypto errors at level severity. Use + * doing to describe our current activities. + */ void crypto_log_errors(int severity, const char *doing) { diff --git a/src/common/include.am b/src/common/include.am index 6dafcea206..c9706c6b4b 100644 --- a/src/common/include.am +++ b/src/common/include.am @@ -118,6 +118,7 @@ LIBOR_CRYPTO_A_SRC = \ src/common/crypto_dh.c \ src/common/crypto_digest.c \ src/common/crypto_format.c \ + src/common/crypto_hkdf.c \ src/common/crypto_openssl_mgt.c \ src/common/crypto_pwbox.c \ src/common/crypto_rand.c \ @@ -175,6 +176,7 @@ COMMONHEADERS = \ src/common/crypto_curve25519.h \ src/common/crypto_ed25519.h \ src/common/crypto_format.h \ + src/common/crypto_hkdf.h \ src/common/crypto_openssl_mgt.h \ src/common/crypto_pwbox.h \ src/common/crypto_rand.h \ diff --git a/src/or/onion_ntor.c b/src/or/onion_ntor.c index 74403ac7ae..3df8c2ab60 100644 --- a/src/or/onion_ntor.c +++ b/src/or/onion_ntor.c @@ -22,7 +22,7 @@ #define ONION_NTOR_PRIVATE #include "crypto.h" -#include "crypto_dh.h" +#include "crypto_hkdf.h" #include "crypto_digest.h" #include "crypto_util.h" #include "onion_ntor.h" diff --git a/src/or/or.h b/src/or/or.h index e64ad1d4b7..30a9828aa8 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -69,6 +69,7 @@ #include "crypto.h" #include "crypto_format.h" #include "crypto_dh.h" +#include "crypto_hkdf.h" #include "tortls.h" #include "torlog.h" #include "container.h"