diff --git a/src/or/hs_service.c b/src/or/hs_service.c index dd91e97bbe..d6416ebcd6 100644 --- a/src/or/hs_service.c +++ b/src/or/hs_service.c @@ -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); diff --git a/src/or/hs_service.h b/src/or/hs_service.h index a5f49ffef9..e1f125d76e 100644 --- a/src/or/hs_service.h +++ b/src/or/hs_service.h @@ -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. */