1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
/* 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 "crypto_hkdf.h"
#include "crypto_util.h"
#include "crypto_digest.h"
/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b>
* ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in
* <b>key_out</b> by taking the first <b>key_out_len</b> 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 <b>key_in_len</b> bytes at <b>key_in</b> are the
* secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the
* <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt"
* and "info" parameters respectively. On success, write <b>key_out_len</b>
* bytes to <b>key_out</b> 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;
}
|