diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 4170fd5a..cc26a857 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -432,6 +432,9 @@ namespace data m_Public = std::make_shared(Identity (keys)); memcpy (m_PrivateKey, keys.privateKey, 256); // 256 memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ()); + m_OfflineSignature.resize (0); + m_TransientSignatureLen = 0; + m_TransientSigningPrivateKeyLen = 0; m_Signer = nullptr; CreateSigner (); return *this; @@ -442,11 +445,22 @@ namespace data m_Public = std::make_shared(*other.m_Public); memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256 memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public->GetSigningPrivateKeyLen ()); + m_OfflineSignature = other.m_OfflineSignature; + m_TransientSignatureLen = other.m_TransientSignatureLen; + m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen; m_Signer = nullptr; CreateSigner (); return *this; } + size_t PrivateKeys::GetFullLen () const + { + size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); + if (IsOfflineSignature ()) + ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen; + return ret; + } + size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len) { m_Public = std::make_shared(); @@ -485,15 +499,16 @@ namespace data return 0; } ret += m_Public->GetSignatureLen (); + m_TransientSignatureLen = transientVerifier->GetSignatureLen (); // copy offline signature size_t offlineInfoLen = buf + ret - offlineInfo; m_OfflineSignature.resize (offlineInfoLen); memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen); // override signing private key - signingPrivateKeySize = transientVerifier->GetPrivateKeyLen (); - if (signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; - memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); - ret += signingPrivateKeySize; + m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen (); + if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0; + memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen); + ret += m_TransientSigningPrivateKeyLen; CreateSigner (keyType); } else @@ -508,9 +523,23 @@ namespace data ret += 256; size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); if(ret + signingPrivateKeySize > len) return 0; // overflow - memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); + if (IsOfflineSignature ()) + memset (buf + ret, 0, signingPrivateKeySize); + else + memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); ret += signingPrivateKeySize; - // TODO: implement offline info + if (IsOfflineSignature ()) + { + // offline signature + auto offlineSignatureLen = m_OfflineSignature.size (); + if (ret + offlineSignatureLen > len) return 0; + memcpy (buf + ret, m_OfflineSignature.data (), offlineSignatureLen); + ret += offlineSignatureLen; + // transient private key + if (ret + m_TransientSigningPrivateKeyLen > len) return 0; + memcpy (buf + ret, m_SigningPrivateKey, m_TransientSigningPrivateKeyLen); + ret += m_TransientSigningPrivateKeyLen; + } return ret; } @@ -589,7 +618,7 @@ namespace data size_t PrivateKeys::GetSignatureLen () const { - return m_Public->GetSignatureLen (); + return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen (); } uint8_t * PrivateKeys::GetPadding() @@ -634,35 +663,7 @@ namespace data PrivateKeys keys; // signature uint8_t signingPublicKey[512]; // signing public key is 512 bytes max - switch (type) - { - case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: - i2p::crypto::CreateECDSAP256RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); - break; - case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: - i2p::crypto::CreateECDSAP384RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); - break; - case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: - i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); - break; - case SIGNING_KEY_TYPE_RSA_SHA256_2048: - case SIGNING_KEY_TYPE_RSA_SHA384_3072: - case SIGNING_KEY_TYPE_RSA_SHA512_4096: - LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); - // no break here - case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); - break; - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey); - break; - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: - i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey); - break; - default: - LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); - return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 - } + GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, signingPublicKey); // encryption uint8_t publicKey[256]; GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); @@ -675,6 +676,39 @@ namespace data return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 } + void PrivateKeys::GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub) + { + switch (type) + { + case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: + i2p::crypto::CreateECDSAP256RandomKeys (priv, pub); + break; + case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: + i2p::crypto::CreateECDSAP384RandomKeys (priv, pub); + break; + case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: + i2p::crypto::CreateECDSAP521RandomKeys (priv, pub); + break; + case SIGNING_KEY_TYPE_RSA_SHA256_2048: + case SIGNING_KEY_TYPE_RSA_SHA384_3072: + case SIGNING_KEY_TYPE_RSA_SHA512_4096: + LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); + // no break here + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); + break; + case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: + i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, priv, pub); + break; + case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: + i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, priv, pub); + break; + default: + LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); + i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1 + } + } + void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub) { switch (type) @@ -694,6 +728,27 @@ namespace data } } + PrivateKeys PrivateKeys::CreateOfflineKeys (SigningKeyType type, uint32_t expires) const + { + PrivateKeys keys (*this); + std::unique_ptr verifier (IdentityEx::CreateVerifier (type)); + if (verifier) + { + size_t pubKeyLen = verifier->GetPublicKeyLen (); + keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen (); + keys.m_TransientSignatureLen = verifier->GetSignatureLen (); + keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6); + htobe32buf (keys.m_OfflineSignature.data (), expires); // expires + htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type + GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 4); // public key + Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6); // signature + // recreate signer + keys.m_Signer = nullptr; + keys.CreateSigner (); + } + return keys; + } + Keys CreateRandomKeys () { Keys keys; diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 1c04916d..476038cd 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -144,12 +144,12 @@ namespace data const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; size_t GetSignatureLen () const; // might not match identity - bool IsOfflineSignature () const { return m_OfflineSignature.size () > 0; }; + bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; }; uint8_t * GetPadding(); void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); } void Sign (const uint8_t * buf, int len, uint8_t * signature) const; - size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); }; + size_t GetFullLen () const; size_t FromBuffer (const uint8_t * buf, size_t len); size_t ToBuffer (uint8_t * buf, size_t len) const; @@ -160,8 +160,11 @@ namespace data static std::shared_ptr CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key); static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); + static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub); static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long + PrivateKeys CreateOfflineKeys (SigningKeyType type, uint32_t expires) const; + private: void CreateSigner () const; @@ -174,6 +177,8 @@ namespace data uint8_t m_SigningPrivateKey[128]; // assume private key doesn't exceed 128 bytes mutable std::unique_ptr m_Signer; std::vector m_OfflineSignature; // non zero length, if applicable + size_t m_TransientSignatureLen = 0; + size_t m_TransientSigningPrivateKeyLen = 0; }; // kademlia