/** Given the rendezvous key seed in <b>ntor_key_seed</b> (of size * DIGEST256_LEN), do the circuit key expansion as specified by section * '4.2.1. Key expansion' and place the keys in <b>keys_out</b> (which must be * of size HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN). * * Return 0 if things went well, else return -1. */ 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) { uint8_t *ptr; uint8_t kdf_input[NTOR_KEY_EXPANSION_KDF_INPUT_LEN]; crypto_xof_t *xof; /* Sanity checks on lengths to make sure we are good */ if (BUG(seed_len != DIGEST256_LEN)) { return -1; } if (BUG(keys_out_len != HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN)) { return -1; } /* Let's build the input to the KDF */ ptr = kdf_input; APPEND(ptr, ntor_key_seed, DIGEST256_LEN); APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND)); tor_assert(ptr == kdf_input + sizeof(kdf_input)); /* Generate the keys */ xof = crypto_xof_new(); crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); crypto_xof_squeeze_bytes(xof, keys_out, HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN); crypto_xof_free(xof); return 0; }
/** * Helper: refill the seed bytes and output buffer of <b>rng</b>, using * the input seed bytes as input (key and IV) for the stream cipher. * * If the n_till_reseed counter has reached zero, mix more random bytes into * the seed before refilling the buffer. **/ static void crypto_fast_rng_refill(crypto_fast_rng_t *rng) { if (rng->n_till_reseed-- == 0) { /* It's time to reseed the RNG. We'll do this by using our XOF to mix the * old value for the seed with some additional bytes from * crypto_strongest_rand(). */ crypto_xof_t *xof = crypto_xof_new(); crypto_xof_add_bytes(xof, rng->buf.seed, SEED_LEN); { uint8_t seedbuf[SEED_LEN]; crypto_strongest_rand(seedbuf, SEED_LEN); crypto_xof_add_bytes(xof, seedbuf, SEED_LEN); memwipe(seedbuf, 0, SEED_LEN); } crypto_xof_squeeze_bytes(xof, rng->buf.seed, SEED_LEN); crypto_xof_free(xof); rng->n_till_reseed = RESEED_AFTER; } /* Now fill rng->buf with output from our stream cipher, initialized from * that seed value. */ crypto_cipher_t *c = cipher_from_seed(rng->buf.seed); memset(&rng->buf, 0, sizeof(rng->buf)); crypto_cipher_crypt_inplace(c, (char*)&rng->buf, sizeof(rng->buf)); crypto_cipher_free(c); rng->bytes_left = sizeof(rng->buf.bytes); }
/** Helper function: Compute the part of the HS ntor handshake that generates * key material for creating and handling INTRODUCE1 cells. Function used * by both client and service. Specifically, calculate the following: * * info = m_hsexpand | subcredential * hs_keys = KDF(intro_secret_hs_input | t_hsenc | info, S_KEY_LEN+MAC_LEN) * ENC_KEY = hs_keys[0:S_KEY_LEN] * MAC_KEY = hs_keys[S_KEY_LEN:S_KEY_LEN+MAC_KEY_LEN] * * where intro_secret_hs_input is <b>secret_input</b> (of size * INTRO_SECRET_HS_INPUT_LEN), and <b>subcredential</b> is of size * DIGEST256_LEN. * * If everything went well, fill <b>hs_ntor_intro_cell_keys_out</b> with the * necessary key material, and return 0. */ 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) { uint8_t keystream[CIPHER256_KEY_LEN + DIGEST256_LEN]; uint8_t info_blob[INFO_BLOB_LEN]; uint8_t kdf_input[KDF_INPUT_LEN]; crypto_xof_t *xof; uint8_t *ptr; /* Let's build info */ ptr = info_blob; APPEND(ptr, M_HSEXPAND, strlen(M_HSEXPAND)); APPEND(ptr, subcredential, DIGEST256_LEN); tor_assert(ptr == info_blob + sizeof(info_blob)); /* Let's build the input to the KDF */ ptr = kdf_input; APPEND(ptr, secret_input, INTRO_SECRET_HS_INPUT_LEN); APPEND(ptr, T_HSENC, strlen(T_HSENC)); APPEND(ptr, info_blob, sizeof(info_blob)); tor_assert(ptr == kdf_input + sizeof(kdf_input)); /* Now we need to run kdf_input over SHAKE-256 */ xof = crypto_xof_new(); crypto_xof_add_bytes(xof, kdf_input, sizeof(kdf_input)); crypto_xof_squeeze_bytes(xof, keystream, sizeof(keystream)) ; crypto_xof_free(xof); { /* Get the keys */ memcpy(&hs_ntor_intro_cell_keys_out->enc_key, keystream,CIPHER256_KEY_LEN); memcpy(&hs_ntor_intro_cell_keys_out->mac_key, keystream+CIPHER256_KEY_LEN, DIGEST256_LEN); } memwipe(keystream, 0, sizeof(keystream)); memwipe(kdf_input, 0, sizeof(kdf_input)); }