diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 64ddeaf4..87c7d6db 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -121,8 +121,8 @@ namespace crypto return passed; } - void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, - uint8_t * signature) const + void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, + const uint8_t * buf, size_t len, uint8_t * signature) const { BN_CTX * bnCtx = BN_CTX_new (); // calculate r @@ -153,6 +153,44 @@ namespace crypto BN_CTX_free (bnCtx); } + void Ed25519::SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, + const uint8_t * buf, size_t len, uint8_t * signature) const + { + BN_CTX * bnCtx = BN_CTX_new (); + // T = 80 random bytes + uint8_t T[80]; + RAND_bytes (T, 80); + // calculate r = H*(T || publickey || data) + SHA512_CTX ctx; + SHA512_Init (&ctx); + SHA512_Update (&ctx, T, 80); + SHA512_Update (&ctx, publicKeyEncoded, 32); + SHA512_Update (&ctx, buf, len); // data + uint8_t digest[64]; + SHA512_Final (digest, &ctx); + BIGNUM * r = DecodeBN<64> (digest); + BN_mod (r, r, l, bnCtx); // % l + EncodeBN (r, digest, 32); + // calculate R + uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf + EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); + // calculate S + SHA512_Init (&ctx); + SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R + SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key + SHA512_Update (&ctx, buf, len); // data + SHA512_Final (digest, &ctx); + BIGNUM * h = DecodeBN<64> (digest); + // S = (r + h*a) % l + BIGNUM * a = DecodeBN (privateKey); + BN_mod_mul (h, h, a, l, bnCtx); // %l + BN_mod_add (h, h, r, l, bnCtx); // %l + memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); + EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S + BN_free (r); BN_free (h); BN_free (a); + BN_CTX_free (bnCtx); + } + EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const { // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) @@ -514,6 +552,18 @@ namespace crypto expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit } + void Ed25519::CreateRedDSAPrivateKey (uint8_t * priv) + { + uint8_t seed[32]; + RAND_bytes (seed, 32); + BIGNUM * p = DecodeBN<32> (seed); + BN_CTX * ctx = BN_CTX_new (); + BN_mod (p, p, l, ctx); // % l + EncodeBN (p, priv, 32); + BN_CTX_free (ctx); + BN_free (p); + } + static std::unique_ptr g_Ed25519; std::unique_ptr& GetEd25519 () { diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index 18f749ea..eb08faeb 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -84,9 +84,11 @@ namespace crypto bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; - + void SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; + static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes - + void CreateRedDSAPrivateKey (uint8_t * priv); // priv is 32 bytes + private: EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index a6b83fca..759c2ab3 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -338,12 +338,13 @@ namespace data case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: return new i2p::crypto::ECDSAP521Verifier (); case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - case SIGNING_KEY_TYPE_REDDSA_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_REDDSA_SHA512_ED25519: + return new i2p::crypto::RedDSA25519Verifier (); case SIGNING_KEY_TYPE_RSA_SHA256_2048: case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA512_4096: @@ -611,7 +612,6 @@ namespace data LogPrint (eLogError, "Identity: RSA signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported"); break; case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, IsOfflineSignature () ? nullptr: m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check break; case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: @@ -620,6 +620,9 @@ namespace data case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: m_Signer.reset (new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, m_SigningPrivateKey)); break; + case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: + m_Signer.reset (new i2p::crypto::RedDSA25519Signer (m_SigningPrivateKey)); + break; default: LogPrint (eLogError, "Identity: Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported"); } @@ -704,7 +707,6 @@ namespace data LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); // no break here case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); break; case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: @@ -713,6 +715,9 @@ namespace data case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, priv, pub); break; + case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: + i2p::crypto::CreateRedDSA25519RandomKeys (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 diff --git a/libi2pd/Signature.h b/libi2pd/Signature.h index 84d4b0aa..0c5f27d6 100644 --- a/libi2pd/Signature.h +++ b/libi2pd/Signature.h @@ -487,6 +487,42 @@ namespace crypto typedef GOSTR3410Signer GOSTR3410_256_Signer; typedef GOSTR3410Verifier GOSTR3410_512_Verifier; typedef GOSTR3410Signer GOSTR3410_512_Signer; + + // RedDSA + typedef EDDSA25519Verifier RedDSA25519Verifier; + class RedDSA25519Signer: public Signer + { + public: + + RedDSA25519Signer (const uint8_t * signingPrivateKey) + { + memcpy (m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); + BN_CTX * ctx = BN_CTX_new (); + auto publicKey = GetEd25519 ()->GeneratePublicKey (m_PrivateKey, ctx); + GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx); + BN_CTX_free (ctx); + } + ~RedDSA25519Signer () {}; + + void Sign (const uint8_t * buf, int len, uint8_t * signature) const + { + GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature); + } + + const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation + + private: + + uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH]; + uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; + }; + + inline void CreateRedDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey); + RedDSA25519Signer signer (signingPrivateKey); + memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); + } } }