Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
relay_crypto_tor1.c
Go to the documentation of this file.
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 relay_crypto_tor1.c
9 * @brief Implementation for legacy (tor1) relay cell encryption.
10 **/
11
12#include "core/or/or.h"
15#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN
16#include "core/crypto/relay_crypto_tor1.h"
17#include "lib/cc/ctassert.h"
18
19#include "core/or/cell_st.h"
21
22/* Offset of digest within relay cell body for v0 cells. */
23#define V0_DIGEST_OFFSET 5
24#define V0_DIGEST_LEN 4
25#define V0_RECOGNIZED_OFFSET 1
26
27/** Update digest from the payload of cell. Assign integrity part to
28 * cell. Record full 20-byte digest in `buf`.
29 */
30static void
31tor1_set_digest_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf)
32{
34 crypto_digest_get_digest(digest, (char*)buf, DIGEST_LEN);
35// log_fn(LOG_DEBUG,"Putting digest of %u %u %u %u into relay cell.",
36// integrity[0], integrity[1], integrity[2], integrity[3]);
37 memcpy(cell->payload + V0_DIGEST_OFFSET, buf, V0_DIGEST_LEN);
38}
39
40/** Does the digest for this circuit indicate that this cell is for us?
41 *
42 * Update digest from the payload of cell (with the integrity part set
43 * to 0). If the integrity part is valid,
44 * return 1 and save the full digest in the 20-byte buffer `buf`,
45 * else restore digest
46 * and cell to their original state and return 0.
47 */
48static int
50 uint8_t *buf)
51{
52 uint32_t received_integrity, calculated_integrity;
53 uint8_t calculated_digest[DIGEST_LEN];
54 crypto_digest_checkpoint_t backup_digest;
55
56 CTASSERT(sizeof(uint32_t) == V0_DIGEST_LEN);
57
58 crypto_digest_checkpoint(&backup_digest, digest);
59
60 memcpy(&received_integrity, cell->payload + V0_DIGEST_OFFSET, V0_DIGEST_LEN);
61 memset(cell->payload + V0_DIGEST_OFFSET, 0, V0_DIGEST_LEN);
62
63// log_fn(LOG_DEBUG,"Reading digest of %u %u %u %u from relay cell.",
64// received_integrity[0], received_integrity[1],
65// received_integrity[2], received_integrity[3]);
66
68 crypto_digest_get_digest(digest, (char*) calculated_digest, DIGEST_LEN);
69 calculated_integrity = get_uint32(calculated_digest);
70
71 int rv = 1;
72
73 if (calculated_integrity != received_integrity) {
74// log_fn(LOG_INFO,"Recognized=0 but bad digest. Not recognizing.");
75// (%d vs %d).", received_integrity, calculated_integrity);
76 /* restore digest to its old form */
77 crypto_digest_restore(digest, &backup_digest);
78 /* restore the relay header */
79 memcpy(cell->payload + V0_DIGEST_OFFSET, &received_integrity,
80 V0_DIGEST_LEN);
81 rv = 0;
82 } else {
83 memcpy(buf, calculated_digest, DIGEST_LEN);
84 }
85
86 memwipe(&backup_digest, 0, sizeof(backup_digest));
87 return rv;
88}
89
90static inline bool
91relay_cell_is_recognized_v0(const cell_t *cell)
92{
93 return get_uint16(cell->payload + V0_RECOGNIZED_OFFSET) == 0;
94}
95
96/** Apply <b>cipher</b> to CELL_PAYLOAD_SIZE bytes of <b>in</b>
97 * (in place).
98 *
99 * Note that we use the same operation for encrypting and for decrypting.
100 */
101static void
102tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
103{
105}
106
107/** Encrypt and authenticate `cell` using the cryptographic
108 * material in `tor1`.
109 *
110 * This method should be used for the first encryption performed
111 * by the client - that is, the one corresponding to the exit node.
112 */
113void
115 cell_t *cell)
116{
117 tor1_set_digest_v0(tor1->f_digest, cell, tor1->sendme_digest);
119}
120
121/** Encrypt and authenticate `cell`, using the cryptographic
122 * material in `tor1`.
123 *
124 * This method should be used by relays when originating cells toward the
125 * client.
126 */
127void
129 cell_t *cell)
130{
131 tor1_set_digest_v0(tor1->b_digest, cell, tor1->sendme_digest);
133}
134
135/** Encrypt `cell` using the cryptographic material in `tor1`.
136 *
137 * This method should be used by clients for cryptographic layers
138 * that are _not_ the final recipient of the cell. */
139void
141{
143}
144
145/** Encrypt `cell` using the cryptographic material in `tor1`.
146 *
147 * This method should be used by relays on cells that are moving
148 * toward the client. */
149void
151{
153}
154
155/** Decrypt `cell` using the cryptographic material in `tor1`.
156 *
157 * Return `true` when we are the destination for this cell.
158 *
159 * This method should be used by relays on cells
160 * that are moving away from the client. */
161bool
163{
165 if (relay_cell_is_recognized_v0(cell)) {
167 tor1->sendme_digest)) {
168 return true;
169 }
170 }
171 return false;
172}
173
174/** Decrypt `cell` using the cryptographic material in `tor1`.
175 *
176 * Return `true` when this cell is recognized and authenticated
177 * as coming from the relay that also holds this cryptographic material.
178 *
179 * This method should be used by clients on incoming cells. */
180bool
182{
184
185 if (relay_cell_is_recognized_v0(cell)) {
187 tor1->sendme_digest)) {
188 return true;
189 }
190 }
191 return false;
192}
193
194/** Return the number of bytes that tor1_crypt_init expects. */
195size_t
197{
198 if (is_hs)
199 return HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN;
200 else
201 return CPATH_KEY_MATERIAL_LEN;
202}
203
204/** Initialize <b>crypto</b> from the key material in key_data.
205 *
206 * If <b>is_hs_v3</b> is set, this cpath will be used for next gen hidden
207 * service circuits and <b>key_data</b> must be
208 * HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN bytes in length.
209 *
210 * If <b>is_hs_v3</b> is not set, key_data must contain CPATH_KEY_MATERIAL_LEN
211 * bytes, which are used as follows:
212 * - 20 to initialize f_digest
213 * - 20 to initialize b_digest
214 * - 16 to key f_crypto
215 * - 16 to key b_crypto
216 *
217 * (If 'reverse' is true, then f_XX and b_XX are swapped.)
218 *
219 * Return 0 if init was successful, else -1 if it failed.
220 */
221int
223 const char *key_data, size_t key_data_len,
224 int reverse, int is_hs_v3)
225{
226 crypto_digest_t *tmp_digest;
227 crypto_cipher_t *tmp_crypto;
228 size_t digest_len = 0;
229 size_t cipher_key_len = 0;
230
231 tor_assert(crypto);
232 tor_assert(key_data);
233 tor_assert(!(crypto->f_crypto || crypto->b_crypto ||
234 crypto->f_digest || crypto->b_digest));
235
236 /* Basic key size validation */
237 if (is_hs_v3 && BUG(key_data_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
238 goto err;
239 } else if (!is_hs_v3 && BUG(key_data_len != CPATH_KEY_MATERIAL_LEN)) {
240 goto err;
241 }
242
243 /* If we are using this crypto for next gen onion services use SHA3-256,
244 otherwise use good ol' SHA1 */
245 if (is_hs_v3) {
246 digest_len = DIGEST256_LEN;
247 cipher_key_len = CIPHER256_KEY_LEN;
248 crypto->f_digest = crypto_digest256_new(DIGEST_SHA3_256);
249 crypto->b_digest = crypto_digest256_new(DIGEST_SHA3_256);
250 } else {
251 digest_len = DIGEST_LEN;
252 cipher_key_len = CIPHER_KEY_LEN;
253 crypto->f_digest = crypto_digest_new();
254 crypto->b_digest = crypto_digest_new();
255 }
256
257 tor_assert(digest_len != 0);
258 tor_assert(cipher_key_len != 0);
259 const int cipher_key_bits = (int) cipher_key_len * 8;
260
261 crypto_digest_add_bytes(crypto->f_digest, key_data, digest_len);
262 crypto_digest_add_bytes(crypto->b_digest, key_data+digest_len, digest_len);
263
264 crypto->f_crypto = crypto_cipher_new_with_bits(key_data+(2*digest_len),
265 cipher_key_bits);
266 if (!crypto->f_crypto) {
267 log_warn(LD_BUG,"Forward cipher initialization failed.");
268 goto err;
269 }
270
272 key_data+(2*digest_len)+cipher_key_len,
273 cipher_key_bits);
274 if (!crypto->b_crypto) {
275 log_warn(LD_BUG,"Backward cipher initialization failed.");
276 goto err;
277 }
278
279 if (reverse) {
280 tmp_digest = crypto->f_digest;
281 crypto->f_digest = crypto->b_digest;
282 crypto->b_digest = tmp_digest;
283 tmp_crypto = crypto->f_crypto;
284 crypto->f_crypto = crypto->b_crypto;
285 crypto->b_crypto = tmp_crypto;
286 }
287
288 return 0;
289 err:
290 tor1_crypt_clear(crypto);
291 return -1;
292}
293
294/** Assert that <b>crypto</b> is valid and set. */
295void
297{
298 tor_assert(crypto->f_crypto);
299 tor_assert(crypto->b_crypto);
300 tor_assert(crypto->f_digest);
301 tor_assert(crypto->b_digest);
302}
303
304void
305tor1_crypt_clear(tor1_crypt_t *crypto)
306{
307 if (BUG(!crypto))
308 return;
309 crypto_cipher_free(crypto->f_crypto);
310 crypto_cipher_free(crypto->b_crypto);
313}
static uint16_t get_uint16(const void *cp)
Definition: bytes.h:42
static uint32_t get_uint32(const void *cp)
Definition: bytes.h:54
Fixed-size cell structure.
crypto_cipher_t * crypto_cipher_new_with_bits(const char *key, int bits)
Definition: crypto_cipher.c:54
void crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len)
Headers for crypto_cipher.c.
#define CIPHER_KEY_LEN
Definition: crypto_cipher.h:22
#define CIPHER256_KEY_LEN
Definition: crypto_cipher.h:26
void crypto_digest_checkpoint(crypto_digest_checkpoint_t *checkpoint, const crypto_digest_t *digest)
void crypto_digest_restore(crypto_digest_t *digest, const crypto_digest_checkpoint_t *checkpoint)
void crypto_digest_get_digest(crypto_digest_t *digest, char *out, size_t out_len)
#define crypto_digest_free(d)
crypto_digest_t * crypto_digest256_new(digest_algorithm_t algorithm)
void crypto_digest_add_bytes(crypto_digest_t *digest, const char *data, size_t len)
crypto_digest_t * crypto_digest_new(void)
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:55
Common functions for cryptographic routines.
Compile-time assertions: CTASSERT(expression).
#define DIGEST_LEN
Definition: digest_sizes.h:20
#define DIGEST256_LEN
Definition: digest_sizes.h:23
CTASSERT(NUMBER_SECOND_GUARDS< 20)
Header for hs_ntor.c.
#define LD_BUG
Definition: log.h:86
Master header file for Tor-specific functionality.
#define CELL_PAYLOAD_SIZE
Definition: or.h:525
Relay-cell encryption state structure.
void tor1_crypt_client_forward(tor1_crypt_t *tor1, cell_t *cell)
void tor1_crypt_assert_ok(const tor1_crypt_t *crypto)
static void tor1_set_digest_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf)
void tor1_crypt_relay_backward(tor1_crypt_t *tor1, cell_t *cell)
void tor1_crypt_relay_originate(tor1_crypt_t *tor1, cell_t *cell)
static int tor1_relay_digest_matches_v0(crypto_digest_t *digest, cell_t *cell, uint8_t *buf)
static void tor1_crypt_one_payload(crypto_cipher_t *cipher, uint8_t *in)
int tor1_crypt_init(tor1_crypt_t *crypto, const char *key_data, size_t key_data_len, int reverse, int is_hs_v3)
void tor1_crypt_client_originate(tor1_crypt_t *tor1, cell_t *cell)
bool tor1_crypt_client_backward(tor1_crypt_t *tor1, cell_t *cell)
size_t tor1_key_material_len(bool is_hs)
bool tor1_crypt_relay_forward(tor1_crypt_t *tor1, cell_t *cell)
Definition: cell_st.h:17
uint8_t payload[CELL_PAYLOAD_SIZE]
Definition: cell_st.h:21
struct crypto_digest_t * b_digest
Definition: tor1_crypt_st.h:29
struct crypto_digest_t * f_digest
Definition: tor1_crypt_st.h:27
uint8_t sendme_digest[DIGEST_LEN]
Definition: tor1_crypt_st.h:36
struct aes_cnt_cipher_t * b_crypto
Definition: tor1_crypt_st.h:24
struct aes_cnt_cipher_t * f_crypto
Definition: tor1_crypt_st.h:21
#define tor_assert(expr)
Definition: util_bug.h:103