diff --git a/Makefile.linux b/Makefile.linux index 0fd8873d..eec1e2cc 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -21,6 +21,8 @@ else ifeq ($(shell expr match ${CXXVER} "4\.6"),3) # = 4.6 NEEDED_CXXFLAGS += -std=c++0x else ifeq ($(shell expr match ${CXXVER} "[5-7]\.[0-9]"),3) # gcc >= 5.0 NEEDED_CXXFLAGS += -std=c++11 +else ifeq ($(shell expr match ${CXXVER} "7"),1) # gcc 7 ubuntu + NEEDED_CXXFLAGS += -std=c++11 else # not supported $(error Compiler too old) endif diff --git a/Makefile.mingw b/Makefile.mingw index 5b9332e2..b40d0ada 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -4,8 +4,8 @@ WINDRES = windres CXXFLAGS = -Os -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN NEEDED_CXXFLAGS = -std=c++11 BOOST_SUFFIX = -mt -INCFLAGS = -I/usr/include/ -I/usr/local/include/ -I. -Idaemon -LDFLAGS = -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ -L/usr/local/lib +INCFLAGS = -Idaemon -I. +LDFLAGS = -s -Wl,-rpath,/usr/local/lib -Wl,-Bstatic -static-libgcc -static-libstdc++ # UPNP Support ifeq ($(USE_UPNP),yes) @@ -30,7 +30,7 @@ LDLIBS += \ ifeq ($(USE_WIN32_APP), yes) CXXFLAGS += -DWIN32_APP - LDFLAGS += -mwindows -s + LDFLAGS += -mwindows DAEMON_RC += Win32/Resource.rc DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index 4c7eae03..f58b4615 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -368,6 +368,9 @@ namespace win32 void StopWin32App () { + HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); + if (hWnd) + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0); UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); } @@ -375,7 +378,7 @@ namespace win32 { HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); if (hWnd) - PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); return hWnd; } @@ -383,7 +386,7 @@ namespace win32 { HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); if (hWnd) - PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0); + PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0); return hWnd; } diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 03e4c450..1f18beb7 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -36,6 +36,7 @@ set (LIBI2PD_SRC "${LIBI2PD_SRC_DIR}/BloomFilter.cpp" "${LIBI2PD_SRC_DIR}/Config.cpp" "${LIBI2PD_SRC_DIR}/Crypto.cpp" + "${LIBI2PD_SRC_DIR}/CryptoKey.cpp" "${LIBI2PD_SRC_DIR}/Garlic.cpp" "${LIBI2PD_SRC_DIR}/Gzip.cpp" "${LIBI2PD_SRC_DIR}/HTTP.cpp" diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index 6c7407f1..7015954f 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -18,22 +18,27 @@ set MSYS2_PATH_TYPE=inherit set CHERE_INVOKING=enabled_from_arguments set MSYSTEM=MSYS +set "xSH=%WD%bash -lc" + REM detecting number of processors and subtract 1. set /a threads=%NUMBER_OF_PROCESSORS%-1 REM we must work in root of repo cd .. +REM deleting old log files +del /S build_*.log >> nul + echo Receiving latest commit and cleaning up... -"%WD%bash" -lc "git pull && make clean" > build/build_git.log 2>&1 +%xSH% "git pull && make clean" > build/build_git.log 2>&1 echo. REM set to variable current commit hash -FOR /F "usebackq" %%a IN (`%WD%bash -lc 'git describe --tags'`) DO ( +FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO ( set tag=%%a ) -"%WD%bash" -lc "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul +%xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul REM starting building set MSYSTEM=MINGW32 @@ -55,12 +60,12 @@ exit /b 0 :BUILDING echo Building i2pd %tag% for win%bitness%: echo Build AVX+AESNI... -"%WD%bash" -lc "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 +%xSH% "make USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 echo Build AVX... -"%WD%bash" -lc "make USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 +%xSH% "make USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 echo Build AESNI... -"%WD%bash" -lc "make USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 +%xSH% "make USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 echo Build without extensions... -"%WD%bash" -lc "make USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 +%xSH% "make USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 :EOF \ No newline at end of file diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index d08b6d20..0577ac15 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -908,7 +908,11 @@ namespace http { i2p::win32::StopGracefulShutdown (); #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { +#ifndef WIN32_APP Daemon.running = false; +#else + i2p::win32::StopWin32App (); +#endif } else { res.code = 400; ShowError(s, "Unknown command: " + cmd); @@ -951,8 +955,8 @@ namespace http { if (needAuth && pass == "") { uint8_t random[16]; char alnum[] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; pass.resize(sizeof(random)); RAND_bytes(random, sizeof(random)); for (size_t i = 0; i < sizeof(random); i++) { diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index caae5d82..ddd42f0d 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -372,8 +372,8 @@ namespace crypto BN_CTX_free (ctx); } -// ECICS - void ECICSEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) +// ECIES + void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) { BN_CTX_start (ctx); BIGNUM * q = BN_CTX_get (ctx); @@ -385,10 +385,11 @@ namespace crypto auto p = EC_POINT_new (curve); EC_POINT_mul (curve, p, k, nullptr, nullptr, ctx); BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); - EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); - bn2buf (x, encrypted, len); - bn2buf (y, encrypted + len, len); - RAND_bytes (encrypted + 2*len, 256 - 2*len); + EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); + encrypted[0] = 0; + bn2buf (x, encrypted + 1, len); + bn2buf (y, encrypted + 1 + len, len); + RAND_bytes (encrypted + 1 + 2*len, 256 - 2*len); // ecryption key and iv EC_POINT_mul (curve, p, nullptr, key, k, ctx); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); @@ -402,15 +403,16 @@ namespace crypto memcpy (m+33, data, 222); SHA256 (m+33, 222, m+1); // encrypt + encrypted[257] = 0; CBCEncryption encryption; encryption.SetKey (shared); encryption.SetIV (iv); - encryption.Encrypt (m, 256, encrypted + 256); + encryption.Encrypt (m, 256, encrypted + 258); EC_POINT_free (p); BN_CTX_end (ctx); } - bool ECICSDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) { bool ret = true; BN_CTX_start (ctx); @@ -419,8 +421,8 @@ namespace crypto int len = BN_num_bytes (q); // point for shared secret BIGNUM * x = BN_CTX_get (ctx), * y = BN_CTX_get (ctx); - BN_bin2bn (encrypted, len, x); - BN_bin2bn (encrypted + len, len, y); + BN_bin2bn (encrypted + 1, len, x); + BN_bin2bn (encrypted + 1 + len, len, y); auto p = EC_POINT_new (curve); if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr)) { @@ -437,7 +439,7 @@ namespace crypto CBCDecryption decryption; decryption.SetKey (shared); decryption.SetIV (iv); - decryption.Decrypt (encrypted + 256, 256, m); + decryption.Decrypt (encrypted + 258, 256, m); // verify and copy uint8_t hash[32]; SHA256 (m + 33, 222, hash); @@ -460,7 +462,7 @@ namespace crypto return ret; } - void GenerateECICSKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub) + void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub) { BN_CTX * ctx = BN_CTX_new (); BIGNUM * q = BN_new (); diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 18948490..2b1bf6a0 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -52,10 +52,10 @@ namespace crypto bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false); void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub); - // ECICS - void ECICSEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 512 bytes encrypted - bool ECICSDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); - void GenerateECICSKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); + // ECIES + void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 514 bytes encrypted + bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); // HMAC typedef i2p::data::Tag<32> MACKey; diff --git a/libi2pd/CryptoKey.cpp b/libi2pd/CryptoKey.cpp new file mode 100644 index 00000000..b1adf2f0 --- /dev/null +++ b/libi2pd/CryptoKey.cpp @@ -0,0 +1,151 @@ +#include +#include "Log.h" +#include "Gost.h" +#include "CryptoKey.h" + +namespace i2p +{ +namespace crypto +{ + ElGamalEncryptor::ElGamalEncryptor (const uint8_t * pub) + { + memcpy (m_PublicKey, pub, 256); + } + + void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + { + ElGamalEncrypt (m_PublicKey, data, encrypted, ctx, true); + } + + ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv) + { + memcpy (m_PrivateKey, priv, 256); + } + + bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + { + return ElGamalDecrypt (m_PrivateKey, encrypted, data, ctx, true); + } + + ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub) + { + m_Curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); + m_PublicKey = EC_POINT_new (m_Curve); + BIGNUM * x = BN_bin2bn (pub, 32, nullptr); + BIGNUM * y = BN_bin2bn (pub + 32, 32, nullptr); + if (!EC_POINT_set_affine_coordinates_GFp (m_Curve, m_PublicKey, x, y, nullptr)) + LogPrint (eLogError, "ECICS P256 invalid public key"); + BN_free (x); BN_free (y); + } + + ECIESP256Encryptor::~ECIESP256Encryptor () + { + if (m_Curve) EC_GROUP_free (m_Curve); + if (m_PublicKey) EC_POINT_free (m_PublicKey); + } + + void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + { + if (m_Curve && m_PublicKey) + ECIESEncrypt (m_Curve, m_PublicKey, data, encrypted, ctx); + } + + ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv) + { + m_Curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); + m_PrivateKey = BN_bin2bn (priv, 32, nullptr); + } + + ECIESP256Decryptor::~ECIESP256Decryptor () + { + if (m_Curve) EC_GROUP_free (m_Curve); + if (m_PrivateKey) BN_free (m_PrivateKey); + } + + bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + { + if (m_Curve && m_PrivateKey) + return ECIESDecrypt (m_Curve, m_PrivateKey, encrypted, data, ctx); + return false; + } + + void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub) + { + EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); + EC_POINT * p = nullptr; + BIGNUM * key = nullptr; + GenerateECIESKeyPair (curve, key, p); + bn2buf (key, priv, 32); + RAND_bytes (priv + 32, 224); + BN_free (key); + BIGNUM * x = BN_new (), * y = BN_new (); + EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL); + bn2buf (x, pub, 32); + bn2buf (y, pub + 32, 32); + RAND_bytes (pub + 64, 192); + EC_POINT_free (p); + BN_free (x); BN_free (y); + EC_GROUP_free (curve); + } + + ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub) + { + auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA); + m_PublicKey = EC_POINT_new (curve->GetGroup ()); + BIGNUM * x = BN_bin2bn (pub, 32, nullptr); + BIGNUM * y = BN_bin2bn (pub + 32, 32, nullptr); + if (!EC_POINT_set_affine_coordinates_GFp (curve->GetGroup (), m_PublicKey, x, y, nullptr)) + LogPrint (eLogError, "ECICS GOST R 34.10 invalid public key"); + BN_free (x); BN_free (y); + } + + ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor () + { + if (m_PublicKey) EC_POINT_free (m_PublicKey); + } + + void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) + { + if (m_PublicKey) + ECIESEncrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PublicKey, data, encrypted, ctx); + } + + ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv) + { + m_PrivateKey = BN_bin2bn (priv, 32, nullptr); + } + + ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor () + { + if (m_PrivateKey) BN_free (m_PrivateKey); + } + + bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) + { + if (m_PrivateKey) + return ECIESDecrypt (GetGOSTR3410Curve (eGOSTR3410CryptoProA)->GetGroup (), m_PrivateKey, encrypted, data, ctx); + return false; + } + + + void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub) + { + auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA); + EC_POINT * p = nullptr; + BIGNUM * key = nullptr; + GenerateECIESKeyPair (curve->GetGroup (), key, p); + bn2buf (key, priv, 32); + RAND_bytes (priv + 32, 224); + BN_free (key); + BIGNUM * x = BN_new (), * y = BN_new (); + EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL); + bn2buf (x, pub, 32); + bn2buf (y, pub + 32, 32); + RAND_bytes (pub + 64, 192); + EC_POINT_free (p); + BN_free (x); BN_free (y); + } + +} +} + diff --git a/libi2pd/CryptoKey.h b/libi2pd/CryptoKey.h new file mode 100644 index 00000000..a2cfdd87 --- /dev/null +++ b/libi2pd/CryptoKey.h @@ -0,0 +1,119 @@ +#ifndef CRYPTO_KEY_H__ +#define CRYPTO_KEY_H__ + +#include +#include "Crypto.h" + +namespace i2p +{ +namespace crypto +{ + class CryptoKeyEncryptor + { + public: + + virtual ~CryptoKeyEncryptor () {}; + virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted + }; + + class CryptoKeyDecryptor + { + public: + + virtual ~CryptoKeyDecryptor () {}; + virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) = 0; // 512 bytes encrypted, 222 bytes data + }; + +// ElGamal + class ElGamalEncryptor: public CryptoKeyEncryptor // for destination + { + public: + + ElGamalEncryptor (const uint8_t * pub); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + + private: + + uint8_t m_PublicKey[256]; + }; + + class ElGamalDecryptor: public CryptoKeyDecryptor // for destination + { + public: + + ElGamalDecryptor (const uint8_t * priv); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + + private: + + uint8_t m_PrivateKey[256]; + }; + +// ECIES P256 + + class ECIESP256Encryptor: public CryptoKeyEncryptor + { + public: + + ECIESP256Encryptor (const uint8_t * pub); + ~ECIESP256Encryptor (); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + + private: + + EC_GROUP * m_Curve; + EC_POINT * m_PublicKey; + }; + + + class ECIESP256Decryptor: public CryptoKeyDecryptor + { + public: + + ECIESP256Decryptor (const uint8_t * priv); + ~ECIESP256Decryptor (); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + + private: + + EC_GROUP * m_Curve; + BIGNUM * m_PrivateKey; + }; + + void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub); + +// ECIES GOST R 34.10 + + class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor + { + public: + + ECIESGOSTR3410Encryptor (const uint8_t * pub); + ~ECIESGOSTR3410Encryptor (); + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); + + private: + + EC_POINT * m_PublicKey; + }; + + + class ECIESGOSTR3410Decryptor: public CryptoKeyDecryptor + { + public: + + ECIESGOSTR3410Decryptor (const uint8_t * priv); + ~ECIESGOSTR3410Decryptor (); + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); + + private: + + BIGNUM * m_PrivateKey; + }; + + void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub); +} +} + +#endif + diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 520fc23f..f57de0c3 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -709,7 +709,9 @@ namespace client if (isPublic) PersistTemporaryKeys (); else - i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); + i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (), + m_EncryptionPrivateKey, m_EncryptionPublicKey); + m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey); if (isPublic) LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); } @@ -927,7 +929,8 @@ namespace client } LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p"); - i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); + i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (), + m_EncryptionPrivateKey, m_EncryptionPublicKey); std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); if (f1) { @@ -951,5 +954,13 @@ namespace client if (m_DatagramDestination) m_DatagramDestination->CleanUp (); } + bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const + { + if (m_Decryptor) + return m_Decryptor->Decrypt (encrypted, data, ctx); + else + LogPrint (eLogError, "Destinations: decryptor is not set"); + return false; + } } } diff --git a/libi2pd/Destination.h b/libi2pd/Destination.h index b4c20fcc..3b87d1d0 100644 --- a/libi2pd/Destination.h +++ b/libi2pd/Destination.h @@ -205,7 +205,7 @@ namespace client i2p::datagram::DatagramDestination * CreateDatagramDestination (); // implements LocalDestination - const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; protected: @@ -228,6 +228,7 @@ namespace client i2p::data::PrivateKeys m_Keys; uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; + std::shared_ptr m_Decryptor; std::shared_ptr m_StreamingDestination; // default std::map > m_StreamingDestinationsByPorts; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 295fdd8a..e84312f8 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -189,7 +189,7 @@ namespace garlic uint8_t iv[32]; // IV is first 16 bytes SHA256(elGamal.preIV, 32, iv); BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::ElGamalEncrypt (m_Destination->GetEncryptionPublicKey (), (uint8_t *)&elGamal, buf, ctx, true); + m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx); BN_CTX_free (ctx); m_Encryption.SetIV (iv); buf += 514; @@ -454,7 +454,7 @@ namespace garlic { // tag not found. Use ElGamal ElGamalBlock elGamal; - if (length >= 514 && i2p::crypto::ElGamalDecrypt (GetEncryptionPrivateKey (), buf, (uint8_t *)&elGamal, m_Ctx, true)) + if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx)) { auto decryption = std::make_shared(elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 9f7738f3..7fde4893 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -327,7 +327,7 @@ namespace i2p { LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); BN_CTX * ctx = BN_CTX_new (); - i2p::crypto::ElGamalDecrypt (i2p::context.GetEncryptionPrivateKey (), record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); + i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); BN_CTX_free (ctx); // replace record to reply if (i2p::context.AcceptsTunnels () && diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index acce5426..6d207dd5 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -39,10 +39,10 @@ namespace data { } - IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type): + IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType): m_IsVerifierCreated (false) - { - memcpy (m_StandardIdentity.publicKey, publicKey, sizeof (m_StandardIdentity.publicKey)); + { + memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of if (type != SIGNING_KEY_TYPE_DSA_SHA1) { size_t excessLen = 0; @@ -103,7 +103,6 @@ namespace data break; } case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST: { // 256 size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64 @@ -112,7 +111,6 @@ namespace data break; } case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST: { // 512 // no padding, key length is 128 @@ -129,7 +127,7 @@ namespace data // fill extended buffer m_ExtendedBuffer = new uint8_t[m_ExtendedLen]; htobe16buf (m_ExtendedBuffer, type); - htobe16buf (m_ExtendedBuffer + 2, CRYPTO_KEY_TYPE_ELGAMAL); + htobe16buf (m_ExtendedBuffer + 2, cryptoType); if (excessLen && excessBuf) { memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen); @@ -397,14 +395,12 @@ namespace data break; } case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST: { 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: - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST: { // zero padding UpdateVerifier (new i2p::crypto::GOSTR3410_512_Verifier (i2p::crypto::eGOSTR3410TC26A512, m_StandardIdentity.signingKey)); @@ -446,6 +442,26 @@ namespace data m_Verifier = nullptr; } + std::shared_ptr IdentityEx::CreateEncryptor (const uint8_t * key) const + { + if (!key) key = GetEncryptionPublicKey (); // use publicKey + switch (GetCryptoKeyType ()) + { + case CRYPTO_KEY_TYPE_ELGAMAL: + return std::make_shared(key); + break; + case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: + return std::make_shared(key); + break; + case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: + return std::make_shared(key); + break; + default: + LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)GetCryptoKeyType ()); + }; + return nullptr; + } + PrivateKeys& PrivateKeys::operator=(const Keys& keys) { m_Public = std::make_shared(Identity (keys)); @@ -553,11 +569,9 @@ namespace data m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); break; case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST: m_Signer.reset (new i2p::crypto::GOSTR3410_256_Signer (i2p::crypto::eGOSTR3410CryptoProA, m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST: m_Signer.reset (new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, m_SigningPrivateKey)); break; default: @@ -573,7 +587,33 @@ namespace data return nullptr; // TODO: implement me } - PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type) + std::shared_ptr PrivateKeys::CreateDecryptor (const uint8_t * key) const + { + if (!key) key = m_PrivateKey; // use privateKey + return CreateDecryptor (m_Public->GetCryptoKeyType (), key); + } + + std::shared_ptr PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key) + { + if (!key) return nullptr; + switch (cryptoType) + { + case CRYPTO_KEY_TYPE_ELGAMAL: + return std::make_shared(key); + break; + case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: + return std::make_shared(key); + break; + case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: + return std::make_shared(key); + break; + default: + LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType); + }; + return nullptr; + } + + PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType) { if (type != SIGNING_KEY_TYPE_DSA_SHA1) { @@ -604,11 +644,9 @@ namespace data i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: - case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST: i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410CryptoProA, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: - case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST: i2p::crypto::CreateGOSTR3410RandomKeys (i2p::crypto::eGOSTR3410TC26A512, keys.m_SigningPrivateKey, signingPublicKey); break; default: @@ -617,9 +655,9 @@ namespace data } // encryption uint8_t publicKey[256]; - i2p::crypto::GenerateElGamalKeyPair (keys.m_PrivateKey, publicKey); + GenerateCryptoKeyPair (cryptoType, keys.m_PrivateKey, publicKey); // identity - keys.m_Public = std::make_shared (publicKey, signingPublicKey, type); + keys.m_Public = std::make_shared (publicKey, signingPublicKey, type, cryptoType); keys.CreateSigner (); return keys; @@ -627,6 +665,24 @@ namespace data return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 } + void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub) + { + switch (type) + { + case CRYPTO_KEY_TYPE_ELGAMAL: + i2p::crypto::GenerateElGamalKeyPair(priv, pub); + break; + case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: + i2p::crypto::CreateECIESP256RandomKeys (priv, pub); + break; + case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: + i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub); + break; + default: + LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported"); + } + } + Keys CreateRandomKeys () { Keys keys; diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 0258823b..b0c6f48a 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -8,6 +8,7 @@ #include #include "Base.h" #include "Signature.h" +#include "CryptoKey.h" namespace i2p { @@ -52,6 +53,9 @@ namespace data const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; + const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 65280; // TODO: change to actual code + const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES + const uint16_t SIGNING_KEY_TYPE_DSA_SHA1 = 0; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA256_P256 = 1; const uint16_t SIGNING_KEY_TYPE_ECDSA_SHA384_P384 = 2; @@ -64,9 +68,6 @@ namespace data // following signature type should never appear in netid=2 const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256 = 9; const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512 = 10; // approved by FSB - // TODO: remove later - const uint16_t SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256_TEST = 65281; - const uint16_t SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512_TEST = 65282; typedef uint16_t SigningKeyType; typedef uint16_t CryptoKeyType; @@ -77,7 +78,7 @@ namespace data IdentityEx (); IdentityEx (const uint8_t * publicKey, const uint8_t * signingKey, - SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1); + SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); IdentityEx (const uint8_t * buf, size_t len); IdentityEx (const IdentityEx& other); IdentityEx (const Identity& standard); @@ -89,11 +90,12 @@ 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; size_t GetSigningPrivateKeyLen () const; @@ -137,7 +139,7 @@ namespace data const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; uint8_t * GetPadding(); - void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); } + 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 (); }; @@ -147,7 +149,11 @@ namespace data size_t FromBase64(const std::string& s); std::string ToBase64 () const; - static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1); + std::shared_ptr CreateDecryptor (const uint8_t * key) const; + + 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 GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long private: @@ -186,9 +192,11 @@ namespace data RoutingDestination () {}; virtual ~RoutingDestination () {}; - virtual const IdentHash& GetIdentHash () const = 0; - virtual const uint8_t * GetEncryptionPublicKey () const = 0; + virtual std::shared_ptr GetIdentity () const = 0; + virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const = 0; // encrypt data for virtual bool IsDestination () const = 0; // for garlic + + const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; }; class LocalDestination @@ -196,7 +204,7 @@ namespace data public: virtual ~LocalDestination() {}; - virtual const uint8_t * GetEncryptionPrivateKey () const = 0; + virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const = 0; virtual std::shared_ptr GetIdentity () const = 0; const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; diff --git a/libi2pd/LeaseSet.cpp b/libi2pd/LeaseSet.cpp index 8b8a17c0..d2709a97 100644 --- a/libi2pd/LeaseSet.cpp +++ b/libi2pd/LeaseSet.cpp @@ -208,6 +208,13 @@ namespace data return ts > m_ExpirationTime; } + void LeaseSet::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const + { + auto encryptor = m_Identity->CreateEncryptor (m_EncryptionKey); + if (encryptor) + encryptor->Encrypt (data, encrypted, ctx); + } + LocalLeaseSet::LocalLeaseSet (std::shared_ptr identity, const uint8_t * encryptionPublicKey, std::vector > tunnels): m_ExpirationTime (0), m_Identity (identity) { diff --git a/libi2pd/LeaseSet.h b/libi2pd/LeaseSet.h index 3499884a..5a4202ee 100644 --- a/libi2pd/LeaseSet.h +++ b/libi2pd/LeaseSet.h @@ -59,8 +59,7 @@ namespace data ~LeaseSet () { delete[] m_Buffer; }; void Update (const uint8_t * buf, size_t len); bool IsNewer (const uint8_t * buf, size_t len) const; - void PopulateLeases (); // from buffer - std::shared_ptr GetIdentity () const { return m_Identity; }; + void PopulateLeases (); // from buffer const uint8_t * GetBuffer () const { return m_Buffer; }; size_t GetBufferLen () const { return m_BufferLen; }; @@ -76,8 +75,8 @@ namespace data { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; // implements RoutingDestination - const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; - const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; }; + std::shared_ptr GetIdentity () const { return m_Identity; }; + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const; bool IsDestination () const { return true; }; private: diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index ff19d27f..a49f1718 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -28,6 +28,7 @@ namespace i2p m_StartupTime = i2p::util::GetSecondsSinceEpoch (); if (!Load ()) CreateNewRouter (); + m_Decryptor = m_Keys.CreateDecryptor (nullptr); UpdateRouterInfo (); } @@ -478,4 +479,9 @@ namespace i2p { return i2p::util::GetSecondsSinceEpoch () - m_StartupTime; } + + bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const + { + return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx) : false; + } } diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index b3146b56..f587e0a5 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -48,8 +48,8 @@ namespace i2p { return std::shared_ptr (this, [](i2p::garlic::GarlicDestination *) {}); - } - + } + uint32_t GetUptime () const; uint32_t GetStartupTime () const { return m_StartupTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; @@ -89,8 +89,7 @@ namespace i2p // implements LocalDestination std::shared_ptr GetIdentity () const { return m_Keys.GetPublic (); }; - const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); }; - const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetStandardIdentity ().publicKey; }; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void SetLeaseSetUpdated () {}; @@ -115,6 +114,7 @@ namespace i2p i2p::data::RouterInfo m_RouterInfo; i2p::data::PrivateKeys m_Keys; + std::shared_ptr m_Decryptor; uint64_t m_LastUpdateTime; bool m_AcceptsTunnels, m_IsFloodfill; uint64_t m_StartupTime; // in seconds since epoch diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 3719e68a..f0ad1b88 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -828,5 +828,12 @@ namespace data m_Profile = GetRouterProfile (GetIdentHash ()); return m_Profile; } + + void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const + { + auto encryptor = m_RouterIdentity->CreateEncryptor (nullptr); + if (encryptor) + encryptor->Encrypt (data, encrypted, ctx); + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index f23fb152..97c0f7b2 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -181,12 +181,13 @@ namespace data void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; bool IsNewer (const uint8_t * buf, size_t len) const; - /** return true if we are in a router family and the signature is valid */ - bool IsFamily(const std::string & fam) const; + /** return true if we are in a router family and the signature is valid */ + bool IsFamily(const std::string & fam) const; // implements RoutingDestination - const IdentHash& GetIdentHash () const { return m_RouterIdentity->GetIdentHash (); }; - const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; }; + std::shared_ptr GetIdentity () const { return m_RouterIdentity; }; + void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const; + bool IsDestination () const { return false; }; private: diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index db5f825e..a1cf536e 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -882,7 +882,8 @@ namespace stream m_PendingIncomingTimer (m_Owner->GetService ()), m_ConnTrackTimer(m_Owner->GetService()), m_ConnsPerMinute(DEFAULT_MAX_CONNS_PER_MIN), - m_LastBanClear(i2p::util::GetMillisecondsSinceEpoch()) + m_LastBanClear(i2p::util::GetMillisecondsSinceEpoch()), + m_EnableDrop(false) { } @@ -946,7 +947,7 @@ namespace stream auto incomingStream = CreateNewIncomingStream (); incomingStream->HandleNextPacket (packet); // SYN auto ident = incomingStream->GetRemoteIdentity(); - if(ident) + if(ident && m_EnableDrop) { auto ih = ident->GetIdentHash(); if(DropNewStream(ih)) @@ -1153,6 +1154,7 @@ namespace stream void StreamingDestination::SetMaxConnsPerMinute(const uint32_t conns) { + m_EnableDrop = conns > 0; m_ConnsPerMinute = conns; LogPrint(eLogDebug, "Streaming: Set max conns per minute per destination to ", conns); } diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index eae959ed..94b356e8 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -317,6 +317,7 @@ namespace stream uint64_t m_LastBanClear; i2p::util::MemoryPool m_PacketsPool; + bool m_EnableDrop; public: diff --git a/libi2pd/version.h b/libi2pd/version.h index 0b5f9874..4633ce0b 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -21,7 +21,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 31 +#define I2P_VERSION_MICRO 32 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index 72cbcd16..4539eac8 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -8,9 +8,8 @@ namespace i2p { namespace client { - BOBI2PInboundTunnel::BOBI2PInboundTunnel (int port, std::shared_ptr localDestination): - BOBI2PTunnel (localDestination), - m_Acceptor (localDestination->GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)) + BOBI2PInboundTunnel::BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr localDestination): + BOBI2PTunnel (localDestination), m_Acceptor (localDestination->GetService (), ep) { } @@ -189,10 +188,22 @@ namespace client } } - void BOBDestination::CreateInboundTunnel (int port) + void BOBDestination::CreateInboundTunnel (int port, const std::string& address) { if (!m_InboundTunnel) - m_InboundTunnel = new BOBI2PInboundTunnel (port, m_LocalDestination); + { + boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), port); + if (!address.empty ()) + { + boost::system::error_code ec; + auto addr = boost::asio::ip::address::from_string (address, ec); + if (!ec) + ep.address (addr); + else + LogPrint (eLogError, "BOB: ", ec.message ()); + } + m_InboundTunnel = new BOBI2PInboundTunnel (ep, m_LocalDestination); + } } void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet) @@ -365,7 +376,7 @@ namespace client m_Owner.AddDestination (m_Nickname, m_CurrentDestination); } if (m_InPort) - m_CurrentDestination->CreateInboundTunnel (m_InPort); + m_CurrentDestination->CreateInboundTunnel (m_InPort, m_Address); if (m_OutPort && !m_Address.empty ()) m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet); m_CurrentDestination->Start (); @@ -448,7 +459,10 @@ namespace client void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: getdest"); - SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); + if (m_Keys.GetPublic ()) // keys are set ? + SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); + else + SendReplyError ("keys are not set"); } void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len) diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index 104073bd..bd29dafd 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.h @@ -68,7 +68,7 @@ namespace client public: - BOBI2PInboundTunnel (int port, std::shared_ptr localDestination); + BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr localDestination); ~BOBI2PInboundTunnel (); void Start (); @@ -125,7 +125,7 @@ namespace client void Start (); void Stop (); void StopTunnels (); - void CreateInboundTunnel (int port); + void CreateInboundTunnel (int port, const std::string& address); void CreateOutboundTunnel (const std::string& address, int port, bool quiet); const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); }; std::shared_ptr GetLocalDestination () const { return m_LocalDestination; }; diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index a15bbb14..b7363b00 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -280,7 +280,8 @@ namespace client } } - bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType) + bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, + i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType) { bool success = true; std::string fullPath = i2p::fs::DataDirPath (filename); @@ -303,8 +304,8 @@ namespace client } else { - LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType); - keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); + LogPrint (eLogError, "Clients: can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); + keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType); std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); size_t len = keys.GetFullLen (); uint8_t * buf = new uint8_t[len]; @@ -488,6 +489,7 @@ namespace client std::string address = section.second.get (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); int destinationPort = section.second.get (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); // I2CP std::map options; ReadI2CPOptions (section, options); @@ -496,7 +498,7 @@ namespace client if (keys.length () > 0) { i2p::data::PrivateKeys k; - if(LoadPrivateKeys (k, keys, sigType)) + if(LoadPrivateKeys (k, keys, sigType, cryptoType)) { localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); if (!localDestination) @@ -595,6 +597,7 @@ namespace client std::string webircpass = section.second.get (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, true); i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); uint32_t maxConns = section.second.get(i2p::stream::I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN, i2p::stream::DEFAULT_MAX_CONNS_PER_MIN); std::string address = section.second.get (I2P_SERVER_TUNNEL_ADDRESS, "127.0.0.1"); bool isUniqueLocal = section.second.get(I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, true); @@ -605,7 +608,7 @@ namespace client std::shared_ptr localDestination = nullptr; i2p::data::PrivateKeys k; - if(!LoadPrivateKeys (k, keys, sigType)) + if(!LoadPrivateKeys (k, keys, sigType, cryptoType)) continue; localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); if (!localDestination) diff --git a/libi2pd_client/ClientContext.h b/libi2pd_client/ClientContext.h index f22c0817..afb3d4d5 100644 --- a/libi2pd_client/ClientContext.h +++ b/libi2pd_client/ClientContext.h @@ -34,6 +34,7 @@ namespace client const char I2P_CLIENT_TUNNEL_DESTINATION[] = "destination"; const char I2P_CLIENT_TUNNEL_KEYS[] = "keys"; const char I2P_CLIENT_TUNNEL_SIGNATURE_TYPE[] = "signaturetype"; + const char I2P_CLIENT_TUNNEL_CRYPTO_TYPE[] = "cryptotype"; const char I2P_CLIENT_TUNNEL_DESTINATION_PORT[] = "destinationport"; const char I2P_CLIENT_TUNNEL_MATCH_TUNNELS[] = "matchtunnels"; const char I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT[] = "connecttimeout"; @@ -70,7 +71,9 @@ namespace client std::shared_ptr CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, const std::string & name, const std::map * params = nullptr); void DeleteLocalDestination (std::shared_ptr destination); std::shared_ptr FindLocalDestination (const i2p::data::IdentHash& destination) const; - bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256); + bool LoadPrivateKeys (i2p::data::PrivateKeys& keys, const std::string& filename, + i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256, + i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); AddressBook& GetAddressBook () { return m_AddressBook; }; const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index e9fb4335..f98b1af3 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -31,6 +31,16 @@ namespace client void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) { memcpy (m_EncryptionPrivateKey, key, 256); + m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), m_EncryptionPrivateKey); + } + + bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const + { + if (m_Decryptor) + return m_Decryptor->Decrypt (encrypted, data, ctx); + else + LogPrint (eLogError, "I2CP: decryptor is not set"); + return false; } void I2CPDestination::HandleDataMessage (const uint8_t * buf, size_t len) diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index b55f43c1..8c4f8ff0 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -71,7 +71,7 @@ namespace client void SendMsgTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint32_t nonce); // called from I2CPSession // implements LocalDestination - const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; + bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; std::shared_ptr GetIdentity () const { return m_Identity; }; protected: @@ -91,6 +91,7 @@ namespace client std::shared_ptr m_Owner; std::shared_ptr m_Identity; uint8_t m_EncryptionPrivateKey[256]; + std::shared_ptr m_Decryptor; uint64_t m_LeaseSetExpirationTime; }; diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 78078904..f575438c 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -30,6 +30,7 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ ../../libi2pd/BloomFilter.cpp \ ../../libi2pd/Config.cpp \ ../../libi2pd/Crypto.cpp \ + ../../libi2pd/CryptoKey.cpp \ ../../libi2pd/Datagram.cpp \ ../../libi2pd/Destination.cpp \ ../../libi2pd/Event.cpp \ @@ -107,6 +108,7 @@ HEADERS += DaemonQT.h mainwindow.h \ ../../libi2pd/BloomFilter.h \ ../../libi2pd/Config.h \ ../../libi2pd/Crypto.h \ + ../../libi2pd/CryptoKey.h \ ../../libi2pd/Datagram.h \ ../../libi2pd/Destination.h \ ../../libi2pd/Event.h \