diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 2371b529..8ce290f1 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -240,12 +240,17 @@ namespace crypto // x25519 X25519Keys::X25519Keys () { +#if OPENSSL_X25519 m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL); m_Pkey = nullptr; +#else + m_Ctx = BN_CTX_new (); +#endif } X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub) { +#if OPENSSL_X25519 m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); if (pub) @@ -255,16 +260,29 @@ namespace crypto size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); } +#else + m_Ctx = BN_CTX_new (); + memcpy (m_PrivateKey, priv, 32); + if (pub) + memcpy (m_PublicKey, pub, 32); + else + GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); +#endif } X25519Keys::~X25519Keys () { +#if OPENSSL_X25519 EVP_PKEY_CTX_free (m_Ctx); if (m_Pkey) EVP_PKEY_free (m_Pkey); +#else + BN_CTX_free (m_Ctx); +#endif } void X25519Keys::GenerateKeys () { +#if OPENSSL_X25519 if (m_Pkey) { EVP_PKEY_free (m_Pkey); @@ -276,11 +294,16 @@ namespace crypto m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx? size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); +#else + RAND_bytes (m_PrivateKey, 32); + GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); +#endif } bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) { if (!pub || (pub[31] & 0x80)) return false; // not x25519 key +#if OPENSSL_X25519 EVP_PKEY_derive_init (m_Ctx); auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32); if (!pkey) return false; @@ -288,17 +311,25 @@ namespace crypto size_t len = 32; EVP_PKEY_derive (m_Ctx, shared, &len); EVP_PKEY_free (pkey); +#else + GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx); +#endif return true; } void X25519Keys::GetPrivateKey (uint8_t * priv) const { +#if OPENSSL_X25519 size_t len = 32; EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len); +#else + memcpy (priv, m_PrivateKey, 32); +#endif } void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic) { +#if OPENSSL_X25519 if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx); if (m_Pkey) EVP_PKEY_free (m_Pkey); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); @@ -308,6 +339,11 @@ namespace crypto size_t len = 32; EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); } +#else + memcpy (m_PrivateKey, priv, 32); + if (calculatePublic) + GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); +#endif } // ElGamal diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 75bd7bb2..13d331c8 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -31,6 +31,7 @@ #if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 # define OPENSSL_HKDF 1 # define OPENSSL_EDDSA 1 +# define OPENSSL_X25519 1 # if (!defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER != 0x030000000)) // 3.0.0, regression in SipHash, not implemented in LibreSSL # define OPENSSL_SIPHASH 1 # endif @@ -69,8 +70,13 @@ namespace crypto private: uint8_t m_PublicKey[32]; +#if OPENSSL_X25519 EVP_PKEY_CTX * m_Ctx; EVP_PKEY * m_Pkey; +#else + BN_CTX * m_Ctx; + uint8_t m_PrivateKey[32]; +#endif bool m_IsElligatorIneligible = false; // true if definitely ineligible }; diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp index 47edb755..3e0795d5 100644 --- a/libi2pd/Ed25519.cpp +++ b/libi2pd/Ed25519.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2023, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -457,6 +457,86 @@ namespace crypto } } +#if !OPENSSL_X25519 + BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const + { + BN_CTX_start (ctx); + auto x1 = BN_CTX_get (ctx); BN_copy (x1, u); + auto x2 = BN_CTX_get (ctx); BN_one (x2); + auto z2 = BN_CTX_get (ctx); BN_zero (z2); + auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); + auto z3 = BN_CTX_get (ctx); BN_one (z3); + auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666); + auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); + unsigned int swap = 0; + auto bits = BN_num_bits (k); + while(bits) + { + --bits; + auto k_t = BN_is_bit_set(k, bits) ? 1 : 0; + swap ^= k_t; + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + swap = k_t; + BN_mod_sub(tmp0, x3, z3, q, ctx); + BN_mod_sub(tmp1, x2, z2, q, ctx); + BN_mod_add(x2, x2, z2, q, ctx); + BN_mod_add(z2, x3, z3, q, ctx); + BN_mod_mul(z3, tmp0, x2, q, ctx); + BN_mod_mul(z2, z2, tmp1, q, ctx); + BN_mod_sqr(tmp0, tmp1, q, ctx); + BN_mod_sqr(tmp1, x2, q, ctx); + BN_mod_add(x3, z3, z2, q, ctx); + BN_mod_sub(z2, z3, z2, q, ctx); + BN_mod_mul(x2, tmp1, tmp0, q, ctx); + BN_mod_sub(tmp1, tmp1, tmp0, q, ctx); + BN_mod_sqr(z2, z2, q, ctx); + BN_mod_mul(z3, tmp1, c121666, q, ctx); + BN_mod_sqr(x3, x3, q, ctx); + BN_mod_add(tmp0, tmp0, z3, q, ctx); + BN_mod_mul(z3, x1, z2, q, ctx); + BN_mod_mul(z2, tmp1, tmp0, q, ctx); + } + if (swap) + { + std::swap (x2, x3); + std::swap (z2, z3); + } + BN_mod_inverse (z2, z2, q, ctx); + BIGNUM * res = BN_new (); // not from ctx + BN_mod_mul(res, x2, z2, q, ctx); + BN_CTX_end (ctx); + return res; + } + + void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM * p1 = DecodeBN<32> (p); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); + } + + void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const + { + BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); + uint8_t k[32]; + memcpy (k, e, 32); + k[0] &= 248; k[31] &= 127; k[31] |= 64; + BIGNUM * n = DecodeBN<32> (k); + BIGNUM * q1 = ScalarMul (p1, n, ctx); + EncodeBN (q1, buf, 32); + BN_free (p1); BN_free (n); BN_free (q1); + } +#endif + void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded) { BN_CTX * ctx = BN_CTX_new (); diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h index 9c0ad801..470d802f 100644 --- a/libi2pd/Ed25519.h +++ b/libi2pd/Ed25519.h @@ -1,5 +1,5 @@ /* -* Copyright (c) 2013-2024, The PurpleI2P Project +* Copyright (c) 2013-2020, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -84,7 +84,10 @@ namespace crypto EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; - +#if !OPENSSL_X25519 + void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 + void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; +#endif void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 @@ -112,6 +115,11 @@ namespace crypto BIGNUM * DecodeBN (const uint8_t * buf) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; +#if !OPENSSL_X25519 + // for x25519 + BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; +#endif + private: BIGNUM * q, * l, * d, * I; diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 6b695371..98007620 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -66,12 +66,12 @@ namespace transport while (m_IsRunning) { int num, total = 0; - while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < m_QueueSize) + while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10) { CreateEphemeralKeys (num); total += num; } - if (total > m_QueueSize) + if (total >= 10) { LogPrint (eLogWarning, "Transports: ", total, " ephemeral keys generated at the time"); std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break @@ -124,12 +124,12 @@ namespace transport { if (pair) { - std::unique_lock l(m_AcquiredMutex); + std::unique_lockl(m_AcquiredMutex); if ((int)m_Queue.size () < 2*m_QueueSize) m_Queue.push (pair); } else - LogPrint(eLogError, "Transports: Return null keys"); + LogPrint(eLogError, "Transports: Return null DHKeys"); } void Peer::UpdateParams (std::shared_ptr router) @@ -149,7 +149,7 @@ namespace transport m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_CheckReserved(true), m_Thread (nullptr), m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), m_UpdateBandwidthTimer (nullptr), m_SSU2Server (nullptr), m_NTCP2Server (nullptr), - m_X25519KeysPairSupplier (NUM_X25519_PRE_GENERATED_KEYS), + m_X25519KeysPairSupplier (15), // 15 pre-generated keys m_TotalSentBytes (0), m_TotalReceivedBytes (0), m_TotalTransitTransmittedBytes (0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth (0), m_InBandwidth15s (0), m_OutBandwidth15s (0), m_TransitBandwidth15s (0), diff --git a/libi2pd/Transports.h b/libi2pd/Transports.h index c7eb7677..095cc81a 100644 --- a/libi2pd/Transports.h +++ b/libi2pd/Transports.h @@ -108,8 +108,7 @@ namespace transport const int PEER_TEST_DELAY_INTERVAL_VARIANCE = 30; // in milliseconds const int MAX_NUM_DELAYED_MESSAGES = 150; const int CHECK_PROFILE_NUM_DELAYED_MESSAGES = 15; // check profile after - const int NUM_X25519_PRE_GENERATED_KEYS = 25; // pre-generated x25519 keys pairs - + const int TRAFFIC_SAMPLE_COUNT = 301; // seconds struct TrafficSample diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6353a683..de319f5d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -49,6 +49,10 @@ set(test-gost-sig_SRCS test-gost-sig.cpp ) +set(test-x25519_SRCS + test-x25519.cpp +) + set(test-aeadchacha20poly1305_SRCS test-aeadchacha20poly1305.cpp ) @@ -73,6 +77,7 @@ add_executable(test-http-url ${test-http-url_SRCS}) add_executable(test-base-64 ${test-base-64_SRCS}) add_executable(test-gost ${test-gost_SRCS}) add_executable(test-gost-sig ${test-gost-sig_SRCS}) +add_executable(test-x25519 ${test-x25519_SRCS}) add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS}) add_executable(test-blinding ${test-blinding_SRCS}) add_executable(test-elligator ${test-elligator_SRCS}) @@ -97,6 +102,7 @@ target_link_libraries(test-http-url ${LIBS}) target_link_libraries(test-base-64 ${LIBS}) target_link_libraries(test-gost ${LIBS}) target_link_libraries(test-gost-sig ${LIBS}) +target_link_libraries(test-x25519 ${LIBS}) target_link_libraries(test-aeadchacha20poly1305 ${LIBS}) target_link_libraries(test-blinding ${LIBS}) target_link_libraries(test-elligator ${LIBS}) @@ -110,6 +116,7 @@ add_test(test-http-url ${TEST_PATH}/test-http-url) add_test(test-base-64 ${TEST_PATH}/test-base-64) add_test(test-gost ${TEST_PATH}/test-gost) add_test(test-gost-sig ${TEST_PATH}/test-gost-sig) +add_test(test-x25519 ${TEST_PATH}/test-x25519) add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305) add_test(test-blinding ${TEST_PATH}/test-blinding) add_test(test-elligator ${TEST_PATH}/test-elligator) diff --git a/tests/Makefile b/tests/Makefile index 51a11dfe..798fab42 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -7,7 +7,7 @@ LIBI2PD = ../libi2pd.a TESTS = \ test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \ - test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \ + test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding \ test-elligator test-eddsa ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS))) @@ -44,6 +44,9 @@ test-gost: test-gost.cpp $(LIBI2PD) test-gost-sig: test-gost-sig.cpp $(LIBI2PD) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) +test-x25519: test-x25519.cpp $(LIBI2PD) + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) + test-aeadchacha20poly1305: test-aeadchacha20poly1305.cpp $(LIBI2PD) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) diff --git a/tests/test-x25519.cpp b/tests/test-x25519.cpp new file mode 100644 index 00000000..a1f3f424 --- /dev/null +++ b/tests/test-x25519.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#include "Ed25519.h" + +const uint8_t k[32] = +{ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, + 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, + 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4 +}; + +const uint8_t u[32] = +{ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, + 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, + 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c +}; + +uint8_t p[32] = +{ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, + 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, + 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52 +}; + +int main () +{ +#if !OPENSSL_X25519 +// we test it for openssl < 1.1.0 + uint8_t buf[32]; + BN_CTX * ctx = BN_CTX_new (); + i2p::crypto::GetEd25519 ()->ScalarMul (u, k, buf, ctx); + BN_CTX_free (ctx); + assert(memcmp (buf, p, 32) == 0); +#endif +}