tor  0.4.2.1-alpha-dev
hs_ntor.c
Go to the documentation of this file.
1 /* Copyright (c) 2017-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
27 #include "core/or/or.h"
31 #include "core/crypto/hs_ntor.h"
32 
33 /* String constants used by the ntor HS protocol */
34 #define PROTOID "tor-hs-ntor-curve25519-sha3-256-1"
35 #define PROTOID_LEN (sizeof(PROTOID) - 1)
36 #define SERVER_STR "Server"
37 #define SERVER_STR_LEN (sizeof(SERVER_STR) - 1)
38 
39 /* Protocol-specific tweaks to our crypto inputs */
40 #define T_HSENC PROTOID ":hs_key_extract"
41 #define T_HSENC_LEN (sizeof(T_HSENC) - 1)
42 #define T_HSVERIFY PROTOID ":hs_verify"
43 #define T_HSMAC PROTOID ":hs_mac"
44 #define M_HSEXPAND PROTOID ":hs_key_expand"
45 #define M_HSEXPAND_LEN (sizeof(M_HSEXPAND) - 1)
46 
47 /************************* Helper functions: *******************************/
48 
51 #define APPEND(ptr, inp, len) \
52  STMT_BEGIN { \
53  memcpy(ptr, (inp), (len)); \
54  ptr += len; \
55  } STMT_END
56 
57 /* Length of EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID */
58 #define REND_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN * 2 + \
59  ED25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN)
60 /* Length of auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server" */
61 #define REND_AUTH_INPUT_LEN (DIGEST256_LEN + ED25519_PUBKEY_LEN + \
62  CURVE25519_PUBKEY_LEN * 3 + PROTOID_LEN + SERVER_STR_LEN)
63 
81 static int
82 get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input,
83  const ed25519_public_key_t *intro_auth_pubkey,
84  const curve25519_public_key_t *intro_enc_pubkey,
85  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
86  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
87  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
88 {
89  int bad = 0;
90  uint8_t ntor_key_seed[DIGEST256_LEN];
91  uint8_t ntor_verify[DIGEST256_LEN];
92  uint8_t rend_auth_input[REND_AUTH_INPUT_LEN];
93  uint8_t rend_cell_auth[DIGEST256_LEN];
94  uint8_t *ptr;
95 
96  /* Let's build NTOR_KEY_SEED */
97  crypto_mac_sha3_256(ntor_key_seed, sizeof(ntor_key_seed),
98  rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
99  (const uint8_t *)T_HSENC, strlen(T_HSENC));
100  bad |= safe_mem_is_zero(ntor_key_seed, DIGEST256_LEN);
101 
102  /* Let's build ntor_verify */
103  crypto_mac_sha3_256(ntor_verify, sizeof(ntor_verify),
104  rend_secret_hs_input, REND_SECRET_HS_INPUT_LEN,
105  (const uint8_t *)T_HSVERIFY, strlen(T_HSVERIFY));
106  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);
107 
108  /* Let's build auth_input: */
109  ptr = rend_auth_input;
110  /* Append ntor_verify */
111  APPEND(ptr, ntor_verify, sizeof(ntor_verify));
112  /* Append AUTH_KEY */
113  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
114  /* Append B */
115  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
116  /* Append Y */
117  APPEND(ptr,
118  service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
119  /* Append X */
120  APPEND(ptr,
121  client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
122  /* Append PROTOID */
123  APPEND(ptr, PROTOID, strlen(PROTOID));
124  /* Append "Server" */
125  APPEND(ptr, SERVER_STR, strlen(SERVER_STR));
126  tor_assert(ptr == rend_auth_input + sizeof(rend_auth_input));
127 
128  /* Let's build auth_input_mac that goes in RENDEZVOUS1 cell */
129  crypto_mac_sha3_256(rend_cell_auth, sizeof(rend_cell_auth),
130  rend_auth_input, sizeof(rend_auth_input),
131  (const uint8_t *)T_HSMAC, strlen(T_HSMAC));
132  bad |= safe_mem_is_zero(ntor_verify, DIGEST256_LEN);
133 
134  { /* Get the computed RENDEZVOUS1 material! */
135  memcpy(&hs_ntor_rend_cell_keys_out->rend_cell_auth_mac,
136  rend_cell_auth, DIGEST256_LEN);
137  memcpy(&hs_ntor_rend_cell_keys_out->ntor_key_seed,
138  ntor_key_seed, DIGEST256_LEN);
139  }
140 
141  memwipe(rend_cell_auth, 0, sizeof(rend_cell_auth));
142  memwipe(rend_auth_input, 0, sizeof(rend_auth_input));
143  memwipe(ntor_key_seed, 0, sizeof(ntor_key_seed));
144 
145  return bad;
146 }
147 
149 #define INTRO_SECRET_HS_INPUT_LEN (CURVE25519_OUTPUT_LEN +ED25519_PUBKEY_LEN +\
150  CURVE25519_PUBKEY_LEN + CURVE25519_PUBKEY_LEN + PROTOID_LEN)
151 /* Length of info = m_hsexpand | subcredential */
152 #define INFO_BLOB_LEN (M_HSEXPAND_LEN + DIGEST256_LEN)
153 /* Length of KDF input = intro_secret_hs_input | t_hsenc | info */
154 #define KDF_INPUT_LEN (INTRO_SECRET_HS_INPUT_LEN + T_HSENC_LEN + INFO_BLOB_LEN)
155 
171 static void
172 get_introduce1_key_material(const uint8_t *secret_input,
173  const uint8_t *subcredential,
174  hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
175 {
176  uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN];
177  uint8_t info_blob[INFO_BLOB_LEN];
178  uint8_t kdf_input[KDF_INPUT_LEN];
179  uint8_t *ptr;
180 
181  /* Let's build info */
182  ptr = info_blob;
183  APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
184  APPEND(ptr, subcredential, DIGEST256_LEN);
185  tor_assert(ptr == info_blob + sizeof(info_blob));
186 
187  /* Let's build the input to the KDF */
188  ptr = kdf_input;
189  APPEND(ptr, secret_input, INTRO_SECRET_HS_INPUT_LEN);
190  APPEND(ptr, T_HSENC, strlen(T_HSENC));
191  APPEND(ptr, info_blob, sizeof(info_blob));
192  tor_assert(ptr == kdf_input + sizeof(kdf_input));
193 
194  /* Now we need to run kdf_input over SHAKE-256 */
195  crypto_xof(keystream, sizeof(keystream),
196  kdf_input, sizeof(kdf_input));
197 
198  { /* Get the keys */
199  memcpy(&hs_ntor_intro_cell_keys_out->enc_key, keystream,CIPHER256_KEY_LEN);
200  memcpy(&hs_ntor_intro_cell_keys_out->mac_key,
201  keystream+CIPHER256_KEY_LEN, DIGEST256_LEN);
202  }
203 
204  memwipe(keystream, 0, sizeof(keystream));
205  memwipe(kdf_input, 0, sizeof(kdf_input));
206 }
207 
224 static void
225 get_intro_secret_hs_input(const uint8_t *dh_result,
226  const ed25519_public_key_t *intro_auth_pubkey,
227  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
228  const curve25519_public_key_t *intro_enc_pubkey,
229  uint8_t *secret_input_out)
230 {
231  uint8_t *ptr;
232 
233  /* Append EXP() */
234  ptr = secret_input_out;
235  APPEND(ptr, dh_result, CURVE25519_OUTPUT_LEN);
236  /* Append AUTH_KEY */
237  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
238  /* Append X */
239  APPEND(ptr, client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
240  /* Append B */
241  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
242  /* Append PROTOID */
243  APPEND(ptr, PROTOID, strlen(PROTOID));
244  tor_assert(ptr == secret_input_out + INTRO_SECRET_HS_INPUT_LEN);
245 }
246 
264 static void
265 get_rend_secret_hs_input(const uint8_t *dh_result1, const uint8_t *dh_result2,
266  const ed25519_public_key_t *intro_auth_pubkey,
267  const curve25519_public_key_t *intro_enc_pubkey,
268  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
269  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
270  uint8_t *rend_secret_hs_input_out)
271 {
272  uint8_t *ptr;
273 
274  ptr = rend_secret_hs_input_out;
275  /* Append the first EXP() */
276  APPEND(ptr, dh_result1, CURVE25519_OUTPUT_LEN);
277  /* Append the other EXP() */
278  APPEND(ptr, dh_result2, CURVE25519_OUTPUT_LEN);
279  /* Append AUTH_KEY */
280  APPEND(ptr, intro_auth_pubkey->pubkey, ED25519_PUBKEY_LEN);
281  /* Append B */
282  APPEND(ptr, intro_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
283  /* Append X */
284  APPEND(ptr,
285  client_ephemeral_enc_pubkey->public_key, CURVE25519_PUBKEY_LEN);
286  /* Append Y */
287  APPEND(ptr,
288  service_ephemeral_rend_pubkey->public_key, CURVE25519_PUBKEY_LEN);
289  /* Append PROTOID */
290  APPEND(ptr, PROTOID, strlen(PROTOID));
291  tor_assert(ptr == rend_secret_hs_input_out + REND_SECRET_HS_INPUT_LEN);
292 }
293 
294 /************************* Public functions: *******************************/
295 
296 /* Public function: Do the appropriate ntor calculations and derive the keys
297  * needed to encrypt and authenticate INTRODUCE1 cells. Return 0 and place the
298  * final key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went
299  * well, otherwise return -1;
300  *
301  * The relevant calculations are as follows:
302  *
303  * intro_secret_hs_input = EXP(B,x) | AUTH_KEY | X | B | PROTOID
304  * info = m_hsexpand | subcredential
305  * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
306  * ENC_KEY = hs_keys[0:S_KEY_LEN]
307  * MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
308  *
309  * where:
310  * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor),
311  * <b>intro_enc_pubkey</b> is B (also found in HS descriptor),
312  * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X)
313  * <b>subcredential</b> is the hidden service subcredential (of size
314  * DIGEST256_LEN). */
315 int
316 hs_ntor_client_get_introduce1_keys(
317  const ed25519_public_key_t *intro_auth_pubkey,
318  const curve25519_public_key_t *intro_enc_pubkey,
319  const curve25519_keypair_t *client_ephemeral_enc_keypair,
320  const uint8_t *subcredential,
321  hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
322 {
323  int bad = 0;
324  uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
325  uint8_t dh_result[CURVE25519_OUTPUT_LEN];
326 
327  tor_assert(intro_auth_pubkey);
328  tor_assert(intro_enc_pubkey);
329  tor_assert(client_ephemeral_enc_keypair);
330  tor_assert(subcredential);
331  tor_assert(hs_ntor_intro_cell_keys_out);
332 
333  /* Calculate EXP(B,x) */
334  curve25519_handshake(dh_result,
335  &client_ephemeral_enc_keypair->seckey,
336  intro_enc_pubkey);
337  bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN);
338 
339  /* Get intro_secret_hs_input */
340  get_intro_secret_hs_input(dh_result, intro_auth_pubkey,
341  &client_ephemeral_enc_keypair->pubkey,
342  intro_enc_pubkey, secret_input);
343  bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
344 
345  /* Get ENC_KEY and MAC_KEY! */
346  get_introduce1_key_material(secret_input, subcredential,
347  hs_ntor_intro_cell_keys_out);
348 
349  /* Cleanup */
350  memwipe(secret_input, 0, sizeof(secret_input));
351  if (bad) {
352  memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t));
353  }
354 
355  return bad ? -1 : 0;
356 }
357 
358 /* Public function: Do the appropriate ntor calculations and derive the keys
359  * needed to verify RENDEZVOUS1 cells and encrypt further rendezvous
360  * traffic. Return 0 and place the final key material in
361  * <b>hs_ntor_rend_cell_keys_out</b> if everything went well, else return -1.
362  *
363  * The relevant calculations are as follows:
364  *
365  * rend_secret_hs_input = EXP(Y,x) | EXP(B,x) | AUTH_KEY | B | X | Y | PROTOID
366  * NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
367  * verify = MAC(rend_secret_hs_input, t_hsverify)
368  * auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
369  * auth_input_mac = MAC(auth_input, t_hsmac)
370  *
371  * where:
372  * <b>intro_auth_pubkey</b> is AUTH_KEY (found in HS descriptor),
373  * <b>client_ephemeral_enc_keypair</b> is freshly generated keypair (x,X)
374  * <b>intro_enc_pubkey</b> is B (also found in HS descriptor),
375  * <b>service_ephemeral_rend_pubkey</b> is Y (SERVER_PK in RENDEZVOUS1 cell) */
376 int
377 hs_ntor_client_get_rendezvous1_keys(
378  const ed25519_public_key_t *intro_auth_pubkey,
379  const curve25519_keypair_t *client_ephemeral_enc_keypair,
380  const curve25519_public_key_t *intro_enc_pubkey,
381  const curve25519_public_key_t *service_ephemeral_rend_pubkey,
382  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
383 {
384  int bad = 0;
385  uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN];
386  uint8_t dh_result1[CURVE25519_OUTPUT_LEN];
387  uint8_t dh_result2[CURVE25519_OUTPUT_LEN];
388 
389  tor_assert(intro_auth_pubkey);
390  tor_assert(client_ephemeral_enc_keypair);
391  tor_assert(intro_enc_pubkey);
392  tor_assert(service_ephemeral_rend_pubkey);
393  tor_assert(hs_ntor_rend_cell_keys_out);
394 
395  /* Compute EXP(Y, x) */
396  curve25519_handshake(dh_result1,
397  &client_ephemeral_enc_keypair->seckey,
398  service_ephemeral_rend_pubkey);
399  bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN);
400 
401  /* Compute EXP(B, x) */
402  curve25519_handshake(dh_result2,
403  &client_ephemeral_enc_keypair->seckey,
404  intro_enc_pubkey);
405  bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN);
406 
407  /* Get rend_secret_hs_input */
408  get_rend_secret_hs_input(dh_result1, dh_result2,
409  intro_auth_pubkey, intro_enc_pubkey,
410  &client_ephemeral_enc_keypair->pubkey,
411  service_ephemeral_rend_pubkey,
412  rend_secret_hs_input);
413 
414  /* Get NTOR_KEY_SEED and the auth_input MAC */
415  bad |= get_rendezvous1_key_material(rend_secret_hs_input,
416  intro_auth_pubkey,
417  intro_enc_pubkey,
418  service_ephemeral_rend_pubkey,
419  &client_ephemeral_enc_keypair->pubkey,
420  hs_ntor_rend_cell_keys_out);
421 
422  memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input));
423  if (bad) {
424  memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t));
425  }
426 
427  return bad ? -1 : 0;
428 }
429 
430 /* Public function: Do the appropriate ntor calculations and derive the keys
431  * needed to decrypt and verify INTRODUCE1 cells. Return 0 and place the final
432  * key material in <b>hs_ntor_intro_cell_keys_out</b> if everything went well,
433  * otherwise return -1;
434  *
435  * The relevant calculations are as follows:
436  *
437  * intro_secret_hs_input = EXP(X,b) | AUTH_KEY | X | B | PROTOID
438  * info = m_hsexpand | subcredential
439  * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN)
440  * HS_DEC_KEY = hs_keys[0:S_KEY_LEN]
441  * HS_MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN]
442  *
443  * where:
444  * <b>intro_auth_pubkey</b> is AUTH_KEY (introduction point auth key),
445  * <b>intro_enc_keypair</b> is (b,B) (introduction point encryption keypair),
446  * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell),
447  * <b>subcredential</b> is the HS subcredential (of size DIGEST256_LEN) */
448 int
449 hs_ntor_service_get_introduce1_keys(
450  const ed25519_public_key_t *intro_auth_pubkey,
451  const curve25519_keypair_t *intro_enc_keypair,
452  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
453  const uint8_t *subcredential,
454  hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
455 {
456  int bad = 0;
457  uint8_t secret_input[INTRO_SECRET_HS_INPUT_LEN];
458  uint8_t dh_result[CURVE25519_OUTPUT_LEN];
459 
460  tor_assert(intro_auth_pubkey);
461  tor_assert(intro_enc_keypair);
462  tor_assert(client_ephemeral_enc_pubkey);
463  tor_assert(subcredential);
464  tor_assert(hs_ntor_intro_cell_keys_out);
465 
466  /* Compute EXP(X, b) */
467  curve25519_handshake(dh_result,
468  &intro_enc_keypair->seckey,
469  client_ephemeral_enc_pubkey);
470  bad |= safe_mem_is_zero(dh_result, CURVE25519_OUTPUT_LEN);
471 
472  /* Get intro_secret_hs_input */
473  get_intro_secret_hs_input(dh_result, intro_auth_pubkey,
474  client_ephemeral_enc_pubkey,
475  &intro_enc_keypair->pubkey,
476  secret_input);
477  bad |= safe_mem_is_zero(secret_input, CURVE25519_OUTPUT_LEN);
478 
479  /* Get ENC_KEY and MAC_KEY! */
480  get_introduce1_key_material(secret_input, subcredential,
481  hs_ntor_intro_cell_keys_out);
482 
483  memwipe(secret_input, 0, sizeof(secret_input));
484  if (bad) {
485  memwipe(hs_ntor_intro_cell_keys_out, 0, sizeof(hs_ntor_intro_cell_keys_t));
486  }
487 
488  return bad ? -1 : 0;
489 }
490 
491 /* Public function: Do the appropriate ntor calculations and derive the keys
492  * needed to create and authenticate RENDEZVOUS1 cells. Return 0 and place the
493  * final key material in <b>hs_ntor_rend_cell_keys_out</b> if all went fine,
494  * return -1 if error happened.
495  *
496  * The relevant calculations are as follows:
497  *
498  * rend_secret_hs_input = EXP(X,y) | EXP(X,b) | AUTH_KEY | B | X | Y | PROTOID
499  * NTOR_KEY_SEED = MAC(rend_secret_hs_input, t_hsenc)
500  * verify = MAC(rend_secret_hs_input, t_hsverify)
501  * auth_input = verify | AUTH_KEY | B | Y | X | PROTOID | "Server"
502  * auth_input_mac = MAC(auth_input, t_hsmac)
503  *
504  * where:
505  * <b>intro_auth_pubkey</b> is AUTH_KEY (intro point auth key),
506  * <b>intro_enc_keypair</b> is (b,B) (intro point enc keypair)
507  * <b>service_ephemeral_rend_keypair</b> is a fresh (y,Y) keypair
508  * <b>client_ephemeral_enc_pubkey</b> is X (CLIENT_PK in INTRODUCE2 cell) */
509 int
510 hs_ntor_service_get_rendezvous1_keys(
511  const ed25519_public_key_t *intro_auth_pubkey,
512  const curve25519_keypair_t *intro_enc_keypair,
513  const curve25519_keypair_t *service_ephemeral_rend_keypair,
514  const curve25519_public_key_t *client_ephemeral_enc_pubkey,
515  hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
516 {
517  int bad = 0;
518  uint8_t rend_secret_hs_input[REND_SECRET_HS_INPUT_LEN];
519  uint8_t dh_result1[CURVE25519_OUTPUT_LEN];
520  uint8_t dh_result2[CURVE25519_OUTPUT_LEN];
521 
522  tor_assert(intro_auth_pubkey);
523  tor_assert(intro_enc_keypair);
524  tor_assert(service_ephemeral_rend_keypair);
525  tor_assert(client_ephemeral_enc_pubkey);
526  tor_assert(hs_ntor_rend_cell_keys_out);
527 
528  /* Compute EXP(X, y) */
529  curve25519_handshake(dh_result1,
530  &service_ephemeral_rend_keypair->seckey,
531  client_ephemeral_enc_pubkey);
532  bad |= safe_mem_is_zero(dh_result1, CURVE25519_OUTPUT_LEN);
533 
534  /* Compute EXP(X, b) */
535  curve25519_handshake(dh_result2,
536  &intro_enc_keypair->seckey,
537  client_ephemeral_enc_pubkey);
538  bad |= safe_mem_is_zero(dh_result2, CURVE25519_OUTPUT_LEN);
539 
540  /* Get rend_secret_hs_input */
541  get_rend_secret_hs_input(dh_result1, dh_result2,
542  intro_auth_pubkey,
543  &intro_enc_keypair->pubkey,
544  client_ephemeral_enc_pubkey,
545  &service_ephemeral_rend_keypair->pubkey,
546  rend_secret_hs_input);
547 
548  /* Get NTOR_KEY_SEED and AUTH_INPUT_MAC! */
549  bad |= get_rendezvous1_key_material(rend_secret_hs_input,
550  intro_auth_pubkey,
551  &intro_enc_keypair->pubkey,
552  &service_ephemeral_rend_keypair->pubkey,
553  client_ephemeral_enc_pubkey,
554  hs_ntor_rend_cell_keys_out);
555 
556  memwipe(rend_secret_hs_input, 0, sizeof(rend_secret_hs_input));
557  if (bad) {
558  memwipe(hs_ntor_rend_cell_keys_out, 0, sizeof(hs_ntor_rend_cell_keys_t));
559  }
560 
561  return bad ? -1 : 0;
562 }
563 
567 int
569  const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys,
570  const uint8_t *rcvd_mac)
571 {
572  tor_assert(rcvd_mac);
573  tor_assert(hs_ntor_rend_cell_keys);
574 
575  return tor_memeq(hs_ntor_rend_cell_keys->rend_cell_auth_mac,
576  rcvd_mac, DIGEST256_LEN);
577 }
578 
579 /* Input length to KDF for key expansion */
580 #define NTOR_KEY_EXPANSION_KDF_INPUT_LEN (DIGEST256_LEN + M_HSEXPAND_LEN)
581 
588 int
589 hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len,
590  uint8_t *keys_out, size_t keys_out_len)
591 {
592  uint8_t *ptr;
593  uint8_t kdf_input[NTOR_KEY_EXPANSION_KDF_INPUT_LEN];
594 
595  /* Sanity checks on lengths to make sure we are good */
596  if (BUG(seed_len != DIGEST256_LEN)) {
597  return -1;
598  }
599  if (BUG(keys_out_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) {
600  return -1;
601  }
602 
603  /* Let's build the input to the KDF */
604  ptr = kdf_input;
605  APPEND(ptr, ntor_key_seed, DIGEST256_LEN);
606  APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND));
607  tor_assert(ptr == kdf_input + sizeof(kdf_input));
608 
609  /* Generate the keys */
610  crypto_xof(keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN,
611  kdf_input, sizeof(kdf_input));
612 
613  return 0;
614 }
#define INTRO_SECRET_HS_INPUT_LEN
Definition: hs_ntor.c:149
int hs_ntor_client_rendezvous2_mac_is_good(const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys, const uint8_t *rcvd_mac)
Definition: hs_ntor.c:568
void memwipe(void *mem, uint8_t byte, size_t sz)
Definition: crypto_util.c:57
void curve25519_handshake(uint8_t *output, const curve25519_secret_key_t *skey, const curve25519_public_key_t *pkey)
#define DIGEST256_LEN
Definition: digest_sizes.h:23
static void get_rend_secret_hs_input(const uint8_t *dh_result1, const uint8_t *dh_result2, const ed25519_public_key_t *intro_auth_pubkey, const curve25519_public_key_t *intro_enc_pubkey, const curve25519_public_key_t *client_ephemeral_enc_pubkey, const curve25519_public_key_t *service_ephemeral_rend_pubkey, uint8_t *rend_secret_hs_input_out)
Definition: hs_ntor.c:265
Common functions for cryptographic routines.
tor_assert(buffer)
int tor_memeq(const void *a, const void *b, size_t sz)
Definition: di_ops.c:107
Master header file for Tor-specific functionality.
static void get_intro_secret_hs_input(const uint8_t *dh_result, const ed25519_public_key_t *intro_auth_pubkey, const curve25519_public_key_t *client_ephemeral_enc_pubkey, const curve25519_public_key_t *intro_enc_pubkey, uint8_t *secret_input_out)
Definition: hs_ntor.c:225
Header for crypto_ed25519.c.
#define CIPHER256_KEY_LEN
Definition: crypto_cipher.h:26
#define APPEND(ptr, inp, len)
Definition: hs_ntor.c:51
void crypto_xof(uint8_t *output, size_t output_len, const uint8_t *input, size_t input_len)
#define CURVE25519_OUTPUT_LEN
Definition: x25519_sizes.h:24
int hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len, uint8_t *keys_out, size_t keys_out_len)
Definition: hs_ntor.c:589
void crypto_mac_sha3_256(uint8_t *mac_out, size_t len_out, const uint8_t *key, size_t key_len, const uint8_t *msg, size_t msg_len)
int safe_mem_is_zero(const void *mem, size_t sz)
Definition: di_ops.c:221
static int get_rendezvous1_key_material(const uint8_t *rend_secret_hs_input, const ed25519_public_key_t *intro_auth_pubkey, const curve25519_public_key_t *intro_enc_pubkey, const curve25519_public_key_t *service_ephemeral_rend_pubkey, const curve25519_public_key_t *client_ephemeral_enc_pubkey, hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out)
Definition: hs_ntor.c:82
static void get_introduce1_key_material(const uint8_t *secret_input, const uint8_t *subcredential, hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out)
Definition: hs_ntor.c:172
Header for crypto_curve25519.c.
#define CURVE25519_PUBKEY_LEN
Definition: x25519_sizes.h:20