Compute OPE cipher structure only when needed.

The OPE cipher is tied to the current blinded key which is tied to the current
time period. Hence create the OPE cipher structure when we create a new
descriptor (and build its blinded key).
This commit is contained in:
George Kadianakis 2018-07-17 12:03:18 -04:00 committed by Nick Mathewson
parent f00b7a7faa
commit d8b71609cb
2 changed files with 40 additions and 26 deletions

View File

@ -1074,6 +1074,7 @@ service_descriptor_free_(hs_service_descriptor_t *desc)
SMARTLIST_FOREACH(desc->previous_hsdirs, char *, s, tor_free(s));
smartlist_free(desc->previous_hsdirs);
}
crypto_ope_free(desc->ope_cipher);
tor_free(desc);
}
@ -1378,13 +1379,30 @@ build_service_desc_plaintext(const hs_service_t *service,
return ret;
}
/** Compute the descriptor's OPE cipher for encrypting revision counters. */
static crypto_ope_t *
generate_ope_cipher_for_desc(const hs_service_descriptor_t *hs_desc)
{
/* Compute OPE key as H("rev-counter-generation" | blinded privkey) */
uint8_t key[DIGEST256_LEN];
crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA3_256);
const char ope_key_prefix[] = "rev-counter-generation";
const ed25519_secret_key_t *eph_privkey = &hs_desc->blinded_kp.seckey;
crypto_digest_add_bytes(digest, ope_key_prefix, sizeof(ope_key_prefix));
crypto_digest_add_bytes(digest, (char*)eph_privkey->seckey,
sizeof(eph_privkey->seckey));
crypto_digest_get_digest(digest, (char *)key, sizeof(key));
crypto_digest_free(digest);
return crypto_ope_new(key);
}
/* For the given service and descriptor object, create the key material which
* is the blinded keypair and the descriptor signing keypair. Return 0 on
* success else -1 on error where the generated keys MUST be ignored. */
static int
build_service_desc_keys(const hs_service_t *service,
hs_service_descriptor_t *desc,
uint64_t time_period_num)
hs_service_descriptor_t *desc)
{
int ret = 0;
ed25519_keypair_t kp;
@ -1400,10 +1418,17 @@ build_service_desc_keys(const hs_service_t *service,
memcpy(&kp.pubkey, &service->keys.identity_pk, sizeof(kp.pubkey));
memcpy(&kp.seckey, &service->keys.identity_sk, sizeof(kp.seckey));
/* Build blinded keypair for this time period. */
hs_build_blinded_keypair(&kp, NULL, 0, time_period_num, &desc->blinded_kp);
hs_build_blinded_keypair(&kp, NULL, 0, desc->time_period_num,
&desc->blinded_kp);
/* Let's not keep too much traces of our keys in memory. */
memwipe(&kp, 0, sizeof(kp));
/* Compute the OPE cipher struct (it's tied to the current blinded key) */
log_info(LD_GENERAL,
"Getting OPE for TP#%u", (unsigned) desc->time_period_num);
tor_assert_nonfatal(!desc->ope_cipher);
desc->ope_cipher = generate_ope_cipher_for_desc(desc);
/* No need for extra strong, this is a temporary key only for this
* descriptor. Nothing long term. */
if (ed25519_keypair_generate(&desc->signing_kp, 0) < 0) {
@ -1438,10 +1463,12 @@ build_service_descriptor(hs_service_t *service, time_t now,
tor_assert(desc_out);
desc = service_descriptor_new();
/* Set current time period */
desc->time_period_num = time_period_num;
/* Create the needed keys so we can setup the descriptor content. */
if (build_service_desc_keys(service, desc, time_period_num) < 0) {
if (build_service_desc_keys(service, desc) < 0) {
goto err;
}
/* Setup plaintext descriptor content. */
@ -2395,28 +2422,11 @@ set_descriptor_revision_counter(hs_service_descriptor_t *hs_desc, time_t now,
seconds_since_start_of_srv = OPE_INPUT_MAX;
}
/* Now we compute the actual revision counter value by encrypting the
plaintext using an OPE construction: */
/* First, compute OPE key as: K = H("rev-counter-generation" | S) */
uint8_t key[DIGEST256_LEN];
{
crypto_digest_t *digest = crypto_digest256_new(DIGEST_SHA3_256);
const char ope_key_prefix[] = "rev-counter-generation";
ed25519_secret_key_t *eph_privkey = &hs_desc->blinded_kp.seckey;
crypto_digest_add_bytes(digest, ope_key_prefix, sizeof(ope_key_prefix));
crypto_digest_add_bytes(digest, (char*)eph_privkey->seckey,
sizeof(eph_privkey->seckey));
crypto_digest_get_digest(digest, (char *)key, sizeof(key));
crypto_digest_free(digest);
}
{ /* Now encrypt the revision counter! */
crypto_ope_t *ope = NULL;
ope = crypto_ope_new(key);
rev_counter = crypto_ope_encrypt(ope, (int) seconds_since_start_of_srv);
crypto_ope_free(ope);
}
/* Now we compute the final revision counter value by encrypting the
plaintext using our OPE cipher: */
tor_assert(hs_desc->ope_cipher);
rev_counter = crypto_ope_encrypt(hs_desc->ope_cipher,
(int) seconds_since_start_of_srv);
/* The OPE module returns UINT64_MAX in case of errors. */
tor_assert_nonfatal(rev_counter < UINT64_MAX);

View File

@ -131,6 +131,10 @@ typedef struct hs_service_descriptor_t {
* from this list, this means we received new dirinfo and we need to
* reupload our descriptor. */
smartlist_t *previous_hsdirs;
/** The OPE cipher for encrypting revision counters for this descriptor.
* Tied to the descriptor blinded key. */
crypto_ope_t *ope_cipher;
} hs_service_descriptor_t;
/* Service key material. */