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