diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index d345c430..cdcd2bf9 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -276,6 +276,13 @@ namespace data return 128; } + const uint8_t * IdentityEx::GetSigningPublicKeyBuffer () const + { + auto keyLen = GetSigningPublicKeyLen (); + if (keyLen > 128) return nullptr; // P521 + return m_StandardIdentity.signingKey + 128 - keyLen; + } + size_t IdentityEx::GetSigningPrivateKeyLen () const { if (!m_Verifier) CreateVerifier (); diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index f9637b19..7e3c95dd 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -100,6 +100,7 @@ namespace data std::shared_ptr CreateEncryptor (const uint8_t * key) const; size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetSigningPublicKeyLen () const; + const uint8_t * GetSigningPublicKeyBuffer () const; // returns NULL for P521 size_t GetSigningPrivateKeyLen () const; size_t GetSignatureLen () const; bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 70c0d0fb..63b09337 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -427,7 +427,8 @@ namespace data size_t offset = 0; // blinded key if (len < 2) return; - uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2; + const uint8_t * stA1 = buf + offset; // stA1 = blinded signature type, 2 bytes big endian + uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2; std::unique_ptr blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType)); if (!blindedVerifier) return; auto blindedKeyLen = blindedVerifier->GetPublicKeyLen (); @@ -464,21 +465,22 @@ namespace data if (verified && identity && lenOuterCiphertext >= 32) { SetIsValid (false); // we must verify it again in Layer 2 - size_t l = identity->GetFullLen(); - std::vector destination (l); - l = identity->ToBuffer (destination.data(), l); - // outer key + // credentials uint8_t credential[32], subcredential[36]; - // credential = H("credential", Destination) - H ("credential", { {destination.data(), l} }, credential); + // A = destination's signing public key + // stA = signature type of A, 2 bytes big endian + uint16_t stA = htobe16 (identity->GetSigningKeyType ()); + // credential = H("credential", A || stA || stA1) + H ("credential", { {identity->GetSigningPublicKeyBuffer (), identity->GetSigningPublicKeyLen ()}, {(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 memcpy (subcredential + 32, publishedTimestamp, 4); // outerSalt = outerCiphertext[0:32] // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44) - uint8_t keys[44]; - HKDF (outerCiphertext, {subcredential, 36}, "ELS2_L1K", keys, 44); + uint8_t keys[64]; // 44 bytes actual data + HKDF (outerCiphertext, {subcredential, 36}, "ELS2_L1K", keys); // decrypt Layer 1 // outerKey = keys[0:31] // outerIV = keys[32:43] @@ -489,7 +491,7 @@ namespace data // innerSalt = innerCiphertext[0:32] // keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44) // skip 1 byte flags - HKDF (outerPlainText.data () + 1, {subcredential, 36}, "ELS2_L2K", keys, 44); // no authCookie + HKDF (outerPlainText.data () + 1, {subcredential, 36}, "ELS2_L2K", keys); // no authCookie // decrypt Layer 2 // innerKey = keys[0:31] // innerIV = keys[32:43] @@ -519,15 +521,15 @@ namespace data SHA256_Final (hash, &ctx); } - void LeaseSet2::HKDF (const uint8_t * salt, const std::pair& ikm, const char * info, uint8_t * out, size_t outLen) - { - uint8_t prk[32], t[41]; unsigned int len; + void LeaseSet2::HKDF (const uint8_t * salt, const std::pair& ikm, const std::string& info, uint8_t * out) + { + uint8_t prk[32]; unsigned int len; HMAC(EVP_sha256(), salt, 32, ikm.first, ikm.second, prk, &len); - memcpy (t, info, 8); t[8] = 0x01; - HMAC(EVP_sha256(), prk, 32, t, 9, out, &len); - memcpy (t, out, 32); memcpy (t + 32, info, 8); t[40] = 0x02; - HMAC(EVP_sha256(), prk, 32, t, 41, t, &len); - memcpy (out + 32, t, outLen % 32); // outLen doesn't exceed 64 + auto l = info.length (); + memcpy (out, info.c_str (), l); out[l] = 0x01; + HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len); + memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02; + HMAC(EVP_sha256(), prk, 32, out, 41, out + 32, &len); } void LeaseSet2::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 01202e9e..84988a65 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -156,7 +156,7 @@ namespace data // for encrypted LS void H (const std::string& p, const std::vector >& bufs, uint8_t * hash); - void HKDF (const uint8_t * salt, const std::pair& ikm, const char * info, uint8_t * out, size_t outLen); // salt - 32, info - 8 + void HKDF (const uint8_t * salt, const std::pair& ikm, const std::string& info, uint8_t * out); // salt - 32, out - 64, info <= 32 private: