diff --git a/libi2pd/Family.cpp b/libi2pd/Family.cpp index 3fb5d862..b7cbf7d4 100644 --- a/libi2pd/Family.cpp +++ b/libi2pd/Family.cpp @@ -64,7 +64,8 @@ namespace data i2p::crypto::bn2buf (x, signingKey, 32); i2p::crypto::bn2buf (y, signingKey + 32, 32); BN_free (x); BN_free (y); - verifier = std::make_shared(signingKey); + verifier = std::make_shared(); + verifier->SetPublicKey (signingKey); } else LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 0e49b8ad..13ed46b0 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -318,62 +318,56 @@ namespace data return CRYPTO_KEY_TYPE_ELGAMAL; } - void IdentityEx::CreateVerifier () const + i2p::crypto::Verifier * IdentityEx::CreateVerifier (uint16_t keyType) { - if (m_Verifier) return; // don't create again - auto keyType = GetSigningKeyType (); switch (keyType) { case SIGNING_KEY_TYPE_DSA_SHA1: - UpdateVerifier (new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey)); - break; + return new i2p::crypto::DSAVerifier (); case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: - { - size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 - UpdateVerifier (new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding)); - break; - } + return new i2p::crypto::ECDSAP256Verifier (); case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: - { - size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 - UpdateVerifier (new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding)); - break; - } + return new i2p::crypto::ECDSAP384Verifier (); case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: - { - uint8_t signingKey[i2p::crypto::ECDSAP521_KEY_LENGTH]; - memcpy (signingKey, m_StandardIdentity.signingKey, 128); - size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128 - memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types - UpdateVerifier (new i2p::crypto::ECDSAP521Verifier (signingKey)); - break; - } + return new i2p::crypto::ECDSAP521Verifier (); + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + return new i2p::crypto::EDDSA25519Verifier (); + case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: + return new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA); + case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: + return new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512); case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: LogPrint (eLogError, "Identity: RSA signing key type ", (int)keyType, " is not supported"); break; - case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - { - size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - UpdateVerifier (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding)); - break; - } - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - { - size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64 - UpdateVerifier (new i2p::crypto::GOSTR3410_256_Verifier (i2p::crypto::eGOSTR3410CryptoProA, m_StandardIdentity.signingKey + padding)); - break; - } - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: - { - // zero padding - UpdateVerifier (new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512, m_StandardIdentity.signingKey)); - break; - } default: LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported"); } + return nullptr; + } + + void IdentityEx::CreateVerifier () const + { + if (m_Verifier) return; // don't create again + auto verifier = CreateVerifier (GetSigningKeyType ()); + if (verifier) + { + auto keyLen = verifier->GetPublicKeyLen (); + if (keyLen <= 128) + verifier->SetPublicKey (m_StandardIdentity.signingKey + 128 - keyLen); + else + { + // for P521 + uint8_t * signingKey = new uint8_t[keyLen]; + memcpy (signingKey, m_StandardIdentity.signingKey, 128); + size_t excessLen = keyLen - 128; + memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types + verifier->SetPublicKey (signingKey); + delete[] signingKey; + } + } + UpdateVerifier (verifier); } void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 584e6475..268068aa 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -91,11 +91,11 @@ namespace data size_t ToBuffer (uint8_t * buf, size_t len) const; size_t FromBase64(const std::string& s); std::string ToBase64 () const; - const Identity& GetStandardIdentity () const { return m_StandardIdentity; }; + const Identity& GetStandardIdentity () const { return m_StandardIdentity; }; const IdentHash& GetIdentHash () const { return m_IdentHash; }; - const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; }; - uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; }; + const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; }; + uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; }; std::shared_ptr CreateEncryptor (const uint8_t * key) const; size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetSigningPublicKeyLen () const; @@ -107,10 +107,11 @@ namespace data CryptoKeyType GetCryptoKeyType () const; void DropVerifier () const; // to save memory - bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); } - - void RecalculateIdentHash(uint8_t * buff=nullptr); + bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); } + void RecalculateIdentHash(uint8_t * buff=nullptr); + static i2p::crypto::Verifier * CreateVerifier (uint16_t keyType); + private: void CreateVerifier () const; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 2999f2f2..a0f781a6 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -245,14 +245,34 @@ namespace data uint16_t expires = bufbe16toh (buf + offset); offset += 2; // expires (seconds) SetExpirationTime ((timestamp + expires)*1000LL); // in milliseconds uint16_t flags = bufbe16toh (buf + offset); offset += 2; // flags - if (flags) return; // offline keys not supported + std::unique_ptr offlineVerifier; + if (flags & 0x0001) + { + // offline key + uint16_t keyType = bufbe16toh (buf + offset); offset += 2; + offlineVerifier.reset (i2p::data::IdentityEx::CreateVerifier (keyType)); + if (!offlineVerifier) return; + auto keyLen = offlineVerifier->GetPublicKeyLen (); + if (offset + keyLen >= len) return; + offlineVerifier->SetPublicKey (buf + offset); offset += keyLen; + if (offset + offlineVerifier->GetSignatureLen () >= len) return; + uint8_t * signedData = new uint8_t[keyLen + 6]; + htobe32buf (signedData, timestamp + expires); + htobe16buf (signedData + 4, keyType); + memcpy (signedData + 6, buf + offset - keyLen, keyLen); + bool verified = identity->Verify (signedData, keyLen + 6, buf + offset); + delete[] signedData; + if (!verified) return; + offset += offlineVerifier->GetSignatureLen (); + } + // properties uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; offset += propertiesLen; // skip for now. TODO: implement properties if (offset + 1 >= len) return; // key sections - //int numKeySections = buf[offset]; offset++; - //for (int i = 0; i < numKeySections; i++) + int numKeySections = buf[offset]; offset++; + for (int i = 0; i < numKeySections; i++) { // skip key for now. TODO: implement encryption key offset += 2; // encryption key type @@ -269,7 +289,7 @@ namespace data uint8_t * buf1 = new uint8_t[offset + 1]; buf1[0] = m_StoreType; memcpy (buf1 + 1, buf, offset); // TODO: implement it better - bool verified = identity->Verify (buf1, offset + 1, buf + offset); // assume online keys + bool verified = offlineVerifier ? offlineVerifier->Verify (buf1, offset + 1, buf + offset) : identity->Verify (buf1, offset + 1, buf + offset); delete[] buf1; if (!verified) LogPrint (eLogWarning, "LeaseSet2: verification failed"); diff --git a/libi2pd/Signature.cpp b/libi2pd/Signature.cpp index 1facccbc..c82c85df 100644 --- a/libi2pd/Signature.cpp +++ b/libi2pd/Signature.cpp @@ -7,36 +7,44 @@ namespace i2p namespace crypto { #if OPENSSL_EDDSA - EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey) + EDDSA25519Verifier::EDDSA25519Verifier () { - m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32); m_MDCtx = EVP_MD_CTX_create (); - EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey); } EDDSA25519Verifier::~EDDSA25519Verifier () { EVP_MD_CTX_destroy (m_MDCtx); - EVP_PKEY_free (m_Pkey); + if (m_Pkey) EVP_PKEY_free (m_Pkey); } + void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) + { + m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32); + EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey); + } + bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len); } #else - EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey) + EDDSA25519Verifier::EDDSA25519Verifier () { - memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); - BN_CTX * ctx = BN_CTX_new (); - m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); - BN_CTX_free (ctx); } EDDSA25519Verifier::~EDDSA25519Verifier () { } + + void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) + { + memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); + BN_CTX * ctx = BN_CTX_new (); + m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); + BN_CTX_free (ctx); + } bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index a51f8955..84d4b0aa 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -24,6 +24,7 @@ namespace crypto virtual size_t GetPublicKeyLen () const = 0; virtual size_t GetSignatureLen () const = 0; virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; }; + virtual void SetPublicKey (const uint8_t * signingKey) = 0; }; class Signer @@ -41,9 +42,13 @@ namespace crypto { public: - DSAVerifier (const uint8_t * signingKey) + DSAVerifier () { m_PublicKey = CreateDSA (); + } + + void SetPublicKey (const uint8_t * signingKey) + { DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); } @@ -154,9 +159,13 @@ namespace crypto { public: - ECDSAVerifier (const uint8_t * signingKey) + ECDSAVerifier () { m_PublicKey = EC_KEY_new_by_curve_name (curve); + } + + void SetPublicKey (const uint8_t * signingKey) + { BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL); BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL); EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y); @@ -275,7 +284,8 @@ namespace crypto { public: - EDDSA25519Verifier (const uint8_t * signingKey); + EDDSA25519Verifier (); + void SetPublicKey (const uint8_t * signingKey); ~EDDSA25519Verifier (); bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; @@ -386,15 +396,22 @@ namespace crypto enum { keyLen = Hash::hashLen }; - GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey): - m_ParamSet (paramSet) + GOSTR3410Verifier (GOSTR3410ParamSet paramSet): + m_ParamSet (paramSet), m_PublicKey (nullptr) + { + } + + void SetPublicKey (const uint8_t * signingKey) { BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL); BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL); m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y); BN_free (x); BN_free (y); } - ~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); } + ~GOSTR3410Verifier () + { + if (m_PublicKey) EC_POINT_free (m_PublicKey); + } bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const {