mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-02-05 12:33:48 +01:00
commit
d6d9f05443
37 changed files with 842 additions and 158 deletions
|
@ -10,6 +10,7 @@
|
||||||
### Fixed
|
### Fixed
|
||||||
- Failure to start on Windows XP
|
- Failure to start on Windows XP
|
||||||
- SAM crash if invalid lookup address
|
- SAM crash if invalid lookup address
|
||||||
|
- Possible crash when UPnP enabled on shutdown
|
||||||
|
|
||||||
## [2.28.0] - 2019-08-27
|
## [2.28.0] - 2019-08-27
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -37,6 +37,10 @@ ifeq ($(USE_WIN32_APP), yes)
|
||||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||||
|
CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||||
|
endif
|
||||||
|
|
||||||
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
||||||
ifeq ($(USE_AESNI),1)
|
ifeq ($(USE_AESNI),1)
|
||||||
CPU_FLAGS += -maes
|
CPU_FLAGS += -maes
|
||||||
|
|
|
@ -2,6 +2,9 @@ CXX = clang++
|
||||||
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
CXXFLAGS := ${CXX_DEBUG} -Wall -std=c++11 -DMAC_OSX
|
||||||
INCFLAGS = -I/usr/local/include
|
INCFLAGS = -I/usr/local/include
|
||||||
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
LDFLAGS := -Wl,-rpath,/usr/local/lib -L/usr/local/lib
|
||||||
|
LDFLAGS += -Wl,-dead_strip
|
||||||
|
LDFLAGS += -Wl,-dead_strip_dylibs
|
||||||
|
LDFLAGS += -Wl,-bind_at_load
|
||||||
|
|
||||||
ifeq ($(USE_STATIC),yes)
|
ifeq ($(USE_STATIC),yes)
|
||||||
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
LDLIBS = -lz /usr/local/lib/libcrypto.a /usr/local/lib/libssl.a /usr/local/lib/libboost_system.a /usr/local/lib/libboost_date_time.a /usr/local/lib/libboost_filesystem.a /usr/local/lib/libboost_program_options.a -lpthread
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
#include "Win32App.h"
|
#include "Win32App.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
|
||||||
#define snprintf _snprintf
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ID_ABOUT 2000
|
#define ID_ABOUT 2000
|
||||||
#define ID_EXIT 2001
|
#define ID_EXIT 2001
|
||||||
#define ID_CONSOLE 2002
|
#define ID_CONSOLE 2002
|
||||||
|
@ -40,6 +36,9 @@ namespace win32
|
||||||
{
|
{
|
||||||
static DWORD GracefulShutdownEndtime = 0;
|
static DWORD GracefulShutdownEndtime = 0;
|
||||||
|
|
||||||
|
typedef DWORD (* IPN)();
|
||||||
|
IPN GetTickCountLocal = (IPN)GetProcAddress (GetModuleHandle ("KERNEL32.dll"), "GetTickCount");
|
||||||
|
|
||||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||||
{
|
{
|
||||||
HMENU hPopup = CreatePopupMenu();
|
HMENU hPopup = CreatePopupMenu();
|
||||||
|
@ -53,7 +52,7 @@ namespace win32
|
||||||
ID_ACCEPT_TRANSIT, "Accept &transit");
|
ID_ACCEPT_TRANSIT, "Accept &transit");
|
||||||
else
|
else
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DECLINE_TRANSIT, "Decline &transit");
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload configs");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_RELOAD, "&Reload tunnels config");
|
||||||
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
if (!i2p::util::DaemonWin32::Instance ().isGraceful)
|
||||||
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_GRACEFUL_SHUTDOWN, "&Graceful shutdown");
|
||||||
else
|
else
|
||||||
|
@ -161,7 +160,7 @@ namespace win32
|
||||||
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
||||||
if (GracefulShutdownEndtime != 0)
|
if (GracefulShutdownEndtime != 0)
|
||||||
{
|
{
|
||||||
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCount()) / 1000;
|
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000;
|
||||||
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -239,7 +238,7 @@ namespace win32
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
||||||
GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
|
GracefulShutdownEndtime = GetTickCountLocal() + 10*60*1000;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
||||||
|
android:requestLegacyExternalStorage="true"
|
||||||
>
|
>
|
||||||
<receiver android:name=".NetworkStateChangeReceiver">
|
<receiver android:name=".NetworkStateChangeReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
|
|
@ -18,9 +18,9 @@ environment:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu --force"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
||||||
|
|
||||||
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu --force"
|
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
|
||||||
|
|
||||||
- if "%MSYSTEM%" == "MINGW64" (
|
- if "%MSYSTEM%" == "MINGW64" (
|
||||||
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
|
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
|
||||||
|
|
|
@ -82,6 +82,8 @@ set (LIBI2PD_SRC
|
||||||
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
|
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
|
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
|
||||||
"${LIBI2PD_SRC_DIR}/Blinding.cpp"
|
"${LIBI2PD_SRC_DIR}/Blinding.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/Elligator.cpp"
|
||||||
|
"${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WITH_WEBSOCKETS)
|
if (WITH_WEBSOCKETS)
|
||||||
|
|
|
@ -54,6 +54,14 @@ set bitness=64
|
||||||
call :BUILDING
|
call :BUILDING
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
|
REM building for WinXP
|
||||||
|
set "WD=C:\msys64-xp\usr\bin\"
|
||||||
|
set MSYSTEM=MINGW32
|
||||||
|
set bitness=32
|
||||||
|
set "xSH=%WD%bash -lc"
|
||||||
|
call :BUILDING_XP
|
||||||
|
echo.
|
||||||
|
|
||||||
del README.txt >> nul
|
del README.txt >> nul
|
||||||
|
|
||||||
echo Build complete...
|
echo Build complete...
|
||||||
|
@ -71,5 +79,11 @@ echo Build AESNI...
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
|
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
|
||||||
echo Build without extensions...
|
echo Build without extensions...
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
|
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
|
||||||
|
goto EOF
|
||||||
|
|
||||||
|
:BUILDING_XP
|
||||||
|
%xSH% "make clean" >> nul
|
||||||
|
echo Building i2pd %tag% for winxp...
|
||||||
|
%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1
|
||||||
|
|
||||||
:EOF
|
:EOF
|
|
@ -1,34 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIF3DCCA8SgAwIBAgIQPxUlcrbHX/xdyJ09E36rJzANBgkqhkiG9w0BAQsFADB3
|
|
||||||
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
|
|
||||||
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEgMB4GA1UEAwwX
|
|
||||||
cmVzZWVkaTJwbmV0aW5AbWFpbC5pMnAwHhcNMTgxMjA3MTYzNDIxWhcNMjgxMjA3
|
|
||||||
MTYzNDIxWjB3MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhY
|
|
||||||
MR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEg
|
|
||||||
MB4GA1UEAwwXcmVzZWVkaTJwbmV0aW5AbWFpbC5pMnAwggIiMA0GCSqGSIb3DQEB
|
|
||||||
AQUAA4ICDwAwggIKAoICAQC912NDk6x85uqB4gyQQcded0RVrbWehWOanDRv7kC3
|
|
||||||
92jeziPbeMtqrLsfU1MdDtQiGijpNkQ/IIitPw+6vJAIh82gyOUZvsn2XOyb/Fz0
|
|
||||||
Fu8OrDghwl39yK8kwtqCFw3VAgafgKxz2oRge9mxFBECi50vYEPIBwNhr4yc/opu
|
|
||||||
wWUmzmRyX4gD7vKmRU6ZTwX4LXnwdl+5VbW3updcZKsDuTnKvC9FGhDRR9kIk2G9
|
|
||||||
43sLN263nCYPykP7DaB1cUdi1vDEMw5dot+eu16qTIbuypEvYNvbB/9FyCQllm1h
|
|
||||||
vBbSku3IYpcnRPmoeyhoR/MmCySRbK5R4SrSsVD1YBpwxgn0Q4+fzEgFzT9P4oez
|
|
||||||
HkDGKVP2HdgmXx9j36fEqqvjqzRleWDwEWwIZVRLCFO+hhhT3JAjnNGJTWv1SQGB
|
|
||||||
8tz9nyYTJuhvyHE/CO5owFeCdeOGMq2KPge9w34T+mvewTEEhGU8yRAt8Xp8s5Y9
|
|
||||||
RCUGvuQ79+edRtj7FJg7yVB8pAQ+VB9msNQvzrTnPYC9Wo7chJhBiraMiIabzIhC
|
|
||||||
f34Gg9lkX1N0dVND5rnZWwzBM6JhNG1iZZCRHVPnXdZRixUlqmFpCP/eekshksj/
|
|
||||||
6UP/WeGA6X4HyEsC6QEf7eMhcHYjyyTzYagKrwCHg77fmIjF8rmpP2LqWSQW8bDD
|
|
||||||
uQIDAQABo2QwYjAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
|
|
||||||
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wIAYDVR0OBBkEF3Jlc2VlZGkycG5l
|
|
||||||
dGluQG1haWwuaTJwMA0GCSqGSIb3DQEBCwUAA4ICAQCWpXs6iuTy/w2R7q7Ua6vl
|
|
||||||
JYZwbQ+czk5ydzkBgcNkMMMNRT7sZR9xYvV+ftiL4bFQP/3ZJyo7cYz2Q6+M3oAm
|
|
||||||
YDcZWBkLUVihSlMxhWwmeFTKV2EL+bzwY1V/cy7wgukKnFIes75dLP/v25jgjdlw
|
|
||||||
Xe6R+fQM0EoHeVzzrWk/qYp6oEwtQXfZnUu/Bf45hRnnHBzzh1wCql41vbEs3Niq
|
|
||||||
+SVwY1wLT0yC1L8HqjCLX1/L5PAXxbvEGzwnXSkLKK4bPxdmVDZvS9uzXrWmTbNi
|
|
||||||
HpKIFnOif16zSgyeaOM7HETIJuVzgooUMtt+Vsr1VGdtm6K7I9J5C+rX/ckU8oaX
|
|
||||||
UjmzhWXudN0VTslogsKUCV6xG2CskeE3wnuT8HYXz9NMw6c/kIGH4hY7LcfU8Teu
|
|
||||||
QjSy2RRvy6InmZNV5sY9lzzO6romEycSoUlpCa3Ltb/5KKoYZFTsXr8suqJk89lC
|
|
||||||
e+TVMHqOZdLK/usqQDcafLypHpw9SH2Tg4jrzV/zLqacbjx6bZD5IrpY0Gf7BXg/
|
|
||||||
pikwyA9c490G6ZcWrSEP8bzh6LL2rA2AwxaeJJNVyLHCSLrn/7DezM5J/qhd90Qg
|
|
||||||
kcZGJrUOCSWl6mDvUZn5XiQ955XwOnZQ+wsM85B3CVX22x5bp0SYWHCQBPnthPwP
|
|
||||||
Q5DD3jExbpwG5n35HEcHYw==
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -192,7 +192,6 @@ namespace config {
|
||||||
"https://netdb.i2p2.no/,"
|
"https://netdb.i2p2.no/,"
|
||||||
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
|
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
|
||||||
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
|
||||||
"https://reseed.i2p.net.in/,"
|
|
||||||
"https://download.xxlspeed.com/,"
|
"https://download.xxlspeed.com/,"
|
||||||
"https://reseed-fr.i2pd.xyz/,"
|
"https://reseed-fr.i2pd.xyz/,"
|
||||||
"https://reseed.memcpy.io/,"
|
"https://reseed.memcpy.io/,"
|
||||||
|
|
|
@ -367,6 +367,18 @@ namespace crypto
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void X25519Keys::SetPrivateKey (const uint8_t * priv)
|
||||||
|
{
|
||||||
|
#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);
|
||||||
|
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||||
|
#else
|
||||||
|
memcpy (m_PrivateKey, priv, 32);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// ElGamal
|
// ElGamal
|
||||||
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
|
||||||
{
|
{
|
||||||
|
@ -1259,18 +1271,29 @@ namespace crypto
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out)
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
|
||||||
|
uint8_t * out, size_t outLen)
|
||||||
{
|
{
|
||||||
#if OPENSSL_HKDF
|
#if OPENSSL_HKDF
|
||||||
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, NULL);
|
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||||
EVP_PKEY_derive_init (pctx);
|
EVP_PKEY_derive_init (pctx);
|
||||||
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
EVP_PKEY_CTX_set_hkdf_md (pctx, EVP_sha256());
|
||||||
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
if (key && keyLen)
|
||||||
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
{
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// zerolen
|
||||||
|
EVP_PKEY_CTX_hkdf_mode (pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY);
|
||||||
|
uint8_t tempKey[32]; unsigned int len;
|
||||||
|
HMAC(EVP_sha256(), salt, 32, nullptr, 0, tempKey, &len);
|
||||||
|
EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len);
|
||||||
|
}
|
||||||
if (info.length () > 0)
|
if (info.length () > 0)
|
||||||
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ());
|
||||||
size_t outlen = 64;
|
EVP_PKEY_derive (pctx, out, &outLen);
|
||||||
EVP_PKEY_derive (pctx, out, &outlen);
|
|
||||||
EVP_PKEY_CTX_free (pctx);
|
EVP_PKEY_CTX_free (pctx);
|
||||||
#else
|
#else
|
||||||
uint8_t prk[32]; unsigned int len;
|
uint8_t prk[32]; unsigned int len;
|
||||||
|
@ -1278,8 +1301,11 @@ namespace crypto
|
||||||
auto l = info.length ();
|
auto l = info.length ();
|
||||||
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
memcpy (out, info.c_str (), l); out[l] = 0x01;
|
||||||
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
HMAC(EVP_sha256(), prk, 32, out, l + 1, out, &len);
|
||||||
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
if (outLen > 32) // 64
|
||||||
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
{
|
||||||
|
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
|
||||||
|
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ namespace crypto
|
||||||
void GenerateKeys ();
|
void GenerateKeys ();
|
||||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
||||||
void GetPrivateKey (uint8_t * priv) const;
|
void GetPrivateKey (uint8_t * priv) const;
|
||||||
|
void SetPrivateKey (const uint8_t * priv); // wihout calculating public
|
||||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -296,7 +297,7 @@ namespace crypto
|
||||||
|
|
||||||
// HKDF
|
// HKDF
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out); // salt - 32, out - 64, info <= 32
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation);
|
||||||
|
|
|
@ -146,6 +146,36 @@ namespace crypto
|
||||||
BN_free (x); BN_free (y);
|
BN_free (x); BN_free (y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor (const uint8_t * pub)
|
||||||
|
{
|
||||||
|
memcpy (m_PublicKey, pub, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t * epriv, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
||||||
|
{
|
||||||
|
X25519Keys ep;
|
||||||
|
ep.SetPrivateKey (epriv);
|
||||||
|
ep.Agree (m_PublicKey, sharedSecret);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv)
|
||||||
|
{
|
||||||
|
m_StaticKeys.SetPrivateKey (priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
|
||||||
|
{
|
||||||
|
m_StaticKeys.Agree (epub, sharedSecret);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub)
|
||||||
|
{
|
||||||
|
X25519Keys k;
|
||||||
|
k.GenerateKeys ();
|
||||||
|
k.GetPrivateKey (priv);
|
||||||
|
memcpy (pub, k.GetPublicKey (), 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,39 @@ namespace crypto
|
||||||
};
|
};
|
||||||
|
|
||||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub);
|
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||||
|
|
||||||
|
// ECIES-X25519-AEAD-Ratchet
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetEncryptor: public CryptoKeyEncryptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetEncryptor (const uint8_t * pub);
|
||||||
|
~ECIESX25519AEADRatchetEncryptor () {};
|
||||||
|
void Encrypt (const uint8_t * epriv, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
// agree with ephemeral priv and return in sharedSecret (32 bytes)
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t m_PublicKey[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetDecryptor: public CryptoKeyDecryptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv);
|
||||||
|
~ECIESX25519AEADRatchetDecryptor () {};
|
||||||
|
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
|
||||||
|
// agree with static and return in sharedSecret (32 bytes)
|
||||||
|
size_t GetPublicKeyLen () const { return 32; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
X25519Keys m_StaticKeys;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -353,30 +353,38 @@ namespace client
|
||||||
|
|
||||||
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msg));
|
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||||
|
m_Service.post (std::bind (&LeaseSetDestination::HandleDeliveryStatusMessage, shared_from_this (), msgID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
void LeaseSetDestination::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[I2NP_HEADER_TYPEID_OFFSET]);
|
||||||
|
LeaseSetDestination::HandleCloveI2NPMessage (typeID, buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LeaseSetDestination::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t typeID = buf[I2NP_HEADER_TYPEID_OFFSET];
|
|
||||||
switch (typeID)
|
switch (typeID)
|
||||||
{
|
{
|
||||||
case eI2NPData:
|
case eI2NPData:
|
||||||
HandleDataMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDataMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
case eI2NPDeliveryStatus:
|
case eI2NPDeliveryStatus:
|
||||||
// we assume tunnel tests non-encrypted
|
// we assume tunnel tests non-encrypted
|
||||||
HandleDeliveryStatusMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
HandleDeliveryStatusMessage (bufbe32toh (payload + DELIVERY_STATUS_MSGID_OFFSET));
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseStore:
|
case eI2NPDatabaseStore:
|
||||||
HandleDatabaseStoreMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDatabaseStoreMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
case eI2NPDatabaseSearchReply:
|
case eI2NPDatabaseSearchReply:
|
||||||
HandleDatabaseSearchReplyMessage (buf + I2NP_HEADER_SIZE, GetI2NPMessageLength(buf, len) - I2NP_HEADER_SIZE);
|
HandleDatabaseSearchReplyMessage (payload, len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
void LeaseSetDestination::HandleDatabaseStoreMessage (const uint8_t * buf, size_t len)
|
||||||
|
@ -511,9 +519,8 @@ namespace client
|
||||||
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
LogPrint (eLogWarning, "Destination: Request for ", key.ToBase64 (), " not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void LeaseSetDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
|
||||||
if (msgID == m_PublishReplyToken)
|
if (msgID == m_PublishReplyToken)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32());
|
LogPrint (eLogDebug, "Destination: Publishing LeaseSet confirmed for ", GetIdentHash().ToBase32());
|
||||||
|
@ -525,7 +532,7 @@ namespace client
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msg);
|
i2p::garlic::GarlicDestination::HandleDeliveryStatusMessage (msgID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LeaseSetDestination::SetLeaseSetUpdated ()
|
void LeaseSetDestination::SetLeaseSetUpdated ()
|
||||||
|
@ -873,10 +880,13 @@ namespace client
|
||||||
m_EncryptionKeyType = std::stoi(it->second);
|
m_EncryptionKeyType = std::stoi(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPublic && m_EncryptionKeyType == GetIdentity ()->GetCryptoKeyType ()) // TODO: presist key type
|
memset (m_EncryptionPrivateKey, 0, 256);
|
||||||
|
memset (m_EncryptionPublicKey, 0, 256);
|
||||||
|
if (isPublic)
|
||||||
PersistTemporaryKeys ();
|
PersistTemporaryKeys ();
|
||||||
else
|
else
|
||||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||||
|
|
||||||
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey);
|
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey);
|
||||||
if (isPublic)
|
if (isPublic)
|
||||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||||
|
@ -1165,8 +1175,8 @@ namespace client
|
||||||
LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p");
|
LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p");
|
||||||
memset (m_EncryptionPrivateKey, 0, 256);
|
memset (m_EncryptionPrivateKey, 0, 256);
|
||||||
memset (m_EncryptionPublicKey, 0, 256);
|
memset (m_EncryptionPublicKey, 0, 256);
|
||||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair (GetIdentity ()->GetCryptoKeyType (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||||
|
// TODO:: persist crypto key type
|
||||||
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
||||||
if (f1) {
|
if (f1) {
|
||||||
f1.write ((char *)m_EncryptionPublicKey, 256);
|
f1.write ((char *)m_EncryptionPublicKey, 256);
|
||||||
|
|
|
@ -121,7 +121,6 @@ namespace client
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet ();
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const { return m_Pool; }
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
|
||||||
|
@ -131,6 +130,10 @@ namespace client
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// implements GarlicDestination
|
||||||
|
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len);
|
||||||
|
|
||||||
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
void SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
||||||
int GetLeaseSetType () const { return m_LeaseSetType; };
|
int GetLeaseSetType () const { return m_LeaseSetType; };
|
||||||
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
void SetLeaseSetType (int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
||||||
|
@ -152,7 +155,7 @@ namespace client
|
||||||
void HandlePublishDelayTimer (const boost::system::error_code& ecode);
|
void HandlePublishDelayTimer (const boost::system::error_code& ecode);
|
||||||
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseStoreMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
void HandleDatabaseSearchReplyMessage (const uint8_t * buf, size_t len);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (uint32_t msgID);
|
||||||
|
|
||||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||||
|
@ -237,6 +240,8 @@ namespace client
|
||||||
// implements LocalDestination
|
// implements LocalDestination
|
||||||
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
|
||||||
|
i2p::data::CryptoKeyType GetEncryptionType () const { return m_EncryptionKeyType; };
|
||||||
|
const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; };
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
132
libi2pd/ECIESX25519AEADRatchetSession.cpp
Normal file
132
libi2pd/ECIESX25519AEADRatchetSession.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Elligator.h"
|
||||||
|
#include "Tag.h"
|
||||||
|
#include "I2PEndian.h"
|
||||||
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace garlic
|
||||||
|
{
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession ()
|
||||||
|
{
|
||||||
|
// TODO : use precalculated hashes
|
||||||
|
static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes
|
||||||
|
SHA256 ((const uint8_t *)protocolName, 40, m_H);
|
||||||
|
memcpy (m_CK, m_H, 32);
|
||||||
|
SHA256 (m_H, 32, m_H);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession::~ECIESX25519AEADRatchetSession ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
SHA256_Init (&ctx);
|
||||||
|
SHA256_Update (&ctx, m_H, 32);
|
||||||
|
SHA256_Update (&ctx, buf, len);
|
||||||
|
SHA256_Final (m_H, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ECIESX25519AEADRatchetSession::NewIncomingSession (const i2p::data::LocalDestination& dest,
|
||||||
|
const uint8_t * buf, size_t len, CloveHandler handleClove)
|
||||||
|
{
|
||||||
|
// we are Bob
|
||||||
|
// KDF1
|
||||||
|
MixHash (dest.GetEncryptionPublicKey (), 32); // h = SHA256(h || bpk)
|
||||||
|
|
||||||
|
uint8_t aepk[32]; // Alice's ephemeral key
|
||||||
|
if (!i2p::crypto::GetElligator ()->Decode (buf, aepk))
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Can't decode elligator");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
buf += 32; len -= 32;
|
||||||
|
MixHash (aepk, 32); // h = SHA256(h || aepk)
|
||||||
|
|
||||||
|
uint8_t sharedSecret[32], keyData[64];
|
||||||
|
dest.Decrypt (aepk, sharedSecret, nullptr); // x25519(bsk, aepk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31]
|
||||||
|
|
||||||
|
// decrypt flags/static
|
||||||
|
uint8_t nonce[12], fs[32];
|
||||||
|
memset (nonce, 0, 12); // n = 0
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 32, m_H, 32, keyData + 32, nonce, fs, 32, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD verification failed ");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MixHash (buf, 48); // h = SHA256(h || ciphertext)
|
||||||
|
buf += 48; len -= 48; // 32 data + 16 poly
|
||||||
|
|
||||||
|
// decrypt payload
|
||||||
|
std::vector<uint8_t> payload (len - 16);
|
||||||
|
// KDF2 for payload
|
||||||
|
bool isStatic = !i2p::data::Tag<32> (fs).IsZero ();
|
||||||
|
if (isStatic)
|
||||||
|
{
|
||||||
|
// static key, fs is apk
|
||||||
|
dest.Decrypt (fs, sharedSecret, nullptr); // x25519(bsk, apk)
|
||||||
|
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", keyData); // keydata = HKDF(chainKey, sharedSecret, "", 64)
|
||||||
|
memcpy (m_CK, keyData, 32); // chainKey = keydata[0:31]
|
||||||
|
}
|
||||||
|
else // all zeros flags
|
||||||
|
htole64buf (nonce + 4, 1); // n = 1
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keyData + 32, nonce, payload.data (), len - 16, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext)
|
||||||
|
|
||||||
|
HandlePayload (payload.data (), len - 16, handleClove);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
while (offset < len)
|
||||||
|
{
|
||||||
|
uint8_t blk = buf[offset];
|
||||||
|
offset++;
|
||||||
|
auto size = bufbe16toh (buf + offset);
|
||||||
|
offset += 2;
|
||||||
|
LogPrint (eLogDebug, "Garlic: Block type ", (int)blk, " of size ", size);
|
||||||
|
if (size > len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: Unexpected block length ", size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (blk)
|
||||||
|
{
|
||||||
|
case eECIESx25519BlkGalicClove:
|
||||||
|
handleClove (buf + offset, size);
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkDateTime:
|
||||||
|
LogPrint (eLogDebug, "Garlic: datetime");
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkOptions:
|
||||||
|
LogPrint (eLogDebug, "Garlic: options");
|
||||||
|
break;
|
||||||
|
case eECIESx25519BlkPadding:
|
||||||
|
LogPrint (eLogDebug, "Garlic: padding");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
|
||||||
|
}
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
48
libi2pd/ECIESX25519AEADRatchetSession.h
Normal file
48
libi2pd/ECIESX25519AEADRatchetSession.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__
|
||||||
|
#define ECIES_X25519_AEAD_RATCHET_SESSION_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <functional>
|
||||||
|
#include "Identity.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace garlic
|
||||||
|
{
|
||||||
|
enum ECIESx25519BlockType
|
||||||
|
{
|
||||||
|
eECIESx25519BlkDateTime = 0,
|
||||||
|
eECIESx25519BlkSessionID = 1,
|
||||||
|
eECIESx25519BlkTermination = 4,
|
||||||
|
eECIESx25519BlkOptions = 5,
|
||||||
|
eECIESx25519BlkNextSessionKey = 7,
|
||||||
|
eECIESx25519BlkGalicClove = 11,
|
||||||
|
eECIESx25519BlkPadding = 254
|
||||||
|
};
|
||||||
|
|
||||||
|
class ECIESX25519AEADRatchetSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef std::function<void (const uint8_t * buf, size_t len)> CloveHandler;
|
||||||
|
|
||||||
|
ECIESX25519AEADRatchetSession ();
|
||||||
|
~ECIESX25519AEADRatchetSession ();
|
||||||
|
|
||||||
|
bool NewIncomingSession (const i2p::data::LocalDestination& dest, const uint8_t * buf, size_t len,
|
||||||
|
CloveHandler handleClove);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void MixHash (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
|
void HandlePayload (const uint8_t * buf, size_t len, CloveHandler& handleClove);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint8_t m_H[32], m_CK[32];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -31,7 +31,7 @@ namespace crypto
|
||||||
BN_mod_inverse (tmp, tmp, q, ctx);
|
BN_mod_inverse (tmp, tmp, q, ctx);
|
||||||
BN_set_word (d, 121665);
|
BN_set_word (d, 121665);
|
||||||
BN_set_negative (d, 1);
|
BN_set_negative (d, 1);
|
||||||
BN_mul (d, d, tmp, ctx);
|
BN_mod_mul (d, d, tmp, q, ctx);
|
||||||
|
|
||||||
// 2^((q-1)/4)
|
// 2^((q-1)/4)
|
||||||
I = BN_new ();
|
I = BN_new ();
|
||||||
|
|
196
libi2pd/Elligator.cpp
Normal file
196
libi2pd/Elligator.cpp
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
#include "Crypto.h"
|
||||||
|
#include "Elligator.h"
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
Elligator2::Elligator2 ()
|
||||||
|
{
|
||||||
|
// TODO: share with Ed22519
|
||||||
|
p = BN_new ();
|
||||||
|
// 2^255-19
|
||||||
|
BN_set_bit (p, 255); // 2^255
|
||||||
|
BN_sub_word (p, 19);
|
||||||
|
p38 = BN_dup (p); BN_add_word (p38, 3); BN_div_word (p38, 8); // (p+3)/8
|
||||||
|
p12 = BN_dup (p); BN_sub_word (p12, 1); BN_div_word (p12, 2); // (p-1)/2
|
||||||
|
p14 = BN_dup (p); BN_sub_word (p14, 1); BN_div_word (p14, 4); // (p-1)/4
|
||||||
|
|
||||||
|
A = BN_new (); BN_set_word (A, 486662);
|
||||||
|
nA = BN_new (); BN_sub (nA, p, A);
|
||||||
|
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
// calculate sqrt(-1)
|
||||||
|
sqrtn1 = BN_new ();
|
||||||
|
BN_set_word (sqrtn1, 2);
|
||||||
|
BN_mod_exp (sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
|
||||||
|
|
||||||
|
u = BN_new (); BN_set_word (u, 2);
|
||||||
|
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx);
|
||||||
|
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Elligator2::~Elligator2 ()
|
||||||
|
{
|
||||||
|
BN_free (p); BN_free (p38); BN_free (p12); BN_free (p14);
|
||||||
|
BN_free (sqrtn1); BN_free (A); BN_free (nA);
|
||||||
|
BN_free (u); BN_free (iu);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY) const
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
BN_CTX_start (ctx);
|
||||||
|
|
||||||
|
uint8_t key1[32];
|
||||||
|
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||||
|
{
|
||||||
|
key1[i] = key[31 - i];
|
||||||
|
key1[31 - i] = key[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGNUM * x = BN_CTX_get (ctx); BN_bin2bn (key1, 32, x);
|
||||||
|
BIGNUM * xA = BN_CTX_get (ctx); BN_add (xA, x, A); // x + A
|
||||||
|
BN_sub (xA, p, xA); // p - (x + A)
|
||||||
|
|
||||||
|
BIGNUM * uxxA = BN_CTX_get (ctx); // u*x*xA
|
||||||
|
BN_mod_mul (uxxA, u, x, p, ctx);
|
||||||
|
BN_mod_mul (uxxA, uxxA, xA, p, ctx);
|
||||||
|
|
||||||
|
if (Legendre (uxxA, ctx) != -1)
|
||||||
|
{
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx);
|
||||||
|
if (highY)
|
||||||
|
{
|
||||||
|
BN_mod_inverse (r, x, p, ctx);
|
||||||
|
BN_mod_mul (r, r, xA, p, ctx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BN_mod_inverse (r, xA, p, ctx);
|
||||||
|
BN_mod_mul (r, r, x, p, ctx);
|
||||||
|
}
|
||||||
|
BN_mod_mul (r, r, iu, p, ctx);
|
||||||
|
|
||||||
|
SquareRoot (r, r, ctx);
|
||||||
|
bn2buf (r, encoded, 32);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 16; i++) // To Little Endian
|
||||||
|
{
|
||||||
|
uint8_t tmp = encoded[i];
|
||||||
|
encoded[i] = encoded[31 - i];
|
||||||
|
encoded[31 - i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
BN_CTX_end (ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Elligator2::Decode (const uint8_t * encoded, uint8_t * key) const
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
|
BN_CTX_start (ctx);
|
||||||
|
|
||||||
|
uint8_t encoded1[32];
|
||||||
|
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||||
|
{
|
||||||
|
encoded1[i] = encoded[31 - i];
|
||||||
|
encoded1[31 - i] = encoded[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx); BN_bin2bn (encoded1, 32, r);
|
||||||
|
|
||||||
|
if (BN_cmp (r, p12) <= 0) // r < (p-1)/2
|
||||||
|
{
|
||||||
|
// v = -A/(1+u*r^2)
|
||||||
|
BIGNUM * v = BN_CTX_get (ctx); BN_mod_sqr (v, r, p, ctx);
|
||||||
|
BN_mod_mul (v, v, u, p, ctx);
|
||||||
|
BN_add_word (v, 1);
|
||||||
|
BN_mod_inverse (v, v, p, ctx);
|
||||||
|
BN_mod_mul (v, v, nA, p, ctx);
|
||||||
|
|
||||||
|
BIGNUM * vpA = BN_CTX_get (ctx);
|
||||||
|
BN_add (vpA, v, A); // v + A
|
||||||
|
// t = v^3+A*v^2+v = v^2*(v+A)+v
|
||||||
|
BIGNUM * t = BN_CTX_get (ctx); BN_mod_sqr (t, v, p, ctx);
|
||||||
|
BN_mod_mul (t, t, vpA, p, ctx);
|
||||||
|
BN_mod_add (t, t, v, p, ctx);
|
||||||
|
|
||||||
|
int legendre = Legendre (t, ctx);
|
||||||
|
BIGNUM * x = BN_CTX_get (ctx);
|
||||||
|
if (legendre == 1)
|
||||||
|
BN_copy (x, v);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BN_sub (x, p, v);
|
||||||
|
BN_mod_sub (x, x, A, p, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
bn2buf (x, key, 32);
|
||||||
|
for (size_t i = 0; i < 16; i++) // To Little Endian
|
||||||
|
{
|
||||||
|
uint8_t tmp = key[i];
|
||||||
|
key[i] = key[31 - i];
|
||||||
|
key[31 - i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = false;
|
||||||
|
|
||||||
|
BN_CTX_end (ctx);
|
||||||
|
BN_CTX_free (ctx);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Elligator2::SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const
|
||||||
|
{
|
||||||
|
BIGNUM * t = BN_CTX_get (ctx);
|
||||||
|
BN_mod_exp (t, x, p14, p, ctx); // t = x^((p-1)/4)
|
||||||
|
BN_mod_exp (r, x, p38, p, ctx); // r = x^((p+3)/8)
|
||||||
|
BN_add_word (t, 1);
|
||||||
|
|
||||||
|
if (!BN_cmp (t, p))
|
||||||
|
BN_mod_mul (r, r, sqrtn1, p, ctx);
|
||||||
|
|
||||||
|
if (BN_cmp (r, p12) > 0) // r > (p-1)/2
|
||||||
|
BN_sub (r, p, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Elligator2::Legendre (const BIGNUM * a, BN_CTX * ctx) const
|
||||||
|
{
|
||||||
|
// assume a < p, so don't check for a % p = 0, but a = 0 only
|
||||||
|
if (BN_is_zero(a)) return 0;
|
||||||
|
BIGNUM * r = BN_CTX_get (ctx);
|
||||||
|
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
|
||||||
|
if (BN_is_word(r, 1))
|
||||||
|
return 1;
|
||||||
|
else if (BN_is_zero(r))
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<Elligator2> g_Elligator;
|
||||||
|
std::unique_ptr<Elligator2>& GetElligator ()
|
||||||
|
{
|
||||||
|
if (!g_Elligator)
|
||||||
|
{
|
||||||
|
auto el = new Elligator2();
|
||||||
|
if (!g_Elligator) // make sure it was not created already
|
||||||
|
g_Elligator.reset (el);
|
||||||
|
else
|
||||||
|
delete el;
|
||||||
|
}
|
||||||
|
return g_Elligator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
39
libi2pd/Elligator.h
Normal file
39
libi2pd/Elligator.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef ELLIGATOR_H__
|
||||||
|
#define ELLIGATOR_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
|
namespace i2p
|
||||||
|
{
|
||||||
|
namespace crypto
|
||||||
|
{
|
||||||
|
|
||||||
|
class Elligator2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Elligator2 ();
|
||||||
|
~Elligator2 ();
|
||||||
|
|
||||||
|
bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false) const;
|
||||||
|
bool Decode (const uint8_t * encoded, uint8_t * key) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const;
|
||||||
|
int Legendre (const BIGNUM * a, BN_CTX * ctx) const; // a/p
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
BIGNUM * p, * p38, * p12, * p14, * sqrtn1, * A, * nA, * u, * iu;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<Elligator2>& GetElligator ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
#include "Garlic.h"
|
#include "Garlic.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -434,6 +435,7 @@ namespace garlic
|
||||||
}
|
}
|
||||||
buf += 4; // length
|
buf += 4; // length
|
||||||
auto it = m_Tags.find (SessionTag(buf));
|
auto it = m_Tags.find (SessionTag(buf));
|
||||||
|
// AES tag might be used even if encryption type is not ElGamal/AES
|
||||||
if (it != m_Tags.end ())
|
if (it != m_Tags.end ())
|
||||||
{
|
{
|
||||||
// tag found. Use AES
|
// tag found. Use AES
|
||||||
|
@ -452,7 +454,13 @@ namespace garlic
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// tag not found. Use ElGamal
|
// tag not found. Handle depending on encryption type
|
||||||
|
if (GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET)
|
||||||
|
{
|
||||||
|
HandleECIESx25519 (buf, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// otherwise assume ElGamal/AES
|
||||||
ElGamalBlock elGamal;
|
ElGamalBlock elGamal;
|
||||||
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
|
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
|
||||||
{
|
{
|
||||||
|
@ -543,7 +551,7 @@ namespace garlic
|
||||||
LogPrint (eLogError, "Garlic: message is too short");
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HandleI2NPMessage (buf, len - offset, from);
|
HandleI2NPMessage (buf, len - offset);
|
||||||
break;
|
break;
|
||||||
case eGarlicDeliveryTypeDestination:
|
case eGarlicDeliveryTypeDestination:
|
||||||
LogPrint (eLogDebug, "Garlic: type destination");
|
LogPrint (eLogDebug, "Garlic: type destination");
|
||||||
|
@ -554,7 +562,7 @@ namespace garlic
|
||||||
LogPrint (eLogError, "Garlic: message is too short");
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
HandleI2NPMessage (buf, len - offset, from);
|
HandleI2NPMessage (buf, len - offset);
|
||||||
break;
|
break;
|
||||||
case eGarlicDeliveryTypeTunnel:
|
case eGarlicDeliveryTypeTunnel:
|
||||||
{
|
{
|
||||||
|
@ -714,9 +722,8 @@ namespace garlic
|
||||||
m_DeliveryStatusSessions[msgID] = session;
|
m_DeliveryStatusSessions[msgID] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void GarlicDestination::HandleDeliveryStatusMessage (uint32_t msgID)
|
||||||
{
|
{
|
||||||
uint32_t msgID = bufbe32toh (msg->GetPayload ());
|
|
||||||
GarlicRoutingSessionPtr session;
|
GarlicRoutingSessionPtr session;
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
||||||
|
@ -748,7 +755,8 @@ namespace garlic
|
||||||
|
|
||||||
void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void GarlicDestination::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
HandleDeliveryStatusMessage (msg);
|
uint32_t msgID = bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET);
|
||||||
|
HandleDeliveryStatusMessage (msgID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::SaveTags ()
|
void GarlicDestination::SaveTags ()
|
||||||
|
@ -821,5 +829,68 @@ namespace garlic
|
||||||
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||||
i2p::fs::Remove (it);
|
i2p::fs::Remove (it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
ECIESX25519AEADRatchetSession session;
|
||||||
|
session.NewIncomingSession (*this, buf, len, std::bind (&GarlicDestination::HandleECIESx25519GarlicClove,
|
||||||
|
this, std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
const uint8_t * buf1 = buf;
|
||||||
|
uint8_t flag = buf[0]; buf++; // flag
|
||||||
|
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
|
||||||
|
switch (deliveryType)
|
||||||
|
{
|
||||||
|
case eGarlicDeliveryTypeDestination:
|
||||||
|
LogPrint (eLogDebug, "Garlic: type destination");
|
||||||
|
buf += 32; // TODO: check destination
|
||||||
|
// no break here
|
||||||
|
case eGarlicDeliveryTypeLocal:
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Garlic: type local");
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
|
||||||
|
buf += (4 + 4); // msgID + expiration
|
||||||
|
ptrdiff_t offset = buf - buf1;
|
||||||
|
if (offset <= (int)len)
|
||||||
|
HandleCloveI2NPMessage (typeID, buf, len - offset);
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Garlic: clove is too long");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case eGarlicDeliveryTypeTunnel:
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||||
|
// gwHash and gwTunnel sequence is reverted
|
||||||
|
const uint8_t * gwHash = buf;
|
||||||
|
buf += 32;
|
||||||
|
ptrdiff_t offset = buf - buf1;
|
||||||
|
if (offset + 13 > (int)len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "Garlic: message is too short");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint32_t gwTunnel = bufbe32toh (buf); buf += 4;
|
||||||
|
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
|
||||||
|
buf += (4 + 4); // msgID + expiration
|
||||||
|
offset += 13;
|
||||||
|
if (GetTunnelPool ())
|
||||||
|
{
|
||||||
|
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
|
||||||
|
if (tunnel)
|
||||||
|
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset));
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,12 +190,13 @@ namespace garlic
|
||||||
|
|
||||||
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
||||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
||||||
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len) = 0; // called from clove only
|
||||||
|
virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) = 0;
|
||||||
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void HandleDeliveryStatusMessage (uint32_t msgID);
|
||||||
|
|
||||||
void SaveTags ();
|
void SaveTags ();
|
||||||
void LoadTags ();
|
void LoadTags ();
|
||||||
|
@ -206,6 +207,10 @@ namespace garlic
|
||||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||||
|
|
||||||
|
// ECIES-X25519-AEAD-Ratchet
|
||||||
|
void HandleECIESx25519 (const uint8_t * buf, size_t len);
|
||||||
|
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
BN_CTX * m_Ctx; // incoming
|
BN_CTX * m_Ctx; // incoming
|
||||||
|
|
|
@ -417,6 +417,9 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||||
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetEncryptor>(key);
|
||||||
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
||||||
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESP256Encryptor>(key);
|
||||||
|
@ -674,6 +677,9 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
||||||
};
|
};
|
||||||
|
@ -750,6 +756,9 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET:
|
||||||
|
i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
|
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ namespace data
|
||||||
|
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
||||||
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET = 4;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
||||||
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 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
|
||||||
|
|
||||||
|
@ -215,6 +216,7 @@ namespace data
|
||||||
virtual bool IsDestination () const = 0; // for garlic
|
virtual bool IsDestination () const = 0; // for garlic
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||||
|
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override in LeaseSet2
|
||||||
};
|
};
|
||||||
|
|
||||||
class LocalDestination
|
class LocalDestination
|
||||||
|
@ -226,6 +228,8 @@ namespace data
|
||||||
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
|
||||||
|
|
||||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||||
|
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override for LeaseSet
|
||||||
|
virtual const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetEncryptionPublicKey (); }; // override for LeaseSet
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -355,7 +355,6 @@ namespace data
|
||||||
offset += propertiesLen; // skip for now. TODO: implement properties
|
offset += propertiesLen; // skip for now. TODO: implement properties
|
||||||
if (offset + 1 >= len) return 0;
|
if (offset + 1 >= len) return 0;
|
||||||
// key sections
|
// key sections
|
||||||
uint16_t currentKeyType = 0;
|
|
||||||
int numKeySections = buf[offset]; offset++;
|
int numKeySections = buf[offset]; offset++;
|
||||||
for (int i = 0; i < numKeySections; i++)
|
for (int i = 0; i < numKeySections; i++)
|
||||||
{
|
{
|
||||||
|
@ -368,10 +367,10 @@ namespace data
|
||||||
// we pick first valid key, higher key type has higher priority 4-1-0
|
// we pick first valid key, higher key type has higher priority 4-1-0
|
||||||
// if two keys with of the same type, pick first
|
// if two keys with of the same type, pick first
|
||||||
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
auto encryptor = i2p::data::IdentityEx::CreateEncryptor (keyType, buf + offset);
|
||||||
if (encryptor && (!m_Encryptor || keyType > currentKeyType))
|
if (encryptor && (!m_Encryptor || keyType > m_EncryptionType))
|
||||||
{
|
{
|
||||||
m_Encryptor = encryptor; // TODO: atomic
|
m_Encryptor = encryptor; // TODO: atomic
|
||||||
currentKeyType = keyType;
|
m_EncryptionType = keyType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += encryptionKeyLen;
|
offset += encryptionKeyLen;
|
||||||
|
|
|
@ -147,6 +147,7 @@ namespace data
|
||||||
|
|
||||||
// implements RoutingDestination
|
// implements RoutingDestination
|
||||||
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
|
||||||
|
CryptoKeyType GetEncryptionType () const { return m_EncryptionType; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -167,6 +168,7 @@ namespace data
|
||||||
uint32_t m_PublishedTimestamp = 0;
|
uint32_t m_PublishedTimestamp = 0;
|
||||||
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
bool m_IsPublic = true, m_IsPublishedEncrypted = false;
|
||||||
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
std::shared_ptr<i2p::crypto::Verifier> m_TransientVerifier;
|
||||||
|
CryptoKeyType m_EncryptionType = CRYPTO_KEY_TYPE_ELGAMAL;
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -441,23 +441,17 @@ namespace transport
|
||||||
|
|
||||||
void NTCP2Session::KeyDerivationFunctionDataPhase ()
|
void NTCP2Session::KeyDerivationFunctionDataPhase ()
|
||||||
{
|
{
|
||||||
uint8_t tempKey[32]; unsigned int len;
|
uint8_t k[64];
|
||||||
HMAC(EVP_sha256(), m_Establisher->GetCK (), 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(ck, zerolen)
|
i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "", k); // k_ab, k_ba = HKDF(ck, zerolen)
|
||||||
static uint8_t one[1] = { 1 };
|
memcpy (m_Kab, k, 32); memcpy (m_Kba, k + 32, 32);
|
||||||
HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Kab, &len); // k_ab = HMAC-SHA256(temp_key, byte(0x01)).
|
uint8_t master[32];
|
||||||
m_Kab[32] = 2;
|
i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "ask", master, 32); // ask_master = HKDF(ck, zerolen, info="ask")
|
||||||
HMAC(EVP_sha256(), tempKey, 32, m_Kab, 33, m_Kba, &len); // k_ba = HMAC-SHA256(temp_key, k_ab || byte(0x02))
|
|
||||||
static uint8_t ask[4] = { 'a', 's', 'k', 1 }, master[32];
|
|
||||||
HMAC(EVP_sha256(), tempKey, 32, ask, 4, master, &len); // ask_master = HMAC-SHA256(temp_key, "ask" || byte(0x01))
|
|
||||||
uint8_t h[39];
|
uint8_t h[39];
|
||||||
memcpy (h, m_Establisher->GetH (), 32);
|
memcpy (h, m_Establisher->GetH (), 32);
|
||||||
memcpy (h + 32, "siphash", 7);
|
memcpy (h + 32, "siphash", 7);
|
||||||
HMAC(EVP_sha256(), master, 32, h, 39, tempKey, &len); // temp_key = HMAC-SHA256(ask_master, h || "siphash")
|
i2p::crypto::HKDF (master, h, 39, "", master, 32); // sip_master = HKDF(ask_master, h || "siphash")
|
||||||
HMAC(EVP_sha256(), tempKey, 32, one, 1, master, &len); // sip_master = HMAC-SHA256(temp_key, byte(0x01))
|
i2p::crypto::HKDF (master, nullptr, 0, "", k); // sipkeys_ab, sipkeys_ba = HKDF(sip_master, zerolen)
|
||||||
HMAC(EVP_sha256(), master, 32, nullptr, 0, tempKey, &len); // temp_key = HMAC-SHA256(sip_master, zerolen)
|
memcpy (m_Sipkeysab, k, 32); memcpy (m_Sipkeysba, k + 32, 32);
|
||||||
HMAC(EVP_sha256(), tempKey, 32, one, 1, m_Sipkeysab, &len); // sipkeys_ab = HMAC-SHA256(temp_key, byte(0x01)).
|
|
||||||
m_Sipkeysab[32] = 2;
|
|
||||||
HMAC(EVP_sha256(), tempKey, 32, m_Sipkeysab, 33, m_Sipkeysba, &len); // sipkeys_ba = HMAC-SHA256(temp_key, sipkeys_ab || byte(0x02))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1035,7 +1029,9 @@ namespace transport
|
||||||
|
|
||||||
if (ecode)
|
if (ecode)
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ());
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ());
|
||||||
|
Terminate ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1260,7 +1256,10 @@ namespace transport
|
||||||
|
|
||||||
bool NTCP2Server::AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming)
|
bool NTCP2Server::AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming)
|
||||||
{
|
{
|
||||||
if (!session || !session->GetRemoteIdentity ()) return false;
|
if (!session) return false;
|
||||||
|
if (incoming)
|
||||||
|
m_PendingIncomingSessions.remove (session);
|
||||||
|
if (!session->GetRemoteIdentity ()) return false;
|
||||||
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
|
auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
|
||||||
auto it = m_NTCP2Sessions.find (ident);
|
auto it = m_NTCP2Sessions.find (ident);
|
||||||
if (it != m_NTCP2Sessions.end ())
|
if (it != m_NTCP2Sessions.end ())
|
||||||
|
@ -1270,8 +1269,6 @@ namespace transport
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_NTCP2Sessions.insert (std::make_pair (ident, session));
|
m_NTCP2Sessions.insert (std::make_pair (ident, session));
|
||||||
if (incoming)
|
|
||||||
m_PendingIncomingSessions.remove (session);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1342,15 +1339,21 @@ namespace transport
|
||||||
{
|
{
|
||||||
conn->ServerLogin ();
|
conn->ServerLogin ();
|
||||||
m_PendingIncomingSessions.push_back (conn);
|
m_PendingIncomingSessions.push_back (conn);
|
||||||
|
conn = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
|
||||||
|
|
||||||
if (error != boost::asio::error::operation_aborted)
|
if (error != boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
conn = std::make_shared<NTCP2Session> (*this);
|
if (!conn) // connection is used, create new one
|
||||||
|
conn = std::make_shared<NTCP2Session> (*this);
|
||||||
|
else // reuse failed
|
||||||
|
conn->Close ();
|
||||||
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
|
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
|
||||||
conn, std::placeholders::_1));
|
conn, std::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
@ -1406,13 +1409,13 @@ namespace transport
|
||||||
// pending
|
// pending
|
||||||
for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
|
for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
|
||||||
{
|
{
|
||||||
if ((*it)->IsEstablished () || (*it)->IsTerminated ())
|
if ((*it)->IsEstablished () || (*it)->IsTerminationTimeoutExpired (ts))
|
||||||
it = m_PendingIncomingSessions.erase (it); // established or terminated
|
|
||||||
else if ((*it)->IsTerminationTimeoutExpired (ts))
|
|
||||||
{
|
{
|
||||||
(*it)->Terminate ();
|
(*it)->Terminate ();
|
||||||
it = m_PendingIncomingSessions.erase (it); // expired
|
it = m_PendingIncomingSessions.erase (it); // etsablished of expired
|
||||||
}
|
}
|
||||||
|
else if ((*it)->IsTerminated ())
|
||||||
|
it = m_PendingIncomingSessions.erase (it); // already terminated
|
||||||
else
|
else
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ namespace transport
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
void TerminateByTimeout ();
|
void TerminateByTimeout ();
|
||||||
void Done ();
|
void Done ();
|
||||||
|
void Close () { m_Socket.close (); }; // for accept
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
|
||||||
|
|
||||||
|
@ -194,7 +195,7 @@ namespace transport
|
||||||
|
|
||||||
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
||||||
// data phase
|
// data phase
|
||||||
uint8_t m_Kab[33], m_Kba[32], m_Sipkeysab[33], m_Sipkeysba[32];
|
uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32];
|
||||||
const uint8_t * m_SendKey, * m_ReceiveKey;
|
const uint8_t * m_SendKey, * m_ReceiveKey;
|
||||||
#if OPENSSL_SIPHASH
|
#if OPENSSL_SIPHASH
|
||||||
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
|
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
|
||||||
|
|
|
@ -27,12 +27,8 @@ namespace i2p
|
||||||
void RouterContext::Init ()
|
void RouterContext::Init ()
|
||||||
{
|
{
|
||||||
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
srand (i2p::util::GetMillisecondsSinceEpoch () % 1000);
|
||||||
#ifdef WIN32
|
|
||||||
// for compatibility with WinXP
|
|
||||||
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
|
||||||
#else
|
|
||||||
m_StartupTime = std::chrono::steady_clock::now();
|
m_StartupTime = std::chrono::steady_clock::now();
|
||||||
#endif
|
|
||||||
if (!Load ())
|
if (!Load ())
|
||||||
CreateNewRouter ();
|
CreateNewRouter ();
|
||||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||||
|
@ -696,9 +692,9 @@ namespace i2p
|
||||||
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
return i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
void RouterContext::HandleI2NPMessage (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len), from));
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
|
@ -721,12 +717,7 @@ namespace i2p
|
||||||
|
|
||||||
uint32_t RouterContext::GetUptime () const
|
uint32_t RouterContext::GetUptime () const
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
|
||||||
// for compatibility with WinXP
|
|
||||||
return i2p::util::GetSecondsSinceEpoch () - m_StartupTime;
|
|
||||||
#else
|
|
||||||
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
|
return std::chrono::duration_cast<std::chrono::seconds> (std::chrono::steady_clock::now() - m_StartupTime).count ();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool RouterContext::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
||||||
|
|
|
@ -115,12 +115,17 @@ namespace i2p
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; };
|
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () { return nullptr; };
|
||||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const;
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
|
||||||
|
|
||||||
// override GarlicDestination
|
// override GarlicDestination
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// implements GarlicDestination
|
||||||
|
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||||
|
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void CreateNewRouter ();
|
void CreateNewRouter ();
|
||||||
|
@ -137,11 +142,7 @@ namespace i2p
|
||||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
||||||
uint64_t m_LastUpdateTime; // in seconds
|
uint64_t m_LastUpdateTime; // in seconds
|
||||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||||
#ifdef WIN32
|
|
||||||
uint64_t m_StartupTime = 0; // in seconds since epoch
|
|
||||||
#else
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
|
||||||
#endif
|
|
||||||
uint64_t m_BandwidthLimit; // allowed bandwidth
|
uint64_t m_BandwidthLimit; // allowed bandwidth
|
||||||
int m_ShareRatio;
|
int m_ShareRatio;
|
||||||
RouterStatus m_Status;
|
RouterStatus m_Status;
|
||||||
|
|
|
@ -465,6 +465,7 @@ namespace transport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
|
||||||
|
i2p::data::netdb.SetUnreachable (ident, true); // we are here because all connection attempts failed
|
||||||
peer.Done ();
|
peer.Done ();
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
m_Peers.erase (ident);
|
m_Peers.erase (ident);
|
||||||
|
@ -647,11 +648,16 @@ namespace transport
|
||||||
auto it = m_Peers.find (ident);
|
auto it = m_Peers.find (ident);
|
||||||
if (it != m_Peers.end ())
|
if (it != m_Peers.end ())
|
||||||
{
|
{
|
||||||
|
auto before = it->second.sessions.size ();
|
||||||
it->second.sessions.remove (session);
|
it->second.sessions.remove (session);
|
||||||
if (it->second.sessions.empty ()) // TODO: why?
|
if (it->second.sessions.empty ())
|
||||||
{
|
{
|
||||||
if (it->second.delayedMessages.size () > 0)
|
if (it->second.delayedMessages.size () > 0)
|
||||||
|
{
|
||||||
|
if (before > 0) // we had an active session before
|
||||||
|
it->second.numAttempts = 0; // start over
|
||||||
ConnectToPeer (ident, it->second);
|
ConnectToPeer (ident, it->second);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PeersMutex);
|
std::unique_lock<std::mutex> l(m_PeersMutex);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
|
||||||
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
|
||||||
|
|
||||||
// inet_pton exists Windows since Vista, but XP haven't that function!
|
// inet_pton exists Windows since Vista, but XP doesn't have that function!
|
||||||
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
// This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
|
||||||
int inet_pton_xp(int af, const char *src, void *dst)
|
int inet_pton_xp(int af, const char *src, void *dst)
|
||||||
{
|
{
|
||||||
|
@ -62,16 +62,21 @@ namespace net
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
bool IsWindowsXPorLater()
|
bool IsWindowsXPorLater()
|
||||||
{
|
{
|
||||||
OSVERSIONINFO osvi;
|
static bool isRequested = false;
|
||||||
|
static bool isXP = false;
|
||||||
|
if (!isRequested)
|
||||||
|
{
|
||||||
|
// request
|
||||||
|
OSVERSIONINFO osvi;
|
||||||
|
|
||||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||||
GetVersionEx(&osvi);
|
GetVersionEx(&osvi);
|
||||||
|
|
||||||
if (osvi.dwMajorVersion <= 5)
|
isXP = osvi.dwMajorVersion <= 5;
|
||||||
return true;
|
isRequested = true;
|
||||||
else
|
}
|
||||||
return false;
|
return isXP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
|
||||||
|
@ -202,21 +207,20 @@ namespace net
|
||||||
std::string localAddressUniversal = localAddress.to_string();
|
std::string localAddressUniversal = localAddress.to_string();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (IsWindowsXPorLater())
|
typedef int (* IPN)(int af, const char *src, void *dst);
|
||||||
{
|
IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
|
||||||
#define inet_pton inet_pton_xp
|
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found
|
||||||
}
|
|
||||||
|
|
||||||
if(localAddress.is_v4())
|
if(localAddress.is_v4())
|
||||||
{
|
{
|
||||||
sockaddr_in inputAddress;
|
sockaddr_in inputAddress;
|
||||||
inet_pton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
inetpton(AF_INET, localAddressUniversal.c_str(), &(inputAddress.sin_addr));
|
||||||
return GetMTUWindowsIpv4(inputAddress, fallback);
|
return GetMTUWindowsIpv4(inputAddress, fallback);
|
||||||
}
|
}
|
||||||
else if(localAddress.is_v6())
|
else if(localAddress.is_v6())
|
||||||
{
|
{
|
||||||
sockaddr_in6 inputAddress;
|
sockaddr_in6 inputAddress;
|
||||||
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
inetpton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
|
||||||
return GetMTUWindowsIpv6(inputAddress, fallback);
|
return GetMTUWindowsIpv6(inputAddress, fallback);
|
||||||
} else {
|
} else {
|
||||||
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
|
||||||
|
@ -312,15 +316,14 @@ namespace net
|
||||||
if (cur_ifname == ifname && cur->ifa_addr && cur->ifa_addr->sa_family == af)
|
if (cur_ifname == ifname && cur->ifa_addr && cur->ifa_addr->sa_family == af)
|
||||||
{
|
{
|
||||||
// match
|
// match
|
||||||
char * addr = new char[INET6_ADDRSTRLEN];
|
char addr[INET6_ADDRSTRLEN];
|
||||||
bzero(addr, INET6_ADDRSTRLEN);
|
memset (addr, 0, INET6_ADDRSTRLEN);
|
||||||
if(af == AF_INET)
|
if(af == AF_INET)
|
||||||
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
|
inet_ntop(af, &((sockaddr_in *)cur->ifa_addr)->sin_addr, addr, INET6_ADDRSTRLEN);
|
||||||
else
|
else
|
||||||
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
|
inet_ntop(af, &((sockaddr_in6 *)cur->ifa_addr)->sin6_addr, addr, INET6_ADDRSTRLEN);
|
||||||
freeifaddrs(addrs);
|
freeifaddrs(addrs);
|
||||||
std::string cur_ifaddr(addr);
|
std::string cur_ifaddr(addr);
|
||||||
delete[] addr;
|
|
||||||
return boost::asio::ip::address::from_string(cur_ifaddr);
|
return boost::asio::ip::address::from_string(cur_ifaddr);
|
||||||
}
|
}
|
||||||
cur = cur->ifa_next;
|
cur = cur->ifa_next;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 43
|
#define I2P_VERSION_MICRO 44
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<translation type="qt" />
|
<translation type="qt" />
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
<release version="2.29.0" date="2019-10-21" />
|
<release version="2.29.0" date="2019-10-21" />
|
||||||
<release version="2.28.0" date="2019-08-27" />
|
<release version="2.28.0" date="2019-08-27" />
|
||||||
<release version="2.27.0" date="2019-07-03" />
|
<release version="2.27.0" date="2019-07-03" />
|
||||||
<release version="2.26.0" date="2019-06-07" />
|
<release version="2.26.0" date="2019-06-07" />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files
|
CXXFLAGS += -Wall -Wextra -pedantic -O0 -g -std=c++11 -D_GLIBCXX_USE_NANOSLEEP=1 -I../libi2pd/ -pthread -Wl,--unresolved-symbols=ignore-in-object-files
|
||||||
|
|
||||||
TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding
|
TESTS = test-gost test-gost-sig test-base-64 test-x25519 test-aeadchacha20poly1305 test-blinding test-elligator
|
||||||
|
|
||||||
all: $(TESTS) run
|
all: $(TESTS) run
|
||||||
|
|
||||||
|
@ -25,6 +25,9 @@ test-aeadchacha20poly1305: ../libi2pd/Crypto.cpp ../libi2pd/ChaCha20.cpp ../libi
|
||||||
test-blinding: ../libi2pd/Crypto.cpp ../libi2pd/Blinding.cpp ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/util.cpp ../libi2pd/Identity.cpp ../libi2pd/Signature.cpp ../libi2pd/Timestamp.cpp test-blinding.cpp
|
test-blinding: ../libi2pd/Crypto.cpp ../libi2pd/Blinding.cpp ../libi2pd/Ed25519.cpp ../libi2pd/I2PEndian.cpp ../libi2pd/Log.cpp ../libi2pd/util.cpp ../libi2pd/Identity.cpp ../libi2pd/Signature.cpp ../libi2pd/Timestamp.cpp test-blinding.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
|
||||||
|
|
||||||
|
test-elligator: ../libi2pd/Elligator.cpp ../libi2pd/Crypto.cpp test-elligator.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -o $@ $^ -lcrypto -lssl -lboost_system
|
||||||
|
|
||||||
run: $(TESTS)
|
run: $(TESTS)
|
||||||
@for TEST in $(TESTS); do ./$$TEST ; done
|
@for TEST in $(TESTS); do ./$$TEST ; done
|
||||||
|
|
||||||
|
|
77
tests/test-elligator.cpp
Normal file
77
tests/test-elligator.cpp
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Elligator.h"
|
||||||
|
|
||||||
|
const uint8_t key[32] =
|
||||||
|
{
|
||||||
|
0x33, 0x95, 0x19, 0x64, 0x00, 0x3c, 0x94, 0x08, 0x78, 0x06, 0x3c, 0xcf, 0xd0, 0x34, 0x8a, 0xf4,
|
||||||
|
0x21, 0x50, 0xca, 0x16, 0xd2, 0x64, 0x6f, 0x2c, 0x58, 0x56, 0xe8, 0x33, 0x83, 0x77, 0xd8, 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t encoded_key[32] =
|
||||||
|
{
|
||||||
|
0x28, 0x20, 0xb6, 0xb2, 0x41, 0xe0, 0xf6, 0x8a, 0x6c, 0x4a, 0x7f, 0xee, 0x3d, 0x97, 0x82, 0x28,
|
||||||
|
0xef, 0x3a, 0xe4, 0x55, 0x33, 0xcd, 0x41, 0x0a, 0xa9, 0x1a, 0x41, 0x53, 0x31, 0xd8, 0x61, 0x2d
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t encoded_key_high_y[32] =
|
||||||
|
{
|
||||||
|
0x3c, 0xfb, 0x87, 0xc4, 0x6c, 0x0b, 0x45, 0x75, 0xca, 0x81, 0x75, 0xe0, 0xed, 0x1c, 0x0a, 0xe9,
|
||||||
|
0xda, 0xe7, 0x9d, 0xb7, 0x8d, 0xf8, 0x69, 0x97, 0xc4, 0x84, 0x7b, 0x9f, 0x20, 0xb2, 0x77, 0x18
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t encoded1[32] =
|
||||||
|
{
|
||||||
|
0xe7, 0x35, 0x07, 0xd3, 0x8b, 0xae, 0x63, 0x99, 0x2b, 0x3f, 0x57, 0xaa, 0xc4, 0x8c, 0x0a, 0xbc,
|
||||||
|
0x14, 0x50, 0x95, 0x89, 0x28, 0x84, 0x57, 0x99, 0x5a, 0x2b, 0x4c, 0xa3, 0x49, 0x0a, 0xa2, 0x07
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t key1[32] =
|
||||||
|
{
|
||||||
|
0x1e, 0x8a, 0xff, 0xfe, 0xd6, 0xbf, 0x53, 0xfe, 0x27, 0x1a, 0xd5, 0x72, 0x47, 0x32, 0x62, 0xde,
|
||||||
|
0xd8, 0xfa, 0xec, 0x68, 0xe5, 0xe6, 0x7e, 0xf4, 0x5e, 0xbb, 0x82, 0xee, 0xba, 0x52, 0x60, 0x4f
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t encoded2[32] =
|
||||||
|
{
|
||||||
|
0x95, 0xa1, 0x60, 0x19, 0x04, 0x1d, 0xbe, 0xfe, 0xd9, 0x83, 0x20, 0x48, 0xed, 0xe1, 0x19, 0x28,
|
||||||
|
0xd9, 0x03, 0x65, 0xf2, 0x4a, 0x38, 0xaa, 0x7a, 0xef, 0x1b, 0x97, 0xe2, 0x39, 0x54, 0x10, 0x1b
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t key2[32] =
|
||||||
|
{
|
||||||
|
0x79, 0x4f, 0x05, 0xba, 0x3e, 0x3a, 0x72, 0x95, 0x80, 0x22, 0x46, 0x8c, 0x88, 0x98, 0x1e, 0x0b,
|
||||||
|
0xe5, 0x78, 0x2b, 0xe1, 0xe1, 0x14, 0x5c, 0xe2, 0xc3, 0xc6, 0xfd, 0xe1, 0x6d, 0xed, 0x53, 0x63
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t encoded3[32] =
|
||||||
|
{
|
||||||
|
0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t key3[32] =
|
||||||
|
{
|
||||||
|
0x9c, 0xdb, 0x52, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||||
|
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
|
||||||
|
};
|
||||||
|
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
uint8_t buf[32];
|
||||||
|
i2p::crypto::Elligator2 el;
|
||||||
|
// encoding tests
|
||||||
|
el.Encode (key, buf);
|
||||||
|
assert(memcmp (buf, encoded_key, 32) == 0);
|
||||||
|
el.Encode (key, buf, true); // with highY
|
||||||
|
assert(memcmp (buf, encoded_key_high_y, 32) == 0);
|
||||||
|
// decoding tests
|
||||||
|
el.Decode (encoded1, buf);
|
||||||
|
assert(memcmp (buf, key1, 32) == 0);
|
||||||
|
el.Decode (encoded2, buf);
|
||||||
|
assert(memcmp (buf, key2, 32) == 0);
|
||||||
|
el.Decode (encoded3, buf);
|
||||||
|
assert(memcmp (buf, key3, 32) == 0);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue