diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index f08ebaf9..954373f6 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -639,22 +639,21 @@ namespace client bool LeaseSetDestination::RequestDestinationWithEncryptedLeaseSet (std::shared_ptr dest, RequestComplete requestComplete) { - if (!m_Pool || !IsReady ()) + if (!dest || !m_Pool || !IsReady ()) { if (requestComplete) m_Service.post ([requestComplete](void){requestComplete (nullptr);}); return false; } - i2p::data::IdentHash storeKey; - i2p::data::LeaseSet2::CalculateStoreHash (dest, storeKey); - auto leaseSet = FindLeaseSet (storeKey); + auto storeHash = dest->GetStoreHash (); + auto leaseSet = FindLeaseSet (storeHash); if (leaseSet) { if (requestComplete) m_Service.post ([requestComplete, leaseSet](void){requestComplete (leaseSet);}); return true; } - m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeKey, requestComplete, dest)); + m_Service.post (std::bind (&LeaseSetDestination::RequestLeaseSet, shared_from_this (), storeHash, requestComplete, dest)); return true; } @@ -675,9 +674,8 @@ namespace client void LeaseSetDestination::CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr dest, bool notify) { - i2p::data::IdentHash ident; - i2p::data::LeaseSet2::CalculateStoreHash (dest, ident); - CancelDestinationRequest (ident, notify); + if (dest) + CancelDestinationRequest (dest->GetStoreHash (), notify); } void LeaseSetDestination::RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr requestedBlindedKey) diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index c748d3ce..db376eb4 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -314,6 +314,67 @@ namespace data return std::string (str, str + l); } + void BlindedPublicKey::GetCredential (uint8_t * credential) const + { + // A = destination's signing public key + // stA = signature type of A, 2 bytes big endian + uint16_t stA = htobe16 (GetSigType ()); + // stA1 = signature type of blinded A, 2 bytes big endian + uint16_t stA1 = htobe16 (GetBlindedSigType ()); + // credential = H("credential", A || stA || stA1) + H ("credential", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, credential); + } + + void BlindedPublicKey::GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const + { + uint8_t credential[32]; + GetCredential (credential); + // subcredential = H("subcredential", credential || blindedPublicKey) + H ("subcredential", { {credential, 32}, {blinded, len} }, subcredential); + } + + void BlindedPublicKey::GetBlindedKey (const char * date, uint8_t * blindedKey) const + { + int16_t stA = htobe16 (GetSigType ()), stA1 = htobe16 (GetBlindedSigType ()); + uint8_t salt[32], seed[64]; + //seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64) + H ("I2PGenerateAlpha", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, salt); + i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed); + i2p::crypto::GetEd25519 ()->BlindPublicKey (GetPublicKey (), seed, blindedKey); + } + + void BlindedPublicKey::H (const std::string& p, const std::vector >& bufs, uint8_t * hash) const + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, p.c_str (), p.length ()); + for (const auto& it: bufs) + SHA256_Update (&ctx, it.first, it.second); + SHA256_Final (hash, &ctx); + } + + i2p::data::IdentHash BlindedPublicKey::GetStoreHash () const + { + i2p::data::IdentHash hash; + if (m_BlindedSigType == i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 || + m_BlindedSigType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) + { + char date[9]; + i2p::util::GetCurrentDate (date); + uint8_t blinded[32]; + GetBlindedKey (date, blinded); + auto stA1 = htobe16 (m_BlindedSigType); + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, (const uint8_t *)&stA1, 2); + SHA256_Update (&ctx, blinded, 32); + SHA256_Final ((uint8_t *)hash, &ctx); + } + else + LogPrint (eLogError, "LeaseSet2: blinded key type ", (int)m_BlindedSigType, " is not supported"); + return hash; + } + LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases): LeaseSet (storeLeases), m_StoreType (storeType) { @@ -533,24 +594,17 @@ namespace data char date[9]; i2p::util::GetCurrentDate (date); uint8_t blinded[32]; - BlindPublicKey (key, date, blinded); + key->GetBlindedKey (date, blinded); if (memcmp (blindedPublicKey, blinded, 32)) { LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match"); return; } } - // credentials - uint8_t credential[32], subcredential[36]; - // A = destination's signing public key - // stA = signature type of A, 2 bytes big endian - uint16_t stA = htobe16 (key->GetSigType ()); - // credential = H("credential", A || stA || stA1) - H ("credential", { {key->GetPublicKey (), key->GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {stA1, 2} }, credential); - // subcredential = H("subcredential", credential || blindedPublicKey) - H ("subcredential", { {credential, 32}, {blindedPublicKey, blindedKeyLen} }, subcredential); // outer key // outerInput = subcredential || publishedTimestamp + uint8_t subcredential[36]; + key->GetSubcredential (blindedPublicKey, blindedKeyLen, subcredential); memcpy (subcredential + 32, publishedTimestamp, 4); // outerSalt = outerCiphertext[0:32] // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44) @@ -563,6 +617,7 @@ namespace data std::vector outerPlainText (lenOuterPlaintext); i2p::crypto::ChaCha20 (outerCiphertext + 32, lenOuterPlaintext, keys, keys + 32, outerPlainText.data ()); // inner key + // innerInput = authCookie || subcredential || publishedTimestamp, TODO: non-empty authCookie // innerSalt = innerCiphertext[0:32] // keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44) // skip 1 byte flags @@ -586,47 +641,6 @@ namespace data } } - void LeaseSet2::H (const std::string& p, const std::vector >& bufs, uint8_t * hash) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, p.c_str (), p.length ()); - for (const auto& it: bufs) - SHA256_Update (&ctx, it.first, it.second); - SHA256_Final (hash, &ctx); - } - - void LeaseSet2::BlindPublicKey (std::shared_ptr key, const char * date, uint8_t * blindedKey) - { - uint16_t stA = htobe16 (key->GetSigType ()), stA1 = htobe16 (key->GetBlindedSigType ()); - uint8_t salt[32], seed[64]; - //seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64) - H ("I2PGenerateAlpha", { {key->GetPublicKey (), key->GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, salt); - i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed); - i2p::crypto::GetEd25519 ()->BlindPublicKey (key->GetPublicKey (), seed, blindedKey); - } - - void LeaseSet2::CalculateStoreHash (std::shared_ptr key, i2p::data::IdentHash& hash) - { - auto blindedKeyType = key->GetBlindedSigType (); - if (blindedKeyType != i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519 && - blindedKeyType != SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) - { - LogPrint (eLogError, "LeaseSet2: blinded key type ", (int)blindedKeyType, " is not supported"); - return; - } - char date[9]; - i2p::util::GetCurrentDate (date); - uint8_t blinded[32]; - BlindPublicKey (key, date, blinded); - auto stA1 = htobe16 (blindedKeyType); - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, (const uint8_t *)&stA1, 2); - SHA256_Update (&ctx, blinded, 32); - SHA256_Final ((uint8_t *)hash, &ctx); - } - void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const { auto encryptor = m_Encryptor; // TODO: atomic diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 9b3fc2b2..00892be8 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -141,6 +141,15 @@ namespace data SigningKeyType GetSigType () const { return m_SigType; }; SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; }; + void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes + void GetBlindedKey (const char * date, uint8_t * blindedKey) const; // blinded key 32 bytes, date is 8 chars "YYYYMMDD" + i2p::data::IdentHash GetStoreHash () const; + + private: + + void GetCredential (uint8_t * credential) const; // 32 bytes + void H (const std::string& p, const std::vector >& bufs, uint8_t * hash) const; + private: std::vector m_PublicKey; @@ -158,8 +167,6 @@ namespace data std::shared_ptr GetTransientVerifier () const { return m_TransientVerifier; }; void Update (const uint8_t * buf, size_t len, bool verifySignature); - static void CalculateStoreHash (std::shared_ptr key, i2p::data::IdentHash& hash); - // implements RoutingDestination void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const; @@ -175,10 +182,6 @@ namespace data uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; - // for encrypted LS - static void H (const std::string& p, const std::vector >& bufs, uint8_t * hash); - static void BlindPublicKey (std::shared_ptr key, const char * date, uint8_t * blindedKey); // blinded key 32 bytes, date is 8 chars "YYYYMMDD" - private: uint8_t m_StoreType;