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 : }
|