fix code syle(spaces->tabs, tabulations)

Signed-off-by: R4SAS <r4sas@i2pmail.org>
pull/1525/head
R4SAS 4 years ago committed by R4SAS
parent 9633c247f0
commit 7a5146ea74

@ -27,8 +27,8 @@ namespace util
i2p::log::SetThrowFunction ([](const std::string& s) i2p::log::SetThrowFunction ([](const std::string& s)
{ {
MessageBox(0, TEXT(s.c_str ()), TEXT("i2pd"), MB_ICONERROR | MB_TASKMODAL | MB_OK ); MessageBox(0, TEXT(s.c_str ()), TEXT("i2pd"), MB_ICONERROR | MB_TASKMODAL | MB_OK );
}); });
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;

@ -1,455 +1,455 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <windows.h> #include <windows.h>
#include <shellapi.h> #include <shellapi.h>
#include "ClientContext.h" #include "ClientContext.h"
#include "Config.h" #include "Config.h"
#include "NetDb.hpp" #include "NetDb.hpp"
#include "RouterContext.h" #include "RouterContext.h"
#include "Transports.h" #include "Transports.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "version.h" #include "version.h"
#include "resource.h" #include "resource.h"
#include "Daemon.h" #include "Daemon.h"
#include "Win32App.h" #include "Win32App.h"
#include "Win32NetState.h" #include "Win32NetState.h"
#define ID_ABOUT 2000 #define ID_ABOUT 2000
#define ID_EXIT 2001 #define ID_EXIT 2001
#define ID_CONSOLE 2002 #define ID_CONSOLE 2002
#define ID_APP 2003 #define ID_APP 2003
#define ID_GRACEFUL_SHUTDOWN 2004 #define ID_GRACEFUL_SHUTDOWN 2004
#define ID_STOP_GRACEFUL_SHUTDOWN 2005 #define ID_STOP_GRACEFUL_SHUTDOWN 2005
#define ID_RELOAD 2006 #define ID_RELOAD 2006
#define ID_ACCEPT_TRANSIT 2007 #define ID_ACCEPT_TRANSIT 2007
#define ID_DECLINE_TRANSIT 2008 #define ID_DECLINE_TRANSIT 2008
#define ID_TRAY_ICON 2050 #define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1) #define WM_TRAYICON (WM_USER + 1)
#define IDT_GRACEFUL_SHUTDOWN_TIMER 2100 #define IDT_GRACEFUL_SHUTDOWN_TIMER 2100
#define FRAME_UPDATE_TIMER 2101 #define FRAME_UPDATE_TIMER 2101
#define IDT_GRACEFUL_TUNNELCHECK_TIMER 2102 #define IDT_GRACEFUL_TUNNELCHECK_TIMER 2102
namespace i2p namespace i2p
{ {
namespace win32 namespace win32
{ {
static DWORD GracefulShutdownEndtime = 0; static DWORD GracefulShutdownEndtime = 0;
typedef DWORD (* IPN)(); typedef DWORD (* IPN)();
IPN GetTickCountLocal = (IPN)GetProcAddress (GetModuleHandle ("KERNEL32.dll"), "GetTickCount"); 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();
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
if(!i2p::context.AcceptsTunnels()) if(!i2p::context.AcceptsTunnels())
InsertMenu (hPopup, -1, InsertMenu (hPopup, -1,
i2p::util::DaemonWin32::Instance ().isGraceful ? MF_BYPOSITION | MF_STRING | MF_GRAYED : MF_BYPOSITION | MF_STRING, i2p::util::DaemonWin32::Instance ().isGraceful ? MF_BYPOSITION | MF_STRING | MF_GRAYED : MF_BYPOSITION | MF_STRING,
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 tunnels config"); 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
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "Stop &graceful shutdown"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_STOP_GRACEFUL_SHUTDOWN, "Stop &graceful shutdown");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_EXIT, "E&xit");
SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE); SetMenuDefaultItem (hPopup, ID_CONSOLE, FALSE);
SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0); SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);
POINT p; POINT p;
if (!curpos) if (!curpos)
{ {
GetCursorPos (&p); GetCursorPos (&p);
curpos = &p; curpos = &p;
} }
WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL); WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
SendMessage (hWnd, WM_COMMAND, cmd, 0); SendMessage (hWnd, WM_COMMAND, cmd, 0);
DestroyMenu(hPopup); DestroyMenu(hPopup);
} }
static void AddTrayIcon (HWND hWnd) static void AddTrayIcon (HWND hWnd)
{ {
NOTIFYICONDATA nid; NOTIFYICONDATA nid;
memset(&nid, 0, sizeof(nid)); memset(&nid, 0, sizeof(nid));
nid.cbSize = sizeof(nid); nid.cbSize = sizeof(nid);
nid.hWnd = hWnd; nid.hWnd = hWnd;
nid.uID = ID_TRAY_ICON; nid.uID = ID_TRAY_ICON;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO; nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
nid.uCallbackMessage = WM_TRAYICON; nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON)); nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (MAINICON));
strcpy (nid.szTip, "i2pd"); strcpy (nid.szTip, "i2pd");
strcpy (nid.szInfo, "i2pd is starting"); strcpy (nid.szInfo, "i2pd is starting");
Shell_NotifyIcon(NIM_ADD, &nid ); Shell_NotifyIcon(NIM_ADD, &nid );
} }
static void RemoveTrayIcon (HWND hWnd) static void RemoveTrayIcon (HWND hWnd)
{ {
NOTIFYICONDATA nid; NOTIFYICONDATA nid;
nid.hWnd = hWnd; nid.hWnd = hWnd;
nid.uID = ID_TRAY_ICON; nid.uID = ID_TRAY_ICON;
Shell_NotifyIcon (NIM_DELETE, &nid); Shell_NotifyIcon (NIM_DELETE, &nid);
} }
static void ShowUptime (std::stringstream& s, int seconds) static void ShowUptime (std::stringstream& s, int seconds)
{ {
int num; int num;
if ((num = seconds / 86400) > 0) { if ((num = seconds / 86400) > 0) {
s << num << " days, "; s << num << " days, ";
seconds -= num * 86400; seconds -= num * 86400;
} }
if ((num = seconds / 3600) > 0) { if ((num = seconds / 3600) > 0) {
s << num << " hours, "; s << num << " hours, ";
seconds -= num * 3600; seconds -= num * 3600;
} }
if ((num = seconds / 60) > 0) { if ((num = seconds / 60) > 0) {
s << num << " min, "; s << num << " min, ";
seconds -= num * 60; seconds -= num * 60;
} }
s << seconds << " seconds\n"; s << seconds << " seconds\n";
} }
template <typename size> static void ShowTransfered (std::stringstream& s, size transfer) template <typename size> static void ShowTransfered (std::stringstream& s, size transfer)
{ {
auto bytes = transfer & 0x03ff; auto bytes = transfer & 0x03ff;
transfer >>= 10; transfer >>= 10;
auto kbytes = transfer & 0x03ff; auto kbytes = transfer & 0x03ff;
transfer >>= 10; transfer >>= 10;
auto mbytes = transfer & 0x03ff; auto mbytes = transfer & 0x03ff;
transfer >>= 10; transfer >>= 10;
auto gbytes = transfer & 0x03ff; auto gbytes = transfer & 0x03ff;
if (gbytes) if (gbytes)
s << gbytes << " GB, "; s << gbytes << " GB, ";
if (mbytes) if (mbytes)
s << mbytes << " MB, "; s << mbytes << " MB, ";
if (kbytes) if (kbytes)
s << kbytes << " KB, "; s << kbytes << " KB, ";
s << bytes << " Bytes\n"; s << bytes << " Bytes\n";
} }
static void PrintMainWindowText (std::stringstream& s) static void PrintMainWindowText (std::stringstream& s)
{ {
s << "\n"; s << "\n";
s << "Status: "; s << "Status: ";
switch (i2p::context.GetStatus()) switch (i2p::context.GetStatus())
{ {
case eRouterStatusOK: s << "OK"; break; case eRouterStatusOK: s << "OK"; break;
case eRouterStatusTesting: s << "Testing"; break; case eRouterStatusTesting: s << "Testing"; break;
case eRouterStatusFirewalled: s << "Firewalled"; break; case eRouterStatusFirewalled: s << "Firewalled"; break;
case eRouterStatusError: case eRouterStatusError:
{ {
switch (i2p::context.GetError()) switch (i2p::context.GetError())
{ {
case eRouterErrorClockSkew: s << "Clock skew"; break; case eRouterErrorClockSkew: s << "Clock skew"; break;
default: s << "Error"; default: s << "Error";
} }
break; break;
} }
default: s << "Unknown"; default: s << "Unknown";
} }
s << "; "; s << "; ";
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
if (GracefulShutdownEndtime != 0) if (GracefulShutdownEndtime != 0)
{ {
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000; DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000;
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft); s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
} }
else else
s << "\n"; s << "\n";
s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; "; s << "Inbound: " << i2p::transport::transports.GetInBandwidth() / 1024 << " KiB/s; ";
s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n"; s << "Outbound: " << i2p::transport::transports.GetOutBandwidth() / 1024 << " KiB/s\n";
s << "Received: "; ShowTransfered (s, i2p::transport::transports.GetTotalReceivedBytes()); s << "Received: "; ShowTransfered (s, i2p::transport::transports.GetTotalReceivedBytes());
s << "Sent: "; ShowTransfered (s, i2p::transport::transports.GetTotalSentBytes()); s << "Sent: "; ShowTransfered (s, i2p::transport::transports.GetTotalSentBytes());
s << "\n"; s << "\n";
s << "Routers: " << i2p::data::netdb.GetNumRouters () << "; "; s << "Routers: " << i2p::data::netdb.GetNumRouters () << "; ";
s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << "; "; s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << "; ";
s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "\n"; s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "\n";
s << "Tunnels: "; s << "Tunnels: ";
s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; "; s << "In: " << i2p::tunnel::tunnels.CountInboundTunnels() << "; ";
s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; "; s << "Out: " << i2p::tunnel::tunnels.CountOutboundTunnels() << "; ";
s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n"; s << "Transit: " << i2p::tunnel::tunnels.CountTransitTunnels() << "\n";
s << "\n"; s << "\n";
} }
static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
static UINT s_uTaskbarRestart; static UINT s_uTaskbarRestart;
switch (uMsg) switch (uMsg)
{ {
case WM_CREATE: case WM_CREATE:
{ {
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
AddTrayIcon (hWnd); AddTrayIcon (hWnd);
break; break;
} }
case WM_CLOSE: case WM_CLOSE:
{ {
RemoveTrayIcon (hWnd); RemoveTrayIcon (hWnd);
KillTimer (hWnd, FRAME_UPDATE_TIMER); KillTimer (hWnd, FRAME_UPDATE_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER); KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
PostQuitMessage (0); PostQuitMessage (0);
break; break;
} }
case WM_COMMAND: case WM_COMMAND:
{ {
switch (LOWORD(wParam)) switch (LOWORD(wParam))
{ {
case ID_ABOUT: case ID_ABOUT:
{ {
std::stringstream text; std::stringstream text;
text << "Version: " << I2PD_VERSION << " " << CODENAME; text << "Version: " << I2PD_VERSION << " " << CODENAME;
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0; return 0;
} }
case ID_EXIT: case ID_EXIT:
{ {
PostMessage (hWnd, WM_CLOSE, 0, 0); PostMessage (hWnd, WM_CLOSE, 0, 0);
return 0; return 0;
} }
case ID_ACCEPT_TRANSIT: case ID_ACCEPT_TRANSIT:
{ {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
std::stringstream text; std::stringstream text;
text << "I2Pd now accept transit tunnels"; text << "I2Pd now accept transit tunnels";
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0; return 0;
} }
case ID_DECLINE_TRANSIT: case ID_DECLINE_TRANSIT:
{ {
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
std::stringstream text; std::stringstream text;
text << "I2Pd now decline new transit tunnels"; text << "I2Pd now decline new transit tunnels";
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0; return 0;
} }
case ID_GRACEFUL_SHUTDOWN: case ID_GRACEFUL_SHUTDOWN:
{ {
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 = GetTickCountLocal() + 10*60*1000; GracefulShutdownEndtime = GetTickCountLocal() + 10*60*1000;
i2p::util::DaemonWin32::Instance ().isGraceful = true; i2p::util::DaemonWin32::Instance ().isGraceful = true;
return 0; return 0;
} }
case ID_STOP_GRACEFUL_SHUTDOWN: case ID_STOP_GRACEFUL_SHUTDOWN:
{ {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER); KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
GracefulShutdownEndtime = 0; GracefulShutdownEndtime = 0;
i2p::util::DaemonWin32::Instance ().isGraceful = false; i2p::util::DaemonWin32::Instance ().isGraceful = false;
return 0; return 0;
} }
case ID_RELOAD: case ID_RELOAD:
{ {
i2p::client::context.ReloadConfig(); i2p::client::context.ReloadConfig();
std::stringstream text; std::stringstream text;
text << "I2Pd reloading configs..."; text << "I2Pd reloading configs...";
MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK ); MessageBox( hWnd, TEXT(text.str ().c_str ()), TEXT("i2pd"), MB_ICONINFORMATION | MB_OK );
return 0; return 0;
} }
case ID_CONSOLE: case ID_CONSOLE:
{ {
char buf[30]; char buf[30];
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort); snprintf(buf, 30, "http://%s:%d", httpAddr.c_str(), httpPort);
ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL); ShellExecute(NULL, "open", buf, NULL, NULL, SW_SHOWNORMAL);
return 0; return 0;
} }
case ID_APP: case ID_APP:
{ {
ShowWindow(hWnd, SW_SHOW); ShowWindow(hWnd, SW_SHOW);
SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL); SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL);
return 0; return 0;
} }
} }
break; break;
} }
case WM_SYSCOMMAND: case WM_SYSCOMMAND:
{ {
switch (wParam) switch (wParam)
{ {
case SC_MINIMIZE: case SC_MINIMIZE:
{ {
ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_HIDE);
KillTimer (hWnd, FRAME_UPDATE_TIMER); KillTimer (hWnd, FRAME_UPDATE_TIMER);
return 0; return 0;
} }
case SC_CLOSE: case SC_CLOSE:
{ {
std::string close; i2p::config::GetOption("close", close); std::string close; i2p::config::GetOption("close", close);
if (0 == close.compare("ask")) if (0 == close.compare("ask"))
switch(::MessageBox(hWnd, "Would you like to minimize instead of exiting?" switch(::MessageBox(hWnd, "Would you like to minimize instead of exiting?"
" You can add 'close' configuration option. Valid values are: ask, minimize, exit.", " You can add 'close' configuration option. Valid values are: ask, minimize, exit.",
"Minimize instead of exiting?", MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1)) "Minimize instead of exiting?", MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1))
{ {
case IDYES: close = "minimize"; break; case IDYES: close = "minimize"; break;
case IDNO: close = "exit"; break; case IDNO: close = "exit"; break;
default: return 0; default: return 0;
} }
if (0 == close.compare("minimize")) if (0 == close.compare("minimize"))
{ {
ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_HIDE);
KillTimer (hWnd, FRAME_UPDATE_TIMER); KillTimer (hWnd, FRAME_UPDATE_TIMER);
return 0; return 0;
} }
if (0 != close.compare("exit")) if (0 != close.compare("exit"))
{ {
::MessageBox(hWnd, close.c_str(), "Unknown close action in config", MB_OK | MB_ICONWARNING); ::MessageBox(hWnd, close.c_str(), "Unknown close action in config", MB_OK | MB_ICONWARNING);
return 0; return 0;
} }
} }
} }
} }
case WM_TRAYICON: case WM_TRAYICON:
{ {
switch (lParam) switch (lParam)
{ {
case WM_LBUTTONUP: case WM_LBUTTONUP:
case WM_RBUTTONUP: case WM_RBUTTONUP:
{ {
SetForegroundWindow (hWnd); SetForegroundWindow (hWnd);
ShowPopupMenu(hWnd, NULL, -1); ShowPopupMenu(hWnd, NULL, -1);
PostMessage (hWnd, WM_APP + 1, 0, 0); PostMessage (hWnd, WM_APP + 1, 0, 0);
break; break;
} }
} }
break; break;
} }
case WM_TIMER: case WM_TIMER:
{ {
switch(wParam) switch(wParam)
{ {
case IDT_GRACEFUL_SHUTDOWN_TIMER: case IDT_GRACEFUL_SHUTDOWN_TIMER:
{ {
GracefulShutdownEndtime = 0; GracefulShutdownEndtime = 0;
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
return 0; return 0;
} }
case IDT_GRACEFUL_TUNNELCHECK_TIMER: case IDT_GRACEFUL_TUNNELCHECK_TIMER:
{ {
if (i2p::tunnel::tunnels.CountTransitTunnels() == 0) if (i2p::tunnel::tunnels.CountTransitTunnels() == 0)
PostMessage (hWnd, WM_CLOSE, 0, 0); PostMessage (hWnd, WM_CLOSE, 0, 0);
else else
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr);
return 0; return 0;
} }
case FRAME_UPDATE_TIMER: case FRAME_UPDATE_TIMER:
{ {
InvalidateRect(hWnd, NULL, TRUE); InvalidateRect(hWnd, NULL, TRUE);
return 0; return 0;
} }
} }
break; break;
} }
case WM_PAINT: case WM_PAINT:
{ {
HDC hDC; HDC hDC;
PAINTSTRUCT ps; PAINTSTRUCT ps;
RECT rp; RECT rp;
HFONT hFont; HFONT hFont;
std::stringstream s; PrintMainWindowText (s); std::stringstream s; PrintMainWindowText (s);
hDC = BeginPaint (hWnd, &ps); hDC = BeginPaint (hWnd, &ps);
GetClientRect(hWnd, &rp); GetClientRect(hWnd, &rp);
SetTextColor(hDC, 0x00D43B69); SetTextColor(hDC, 0x00D43B69);
hFont = CreateFont(18,0,0,0,0,0,0,0,DEFAULT_CHARSET,0,0,0,0,TEXT("Times New Roman")); hFont = CreateFont(18,0,0,0,0,0,0,0,DEFAULT_CHARSET,0,0,0,0,TEXT("Times New Roman"));
SelectObject(hDC,hFont); SelectObject(hDC,hFont);
DrawText(hDC, TEXT(s.str().c_str()), s.str().length(), &rp, DT_CENTER|DT_VCENTER); DrawText(hDC, TEXT(s.str().c_str()), s.str().length(), &rp, DT_CENTER|DT_VCENTER);
DeleteObject(hFont); DeleteObject(hFont);
EndPaint(hWnd, &ps); EndPaint(hWnd, &ps);
break; break;
} }
default: default:
{ {
if (uMsg == s_uTaskbarRestart) if (uMsg == s_uTaskbarRestart)
AddTrayIcon (hWnd); AddTrayIcon (hWnd);
break; break;
} }
} }
return DefWindowProc( hWnd, uMsg, wParam, lParam); return DefWindowProc( hWnd, uMsg, wParam, lParam);
} }
bool StartWin32App () bool StartWin32App ()
{ {
if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"))) if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
{ {
MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK); MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
return false; return false;
} }
// register main window // register main window
auto hInst = GetModuleHandle(NULL); auto hInst = GetModuleHandle(NULL);
WNDCLASSEX wclx; WNDCLASSEX wclx;
memset (&wclx, 0, sizeof(wclx)); memset (&wclx, 0, sizeof(wclx));
wclx.cbSize = sizeof(wclx); wclx.cbSize = sizeof(wclx);
wclx.style = 0; wclx.style = 0;
wclx.lpfnWndProc = WndProc; wclx.lpfnWndProc = WndProc;
//wclx.cbClsExtra = 0; //wclx.cbClsExtra = 0;
//wclx.cbWndExtra = 0; //wclx.cbWndExtra = 0;
wclx.hInstance = hInst; wclx.hInstance = hInst;
wclx.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(MAINICON)); wclx.hIcon = LoadIcon (hInst, MAKEINTRESOURCE(MAINICON));
wclx.hCursor = LoadCursor (NULL, IDC_ARROW); wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
//wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); //wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wclx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wclx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wclx.lpszMenuName = NULL; wclx.lpszMenuName = NULL;
wclx.lpszClassName = I2PD_WIN32_CLASSNAME; wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
RegisterClassEx (&wclx); RegisterClassEx (&wclx);
// create new window // create new window
if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 210, NULL, NULL, hInst, NULL)) if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, 100, 100, 350, 210, NULL, NULL, hInst, NULL))
{ {
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false; return false;
} }
SubscribeToEvents(); SubscribeToEvents();
return true; return true;
} }
int RunWin32App () int RunWin32App ()
{ {
MSG msg; MSG msg;
while (GetMessage (&msg, NULL, 0, 0 )) while (GetMessage (&msg, NULL, 0, 0 ))
{ {
TranslateMessage (&msg); TranslateMessage (&msg);
DispatchMessage (&msg); DispatchMessage (&msg);
} }
return msg.wParam; return msg.wParam;
} }
void StopWin32App () void StopWin32App ()
{ {
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd) if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
// UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app // UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
} }
bool GracefulShutdown () bool GracefulShutdown ()
{ {
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd) if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_GRACEFUL_SHUTDOWN, 0), 0);
return hWnd; return hWnd;
} }
bool StopGracefulShutdown () bool StopGracefulShutdown ()
{ {
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd) 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; return hWnd;
} }
} }
} }

@ -1,17 +1,17 @@
#ifndef WIN32APP_H__ #ifndef WIN32APP_H__
#define WIN32APP_H__ #define WIN32APP_H__
#define I2PD_WIN32_CLASSNAME "i2pd main window" #define I2PD_WIN32_CLASSNAME "i2pd main window"
namespace i2p namespace i2p
{ {
namespace win32 namespace win32
{ {
bool StartWin32App (); bool StartWin32App ();
void StopWin32App (); void StopWin32App ();
int RunWin32App (); int RunWin32App ();
bool GracefulShutdown (); bool GracefulShutdown ();
bool StopGracefulShutdown (); bool StopGracefulShutdown ();
} }
} }
#endif // WIN32APP_H__ #endif // WIN32APP_H__

@ -26,48 +26,48 @@
class I2PService class I2PService
{ {
public: public:
I2PService(PSTR pszServiceName, I2PService(PSTR pszServiceName,
BOOL fCanStop = TRUE, BOOL fCanStop = TRUE,
BOOL fCanShutdown = TRUE, BOOL fCanShutdown = TRUE,
BOOL fCanPauseContinue = FALSE); BOOL fCanPauseContinue = FALSE);
virtual ~I2PService(void); virtual ~I2PService(void);
static BOOL isService(); static BOOL isService();
static BOOL Run(I2PService &service); static BOOL Run(I2PService &service);
void Stop(); void Stop();
protected: protected:
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
virtual void OnStop(); virtual void OnStop();
virtual void OnPause(); virtual void OnPause();
virtual void OnContinue(); virtual void OnContinue();
virtual void OnShutdown(); virtual void OnShutdown();
void SetServiceStatus(DWORD dwCurrentState, void SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode = NO_ERROR, DWORD dwWin32ExitCode = NO_ERROR,
DWORD dwWaitHint = 0); DWORD dwWaitHint = 0);
private: private:
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
void WorkerThread(); void WorkerThread();
void Start(DWORD dwArgc, PSTR *pszArgv); void Start(DWORD dwArgc, PSTR *pszArgv);
void Pause(); void Pause();
void Continue(); void Continue();
void Shutdown(); void Shutdown();
static I2PService* s_service; static I2PService* s_service;
PSTR m_name; PSTR m_name;
SERVICE_STATUS m_status; SERVICE_STATUS m_status;
SERVICE_STATUS_HANDLE m_statusHandle; SERVICE_STATUS_HANDLE m_statusHandle;
BOOL m_fStopping; BOOL m_fStopping;
HANDLE m_hStoppedEvent; HANDLE m_hStoppedEvent;
std::thread* _worker; std::thread* _worker;
}; };
void InstallService( void InstallService(
@ -77,8 +77,8 @@ void InstallService(
PCSTR pszDependencies, PCSTR pszDependencies,
PCSTR pszAccount, PCSTR pszAccount,
PCSTR pszPassword PCSTR pszPassword
); );
void UninstallService(PCSTR pszServiceName); void UninstallService(PCSTR pszServiceName);
#endif // WIN_32_SERVICE_H__ #endif // WIN_32_SERVICE_H__

@ -1,11 +1,11 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
#define MAINICON 101 #define MAINICON 101
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

@ -127,8 +127,8 @@ namespace i2p
i2p::context.SetNetID (netID); i2p::context.SetNetID (netID);
i2p::context.Init (); i2p::context.Init ();
bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv4; i2p::config::GetOption("ipv4", ipv4);
#ifdef MESHNET #ifdef MESHNET
// manual override for meshnet // manual override for meshnet
ipv4 = false; ipv4 = false;
@ -143,8 +143,8 @@ namespace i2p
i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV6 (ipv6);
i2p::context.SetSupportsV4 (ipv4); i2p::context.SetSupportsV4 (ipv4);
bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ntcp; i2p::config::GetOption("ntcp", ntcp);
i2p::context.PublishNTCPAddress (ntcp, !ipv6); i2p::context.PublishNTCPAddress (ntcp, !ipv6);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2) if (ntcp2)
{ {
@ -172,10 +172,13 @@ namespace i2p
SetMaxNumTransitTunnels (transitTunnels); SetMaxNumTransitTunnels (transitTunnels);
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
if (isFloodfill) { if (isFloodfill)
{
LogPrint(eLogInfo, "Daemon: router will be floodfill"); LogPrint(eLogInfo, "Daemon: router will be floodfill");
i2p::context.SetFloodfill (true); i2p::context.SetFloodfill (true);
} else { }
else
{
i2p::context.SetFloodfill (false); i2p::context.SetFloodfill (false);
} }
@ -243,7 +246,8 @@ namespace i2p
i2p::transport::transports.RestrictRoutesToFamilies(fams); i2p::transport::transports.RestrictRoutesToFamilies(fams);
restricted = fams.size() > 0; restricted = fams.size() > 0;
} }
if (routers.length() > 0) { if (routers.length() > 0)
{
std::set<i2p::data::IdentHash> idents; std::set<i2p::data::IdentHash> idents;
size_t pos = 0, comma; size_t pos = 0, comma;
do do
@ -279,7 +283,8 @@ namespace i2p
i2p::data::netdb.Start(); i2p::data::netdb.Start();
bool upnp; i2p::config::GetOption("upnp.enabled", upnp); bool upnp; i2p::config::GetOption("upnp.enabled", upnp);
if (upnp) { if (upnp)
{
d.UPnP = std::unique_ptr<i2p::transport::UPnP>(new i2p::transport::UPnP); d.UPnP = std::unique_ptr<i2p::transport::UPnP>(new i2p::transport::UPnP);
d.UPnP->Start (); d.UPnP->Start ();
} }
@ -292,15 +297,15 @@ namespace i2p
} }
bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ntcp; i2p::config::GetOption("ntcp", ntcp);
bool ssu; i2p::config::GetOption("ssu", ssu); bool ssu; i2p::config::GetOption("ssu", ssu);
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: starting Transports");
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled"); if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled");
if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled"); if(!ntcp) LogPrint(eLogInfo, "Daemon: ntcp disabled");
i2p::transport::transports.Start(ntcp, ssu); i2p::transport::transports.Start(ntcp, ssu);
if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2()) if (i2p::transport::transports.IsBoundNTCP() || i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");
else else
{ {
LogPrint(eLogError, "Daemon: failed to start Transports"); LogPrint(eLogError, "Daemon: failed to start Transports");
/** shut down netdb right away */ /** shut down netdb right away */
@ -310,23 +315,23 @@ namespace i2p
} }
bool http; i2p::config::GetOption("http.enabled", http); bool http; i2p::config::GetOption("http.enabled", http);
if (http) { if (http)
{
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting webconsole at ", httpAddr, ":", httpPort); LogPrint(eLogInfo, "Daemon: starting webconsole at ", httpAddr, ":", httpPort);
try try
{ {
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort)); d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
d.httpServer->Start(); d.httpServer->Start();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: failed to start webconsole: ", ex.what ()); LogPrint (eLogError, "Daemon: failed to start webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ()); ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
} }
} }
LogPrint(eLogInfo, "Daemon: starting Tunnels"); LogPrint(eLogInfo, "Daemon: starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
@ -339,12 +344,12 @@ namespace i2p
std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr); std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort); uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort); LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
try try
{ {
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
d.m_I2PControlService->Start (); d.m_I2PControlService->Start ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: failed to start I2PControl: ", ex.what ()); LogPrint (eLogError, "Daemon: failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ()); ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
@ -361,7 +366,7 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: stopping Tunnels"); LogPrint(eLogInfo, "Daemon: stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
if (d.UPnP) if (d.UPnP)
{ {
d.UPnP->Stop (); d.UPnP->Stop ();
d.UPnP = nullptr; d.UPnP = nullptr;

@ -13,9 +13,10 @@ namespace util
class Daemon_Singleton class Daemon_Singleton
{ {
public: public:
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init(int argc, char* argv[]); virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool start(); virtual bool init(int argc, char* argv[]);
virtual bool start();
virtual bool stop(); virtual bool stop();
virtual void run () {}; virtual void run () {};
@ -23,6 +24,7 @@ namespace util
bool running; bool running;
protected: protected:
Daemon_Singleton(); Daemon_Singleton();
virtual ~Daemon_Singleton(); virtual ~Daemon_Singleton();
@ -39,6 +41,7 @@ namespace util
class DaemonQT: public i2p::util::Daemon_Singleton class DaemonQT: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonQT& Instance() static DaemonQT& Instance()
{ {
static DaemonQT instance; static DaemonQT instance;
@ -51,6 +54,7 @@ namespace util
class DaemonWin32 : public Daemon_Singleton class DaemonWin32 : public Daemon_Singleton
{ {
public: public:
static DaemonWin32& Instance() static DaemonWin32& Instance()
{ {
static DaemonWin32 instance; static DaemonWin32 instance;
@ -72,6 +76,7 @@ namespace util
class DaemonAndroid: public i2p::util::Daemon_Singleton class DaemonAndroid: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonAndroid& Instance() static DaemonAndroid& Instance()
{ {
static DaemonAndroid instance; static DaemonAndroid instance;
@ -83,6 +88,7 @@ namespace util
class DaemonLinux : public Daemon_Singleton class DaemonLinux : public Daemon_Singleton
{ {
public: public:
static DaemonLinux& Instance() static DaemonLinux& Instance()
{ {
static DaemonLinux instance; static DaemonLinux instance;
@ -94,10 +100,12 @@ namespace util
void run (); void run ();
private: private:
std::string pidfile; std::string pidfile;
int pidFH; int pidFH;
public: public:
int gracefulShutdownInterval; // in seconds int gracefulShutdownInterval; // in seconds
}; };
#endif #endif

@ -892,8 +892,8 @@ namespace http {
void HTTPConnection::Receive () void HTTPConnection::Receive ()
{ {
m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE),
std::bind(&HTTPConnection::HandleReceive, shared_from_this (), std::bind(&HTTPConnection::HandleReceive, shared_from_this (),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} }
void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred) void HTTPConnection::HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred)

@ -79,17 +79,17 @@ namespace http
std::string m_Hostname; std::string m_Hostname;
}; };
//all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml //all the below functions are also used by Qt GUI, see mainwindow.cpp -> getStatusPageHtml
enum OutputFormatEnum { forWebConsole, forQtUi }; enum OutputFormatEnum { forWebConsole, forQtUi };
void ShowStatus (std::stringstream& s, bool includeHiddenContent, OutputFormatEnum outputFormat); void ShowStatus (std::stringstream& s, bool includeHiddenContent, OutputFormatEnum outputFormat);
void ShowLocalDestinations (std::stringstream& s); void ShowLocalDestinations (std::stringstream& s);
void ShowLeasesSets(std::stringstream& s); void ShowLeasesSets(std::stringstream& s);
void ShowTunnels (std::stringstream& s); void ShowTunnels (std::stringstream& s);
void ShowTransitTunnels (std::stringstream& s); void ShowTransitTunnels (std::stringstream& s);
void ShowTransports (std::stringstream& s); void ShowTransports (std::stringstream& s);
void ShowSAMSessions (std::stringstream& s); void ShowSAMSessions (std::stringstream& s);
void ShowI2PTunnels (std::stringstream& s); void ShowI2PTunnels (std::stringstream& s);
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token); void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
} // http } // http
} // i2p } // i2p

@ -59,29 +59,28 @@ namespace client
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem); m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem);
// handlers // handlers
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler; m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler; m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler; m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler; m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler; m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
// I2PControl // I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo // RouterInfo
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler; m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler; m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler; m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler; m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler; m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S; m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S; m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler; m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler; m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
&I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes; m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes; m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
@ -97,10 +96,10 @@ namespace client
// ClientServicesInfo // ClientServicesInfo
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler; m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler; m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler; m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler; m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler; m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler; m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
} }
I2PControlService::~I2PControlService () I2PControlService::~I2PControlService ()
@ -401,8 +400,8 @@ namespace client
auto it1 = m_RouterInfoHandlers.find (it->first); auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ()) if (it1 != m_RouterInfoHandlers.end ())
{ {
if (!first) results << ","; if (!first) results << ",";
else first = false; else first = false;
(this->*(it1->second))(results); (this->*(it1->second))(results);
} }
else else
@ -500,7 +499,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
{ {
Daemon.running = 0; Daemon.running = 0;
}); });
} }
@ -514,7 +513,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
{ {
Daemon.running = 0; Daemon.running = 0;
}); });
} }

@ -27,6 +27,7 @@ namespace client
class I2PControlService class I2PControlService
{ {
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket; typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
public: public:
I2PControlService (const std::string& address, int port); I2PControlService (const std::string& address, int port);

@ -80,10 +80,10 @@ namespace transport
void UPnP::Discover () void UPnP::Discover ()
{ {
bool isError; bool isError;
int err; int err;
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS)) #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
err = UPNPDISCOVER_SUCCESS; err = UPNPDISCOVER_SUCCESS;
#if (MINIUPNPC_API_VERSION >= 14) #if (MINIUPNPC_API_VERSION >= 14)
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err); m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0, 0, 2, &err);
@ -92,9 +92,9 @@ namespace transport
#endif #endif
isError = err != UPNPDISCOVER_SUCCESS; isError = err != UPNPDISCOVER_SUCCESS;
#else // MINIUPNPC_API_VERSION >= 8 #else // MINIUPNPC_API_VERSION >= 8
err = 0; err = 0;
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0); m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
isError = m_Devlist == NULL; isError = m_Devlist == NULL;
#endif // MINIUPNPC_API_VERSION >= 8 #endif // MINIUPNPC_API_VERSION >= 8
{ {
@ -105,15 +105,15 @@ namespace transport
if (isError) if (isError)
{ {
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err); LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err);
return; return;
} }
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
m_upnpUrlsInitialized=err!=0; m_upnpUrlsInitialized = err != 0;
if (err == UPNP_IGD_VALID_CONNECTED) if (err == UPNP_IGD_VALID_CONNECTED)
{ {
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(err != UPNPCOMMAND_SUCCESS) if(err != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: unable to get external address: error ", err); LogPrint (eLogError, "UPnP: unable to get external address: error ", err);
@ -124,14 +124,14 @@ namespace transport
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL); LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL);
if (!m_externalIPAddress[0]) if (!m_externalIPAddress[0])
{ {
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address"); LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address");
return; return;
} }
} }
} }
else else
{ {
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err); LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err);
return; return;
} }
@ -182,7 +182,7 @@ namespace transport
err = CheckMapping (strPort.c_str (), strType.c_str ()); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
{ {
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err); LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err);
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS)) #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL); err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL);
@ -202,7 +202,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device"); LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
return; return;
} }
} }
@ -219,14 +219,14 @@ namespace transport
void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address) void UPnP::CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{ {
if(!m_upnpUrlsInitialized) { if(!m_upnpUrlsInitialized) {
return; return;
} }
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int err = UPNPCOMMAND_SUCCESS; int err = UPNPCOMMAND_SUCCESS;
err = CheckMapping (strPort.c_str (), strType.c_str ()); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err == UPNPCOMMAND_SUCCESS) if (err == UPNPCOMMAND_SUCCESS)
{ {
err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL); err = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), NULL);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", err);
@ -237,11 +237,11 @@ namespace transport
{ {
freeUPNPDevlist (m_Devlist); freeUPNPDevlist (m_Devlist);
m_Devlist = 0; m_Devlist = 0;
if(m_upnpUrlsInitialized){ if(m_upnpUrlsInitialized){
FreeUPNPUrls (&m_upnpUrls); FreeUPNPUrls (&m_upnpUrls);
m_upnpUrlsInitialized=false; m_upnpUrlsInitialized=false;
} }
} }
std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address) std::string UPnP::GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address)
{ {

@ -33,41 +33,41 @@ namespace transport
{ {
public: public:
UPnP (); UPnP ();
~UPnP (); ~UPnP ();
void Close (); void Close ();
void Start (); void Start ();
void Stop (); void Stop ();
private: private:
void Discover (); void Discover ();
int CheckMapping (const char* port, const char* type); int CheckMapping (const char* port, const char* type);
void PortMapping (); void PortMapping ();
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address); void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void CloseMapping (); void CloseMapping ();
void CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address); void CloseMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void Run (); void Run ();
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address); std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started; std::condition_variable m_Started;
std::mutex m_StartedMutex; std::mutex m_StartedMutex;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
bool m_upnpUrlsInitialized=false; bool m_upnpUrlsInitialized = false;
struct UPNPUrls m_upnpUrls; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData; struct IGDdatas m_upnpData;
// For miniupnpc // For miniupnpc
struct UPNPDev * m_Devlist = 0; struct UPNPDev * m_Devlist = 0;
char m_NetworkAddr[64]; char m_NetworkAddr[64];
char m_externalIPAddress[40]; char m_externalIPAddress[40];
}; };
} }
} }
@ -79,10 +79,10 @@ namespace transport {
class UPnP { class UPnP {
public: public:
UPnP () {}; UPnP () {};
~UPnP () {}; ~UPnP () {};
void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); } void Start () { LogPrint(eLogWarning, "UPnP: this module was disabled at compile-time"); }
void Stop () {}; void Stop () {};
}; };
} }
} }

@ -196,5 +196,4 @@ namespace i2p
} }
} }
} }
#endif #endif

@ -2,7 +2,6 @@
#include "Daemon.h" #include "Daemon.h"
#if defined(QT_GUI_LIB) #if defined(QT_GUI_LIB)
namespace i2p namespace i2p
{ {
namespace qt namespace qt
@ -10,11 +9,11 @@ namespace qt
int RunQT (int argc, char* argv[]); int RunQT (int argc, char* argv[]);
} }
} }
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {
return i2p::qt::RunQT (argc, argv); return i2p::qt::RunQT (argc, argv);
} }
#else #else
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {

@ -7,7 +7,8 @@ namespace i2p
{ {
namespace data namespace data
{ {
static const char T32[32] = { static const char T32[32] =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
@ -29,15 +30,16 @@ namespace data
* Direct Substitution Table * Direct Substitution Table
*/ */
static const char T64[64] = { static const char T64[64] =
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', {
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'w', 'x', 'y', 'z', '0', '1', '2', '3', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'4', '5', '6', '7', '8', '9', '-', '~' 'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '-', '~'
}; };
const char * GetBase64SubstitutionTable () const char * GetBase64SubstitutionTable ()
@ -67,14 +69,12 @@ namespace data
* *
*/ */
size_t /* Number of bytes in the encoded buffer */ size_t ByteStreamToBase64 ( /* Number of bytes in the encoded buffer */
ByteStreamToBase64 ( const uint8_t * InBuffer, /* Input buffer, binary data */
const uint8_t * InBuffer, /* Input buffer, binary data */ size_t InCount, /* Number of bytes in the input buffer */
size_t InCount, /* Number of bytes in the input buffer */ char * OutBuffer, /* output buffer */
char * OutBuffer, /* output buffer */ size_t len /* length of output buffer */
size_t len /* length of output buffer */
) )
{ {
unsigned char * ps; unsigned char * ps;
unsigned char * pd; unsigned char * pd;
@ -83,55 +83,60 @@ namespace data
int i; int i;
int n; int n;
int m; int m;
size_t outCount; size_t outCount;
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
n = InCount/3; n = InCount / 3;
m = InCount%3; m = InCount % 3;
if (!m) if (!m)
outCount = 4*n; outCount = 4 * n;
else else
outCount = 4*(n+1); outCount = 4 * (n + 1);
if (outCount > len) return 0; if (outCount > len) return 0;
pd = (unsigned char *)OutBuffer; pd = (unsigned char *)OutBuffer;
for ( i = 0; i<n; i++ ){ for ( i = 0; i < n; i++ )
acc_1 = *ps++; {
acc_2 = (acc_1<<4)&0x30; acc_1 = *ps++;
acc_1 >>= 2; /* base64 digit #1 */ acc_2 = (acc_1 << 4) & 0x30;
*pd++ = T64[acc_1]; acc_1 >>= 2; /* base64 digit #1 */
acc_1 = *ps++; *pd++ = T64[acc_1];
acc_2 |= acc_1 >> 4; /* base64 digit #2 */ acc_1 = *ps++;
*pd++ = T64[acc_2]; acc_2 |= acc_1 >> 4; /* base64 digit #2 */
acc_1 &= 0x0f; *pd++ = T64[acc_2];
acc_1 <<=2; acc_1 &= 0x0f;
acc_2 = *ps++; acc_1 <<= 2;
acc_1 |= acc_2>>6; /* base64 digit #3 */ acc_2 = *ps++;
*pd++ = T64[acc_1]; acc_1 |= acc_2 >> 6; /* base64 digit #3 */
acc_2 &= 0x3f; /* base64 digit #4 */ *pd++ = T64[acc_1];
*pd++ = T64[acc_2]; acc_2 &= 0x3f; /* base64 digit #4 */
*pd++ = T64[acc_2];
} }
if ( m == 1 ){ if ( m == 1 )
acc_1 = *ps++; {
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */ acc_1 = *ps++;
acc_1 >>= 2; /* base64 digit #1 */ acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
*pd++ = T64[acc_1]; acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_2]; *pd++ = T64[acc_1];
*pd++ = P64; *pd++ = T64[acc_2];
*pd++ = P64; *pd++ = P64;
*pd++ = P64;
} }
else if ( m == 2 ){ else if ( m == 2 )
acc_1 = *ps++; {
acc_2 = (acc_1<<4)&0x3f; acc_1 = *ps++;
acc_1 >>= 2; /* base64 digit #1 */ acc_2 = (acc_1 << 4) & 0x3f;
*pd++ = T64[acc_1]; acc_1 >>= 2; /* base64 digit #1 */
acc_1 = *ps++; *pd++ = T64[acc_1];
acc_2 |= acc_1 >> 4; /* base64 digit #2 */ acc_1 = *ps++;
*pd++ = T64[acc_2]; acc_2 |= acc_1 >> 4; /* base64 digit #2 */
acc_1 &= 0x0f; *pd++ = T64[acc_2];
acc_1 <<=2; /* base64 digit #3 */ acc_1 &= 0x0f;
*pd++ = T64[acc_1]; acc_1 <<= 2; /* base64 digit #3 */
*pd++ = P64; *pd++ = T64[acc_1];
*pd++ = P64;
} }
return outCount; return outCount;
@ -147,12 +152,11 @@ namespace data
* *
*/ */
size_t /* Number of output bytes */ size_t Base64ToByteStream ( /* Number of output bytes */
Base64ToByteStream ( const char * InBuffer, /* BASE64 encoded buffer */
const char * InBuffer, /* BASE64 encoded buffer */ size_t InCount, /* Number of input bytes */
size_t InCount, /* Number of input bytes */ uint8_t * OutBuffer, /* output buffer length */
uint8_t * OutBuffer, /* output buffer length */ size_t len /* length of output buffer */
size_t len /* length of output buffer */
) )
{ {
unsigned char * ps; unsigned char * ps;
@ -162,42 +166,52 @@ namespace data
int i; int i;
int n; int n;
int m; int m;
size_t outCount; size_t outCount;
if (isFirstTime)
iT64Build();
n = InCount / 4;
m = InCount % 4;
if (isFirstTime) iT64Build();
n = InCount/4;
m = InCount%4;
if (InCount && !m) if (InCount && !m)
outCount = 3*n; outCount = 3 * n;
else { else
outCount = 0; {
return 0; outCount = 0;
return 0;
} }
ps = (unsigned char *)(InBuffer + InCount - 1); ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) outCount--; while ( *ps-- == P64 )
outCount--;
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
if (outCount > len) return -1; if (outCount > len)
return -1;
pd = OutBuffer; pd = OutBuffer;
auto endOfOutBuffer = OutBuffer + outCount; auto endOfOutBuffer = OutBuffer + outCount;
for ( i = 0; i < n; i++ ){ for ( i = 0; i < n; i++ )
acc_1 = iT64[*ps++]; {
acc_2 = iT64[*ps++]; acc_1 = iT64[*ps++];
acc_1 <<= 2; acc_2 = iT64[*ps++];
acc_1 |= acc_2>>4; acc_1 <<= 2;
*pd++ = acc_1; acc_1 |= acc_2 >> 4;
if (pd >= endOfOutBuffer) break; *pd++ = acc_1;
if (pd >= endOfOutBuffer)
acc_2 <<= 4; break;
acc_1 = iT64[*ps++];
acc_2 |= acc_1 >> 2; acc_2 <<= 4;
*pd++ = acc_2; acc_1 = iT64[*ps++];
if (pd >= endOfOutBuffer) break; acc_2 |= acc_1 >> 2;
*pd++ = acc_2;
acc_2 = iT64[*ps++]; if (pd >= endOfOutBuffer)
acc_2 |= acc_1 << 6; break;
*pd++ = acc_2;
acc_2 = iT64[*ps++];
acc_2 |= acc_1 << 6;
*pd++ = acc_2;
} }
return outCount; return outCount;
@ -206,20 +220,25 @@ namespace data
size_t Base64EncodingBufferSize (const size_t input_size) size_t Base64EncodingBufferSize (const size_t input_size)
{ {
auto d = div (input_size, 3); auto d = div (input_size, 3);
if (d.rem) d.quot++; if (d.rem)
return 4*d.quot; d.quot++;
return 4 * d.quot;
} }
std::string ToBase64Standard (const std::string& in) std::string ToBase64Standard (const std::string& in)
{ {
auto len = Base64EncodingBufferSize (in.length ()); auto len = Base64EncodingBufferSize (in.length ());
char * str = new char[len+1]; char * str = new char[len + 1];
auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len); auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len);
str[l] = 0; str[l] = 0;
// replace '-' by '+' and '~' by '/' // replace '-' by '+' and '~' by '/'
for (size_t i = 0; i < l; i++) for (size_t i = 0; i < l; i++)
if (str[i] == '-') str[i] = '+'; if (str[i] == '-')
else if (str[i] == '~') str[i] = '/'; str[i] = '+';
else if (str[i] == '~')
str[i] = '/';
std::string s(str); std::string s(str);
delete[] str; delete[] str;
return s; return s;
@ -236,10 +255,10 @@ namespace data
static void iT64Build() static void iT64Build()
{ {
int i; int i;
isFirstTime = 0; isFirstTime = 0;
for ( i=0; i<256; i++ ) iT64[i] = -1; for ( i = 0; i < 256; i++ ) iT64[i] = -1;
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i; for ( i = 0; i < 64; i++ ) iT64[(int)T64[i]] = i;
iT64[(int)P64] = 0; iT64[(int)P64] = 0;
} }
@ -302,4 +321,3 @@ namespace data
} }
} }
} }

@ -15,13 +15,13 @@ namespace data {
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
/** /**
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
*/ */
size_t Base64EncodingBufferSize(const size_t input_size); size_t Base64EncodingBufferSize(const size_t input_size);
std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization
} // data } // data
} // i2p } // i2p

@ -17,21 +17,21 @@ namespace i2p
namespace data namespace data
{ {
static EC_POINT * BlindPublicKeyECDSA (const EC_GROUP * group, const EC_POINT * pub, const uint8_t * seed) static EC_POINT * BlindPublicKeyECDSA (const EC_GROUP * group, const EC_POINT * pub, const uint8_t * seed)
{ {
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx); BN_CTX_start (ctx);
BIGNUM * q = BN_CTX_get (ctx); BIGNUM * q = BN_CTX_get (ctx);
EC_GROUP_get_order (group, q, ctx); EC_GROUP_get_order (group, q, ctx);
// calculate alpha = seed mod q // calculate alpha = seed mod q
BIGNUM * alpha = BN_CTX_get (ctx); BIGNUM * alpha = BN_CTX_get (ctx);
BN_bin2bn (seed, 64, alpha); // seed is in BigEndian BN_bin2bn (seed, 64, alpha); // seed is in BigEndian
BN_mod (alpha, alpha, q, ctx); // % q BN_mod (alpha, alpha, q, ctx); // % q
// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha) // A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
auto p = EC_POINT_new (group); auto p = EC_POINT_new (group);
EC_POINT_mul (group, p, alpha, nullptr, nullptr, ctx); // B*alpha EC_POINT_mul (group, p, alpha, nullptr, nullptr, ctx); // B*alpha
EC_POINT_add (group, p, pub, p, ctx); // pub + B*alpha EC_POINT_add (group, p, pub, p, ctx); // pub + B*alpha
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
return p; return p;
} }
@ -39,18 +39,18 @@ namespace data
{ {
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx); BN_CTX_start (ctx);
BIGNUM * q = BN_CTX_get (ctx); BIGNUM * q = BN_CTX_get (ctx);
EC_GROUP_get_order (group, q, ctx); EC_GROUP_get_order (group, q, ctx);
// calculate alpha = seed mod q // calculate alpha = seed mod q
BIGNUM * alpha = BN_CTX_get (ctx); BIGNUM * alpha = BN_CTX_get (ctx);
BN_bin2bn (seed, 64, alpha); // seed is in BigEndian BN_bin2bn (seed, 64, alpha); // seed is in BigEndian
BN_mod (alpha, alpha, q, ctx); // % q BN_mod (alpha, alpha, q, ctx); // % q
BN_add (alpha, alpha, priv); // alpha = alpha + priv BN_add (alpha, alpha, priv); // alpha = alpha + priv
// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod q // a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod q
BN_mod (blindedPriv, alpha, q, ctx); // % q BN_mod (blindedPriv, alpha, q, ctx); // % q
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
static void BlindEncodedPublicKeyECDSA (size_t publicKeyLen, const EC_GROUP * group, const uint8_t * pub, const uint8_t * seed, uint8_t * blindedPub) static void BlindEncodedPublicKeyECDSA (size_t publicKeyLen, const EC_GROUP * group, const uint8_t * pub, const uint8_t * seed, uint8_t * blindedPub)
{ {
@ -63,7 +63,7 @@ namespace data
EC_POINT_get_affine_coordinates_GFp (group, p1, x, y, NULL); EC_POINT_get_affine_coordinates_GFp (group, p1, x, y, NULL);
EC_POINT_free (p1); EC_POINT_free (p1);
i2p::crypto::bn2buf (x, blindedPub, publicKeyLen/2); i2p::crypto::bn2buf (x, blindedPub, publicKeyLen/2);
i2p::crypto::bn2buf (y, blindedPub + publicKeyLen/2, publicKeyLen/2); i2p::crypto::bn2buf (y, blindedPub + publicKeyLen/2, publicKeyLen/2);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
@ -85,7 +85,7 @@ namespace data
i2p::crypto::bn2buf (x, blindedPub, publicKeyLen/2); i2p::crypto::bn2buf (x, blindedPub, publicKeyLen/2);
i2p::crypto::bn2buf (y, blindedPub + publicKeyLen/2, publicKeyLen/2); i2p::crypto::bn2buf (y, blindedPub + publicKeyLen/2, publicKeyLen/2);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
template<typename Fn, typename...Args> template<typename Fn, typename...Args>
static size_t BlindECDSA (i2p::data::SigningKeyType sigType, const uint8_t * key, const uint8_t * seed, Fn blind, Args&&...args) static size_t BlindECDSA (i2p::data::SigningKeyType sigType, const uint8_t * key, const uint8_t * seed, Fn blind, Args&&...args)
@ -97,7 +97,7 @@ namespace data
{ {
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{ {
publicKeyLength = i2p::crypto::ECDSAP256_KEY_LENGTH; publicKeyLength = i2p::crypto::ECDSAP256_KEY_LENGTH;
group = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); group = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1);
break; break;
} }
@ -116,18 +116,18 @@ namespace data
default: default:
LogPrint (eLogError, "Blinding: signature type ", (int)sigType, " is not ECDSA"); LogPrint (eLogError, "Blinding: signature type ", (int)sigType, " is not ECDSA");
} }
if (group) if (group)
{ {
blind (publicKeyLength, group, key, seed, std::forward<Args>(args)...); blind (publicKeyLength, group, key, seed, std::forward<Args>(args)...);
EC_GROUP_free (group); EC_GROUP_free (group);
} }
return publicKeyLength; return publicKeyLength;
} }
//---------------------------------------------------------- //----------------------------------------------------------
const uint8_t B33_TWO_BYTES_SIGTYPE_FLAG = 0x01; const uint8_t B33_TWO_BYTES_SIGTYPE_FLAG = 0x01;
const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now
const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04; const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04;
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth): BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth):
@ -138,7 +138,7 @@ namespace data
m_PublicKey.resize (len); m_PublicKey.resize (len);
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len); memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
m_SigType = identity->GetSigningKeyType (); m_SigType = identity->GetSigningKeyType ();
m_BlindedSigType = m_SigType; m_BlindedSigType = m_SigType;
} }
BlindedPublicKey::BlindedPublicKey (const std::string& b33): BlindedPublicKey::BlindedPublicKey (const std::string& b33):
@ -150,12 +150,12 @@ namespace data
{ {
LogPrint (eLogError, "Blinding: malformed b33 ", b33); LogPrint (eLogError, "Blinding: malformed b33 ", b33);
return; return;
} }
uint32_t checksum = crc32 (0, addr + 3, l - 3); uint32_t checksum = crc32 (0, addr + 3, l - 3);
// checksum is Little Endian // checksum is Little Endian
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16); addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
uint8_t flags = addr[0]; uint8_t flags = addr[0];
size_t offset = 1; size_t offset = 1;
if (flags & B33_TWO_BYTES_SIGTYPE_FLAG) // two bytes signatures if (flags & B33_TWO_BYTES_SIGTYPE_FLAG) // two bytes signatures
{ {
m_SigType = bufbe16toh (addr + offset); offset += 2; m_SigType = bufbe16toh (addr + offset); offset += 2;
@ -178,7 +178,7 @@ namespace data
memcpy (m_PublicKey.data (), addr + offset, len); memcpy (m_PublicKey.data (), addr + offset, len);
} }
else else
LogPrint (eLogError, "Blinding: public key in b33 address is too short for signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: public key in b33 address is too short for signature type ", (int)m_SigType);
} }
else else
LogPrint (eLogError, "Blinding: unknown signature type ", (int)m_SigType, " in b33"); LogPrint (eLogError, "Blinding: unknown signature type ", (int)m_SigType, " in b33");
@ -189,25 +189,25 @@ namespace data
if (m_PublicKey.size () > 32) return ""; // assume 25519 if (m_PublicKey.size () > 32) return ""; // assume 25519
uint8_t addr[35]; char str[60]; // TODO: define actual length uint8_t addr[35]; char str[60]; // TODO: define actual length
uint8_t flags = 0; uint8_t flags = 0;
if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG; if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG;
addr[0] = flags; // flags addr[0] = flags; // flags
addr[1] = m_SigType; // sig type addr[1] = m_SigType; // sig type
addr[2] = m_BlindedSigType; // blinded sig type addr[2] = m_BlindedSigType; // blinded sig type
memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ()); memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ());
uint32_t checksum = crc32 (0, addr + 3, m_PublicKey.size ()); uint32_t checksum = crc32 (0, addr + 3, m_PublicKey.size ());
// checksum is Little Endian // checksum is Little Endian
addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16); addr[0] ^= checksum; addr[1] ^= (checksum >> 8); addr[2] ^= (checksum >> 16);
auto l = ByteStreamToBase32 (addr, m_PublicKey.size () + 3, str, 60); auto l = ByteStreamToBase32 (addr, m_PublicKey.size () + 3, str, 60);
return std::string (str, str + l); return std::string (str, str + l);
} }
void BlindedPublicKey::GetCredential (uint8_t * credential) const void BlindedPublicKey::GetCredential (uint8_t * credential) const
{ {
// A = destination's signing public key // A = destination's signing public key
// stA = signature type of A, 2 bytes big endian // stA = signature type of A, 2 bytes big endian
uint16_t stA = htobe16 (GetSigType ()); uint16_t stA = htobe16 (GetSigType ());
// stA1 = signature type of blinded A, 2 bytes big endian // stA1 = signature type of blinded A, 2 bytes big endian
uint16_t stA1 = htobe16 (GetBlindedSigType ()); uint16_t stA1 = htobe16 (GetBlindedSigType ());
// credential = H("credential", A || stA || stA1) // credential = H("credential", A || stA || stA1)
H ("credential", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, credential); H ("credential", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, credential);
} }
@ -224,15 +224,15 @@ namespace data
{ {
uint16_t stA = htobe16 (GetSigType ()), stA1 = htobe16 (GetBlindedSigType ()); uint16_t stA = htobe16 (GetSigType ()), stA1 = htobe16 (GetBlindedSigType ());
uint8_t salt[32]; uint8_t salt[32];
//seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64) //seed = HKDF(H("I2PGenerateAlpha", keydata), datestring || secret, "i2pblinding1", 64)
H ("I2PGenerateAlpha", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, salt); H ("I2PGenerateAlpha", { {GetPublicKey (), GetPublicKeyLen ()}, {(const uint8_t *)&stA, 2}, {(const uint8_t *)&stA1, 2} }, salt);
i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed); i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed);
} }
size_t BlindedPublicKey::GetBlindedKey (const char * date, uint8_t * blindedKey) const size_t BlindedPublicKey::GetBlindedKey (const char * date, uint8_t * blindedKey) const
{ {
uint8_t seed[64]; uint8_t seed[64];
GenerateAlpha (date, seed); GenerateAlpha (date, seed);
size_t publicKeyLength = 0; size_t publicKeyLength = 0;
switch (m_SigType) switch (m_SigType)
@ -244,7 +244,7 @@ namespace data
break; break;
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::GetEd25519 ()->BlindPublicKey (GetPublicKey (), seed, blindedKey); i2p::crypto::GetEd25519 ()->BlindPublicKey (GetPublicKey (), seed, blindedKey);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
default: default:
@ -255,8 +255,8 @@ namespace data
size_t BlindedPublicKey::BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const size_t BlindedPublicKey::BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const
{ {
uint8_t seed[64]; uint8_t seed[64];
GenerateAlpha (date, seed); GenerateAlpha (date, seed);
size_t publicKeyLength = 0; size_t publicKeyLength = 0;
switch (m_SigType) switch (m_SigType)
{ {
@ -272,15 +272,15 @@ namespace data
default: default:
LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType);
} }
return publicKeyLength; return publicKeyLength;
} }
void BlindedPublicKey::H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const void BlindedPublicKey::H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const
{ {
SHA256_CTX ctx; SHA256_CTX ctx;
SHA256_Init (&ctx); SHA256_Init (&ctx);
SHA256_Update (&ctx, p.c_str (), p.length ()); SHA256_Update (&ctx, p.c_str (), p.length ());
for (const auto& it: bufs) for (const auto& it: bufs)
SHA256_Update (&ctx, it.first, it.second); SHA256_Update (&ctx, it.first, it.second);
SHA256_Final (hash, &ctx); SHA256_Final (hash, &ctx);
} }
@ -289,15 +289,15 @@ namespace data
{ {
i2p::data::IdentHash hash; i2p::data::IdentHash hash;
uint8_t blinded[128]; uint8_t blinded[128];
size_t publicKeyLength = 0; size_t publicKeyLength = 0;
if (date) if (date)
publicKeyLength = GetBlindedKey (date, blinded); publicKeyLength = GetBlindedKey (date, blinded);
else else
{ {
char currentDate[9]; char currentDate[9];
i2p::util::GetCurrentDate (currentDate); i2p::util::GetCurrentDate (currentDate);
publicKeyLength = GetBlindedKey (currentDate, blinded); publicKeyLength = GetBlindedKey (currentDate, blinded);
} }
if (publicKeyLength) if (publicKeyLength)
{ {
auto stA1 = htobe16 (m_BlindedSigType); auto stA1 = htobe16 (m_BlindedSigType);
@ -308,10 +308,9 @@ namespace data
SHA256_Final ((uint8_t *)hash, &ctx); SHA256_Final ((uint8_t *)hash, &ctx);
} }
else else
LogPrint (eLogError, "Blinding: blinded key type ", (int)m_BlindedSigType, " is not supported"); LogPrint (eLogError, "Blinding: blinded key type ", (int)m_BlindedSigType, " is not supported");
return hash; return hash;
} }
} }
} }

@ -15,7 +15,7 @@ namespace data
public: public:
BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth = false); BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth = false);
BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p BlindedPublicKey (const std::string& b33); // from b33 without .b32.i2p
std::string ToB33 () const; std::string ToB33 () const;
const uint8_t * GetPublicKey () const { return m_PublicKey.data (); }; const uint8_t * GetPublicKey () const { return m_PublicKey.data (); };
@ -25,14 +25,14 @@ namespace data
bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes
size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length
size_t BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const; // date is 8 chars "YYYYMMDD", return public key length size_t BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const; // date is 8 chars "YYYYMMDD", return public key length
i2p::data::IdentHash GetStoreHash (const char * date = nullptr) const; // date is 8 chars "YYYYMMDD", use current if null i2p::data::IdentHash GetStoreHash (const char * date = nullptr) const; // date is 8 chars "YYYYMMDD", use current if null
private: private:
void GetCredential (uint8_t * credential) const; // 32 bytes void GetCredential (uint8_t * credential) const; // 32 bytes
void GenerateAlpha (const char * date, uint8_t * seed) const; // 64 bytes, date is 8 chars "YYYYMMDD" void GenerateAlpha (const char * date, uint8_t * seed) const; // 64 bytes, date is 8 chars "YYYYMMDD"
void H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const; void H (const std::string& p, const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * hash) const;
private: private:

@ -5,10 +5,10 @@ namespace i2p
{ {
namespace cpu namespace cpu
{ {
extern bool aesni; extern bool aesni;
extern bool avx; extern bool avx;
void Detect(); void Detect();
} }
} }

@ -12,73 +12,72 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "ChaCha20.h" #include "ChaCha20.h"
#if !OPENSSL_AEAD_CHACHA20_POLY1305 #if !OPENSSL_AEAD_CHACHA20_POLY1305
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
{ {
namespace chacha namespace chacha
{ {
void u32t8le(uint32_t v, uint8_t * p) void u32t8le(uint32_t v, uint8_t * p)
{ {
p[0] = v & 0xff; p[0] = v & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
} }
uint32_t u8t32le(const uint8_t * p) uint32_t u8t32le(const uint8_t * p)
{ {
uint32_t value = p[3]; uint32_t value = p[3];
value = (value << 8) | p[2]; value = (value << 8) | p[2];
value = (value << 8) | p[1]; value = (value << 8) | p[1];
value = (value << 8) | p[0]; value = (value << 8) | p[0];
return value; return value;
} }
uint32_t rotl32(uint32_t x, int n) uint32_t rotl32(uint32_t x, int n)
{ {
return x << n | (x >> (-n & 31)); return x << n | (x >> (-n & 31));
} }
void quarterround(uint32_t *x, int a, int b, int c, int d) void quarterround(uint32_t *x, int a, int b, int c, int d)
{ {
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8);
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
} }
void Chacha20Block::operator << (const Chacha20State & st) void Chacha20Block::operator << (const Chacha20State & st)
{ {
int i; int i;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
u32t8le(st.data[i], data + (i << 2)); u32t8le(st.data[i], data + (i << 2));
} }
void block (Chacha20State &input, int rounds) void block (Chacha20State &input, int rounds)
{ {
int i; int i;
Chacha20State x; Chacha20State x;
x.Copy(input); x.Copy(input);
for (i = rounds; i > 0; i -= 2)
{
quarterround(x.data, 0, 4, 8, 12);
quarterround(x.data, 1, 5, 9, 13);
quarterround(x.data, 2, 6, 10, 14);
quarterround(x.data, 3, 7, 11, 15);
quarterround(x.data, 0, 5, 10, 15);
quarterround(x.data, 1, 6, 11, 12);
quarterround(x.data, 2, 7, 8, 13);
quarterround(x.data, 3, 4, 9, 14);
}
x += input;
input.block << x;
for (i = rounds; i > 0; i -= 2)
{
quarterround(x.data, 0, 4, 8, 12);
quarterround(x.data, 1, 5, 9, 13);
quarterround(x.data, 2, 6, 10, 14);
quarterround(x.data, 3, 7, 11, 15);
quarterround(x.data, 0, 5, 10, 15);
quarterround(x.data, 1, 6, 11, 12);
quarterround(x.data, 2, 7, 8, 13);
quarterround(x.data, 3, 4, 9, 14);
}
x += input;
input.block << x;
} }
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter) void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
@ -87,52 +86,52 @@ void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t *
state.data[1] = 0x3320646e; state.data[1] = 0x3320646e;
state.data[2] = 0x79622d32; state.data[2] = 0x79622d32;
state.data[3] = 0x6b206574; state.data[3] = 0x6b206574;
for (size_t i = 0; i < 8; i++) for (size_t i = 0; i < 8; i++)
state.data[4 + i] = chacha::u8t32le(key + i * 4); state.data[4 + i] = chacha::u8t32le(key + i * 4);
state.data[12] = htole32 (counter); state.data[12] = htole32 (counter);
for (size_t i = 0; i < 3; i++) for (size_t i = 0; i < 3; i++)
state.data[13 + i] = chacha::u8t32le(nonce + i * 4); state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
} }
void Chacha20SetCounter (Chacha20State& state, uint32_t counter) void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
{ {
state.data[12] = htole32 (counter); state.data[12] = htole32 (counter);
state.offset = 0; state.offset = 0;
} }
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz) void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
{ {
if (state.offset > 0) if (state.offset > 0)
{ {
// previous block if any // previous block if any
auto s = chacha::blocksize - state.offset; auto s = chacha::blocksize - state.offset;
if (sz < s) s = sz; if (sz < s) s = sz;
for (size_t i = 0; i < s; i++) for (size_t i = 0; i < s; i++)
buf[i] ^= state.block.data[state.offset + i]; buf[i] ^= state.block.data[state.offset + i];
buf += s; buf += s;
sz -= s; sz -= s;
state.offset += s; state.offset += s;
if (state.offset >= chacha::blocksize) state.offset = 0; if (state.offset >= chacha::blocksize) state.offset = 0;
} }
for (size_t i = 0; i < sz; i += chacha::blocksize) for (size_t i = 0; i < sz; i += chacha::blocksize)
{ {
chacha::block(state, chacha::rounds); chacha::block(state, chacha::rounds);
state.data[12]++; state.data[12]++;
for (size_t j = i; j < i + chacha::blocksize; j++) for (size_t j = i; j < i + chacha::blocksize; j++)
{ {
if (j >= sz) if (j >= sz)
{ {
state.offset = j & 0x3F; // % 64 state.offset = j & 0x3F; // % 64
break; break;
} }
buf[j] ^= state.block.data[j - i]; buf[j] ^= state.block.data[j - i];
} }
} }
} }
} // namespace chacha } // namespace chacha
} // namespace crypto
} // namespace i2p
}
}
#endif #endif

@ -21,23 +21,23 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
const std::size_t CHACHA20_KEY_BYTES = 32; const std::size_t CHACHA20_KEY_BYTES = 32;
const std::size_t CHACHA20_NOUNCE_BYTES = 12; const std::size_t CHACHA20_NOUNCE_BYTES = 12;
namespace chacha namespace chacha
{ {
constexpr std::size_t blocksize = 64; constexpr std::size_t blocksize = 64;
constexpr int rounds = 20; constexpr int rounds = 20;
struct Chacha20State; struct Chacha20State;
struct Chacha20Block struct Chacha20Block
{ {
Chacha20Block () {}; Chacha20Block () {};
Chacha20Block (Chacha20Block &&) = delete; Chacha20Block (Chacha20Block &&) = delete;
uint8_t data[blocksize]; uint8_t data[blocksize];
void operator << (const Chacha20State & st); void operator << (const Chacha20State & st);
}; };
struct Chacha20State struct Chacha20State
@ -54,19 +54,19 @@ namespace chacha
void Copy(const Chacha20State & other) void Copy(const Chacha20State & other)
{ {
memcpy(data, other.data, sizeof(uint32_t) * 16); memcpy(data, other.data, sizeof(uint32_t) * 16);
} }
uint32_t data[16]; uint32_t data[16];
Chacha20Block block; Chacha20Block block;
size_t offset; size_t offset;
}; };
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter); void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
void Chacha20SetCounter (Chacha20State& state, uint32_t counter); void Chacha20SetCounter (Chacha20State& state, uint32_t counter);
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place
} } // namespace chacha
} } // namespace crypto
} } // namespace i2p
#endif
#endif #endif
#endif

@ -242,7 +242,7 @@ namespace config {
"1.pool.ntp.org," "1.pool.ntp.org,"
"2.pool.ntp.org," "2.pool.ntp.org,"
"3.pool.ntp.org" "3.pool.ntp.org"
), "Comma separated list of NTCP servers") ), "Comma separated list of NTCP servers")
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)") ("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)")
; ;

@ -18,98 +18,101 @@
namespace i2p { namespace i2p {
namespace config { namespace config {
extern boost::program_options::variables_map m_Options; extern boost::program_options::variables_map m_Options;
/** /**
* @brief Initialize list of acceptable parameters * @brief Initialize list of acceptable parameters
* *
* Should be called before any Parse* functions. * Should be called before any Parse* functions.
*/ */
void Init(); void Init();
/** /**
* @brief Parse cmdline parameters, and show help if requested * @brief Parse cmdline parameters, and show help if requested
* @param argc Cmdline arguments count, should be passed from main(). * @param argc Cmdline arguments count, should be passed from main().
* @param argv Cmdline parameters array, should be passed from main() * @param argv Cmdline parameters array, should be passed from main()
* *
* If --help is given in parameters, shows its list with description * If --help is given in parameters, shows its list with description
* and terminates the program with exitcode 0. * and terminates the program with exitcode 0.
* *
* In case of parameter misuse boost throws an exception. * In case of parameter misuse boost throws an exception.
* We internally handle type boost::program_options::unknown_option, * We internally handle type boost::program_options::unknown_option,
* and then terminate the program with exitcode 1. * and then terminate the program with exitcode 1.
* *
* Other exceptions will be passed to higher level. * Other exceptions will be passed to higher level.
*/ */
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false); void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false);
/** /**
* @brief Load and parse given config file * @brief Load and parse given config file
* @param path Path to config file * @param path Path to config file
* *
* If error occurred when opening file path is points to, * If error occurred when opening file path is points to,
* we show the error message and terminate program. * we show the error message and terminate program.
* *
* In case of parameter misuse boost throws an exception. * In case of parameter misuse boost throws an exception.
* We internally handle type boost::program_options::unknown_option, * We internally handle type boost::program_options::unknown_option,
* and then terminate program with exitcode 1. * and then terminate program with exitcode 1.
* *
* Other exceptions will be passed to higher level. * Other exceptions will be passed to higher level.
*/ */
void ParseConfig(const std::string& path); void ParseConfig(const std::string& path);
/** /**
* @brief Used to combine options from cmdline, config and default values * @brief Used to combine options from cmdline, config and default values
*/ */
void Finalize(); void Finalize();
/* @brief Accessor to parameters by name /**
* @param name Name of the requested parameter * @brief Accessor to parameters by name
* @param value Variable where to store option * @param name Name of the requested parameter
* @return this function returns false if parameter not found * @param value Variable where to store option
* * @return this function returns false if parameter not found
* Example: uint16_t port; GetOption("sam.port", port); *
*/ * Example: uint16_t port; GetOption("sam.port", port);
template<typename T> */
bool GetOption(const char *name, T& value) { template<typename T>
if (!m_Options.count(name)) bool GetOption(const char *name, T& value)
return false; {
value = m_Options[name].as<T>(); if (!m_Options.count(name))
return true; return false;
} value = m_Options[name].as<T>();
return true;
}
template<typename T> template<typename T>
bool GetOption(const std::string& name, T& value) bool GetOption(const std::string& name, T& value)
{ {
return GetOption (name.c_str (), value); return GetOption (name.c_str (), value);
} }
bool GetOptionAsAny(const char *name, boost::any& value); bool GetOptionAsAny(const char *name, boost::any& value);
bool GetOptionAsAny(const std::string& name, boost::any& value); bool GetOptionAsAny(const std::string& name, boost::any& value);
/** /**
* @brief Set value of given parameter * @brief Set value of given parameter
* @param name Name of settable parameter * @param name Name of settable parameter
* @param value New parameter value * @param value New parameter value
* @return true if value set up successful, false otherwise * @return true if value set up successful, false otherwise
* *
* Example: uint16_t port = 2827; SetOption("bob.port", port); * Example: uint16_t port = 2827; SetOption("bob.port", port);
*/ */
template<typename T> template<typename T>
bool SetOption(const char *name, const T& value) { bool SetOption(const char *name, const T& value)
if (!m_Options.count(name)) {
return false; if (!m_Options.count(name))
m_Options.at(name).value() = value; return false;
notify(m_Options); m_Options.at(name).value() = value;
return true; notify(m_Options);
} return true;
}
/** /**
* @brief Check is value explicitly given or default * @brief Check is value explicitly given or default
* @param name Name of checked parameter * @param name Name of checked parameter
* @return true if value set to default, false otherwise * @return true if value set to default, false otherwise
*/ */
bool IsDefault(const char *name); bool IsDefault(const char *name);
} }
} }

@ -286,14 +286,14 @@ namespace crypto
#if OPENSSL_X25519 #if OPENSSL_X25519
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL); m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
m_Pkey = nullptr; m_Pkey = nullptr;
#else #else
m_Ctx = BN_CTX_new (); m_Ctx = BN_CTX_new ();
#endif #endif
} }
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub) X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
if (pub) if (pub)
@ -302,33 +302,33 @@ namespace crypto
{ {
size_t len = 32; size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
} }
#else #else
m_Ctx = BN_CTX_new (); m_Ctx = BN_CTX_new ();
memcpy (m_PrivateKey, priv, 32); memcpy (m_PrivateKey, priv, 32);
if (pub) if (pub)
memcpy (m_PublicKey, pub, 32); memcpy (m_PublicKey, pub, 32);
else else
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
#endif #endif
} }
X25519Keys::~X25519Keys () X25519Keys::~X25519Keys ()
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
EVP_PKEY_CTX_free (m_Ctx); EVP_PKEY_CTX_free (m_Ctx);
if (m_Pkey) EVP_PKEY_free (m_Pkey); if (m_Pkey) EVP_PKEY_free (m_Pkey);
#else #else
BN_CTX_free (m_Ctx); BN_CTX_free (m_Ctx);
#endif #endif
} }
void X25519Keys::GenerateKeys () void X25519Keys::GenerateKeys ()
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
if (m_Pkey) if (m_Pkey)
{ {
EVP_PKEY_free (m_Pkey); EVP_PKEY_free (m_Pkey);
m_Pkey = nullptr; m_Pkey = nullptr;
} }
EVP_PKEY_keygen_init (m_Ctx); EVP_PKEY_keygen_init (m_Ctx);
@ -337,26 +337,26 @@ namespace crypto
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx? m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); // TODO: do we really need to re-create m_Ctx?
size_t len = 32; size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
#else #else
RAND_bytes (m_PrivateKey, 32); RAND_bytes (m_PrivateKey, 32);
GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx); GetEd25519 ()->ScalarMulB (m_PrivateKey, m_PublicKey, m_Ctx);
#endif #endif
} }
void X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) void X25519Keys::Agree (const uint8_t * pub, uint8_t * shared)
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
EVP_PKEY_derive_init (m_Ctx); EVP_PKEY_derive_init (m_Ctx);
auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32); auto pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_X25519, NULL, pub, 32);
EVP_PKEY_derive_set_peer (m_Ctx, pkey); EVP_PKEY_derive_set_peer (m_Ctx, pkey);
size_t len = 32; size_t len = 32;
EVP_PKEY_derive (m_Ctx, shared, &len); EVP_PKEY_derive (m_Ctx, shared, &len);
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
#else #else
GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx); GetEd25519 ()->ScalarMul (pub, m_PrivateKey, shared, m_Ctx);
#endif #endif
} }
void X25519Keys::GetPrivateKey (uint8_t * priv) const void X25519Keys::GetPrivateKey (uint8_t * priv) const
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
@ -369,14 +369,14 @@ namespace crypto
void X25519Keys::SetPrivateKey (const uint8_t * priv) void X25519Keys::SetPrivateKey (const uint8_t * priv)
{ {
#if OPENSSL_X25519 #if OPENSSL_X25519
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx); if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
if (m_Pkey) EVP_PKEY_free (m_Pkey); if (m_Pkey) EVP_PKEY_free (m_Pkey);
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL); m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
#else #else
memcpy (m_PrivateKey, priv, 32); memcpy (m_PrivateKey, priv, 32);
#endif #endif
} }
// ElGamal // ElGamal
@ -681,12 +681,12 @@ namespace crypto
// AES // AES
#ifdef __AES__ #ifdef __AES__
#ifdef ARM64AES #ifdef ARM64AES
void init_aesenc(void){ void init_aesenc(void){
// TODO: Implementation // TODO: Implementation
} }
#endif #endif
#define KeyExpansion256(round0,round1) \ #define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \
@ -884,7 +884,6 @@ namespace crypto
} }
} }
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#ifdef __AES__ #ifdef __AES__
@ -1139,10 +1138,10 @@ namespace crypto
} }
EVP_CIPHER_CTX_free (ctx); EVP_CIPHER_CTX_free (ctx);
#else #else
chacha::Chacha20State state; chacha::Chacha20State state;
// generate one time poly key // generate one time poly key
chacha::Chacha20Init (state, nonce, key, 0); chacha::Chacha20Init (state, nonce, key, 0);
uint64_t polyKey[8]; uint64_t polyKey[8];
memset(polyKey, 0, sizeof(polyKey)); memset(polyKey, 0, sizeof(polyKey));
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64); chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
@ -1158,7 +1157,7 @@ namespace crypto
{ {
// padding1 // padding1
rem = 16 - rem; rem = 16 - rem;
polyHash.Update (padding, rem); polyHash.Update (padding, rem);
} }
} }
// encrypt/decrypt data and add to hash // encrypt/decrypt data and add to hash
@ -1174,20 +1173,20 @@ namespace crypto
{ {
polyHash.Update (buf, msgLen); // before decryption polyHash.Update (buf, msgLen); // before decryption
chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt
} }
auto rem = msgLen & 0x0F; // %16 auto rem = msgLen & 0x0F; // %16
if (rem) if (rem)
{ {
// padding2 // padding2
rem = 16 - rem; rem = 16 - rem;
polyHash.Update (padding, rem); polyHash.Update (padding, rem);
} }
// adLen and msgLen // adLen and msgLen
htole64buf (padding, adLen); htole64buf (padding, adLen);
htole64buf (padding + 8, msgLen); htole64buf (padding + 8, msgLen);
polyHash.Update (padding, 16); polyHash.Update (padding, 16);
if (encrypt) if (encrypt)
// calculate Poly1305 tag and write in after encrypted data // calculate Poly1305 tag and write in after encrypted data
polyHash.Finish ((uint64_t *)(buf + msgLen)); polyHash.Finish ((uint64_t *)(buf + msgLen));
@ -1195,7 +1194,7 @@ namespace crypto
{ {
uint64_t tag[4]; uint64_t tag[4];
// calculate Poly1305 tag // calculate Poly1305 tag
polyHash.Finish (tag); polyHash.Finish (tag);
if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided
} }
#endif #endif
@ -1211,20 +1210,20 @@ namespace crypto
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce); EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
for (const auto& it: bufs) for (const auto& it: bufs)
EVP_EncryptUpdate(ctx, it.first, &outlen, it.first, it.second); EVP_EncryptUpdate(ctx, it.first, &outlen, it.first, it.second);
EVP_EncryptFinal_ex(ctx, NULL, &outlen); EVP_EncryptFinal_ex(ctx, NULL, &outlen);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
EVP_CIPHER_CTX_free (ctx); EVP_CIPHER_CTX_free (ctx);
#else #else
chacha::Chacha20State state; chacha::Chacha20State state;
// generate one time poly key // generate one time poly key
chacha::Chacha20Init (state, nonce, key, 0); chacha::Chacha20Init (state, nonce, key, 0);
uint64_t polyKey[8]; uint64_t polyKey[8];
memset(polyKey, 0, sizeof(polyKey)); memset(polyKey, 0, sizeof(polyKey));
chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64); chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
Poly1305 polyHash (polyKey); Poly1305 polyHash (polyKey);
// encrypt buffers // encrypt buffers
Chacha20SetCounter (state, 1); Chacha20SetCounter (state, 1);
size_t size = 0; size_t size = 0;
for (const auto& it: bufs) for (const auto& it: bufs)
@ -1234,22 +1233,22 @@ namespace crypto
size += it.second; size += it.second;
} }
// padding // padding
uint8_t padding[16]; uint8_t padding[16];
memset (padding, 0, 16); memset (padding, 0, 16);
auto rem = size & 0x0F; // %16 auto rem = size & 0x0F; // %16
if (rem) if (rem)
{ {
// padding2 // padding2
rem = 16 - rem; rem = 16 - rem;
polyHash.Update (padding, rem); polyHash.Update (padding, rem);
} }
// adLen and msgLen // adLen and msgLen
// adLen is always zero // adLen is always zero
htole64buf (padding + 8, size); htole64buf (padding + 8, size);
polyHash.Update (padding, 16); polyHash.Update (padding, 16);
// MAC // MAC
polyHash.Finish ((uint64_t *)mac); polyHash.Finish ((uint64_t *)mac);
#endif #endif
} }
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out) void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
@ -1265,13 +1264,13 @@ namespace crypto
EVP_CIPHER_CTX_free (ctx); EVP_CIPHER_CTX_free (ctx);
#else #else
chacha::Chacha20State state; chacha::Chacha20State state;
chacha::Chacha20Init (state, nonce, key, 1); chacha::Chacha20Init (state, nonce, key, 1);
if (out != msg) memcpy (out, msg, msgLen); if (out != msg) memcpy (out, msg, msgLen);
chacha::Chacha20Encrypt (state, out, msgLen); chacha::Chacha20Encrypt (state, out, msgLen);
#endif #endif
} }
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
uint8_t * out, size_t outLen) uint8_t * out, size_t outLen)
{ {
#if OPENSSL_HKDF #if OPENSSL_HKDF
@ -1279,10 +1278,10 @@ namespace crypto
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());
if (key && keyLen) if (key && keyLen)
{ {
EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32); EVP_PKEY_CTX_set1_hkdf_salt (pctx, salt, 32);
EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen); EVP_PKEY_CTX_set1_hkdf_key (pctx, key, keyLen);
} }
else else
{ {
// zerolen // zerolen
@ -1290,22 +1289,22 @@ namespace crypto
uint8_t tempKey[32]; unsigned int len; uint8_t tempKey[32]; unsigned int len;
HMAC(EVP_sha256(), salt, 32, nullptr, 0, tempKey, &len); HMAC(EVP_sha256(), salt, 32, nullptr, 0, tempKey, &len);
EVP_PKEY_CTX_set1_hkdf_key (pctx, 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 ());
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;
HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len); HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len);
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);
if (outLen > 32) // 64 if (outLen > 32) // 64
{ {
memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02; memcpy (out + 32, info.c_str (), l); out[l + 32] = 0x02;
HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len); HMAC(EVP_sha256(), prk, 32, out, l + 33, out + 32, &len);
} }
#endif #endif
} }
@ -1323,10 +1322,10 @@ namespace crypto
} }
}*/ }*/
void InitCrypto (bool precomputation) void InitCrypto (bool precomputation)
{ {
i2p::cpu::Detect (); i2p::cpu::Detect ();
#if LEGACY_OPENSSL #if LEGACY_OPENSSL
SSL_library_init (); SSL_library_init ();
#endif #endif
@ -1364,4 +1363,3 @@ namespace crypto
} }
} }
} }

@ -28,13 +28,13 @@
#else #else
# define LEGACY_OPENSSL 0 # define LEGACY_OPENSSL 0
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 # if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_HKDF 1 # define OPENSSL_HKDF 1
# define OPENSSL_EDDSA 1 # define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1 # define OPENSSL_X25519 1
# define OPENSSL_SIPHASH 1 # define OPENSSL_SIPHASH 1
# endif # endif
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them # if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
# define OPENSSL_AEAD_CHACHA20_POLY1305 1 # define OPENSSL_AEAD_CHACHA20_POLY1305 1
# endif # endif
#endif #endif
@ -81,20 +81,20 @@ namespace crypto
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 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:
uint8_t m_PublicKey[32]; uint8_t m_PublicKey[32];
#if OPENSSL_X25519 #if OPENSSL_X25519
EVP_PKEY_CTX * m_Ctx; EVP_PKEY_CTX * m_Ctx;
EVP_PKEY * m_Pkey; EVP_PKEY * m_Pkey;
#else #else
BN_CTX * m_Ctx; BN_CTX * m_Ctx;
uint8_t m_PrivateKey[32]; uint8_t m_PrivateKey[32];
#endif #endif
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false); void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false);
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false); bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
@ -117,15 +117,15 @@ namespace crypto
void operator^=(const ChipherBlock& other) // XOR void operator^=(const ChipherBlock& other) // XOR
{ {
if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ? if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
reinterpret_cast<uint32_t *>(buf)[i] ^= reinterpret_cast<const uint32_t *>(other.buf)[i]; reinterpret_cast<uint32_t *>(buf)[i] ^= reinterpret_cast<const uint32_t *>(other.buf)[i];
} }
else else
{ {
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i]; buf[i] ^= other.buf[i];
} }
} }
}; };
@ -297,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, size_t outLen = 64); // salt - 32, out - 32 or 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);

@ -151,7 +151,7 @@ namespace crypto
ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor (const uint8_t * pub) ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor (const uint8_t * pub)
{ {
memcpy (m_PublicKey, pub, 32); memcpy (m_PublicKey, pub, 32);
} }
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool) void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool)
{ {
@ -166,16 +166,15 @@ namespace crypto
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding) bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding)
{ {
m_StaticKeys.Agree (epub, sharedSecret); m_StaticKeys.Agree (epub, sharedSecret);
return true; return true;
} }
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub)
{ {
X25519Keys k; X25519Keys k;
k.GenerateKeys (); k.GenerateKeys ();
k.GetPrivateKey (priv); k.GetPrivateKey (priv);
memcpy (pub, k.GetPublicKey (), 32); memcpy (pub, k.GetPublicKey (), 32);
} }
} }
} }

@ -45,7 +45,7 @@ namespace crypto
ElGamalDecryptor (const uint8_t * priv); ElGamalDecryptor (const uint8_t * priv);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
size_t GetPublicKeyLen () const { return 256; }; size_t GetPublicKeyLen () const { return 256; };
private: private:
uint8_t m_PrivateKey[256]; uint8_t m_PrivateKey[256];
@ -76,7 +76,7 @@ namespace crypto
~ECIESP256Decryptor (); ~ECIESP256Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
size_t GetPublicKeyLen () const { return 64; }; size_t GetPublicKeyLen () const { return 64; };
private: private:
EC_GROUP * m_Curve; EC_GROUP * m_Curve;
@ -109,7 +109,7 @@ namespace crypto
~ECIESGOSTR3410Decryptor (); ~ECIESGOSTR3410Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding);
size_t GetPublicKeyLen () const { return 64; }; size_t GetPublicKeyLen () const { return 64; };
private: private:
BIGNUM * m_PrivateKey; BIGNUM * m_PrivateKey;
@ -119,14 +119,14 @@ namespace crypto
// ECIES-X25519-AEAD-Ratchet // ECIES-X25519-AEAD-Ratchet
class ECIESX25519AEADRatchetEncryptor: public CryptoKeyEncryptor class ECIESX25519AEADRatchetEncryptor: public CryptoKeyEncryptor
{ {
public: public:
ECIESX25519AEADRatchetEncryptor (const uint8_t * pub); ECIESX25519AEADRatchetEncryptor (const uint8_t * pub);
~ECIESX25519AEADRatchetEncryptor () {}; ~ECIESX25519AEADRatchetEncryptor () {};
void Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool); void Encrypt (const uint8_t *, uint8_t * pub, BN_CTX *, bool);
// copies m_PublicKey to pub // copies m_PublicKey to pub
private: private:
@ -139,7 +139,7 @@ namespace crypto
ECIESX25519AEADRatchetDecryptor (const uint8_t * priv); ECIESX25519AEADRatchetDecryptor (const uint8_t * priv);
~ECIESX25519AEADRatchetDecryptor () {}; ~ECIESX25519AEADRatchetDecryptor () {};
bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding); bool Decrypt (const uint8_t * epub, uint8_t * sharedSecret, BN_CTX * ctx, bool zeroPadding);
// agree with static and return in sharedSecret (32 bytes) // agree with static and return in sharedSecret (32 bytes)
size_t GetPublicKeyLen () const { return 32; }; size_t GetPublicKeyLen () const { return 32; };
@ -153,4 +153,3 @@ namespace crypto
} }
#endif #endif

@ -77,5 +77,4 @@ namespace worker
} }
} }
#endif #endif

@ -13,10 +13,10 @@ namespace datagram
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip): DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip):
m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip) m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip)
{ {
auto identityLen = m_Owner->GetIdentity ()->GetFullLen (); auto identityLen = m_Owner->GetIdentity ()->GetFullLen ();
m_From.resize (identityLen); m_From.resize (identityLen);
m_Owner->GetIdentity ()->ToBuffer (m_From.data (), identityLen); m_Owner->GetIdentity ()->ToBuffer (m_From.data (), identityLen);
m_Signature.resize (m_Owner->GetIdentity ()->GetSignatureLen ()); m_Signature.resize (m_Owner->GetIdentity ()->GetSignatureLen ());
} }
DatagramDestination::~DatagramDestination () DatagramDestination::~DatagramDestination ()
@ -36,7 +36,7 @@ namespace datagram
m_Owner->Sign (payload, len, m_Signature.data ()); m_Owner->Sign (payload, len, m_Signature.data ());
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}}, auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}},
fromPort, toPort, false, !session->IsRatchets ()); // datagram fromPort, toPort, false, !session->IsRatchets ()); // datagram
session->SendMsg(msg); session->SendMsg(msg);
} }
@ -46,8 +46,8 @@ namespace datagram
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
auto msg = CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ()); // raw auto msg = CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ()); // raw
session->SendMsg(msg); session->SendMsg(msg);
} }
void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len) void DatagramDestination::HandleDatagram (uint16_t fromPort, uint16_t toPort,uint8_t * const &buf, size_t len)
{ {
i2p::data::IdentityEx identity; i2p::data::IdentityEx identity;
@ -86,8 +86,8 @@ namespace datagram
m_RawReceiver (fromPort, toPort, buf, len); m_RawReceiver (fromPort, toPort, buf, len);
else else
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram"); LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
} }
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
{ {
std::lock_guard<std::mutex> lock(m_ReceiversMutex); std::lock_guard<std::mutex> lock(m_ReceiversMutex);
@ -107,23 +107,22 @@ namespace datagram
{ {
if (isRaw) if (isRaw)
HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen); HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen);
else else
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
} }
else else
LogPrint (eLogWarning, "Datagram: decompression failed"); LogPrint (eLogWarning, "Datagram: decompression failed");
} }
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage ( std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (
const std::vector<std::pair<const uint8_t *, size_t> >& payloads, const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum) uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
{ {
auto msg = NewI2NPMessage (); auto msg = NewI2NPMessage ();
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for length buf += 4; // reserve for length
size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) : size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) :
i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len); i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len);
if (size) if (size)
{ {
htobe32buf (msg->GetPayload (), size); // length htobe32buf (msg->GetPayload (), size); // length
@ -186,7 +185,7 @@ namespace datagram
} }
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
const i2p::data::IdentHash & remoteIdent) : const i2p::data::IdentHash & remoteIdent) :
m_LocalDestination(localDestination), m_LocalDestination(localDestination),
m_RemoteIdent(remoteIdent), m_RemoteIdent(remoteIdent),
m_SendQueueTimer(localDestination->GetService()), m_SendQueueTimer(localDestination->GetService()),
@ -384,4 +383,3 @@ namespace datagram
} }
} }
} }

@ -32,68 +32,71 @@ namespace datagram
const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000; const uint64_t DATAGRAM_SESSION_LEASE_HANDOVER_FUDGE = 1000;
// milliseconds minimum time between path switches // milliseconds minimum time between path switches
const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000; const uint64_t DATAGRAM_SESSION_PATH_MIN_LIFETIME = 5 * 1000;
// max 64 messages buffered in send queue for each datagram session // max 64 messages buffered in send queue for each datagram session
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64; const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
class DatagramSession : public std::enable_shared_from_this<DatagramSession> class DatagramSession : public std::enable_shared_from_this<DatagramSession>
{ {
public:
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent);
void Start (); public:
void Stop ();
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent);
void Start ();
void Stop ();
/** @brief ack the garlic routing path */ /** @brief ack the garlic routing path */
void Ack(); void Ack();
/** send an i2np message to remote endpoint for this session */ /** send an i2np message to remote endpoint for this session */
void SendMsg(std::shared_ptr<I2NPMessage> msg); void SendMsg(std::shared_ptr<I2NPMessage> msg);
/** get the last time in milliseconds for when we used this datagram session */ /** get the last time in milliseconds for when we used this datagram session */
uint64_t LastActivity() const { return m_LastUse; } uint64_t LastActivity() const { return m_LastUse; }
bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); } bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); }
struct Info struct Info
{ {
std::shared_ptr<const i2p::data::IdentHash> IBGW; std::shared_ptr<const i2p::data::IdentHash> IBGW;
std::shared_ptr<const i2p::data::IdentHash> OBEP; std::shared_ptr<const i2p::data::IdentHash> OBEP;
const uint64_t activity; const uint64_t activity;
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {} Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) : Info(const uint8_t * ibgw, const uint8_t * obep, const uint64_t a) :
activity(a) { activity(a) {
if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw); if(ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
else IBGW = nullptr; else IBGW = nullptr;
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep); if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
else OBEP = nullptr; else OBEP = nullptr;
} }
}; };
Info GetSessionInfo() const; Info GetSessionInfo() const;
private: private:
void FlushSendQueue(); void FlushSendQueue();
void ScheduleFlushSendQueue(); void ScheduleFlushSendQueue();
void HandleSend(std::shared_ptr<I2NPMessage> msg); void HandleSend(std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath(); std::shared_ptr<i2p::garlic::GarlicRoutingPath> GetSharedRoutingPath();
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls); void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
private: private:
std::shared_ptr<i2p::client::ClientDestination> m_LocalDestination;
i2p::data::IdentHash m_RemoteIdent; std::shared_ptr<i2p::client::ClientDestination> m_LocalDestination;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet; i2p::data::IdentHash m_RemoteIdent;
std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession; std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease; std::shared_ptr<i2p::garlic::GarlicRoutingSession> m_RoutingSession;
std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel; std::shared_ptr<const i2p::data::Lease> m_CurrentRemoteLease;
boost::asio::deadline_timer m_SendQueueTimer; std::shared_ptr<i2p::tunnel::OutboundTunnel> m_CurrentOutboundTunnel;
std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue; boost::asio::deadline_timer m_SendQueueTimer;
uint64_t m_LastUse; std::vector<std::shared_ptr<I2NPMessage> > m_SendQueue;
bool m_RequestingLS; uint64_t m_LastUse;
bool m_RequestingLS;
}; };
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr; typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
@ -104,17 +107,15 @@ namespace datagram
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver; typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver; typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver;
public: public:
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip);
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip);
~DatagramDestination (); ~DatagramDestination ();
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
void ResetReceiver () { m_Receiver = nullptr; }; void ResetReceiver () { m_Receiver = nullptr; };
@ -123,7 +124,7 @@ namespace datagram
void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; }; void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
void ResetRawReceiver () { m_RawReceiver = nullptr; }; void ResetRawReceiver () { m_RawReceiver = nullptr; };
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote); std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
// clean up stale sessions // clean up stale sessions
@ -131,14 +132,14 @@ namespace datagram
private: private:
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident); std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
std::shared_ptr<I2NPMessage> CreateDataMessage (const std::vector<std::pair<const uint8_t *, size_t> >& payloads, std::shared_ptr<I2NPMessage> CreateDataMessage (const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true); uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true);
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
/** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */ /** find a receiver by port, if none by port is found try default receiever, otherwise returns nullptr */
Receiver FindReceiver(uint16_t port); Receiver FindReceiver(uint16_t port);

@ -16,8 +16,8 @@ namespace i2p
namespace client namespace client
{ {
LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service, LeaseSetDestination::LeaseSetDestination (boost::asio::io_service& service,
bool isPublic, const std::map<std::string, std::string> * params): bool isPublic, const std::map<std::string, std::string> * params):
m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0), m_Service (service), m_IsPublic (isPublic), m_PublishReplyToken (0),
m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service), m_LastSubmissionTime (0), m_PublishConfirmationTimer (m_Service),
m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service), m_PublishVerificationTimer (m_Service), m_PublishDelayTimer (m_Service), m_CleanupTimer (m_Service),
m_LeaseSetType (DEFAULT_LEASESET_TYPE), m_AuthType (i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE) m_LeaseSetType (DEFAULT_LEASESET_TYPE), m_AuthType (i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_NONE)
@ -160,13 +160,12 @@ namespace client
bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params) bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params)
{ {
auto itr = params.find("i2cp.dontPublishLeaseSet"); auto itr = params.find("i2cp.dontPublishLeaseSet");
if (itr != params.end()) if (itr != params.end())
{ {
m_IsPublic = itr->second != "true"; m_IsPublic = itr->second != "true";
} }
int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency; int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency;
std::map<std::string, int&> intOpts = { std::map<std::string, int&> intOpts = {
{I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen}, {I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen},
@ -185,7 +184,7 @@ namespace client
outQuant = pool->GetNumOutboundTunnels(); outQuant = pool->GetNumOutboundTunnels();
minLatency = 0; minLatency = 0;
maxLatency = 0; maxLatency = 0;
for (auto & opt : intOpts) for (auto & opt : intOpts)
{ {
itr = params.find(opt.first); itr = params.find(opt.first);
@ -197,7 +196,7 @@ namespace client
pool->RequireLatency(minLatency, maxLatency); pool->RequireLatency(minLatency, maxLatency);
return pool->Reconfigure(inLen, outLen, inQuant, outQuant); return pool->Reconfigure(inLen, outLen, inQuant, outQuant);
} }
std::shared_ptr<i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident) std::shared_ptr<i2p::data::LeaseSet> LeaseSetDestination::FindLeaseSet (const i2p::data::IdentHash& ident)
{ {
std::shared_ptr<i2p::data::LeaseSet> remoteLS; std::shared_ptr<i2p::data::LeaseSet> remoteLS;
@ -266,7 +265,7 @@ namespace client
std::lock_guard<std::mutex> l(m_LeaseSetMutex); std::lock_guard<std::mutex> l(m_LeaseSetMutex);
return m_LeaseSet; return m_LeaseSet;
} }
void LeaseSetDestination::SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet) void LeaseSetDestination::SetLeaseSet (std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet)
{ {
{ {
@ -281,7 +280,7 @@ namespace client
{ {
s->m_PublishVerificationTimer.cancel (); s->m_PublishVerificationTimer.cancel ();
s->Publish (); s->Publish ();
}); });
} }
} }
@ -565,12 +564,12 @@ namespace client
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again"); LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
Publish (); Publish ();
} }
else else
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ()); LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds from Java floodfill for crypto type ", (int)GetIdentity ()->GetCryptoKeyType ());
// Java floodfill never sends confirmation back for unknown crypto type // Java floodfill never sends confirmation back for unknown crypto type
// assume it successive and try to verify // assume it successive and try to verify
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
@ -591,7 +590,7 @@ namespace client
{ {
LogPrint (eLogWarning, "Destination: couldn't verify LeaseSet for ", GetIdentHash().ToBase32()); LogPrint (eLogWarning, "Destination: couldn't verify LeaseSet for ", GetIdentHash().ToBase32());
return; return;
} }
auto s = shared_from_this (); auto s = shared_from_this ();
// we must capture this for gcc 4.7 due the bug // we must capture this for gcc 4.7 due the bug
RequestLeaseSet (ls->GetStoreHash (), RequestLeaseSet (ls->GetStoreHash (),
@ -643,9 +642,9 @@ namespace client
if (requestComplete) if (requestComplete)
m_Service.post ([requestComplete](void){requestComplete (nullptr);}); m_Service.post ([requestComplete](void){requestComplete (nullptr);});
return false; return false;
} }
auto storeHash = dest->GetStoreHash (); auto storeHash = dest->GetStoreHash ();
auto leaseSet = FindLeaseSet (storeHash); auto leaseSet = FindLeaseSet (storeHash);
if (leaseSet) if (leaseSet)
{ {
if (requestComplete) if (requestComplete)
@ -720,7 +719,7 @@ namespace client
} }
bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest, bool LeaseSetDestination::SendLeaseSetRequest (const i2p::data::IdentHash& dest,
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request) std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request)
{ {
if (!request->replyTunnel || !request->replyTunnel->IsEstablished ()) if (!request->replyTunnel || !request->replyTunnel->IsEstablished ())
request->replyTunnel = m_Pool->GetNextInboundTunnel (); request->replyTunnel = m_Pool->GetNextInboundTunnel ();
@ -783,7 +782,7 @@ namespace client
} }
else else
{ {
LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds"); LogPrint (eLogWarning, "Destination: ", dest.ToBase64 (), " was not found within ", MAX_LEASESET_REQUEST_TIMEOUT, " seconds");
done = true; done = true;
} }
@ -829,13 +828,13 @@ namespace client
i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const
{ {
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET;
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
} }
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
bool isPublic, const std::map<std::string, std::string> * params): bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params), LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service) m_ReadyChecker(service)
@ -846,7 +845,7 @@ namespace client
// extract encryption type params for LS2 // extract encryption type params for LS2
std::set<i2p::data::CryptoKeyType> encryptionKeyTypes; std::set<i2p::data::CryptoKeyType> encryptionKeyTypes;
if ((GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 || if ((GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 ||
GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) && params) GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) && params)
{ {
auto it = params->find (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE); auto it = params->find (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE);
if (it != params->end ()) if (it != params->end ())
@ -864,37 +863,37 @@ namespace client
{ {
LogPrint (eLogInfo, "Destination: Unexpected crypto type ", it1, ". ", ex.what ()); LogPrint (eLogInfo, "Destination: Unexpected crypto type ", it1, ". ", ex.what ());
continue; continue;
} }
} }
} }
} }
// if no param or valid crypto type use from identity // if no param or valid crypto type use from identity
bool isSingleKey = false; bool isSingleKey = false;
if (encryptionKeyTypes.empty ()) if (encryptionKeyTypes.empty ())
{ {
isSingleKey = true; isSingleKey = true;
encryptionKeyTypes.insert (GetIdentity ()->GetCryptoKeyType ()); encryptionKeyTypes.insert (GetIdentity ()->GetCryptoKeyType ());
} }
for (auto& it: encryptionKeyTypes) for (auto& it: encryptionKeyTypes)
{ {
auto encryptionKey = new EncryptionKey (it); auto encryptionKey = new EncryptionKey (it);
if (isPublic) if (isPublic)
PersistTemporaryKeys (encryptionKey, isSingleKey); PersistTemporaryKeys (encryptionKey, isSingleKey);
else else
encryptionKey->GenerateKeys (); encryptionKey->GenerateKeys ();
encryptionKey->CreateDecryptor (); encryptionKey->CreateDecryptor ();
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
m_ECIESx25519EncryptionKey.reset (encryptionKey); m_ECIESx25519EncryptionKey.reset (encryptionKey);
else else
m_StandardEncryptionKey.reset (encryptionKey); m_StandardEncryptionKey.reset (encryptionKey);
} }
if (isPublic) if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
try try
{ {
if (params) if (params)
{ {
// extract streaming params // extract streaming params
@ -910,9 +909,9 @@ namespace client
{ {
m_AuthKeys = std::make_shared<std::vector<i2p::data::AuthPublicKey> >(); m_AuthKeys = std::make_shared<std::vector<i2p::data::AuthPublicKey> >();
if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_DH) if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_DH)
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_DH, params); ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_DH, params);
else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK) else if (authType == i2p::data::ENCRYPTED_LEASESET_AUTH_TYPE_PSK)
ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params); ReadAuthKey (I2CP_PARAM_LEASESET_CLIENT_PSK, params);
else else
LogPrint (eLogError, "Destination: Unexpected auth type ", authType); LogPrint (eLogError, "Destination: Unexpected auth type ", authType);
if (m_AuthKeys->size ()) if (m_AuthKeys->size ())
@ -920,7 +919,7 @@ namespace client
else else
{ {
LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType); LogPrint (eLogError, "Destination: No auth keys read for auth type ", authType);
m_AuthKeys = nullptr; m_AuthKeys = nullptr;
} }
} }
} }
@ -1002,7 +1001,7 @@ namespace client
m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true); m_DatagramDestination->HandleDataMessagePayload (fromPort, toPort, buf, length, true);
else else
LogPrint (eLogError, "Destination: Missing raw datagram destination"); LogPrint (eLogError, "Destination: Missing raw datagram destination");
break; break;
default: default:
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]);
} }
@ -1105,7 +1104,7 @@ namespace client
return dest; return dest;
} }
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip) i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
{ {
if (m_DatagramDestination == nullptr) if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip); m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
@ -1130,7 +1129,7 @@ namespace client
{ {
if (!keys) return; if (!keys) return;
std::string ident = GetIdentHash().ToBase32(); std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("destinations", std::string path = i2p::fs::DataDirPath("destinations",
isSingleKey ? (ident + ".dat") : (ident + "." + std::to_string (keys->keyType) + ".dat")); isSingleKey ? (ident + ".dat") : (ident + "." + std::to_string (keys->keyType) + ".dat"));
std::ifstream f(path, std::ifstream::binary); std::ifstream f(path, std::ifstream::binary);
@ -1142,12 +1141,12 @@ 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 (keys->priv, 0, 256); memset (keys->priv, 0, 256);
memset (keys->pub, 0, 256); memset (keys->pub, 0, 256);
keys->GenerateKeys (); keys->GenerateKeys ();
// TODO:: persist crypto key type // 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 *)keys->pub, 256); f1.write ((char *)keys->pub, 256);
f1.write ((char *)keys->priv, 256); f1.write ((char *)keys->priv, 256);
return; return;
} }
@ -1160,11 +1159,11 @@ namespace client
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
{ {
if (m_StandardEncryptionKey) if (m_StandardEncryptionKey)
{ {
leaseSet = std::make_shared<i2p::data::LocalLeaseSet> (GetIdentity (), m_StandardEncryptionKey->pub, tunnels); leaseSet = std::make_shared<i2p::data::LocalLeaseSet> (GetIdentity (), m_StandardEncryptionKey->pub, tunnels);
// sign // sign
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ());
} }
else else
LogPrint (eLogError, "Destinations: Wrong encryption key type for LeaseSet type 1"); LogPrint (eLogError, "Destinations: Wrong encryption key type for LeaseSet type 1");
} }
@ -1175,9 +1174,9 @@ namespace client
if (m_ECIESx25519EncryptionKey) if (m_ECIESx25519EncryptionKey)
keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, 32, m_ECIESx25519EncryptionKey->pub} ); keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, 32, m_ECIESx25519EncryptionKey->pub} );
if (m_StandardEncryptionKey) if (m_StandardEncryptionKey)
keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} ); keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} );
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted); m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted);
if (isPublishedEncrypted) // encrypt if type 5 if (isPublishedEncrypted) // encrypt if type 5
@ -1204,18 +1203,18 @@ namespace client
return false; return false;
} }
bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
{ {
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey; return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey;
} }
const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
{ {
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr; return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr;
return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr; return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr;
} }
void ClientDestination::ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params) void ClientDestination::ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params)
{ {
for (auto it: *params) for (auto it: *params)
@ -1229,7 +1228,7 @@ namespace client
m_AuthKeys->push_back (pubKey); m_AuthKeys->push_back (pubKey);
else else
LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1)); LogPrint (eLogError, "Destination: Unexpected auth key ", it.second.substr (pos+1));
} }
} }
} }
@ -1241,10 +1240,10 @@ namespace client
if (it.second->DeleteStream (recvStreamID)) if (it.second->DeleteStream (recvStreamID))
return true; return true;
return false; return false;
} }
RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params): RunnableClientDestination::RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params):
RunnableService ("Destination"), RunnableService ("Destination"),
ClientDestination (GetIOService (), keys, isPublic, params) ClientDestination (GetIOService (), keys, isPublic, params)
{ {
} }
@ -1253,7 +1252,7 @@ namespace client
{ {
if (IsRunning ()) if (IsRunning ())
Stop (); Stop ();
} }
void RunnableClientDestination::Start () void RunnableClientDestination::Start ()
{ {

@ -52,13 +52,13 @@ namespace client
const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname"; const char I2CP_PARAM_INBOUND_NICKNAME[] = "inbound.nickname";
const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname"; const char I2CP_PARAM_OUTBOUND_NICKNAME[] = "outbound.nickname";
const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType"; const char I2CP_PARAM_LEASESET_TYPE[] = "i2cp.leaseSetType";
const int DEFAULT_LEASESET_TYPE = 1; const int DEFAULT_LEASESET_TYPE = 1;
const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType"; const char I2CP_PARAM_LEASESET_ENCRYPTION_TYPE[] = "i2cp.leaseSetEncType";
const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64
const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType";
const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn
const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn
// latency // latency
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
const int DEFAULT_MIN_TUNNEL_LATENCY = 0; const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
@ -94,7 +94,6 @@ namespace client
} }
}; };
public: public:
LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr); LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
@ -107,12 +106,12 @@ namespace client
/** i2cp reconfigure */ /** i2cp reconfigure */
virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts); virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts);
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; }; std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () { return m_Pool; };
bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; }; bool IsReady () const { return m_LeaseSet && !m_LeaseSet->IsExpired () && m_Pool->GetOutboundTunnels ().size () > 0; };
std::shared_ptr<i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident); std::shared_ptr<i2p::data::LeaseSet> FindLeaseSet (const i2p::data::IdentHash& ident);
bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr); bool RequestDestination (const i2p::data::IdentHash& dest, RequestComplete requestComplete = nullptr);
bool RequestDestinationWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, RequestComplete requestComplete = nullptr); bool RequestDestinationWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, RequestComplete requestComplete = nullptr);
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true); void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true); void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true);
@ -155,7 +154,7 @@ namespace client
void HandleDeliveryStatusMessage (uint32_t msgID); 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);
void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest); void HandleRequestTimoutTimer (const boost::system::error_code& ecode, const i2p::data::IdentHash& dest);
void HandleCleanupTimer (const boost::system::error_code& ecode); void HandleCleanupTimer (const boost::system::error_code& ecode);
void CleanupRemoteLeaseSets (); void CleanupRemoteLeaseSets ();
@ -202,11 +201,11 @@ namespace client
EncryptionKey (i2p::data::CryptoKeyType t):keyType(t) { memset (pub, 0, 256); memset (priv, 0, 256); }; EncryptionKey (i2p::data::CryptoKeyType t):keyType(t) { memset (pub, 0, 256); memset (priv, 0, 256); };
void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv, pub); }; void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv, pub); };
void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv); }; void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv); };
}; };
public: public:
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
bool isPublic, const std::map<std::string, std::string> * params = nullptr); bool isPublic, const std::map<std::string, std::string> * params = nullptr);
~ClientDestination (); ~ClientDestination ();
@ -235,13 +234,13 @@ namespace client
int GetStreamingAckDelay () const { return m_StreamingAckDelay; } int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true); i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);
// implements LocalDestination // implements LocalDestination
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) 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 (); };
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const; bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const; const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const;
protected: protected:
@ -259,8 +258,8 @@ namespace client
void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey); void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params); void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
private: private:
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
std::unique_ptr<EncryptionKey> m_StandardEncryptionKey; std::unique_ptr<EncryptionKey> m_StandardEncryptionKey;
std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey; std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
@ -273,7 +272,7 @@ namespace client
boost::asio::deadline_timer m_ReadyChecker; boost::asio::deadline_timer m_ReadyChecker;
std::shared_ptr<std::vector<i2p::data::AuthPublicKey> > m_AuthKeys; // we don't need them for I2CP std::shared_ptr<std::vector<i2p::data::AuthPublicKey> > m_AuthKeys; // we don't need them for I2CP
public: public:
@ -287,7 +286,7 @@ namespace client
public: public:
RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr); RunnableClientDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
~RunnableClientDestination (); ~RunnableClientDestination ();
void Start (); void Start ();
void Stop (); void Stop ();

File diff suppressed because it is too large Load Diff

@ -25,22 +25,22 @@ namespace garlic
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160; const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160;
const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12; const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12;
const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */ const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */
// - 16 /* I2NP header */ - 16 /* poly hash */ - 8 /* tag */ - 4 /* garlic length */ // - 16 /* I2NP header */ - 16 /* poly hash */ - 8 /* tag */ - 4 /* garlic length */
class ECIESX25519AEADRatchetSession; class ECIESX25519AEADRatchetSession;
class RatchetTagSet class RatchetTagSet
{ {
public: public:
RatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session): m_Session (session) {}; RatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session): m_Session (session) {};
void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
void NextSessionTagRatchet (); void NextSessionTagRatchet ();
uint64_t GetNextSessionTag (); uint64_t GetNextSessionTag ();
const uint8_t * GetNextRootKey () const { return m_NextRootKey; }; const uint8_t * GetNextRootKey () const { return m_NextRootKey; };
int GetNextIndex () const { return m_NextIndex; }; int GetNextIndex () const { return m_NextIndex; };
void GetSymmKey (int index, uint8_t * key); void GetSymmKey (int index, uint8_t * key);
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session.lock (); }; std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session.lock (); };
@ -49,54 +49,54 @@ namespace garlic
void Expire (); void Expire ();
bool IsExpired (uint64_t ts) const { return m_ExpirationTimestamp && ts > m_ExpirationTimestamp; }; bool IsExpired (uint64_t ts) const { return m_ExpirationTimestamp && ts > m_ExpirationTimestamp; };
private: private:
union union
{ {
uint64_t ll[8]; uint64_t ll[8];
uint8_t buf[64]; uint8_t buf[64];
const uint8_t * GetSessTagCK () const { return buf; }; // sessTag_chainKey = keydata[0:31] const uint8_t * GetSessTagCK () const { return buf; }; // sessTag_chainKey = keydata[0:31]
const uint8_t * GetSessTagConstant () const { return buf + 32; }; // SESSTAG_CONSTANT = keydata[32:63] const uint8_t * GetSessTagConstant () const { return buf + 32; }; // SESSTAG_CONSTANT = keydata[32:63]
uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39] uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39]
} m_KeyData; } m_KeyData;
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32]; uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
int m_NextIndex, m_NextSymmKeyIndex; int m_NextIndex, m_NextSymmKeyIndex;
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys; std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
std::weak_ptr<ECIESX25519AEADRatchetSession> m_Session; std::weak_ptr<ECIESX25519AEADRatchetSession> m_Session;
int m_TagSetID = 0; int m_TagSetID = 0;
uint64_t m_ExpirationTimestamp = 0; uint64_t m_ExpirationTimestamp = 0;
}; };
enum ECIESx25519BlockType enum ECIESx25519BlockType
{ {
eECIESx25519BlkDateTime = 0, eECIESx25519BlkDateTime = 0,
eECIESx25519BlkSessionID = 1, eECIESx25519BlkSessionID = 1,
eECIESx25519BlkTermination = 4, eECIESx25519BlkTermination = 4,
eECIESx25519BlkOptions = 5, eECIESx25519BlkOptions = 5,
eECIESx25519BlkNextKey = 7, eECIESx25519BlkNextKey = 7,
eECIESx25519BlkAck = 8, eECIESx25519BlkAck = 8,
eECIESx25519BlkAckRequest = 9, eECIESx25519BlkAckRequest = 9,
eECIESx25519BlkGalicClove = 11, eECIESx25519BlkGalicClove = 11,
eECIESx25519BlkPadding = 254 eECIESx25519BlkPadding = 254
}; };
const uint8_t ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG = 0x01; const uint8_t ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG = 0x01;
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02; const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04; const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
{ {
enum SessionState enum SessionState
{ {
eSessionStateNew =0, eSessionStateNew = 0,
eSessionStateNewSessionReceived, eSessionStateNewSessionReceived,
eSessionStateNewSessionSent, eSessionStateNewSessionSent,
eSessionStateNewSessionReplySent, eSessionStateNewSessionReplySent,
eSessionStateEstablished eSessionStateEstablished
}; };
struct DHRatchet struct DHRatchet
{ {
@ -104,65 +104,65 @@ namespace garlic
i2p::crypto::X25519Keys key; i2p::crypto::X25519Keys key;
uint8_t remote[32]; // last remote public key uint8_t remote[32]; // last remote public key
bool newKey = true; bool newKey = true;
}; };
public:
ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet); public:
~ECIESX25519AEADRatchetSession ();
ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet);
~ECIESX25519AEADRatchetSession ();
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index = 0); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index = 0);
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
void SetDestination (const i2p::data::IdentHash& dest) // TODO: void SetDestination (const i2p::data::IdentHash& dest) // TODO:
{ {
if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest)); if (!m_Destination) m_Destination.reset (new i2p::data::IdentHash (dest));
} }
bool CheckExpired (uint64_t ts); // true is expired bool CheckExpired (uint64_t ts); // true is expired
bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; }
bool IsRatchets () const { return true; }; bool IsRatchets () const { return true; };
private: private:
void ResetKeys (); void ResetKeys ();
void MixHash (const uint8_t * buf, size_t len); void MixHash (const uint8_t * buf, size_t len);
void CreateNonce (uint64_t seqn, uint8_t * nonce); void CreateNonce (uint64_t seqn, uint8_t * nonce);
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
std::shared_ptr<RatchetTagSet> CreateNewSessionTagset (); std::shared_ptr<RatchetTagSet> CreateNewSessionTagset ();
bool HandleNewIncomingSession (const uint8_t * buf, size_t len); bool HandleNewIncomingSession (const uint8_t * buf, size_t len);
bool HandleNewOutgoingSessionReply (uint8_t * buf, size_t len); bool HandleNewOutgoingSessionReply (uint8_t * buf, size_t len);
bool HandleExistingSessionMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index); bool HandleExistingSessionMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index);
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset, int index); void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset, int index);
void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset); void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset);
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first); std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first);
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false); size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false);
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len); size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
void GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags); void GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags);
void NewNextSendRatchet (); void NewNextSendRatchet ();
private:
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; private:
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32];
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only
i2p::crypto::X25519Keys m_EphemeralKeys; i2p::crypto::X25519Keys m_EphemeralKeys;
SessionState m_State = eSessionStateNew; SessionState m_State = eSessionStateNew;
uint64_t m_LastActivityTimestamp = 0; // incoming uint64_t m_LastActivityTimestamp = 0; // incoming
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRTagset; std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRTagset;
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index) std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
bool m_SendReverseKey = false, m_SendForwardKey = false; bool m_SendReverseKey = false, m_SendForwardKey = false;
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet; std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
@ -174,8 +174,8 @@ namespace garlic
i2p::data::IdentHash GetDestination () const i2p::data::IdentHash GetDestination () const
{ {
return m_Destination ? *m_Destination : i2p::data::IdentHash (); return m_Destination ? *m_Destination : i2p::data::IdentHash ();
} }
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag); std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
} }

@ -121,7 +121,7 @@ namespace crypto
return passed; return passed;
} }
void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded,
const uint8_t * buf, size_t len, uint8_t * signature) const const uint8_t * buf, size_t len, uint8_t * signature) const
{ {
BN_CTX * bnCtx = BN_CTX_new (); BN_CTX * bnCtx = BN_CTX_new ();
@ -153,7 +153,7 @@ namespace crypto
BN_CTX_free (bnCtx); BN_CTX_free (bnCtx);
} }
void Ed25519::SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, void Ed25519::SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded,
const uint8_t * buf, size_t len, uint8_t * signature) const const uint8_t * buf, size_t len, uint8_t * signature) const
{ {
BN_CTX * bnCtx = BN_CTX_new (); BN_CTX * bnCtx = BN_CTX_new ();
@ -164,16 +164,16 @@ namespace crypto
SHA512_CTX ctx; SHA512_CTX ctx;
SHA512_Init (&ctx); SHA512_Init (&ctx);
SHA512_Update (&ctx, T, 80); SHA512_Update (&ctx, T, 80);
SHA512_Update (&ctx, publicKeyEncoded, 32); SHA512_Update (&ctx, publicKeyEncoded, 32);
SHA512_Update (&ctx, buf, len); // data SHA512_Update (&ctx, buf, len); // data
uint8_t digest[64]; uint8_t digest[64];
SHA512_Final (digest, &ctx); SHA512_Final (digest, &ctx);
BIGNUM * r = DecodeBN<64> (digest); BIGNUM * r = DecodeBN<64> (digest);
BN_mod (r, r, l, bnCtx); // % l BN_mod (r, r, l, bnCtx); // % l
EncodeBN (r, digest, 32); EncodeBN (r, digest, 32);
// calculate R // calculate R
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R);
// calculate S // calculate S
SHA512_Init (&ctx); SHA512_Init (&ctx);
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
@ -182,7 +182,7 @@ namespace crypto
SHA512_Final (digest, &ctx); SHA512_Final (digest, &ctx);
BIGNUM * h = DecodeBN<64> (digest); BIGNUM * h = DecodeBN<64> (digest);
// S = (r + h*a) % l // S = (r + h*a) % l
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey); BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);
BN_mod_mul (h, h, a, l, bnCtx); // %l BN_mod_mul (h, h, a, l, bnCtx); // %l
BN_mod_add (h, h, r, l, bnCtx); // %l BN_mod_add (h, h, r, l, bnCtx); // %l
memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
@ -190,7 +190,7 @@ namespace crypto
BN_free (r); BN_free (h); BN_free (a); BN_free (r); BN_free (h); BN_free (a);
BN_CTX_free (bnCtx); BN_CTX_free (bnCtx);
} }
EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
{ {
// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2) // x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
@ -467,7 +467,7 @@ namespace crypto
--bits; --bits;
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0; auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
swap ^= k_t; swap ^= k_t;
if (swap) if (swap)
{ {
std::swap (x2, x3); std::swap (x2, x3);
std::swap (z2, z3); std::swap (z2, z3);
@ -492,7 +492,7 @@ namespace crypto
BN_mod_mul(z3, x1, z2, q, ctx); BN_mod_mul(z3, x1, z2, q, ctx);
BN_mod_mul(z2, tmp1, tmp0, q, ctx); BN_mod_mul(z2, tmp1, tmp0, q, ctx);
} }
if (swap) if (swap)
{ {
std::swap (x2, x3); std::swap (x2, x3);
std::swap (z2, z3); std::swap (z2, z3);
@ -533,9 +533,9 @@ namespace crypto
{ {
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
// calculate alpha = seed mod l // calculate alpha = seed mod l
BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
BN_mod (alpha, alpha, l, ctx); // % l BN_mod (alpha, alpha, l, ctx); // % l
uint8_t priv[32]; uint8_t priv[32];
EncodeBN (alpha, priv, 32); // back to Little Endian EncodeBN (alpha, priv, 32); // back to Little Endian
BN_free (alpha); BN_free (alpha);
// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha) // A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
@ -548,16 +548,16 @@ namespace crypto
{ {
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
// calculate alpha = seed mod l // calculate alpha = seed mod l
BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
BN_mod (alpha, alpha, l, ctx); // % l BN_mod (alpha, alpha, l, ctx); // % l
BIGNUM * p = DecodeBN<32> (priv); // priv is in Little Endian BIGNUM * p = DecodeBN<32> (priv); // priv is in Little Endian
BN_add (alpha, alpha, p); // alpha = alpha + priv BN_add (alpha, alpha, p); // alpha = alpha + priv
// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L // a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
BN_mod (alpha, alpha, l, ctx); // % l BN_mod (alpha, alpha, l, ctx); // % l
EncodeBN (alpha, blindedPriv, 32); EncodeBN (alpha, blindedPriv, 32);
// A' = DERIVE_PUBLIC(a') // A' = DERIVE_PUBLIC(a')
auto A1 = MulB (blindedPriv, ctx); auto A1 = MulB (blindedPriv, ctx);
EncodePublicKey (A1, blindedPub, ctx); EncodePublicKey (A1, blindedPub, ctx);
BN_free (alpha); BN_free (p); BN_free (alpha); BN_free (p);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
@ -574,14 +574,14 @@ namespace crypto
{ {
uint8_t seed[32]; uint8_t seed[32];
RAND_bytes (seed, 32); RAND_bytes (seed, 32);
BIGNUM * p = DecodeBN<32> (seed); BIGNUM * p = DecodeBN<32> (seed);
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_mod (p, p, l, ctx); // % l BN_mod (p, p, l, ctx); // % l
EncodeBN (p, priv, 32); EncodeBN (p, priv, 32);
BN_CTX_free (ctx); BN_CTX_free (ctx);
BN_free (p); BN_free (p);
} }
static std::unique_ptr<Ed25519> g_Ed25519; static std::unique_ptr<Ed25519> g_Ed25519;
std::unique_ptr<Ed25519>& GetEd25519 () std::unique_ptr<Ed25519>& GetEd25519 ()
{ {
@ -597,4 +597,3 @@ namespace crypto
} }
} }
} }

@ -86,10 +86,10 @@ namespace crypto
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const;
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
void SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; void SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes static void ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey); // key - 32 bytes, expandedKey - 64 bytes
void CreateRedDSAPrivateKey (uint8_t * priv); // priv is 32 bytes void CreateRedDSAPrivateKey (uint8_t * priv); // priv is 32 bytes
private: private:
EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const; EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const;
@ -97,8 +97,8 @@ namespace crypto
EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const; EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const;
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const; // B*e, e is 32 bytes Little Endian EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const; // B*e, e is 32 bytes Little Endian
EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const; EDDSAPoint Normalize (const EDDSAPoint& p, BN_CTX * ctx) const;
bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const; bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const;
BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const; BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const;
EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const; EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const;
void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const; void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const;
@ -109,7 +109,7 @@ namespace crypto
#if !OPENSSL_X25519 #if !OPENSSL_X25519
// for x25519 // for x25519
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
#endif #endif
private: private:
@ -121,13 +121,11 @@ namespace crypto
// if j > 128 we use 256 - j and carry 1 to next byte // if j > 128 we use 256 - j and carry 1 to next byte
// Bi256[0][0] = B, base point // Bi256[0][0] = B, base point
EDDSAPoint Bi256Carry; // Bi256[32][0] EDDSAPoint Bi256Carry; // Bi256[32][0]
}; };
std::unique_ptr<Ed25519>& GetEd25519 (); std::unique_ptr<Ed25519>& GetEd25519 ();
} }
} }
#endif #endif

@ -6,7 +6,7 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
Elligator2::Elligator2 () Elligator2::Elligator2 ()
{ {
// TODO: share with Ed22519 // TODO: share with Ed22519
@ -21,32 +21,32 @@ namespace crypto
A = BN_new (); BN_set_word (A, 486662); A = BN_new (); BN_set_word (A, 486662);
nA = BN_new (); BN_sub (nA, p, A); nA = BN_new (); BN_sub (nA, p, A);
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
// calculate sqrt(-1) // calculate sqrt(-1)
sqrtn1 = BN_new (); sqrtn1 = BN_new ();
BN_set_word (sqrtn1, 2); BN_set_word (sqrtn1, 2);
BN_mod_exp (sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4 BN_mod_exp (sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
u = BN_new (); BN_set_word (u, 2); u = BN_new (); BN_set_word (u, 2);
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx); iu = BN_new (); BN_mod_inverse (iu, u, p, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
Elligator2::~Elligator2 () Elligator2::~Elligator2 ()
{ {
BN_free (p); BN_free (p38); BN_free (p12); BN_free (p14); BN_free (p); BN_free (p38); BN_free (p12); BN_free (p14);
BN_free (sqrtn1); BN_free (A); BN_free (nA); BN_free (sqrtn1); BN_free (A); BN_free (nA);
BN_free (u); BN_free (iu); BN_free (u); BN_free (iu);
} }
bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, bool random) const bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, bool random) const
{ {
bool ret = true; bool ret = true;
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx); BN_CTX_start (ctx);
uint8_t key1[32]; uint8_t key1[32];
for (size_t i = 0; i < 16; i++) // from Little Endian for (size_t i = 0; i < 16; i++) // from Little Endian
{ {
key1[i] = key[31 - i]; key1[i] = key[31 - i];
@ -59,35 +59,35 @@ namespace crypto
BIGNUM * uxxA = BN_CTX_get (ctx); // u*x*xA BIGNUM * uxxA = BN_CTX_get (ctx); // u*x*xA
BN_mod_mul (uxxA, u, x, p, ctx); BN_mod_mul (uxxA, u, x, p, ctx);
BN_mod_mul (uxxA, uxxA, xA, p, ctx); BN_mod_mul (uxxA, uxxA, xA, p, ctx);
if (Legendre (uxxA, ctx) != -1) if (Legendre (uxxA, ctx) != -1)
{ {
uint8_t randByte = 0; // random highest bits and high y uint8_t randByte = 0; // random highest bits and high y
if (random) if (random)
{ {
RAND_bytes (&randByte, 1); RAND_bytes (&randByte, 1);
highY = randByte & 0x01; highY = randByte & 0x01;
} }
BIGNUM * r = BN_CTX_get (ctx); BIGNUM * r = BN_CTX_get (ctx);
if (highY) if (highY)
{ {
BN_mod_inverse (r, x, p, ctx); BN_mod_inverse (r, x, p, ctx);
BN_mod_mul (r, r, xA, p, ctx); BN_mod_mul (r, r, xA, p, ctx);
} }
else else
{ {
BN_mod_inverse (r, xA, p, ctx); BN_mod_inverse (r, xA, p, ctx);
BN_mod_mul (r, r, x, p, ctx); BN_mod_mul (r, r, x, p, ctx);
} }
BN_mod_mul (r, r, iu, p, ctx); BN_mod_mul (r, r, iu, p, ctx);
SquareRoot (r, r, ctx); SquareRoot (r, r, ctx);
bn2buf (r, encoded, 32); bn2buf (r, encoded, 32);
if (random) if (random)
encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte
for (size_t i = 0; i < 16; i++) // To Little Endian for (size_t i = 0; i < 16; i++) // To Little Endian
{ {
uint8_t tmp = encoded[i]; uint8_t tmp = encoded[i];
@ -98,7 +98,7 @@ namespace crypto
else else
ret = false; ret = false;
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
return ret; return ret;
} }
@ -109,31 +109,31 @@ namespace crypto
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx); BN_CTX_start (ctx);
uint8_t encoded1[32]; uint8_t encoded1[32];
for (size_t i = 0; i < 16; i++) // from Little Endian for (size_t i = 0; i < 16; i++) // from Little Endian
{ {
encoded1[i] = encoded[31 - i]; encoded1[i] = encoded[31 - i];
encoded1[31 - i] = encoded[i]; encoded1[31 - i] = encoded[i];
} }
encoded1[0] &= 0x3F; // drop two highest bits encoded1[0] &= 0x3F; // drop two highest bits
BIGNUM * r = BN_CTX_get (ctx); BN_bin2bn (encoded1, 32, r); BIGNUM * r = BN_CTX_get (ctx); BN_bin2bn (encoded1, 32, r);
if (BN_cmp (r, p12) <= 0) // r < (p-1)/2 if (BN_cmp (r, p12) <= 0) // r < (p-1)/2
{ {
// v = -A/(1+u*r^2) // v = -A/(1+u*r^2)
BIGNUM * v = BN_CTX_get (ctx); BN_mod_sqr (v, r, p, ctx); BIGNUM * v = BN_CTX_get (ctx); BN_mod_sqr (v, r, p, ctx);
BN_mod_mul (v, v, u, p, ctx); BN_mod_mul (v, v, u, p, ctx);
BN_add_word (v, 1); BN_add_word (v, 1);
BN_mod_inverse (v, v, p, ctx); BN_mod_inverse (v, v, p, ctx);
BN_mod_mul (v, v, nA, p, ctx); BN_mod_mul (v, v, nA, p, ctx);
BIGNUM * vpA = BN_CTX_get (ctx); BIGNUM * vpA = BN_CTX_get (ctx);
BN_add (vpA, v, A); // v + A BN_add (vpA, v, A); // v + A
// t = v^3+A*v^2+v = v^2*(v+A)+v // 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); BIGNUM * t = BN_CTX_get (ctx); BN_mod_sqr (t, v, p, ctx);
BN_mod_mul (t, t, vpA, p, ctx); BN_mod_mul (t, t, vpA, p, ctx);
BN_mod_add (t, t, v, p, ctx); BN_mod_add (t, t, v, p, ctx);
int legendre = Legendre (t, ctx); int legendre = Legendre (t, ctx);
BIGNUM * x = BN_CTX_get (ctx); BIGNUM * x = BN_CTX_get (ctx);
@ -143,9 +143,9 @@ namespace crypto
{ {
BN_sub (x, p, v); BN_sub (x, p, v);
BN_mod_sub (x, x, A, p, ctx); BN_mod_sub (x, x, A, p, ctx);
} }
bn2buf (x, key, 32); bn2buf (x, key, 32);
for (size_t i = 0; i < 16; i++) // To Little Endian for (size_t i = 0; i < 16; i++) // To Little Endian
{ {
uint8_t tmp = key[i]; uint8_t tmp = key[i];
@ -156,7 +156,7 @@ namespace crypto
else else
ret = false; ret = false;
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
return ret; return ret;
@ -170,21 +170,21 @@ namespace crypto
BN_add_word (t, 1); BN_add_word (t, 1);
if (!BN_cmp (t, p)) if (!BN_cmp (t, p))
BN_mod_mul (r, r, sqrtn1, p, ctx); BN_mod_mul (r, r, sqrtn1, p, ctx);
if (BN_cmp (r, p12) > 0) // r > (p-1)/2 if (BN_cmp (r, p12) > 0) // r > (p-1)/2
BN_sub (r, p, r); BN_sub (r, p, r);
} }
int Elligator2::Legendre (const BIGNUM * a, BN_CTX * ctx) const 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 // assume a < p, so don't check for a % p = 0, but a = 0 only
if (BN_is_zero(a)) return 0; if (BN_is_zero(a)) return 0;
BIGNUM * r = BN_CTX_get (ctx); BIGNUM * r = BN_CTX_get (ctx);
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
if (BN_is_word(r, 1)) if (BN_is_word(r, 1))
return 1; return 1;
else if (BN_is_zero(r)) else if (BN_is_zero(r))
return 0; return 0;
return -1; return -1;
} }
@ -204,4 +204,3 @@ namespace crypto
} }
} }
} }

@ -20,11 +20,11 @@ namespace crypto
bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false, bool random = true) const; bool Encode (const uint8_t * key, uint8_t * encoded, bool highY = false, bool random = true) const;
bool Decode (const uint8_t * encoded, uint8_t * key) const; bool Decode (const uint8_t * encoded, uint8_t * key) const;
private: private:
void SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const; void SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const;
int Legendre (const BIGNUM * a, BN_CTX * ctx) const; // a/p int Legendre (const BIGNUM * a, BN_CTX * ctx) const; // a/p
private: private:
BIGNUM * p, * p38, * p12, * p14, * sqrtn1, * A, * nA, * u, * iu; BIGNUM * p, * p38, * p12, * p14, * sqrtn1, * A, * nA, * u, * iu;
@ -35,5 +35,3 @@ namespace crypto
} }
#endif #endif

@ -17,133 +17,136 @@
namespace i2p { namespace i2p {
namespace fs { namespace fs {
extern std::string dirSep; extern std::string dirSep;
/** /**
* @brief Class to work with NetDb & Router profiles * @brief Class to work with NetDb & Router profiles
* *
* Usage: * Usage:
* *
* const char alphabet[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}; * const char alphabet[8] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};
* auto h = HashedStorage("name", "y", "z-", ".txt"); * auto h = HashedStorage("name", "y", "z-", ".txt");
* h.SetPlace("/tmp/hs-test"); * h.SetPlace("/tmp/hs-test");
* h.GetName() -> gives "name" * h.GetName() -> gives "name"
* h.GetRoot() -> gives "/tmp/hs-test/name" * h.GetRoot() -> gives "/tmp/hs-test/name"
* h.Init(alphabet, 8); <- creates needed dirs, 8 is size of alphabet * h.Init(alphabet, 8); <- creates needed dirs, 8 is size of alphabet
* h.Path("abcd"); <- returns /tmp/hs-test/name/ya/z-abcd.txt * h.Path("abcd"); <- returns /tmp/hs-test/name/ya/z-abcd.txt
* h.Remove("abcd"); <- removes /tmp/hs-test/name/ya/z-abcd.txt, if it exists * h.Remove("abcd"); <- removes /tmp/hs-test/name/ya/z-abcd.txt, if it exists
* std::vector<std::string> files; * std::vector<std::string> files;
* h.Traverse(files); <- finds all files in storage and saves in given vector * h.Traverse(files); <- finds all files in storage and saves in given vector
*/ */
class HashedStorage { class HashedStorage
protected: {
std::string root; /**< path to storage with it's name included */ protected:
std::string name; /**< name of the storage */
std::string prefix1; /**< hashed directory prefix */ std::string root; /**< path to storage with it's name included */
std::string prefix2; /**< prefix of file in storage */ std::string name; /**< name of the storage */
std::string suffix; /**< suffix of file in storage (extension) */ std::string prefix1; /**< hashed directory prefix */
std::string prefix2; /**< prefix of file in storage */
public: std::string suffix; /**< suffix of file in storage (extension) */
typedef std::function<void(const std::string &)> FilenameVisitor;
HashedStorage(const char *n, const char *p1, const char *p2, const char *s): public:
name(n), prefix1(p1), prefix2(p2), suffix(s) {};
typedef std::function<void(const std::string &)> FilenameVisitor;
/** create subdirs in storage */ HashedStorage(const char *n, const char *p1, const char *p2, const char *s):
bool Init(const char* chars, size_t cnt); name(n), prefix1(p1), prefix2(p2), suffix(s) {};
const std::string & GetRoot() const { return root; }
const std::string & GetName() const { return name; } /** create subdirs in storage */
/** set directory where to place storage directory */ bool Init(const char* chars, size_t cnt);
void SetPlace(const std::string & path); const std::string & GetRoot() const { return root; }
/** path to file with given ident */ const std::string & GetName() const { return name; }
std::string Path(const std::string & ident) const; /** set directory where to place storage directory */
/** remove file by ident */ void SetPlace(const std::string & path);
void Remove(const std::string & ident); /** path to file with given ident */
/** find all files in storage and store list in provided vector */ std::string Path(const std::string & ident) const;
void Traverse(std::vector<std::string> & files); /** remove file by ident */
/** visit every file in this storage with a visitor */ void Remove(const std::string & ident);
void Iterate(FilenameVisitor v); /** find all files in storage and store list in provided vector */
}; void Traverse(std::vector<std::string> & files);
/** visit every file in this storage with a visitor */
/** @brief Returns current application name, default 'i2pd' */ void Iterate(FilenameVisitor v);
};
/** @brief Returns current application name, default 'i2pd' */
const std::string & GetAppName (); const std::string & GetAppName ();
/** @brief Set application name, affects autodetection of datadir */ /** @brief Set application name, affects autodetection of datadir */
void SetAppName (const std::string& name); void SetAppName (const std::string& name);
/** @brief Returns datadir path */ /** @brief Returns datadir path */
const std::string & GetDataDir(); const std::string & GetDataDir();
/** /**
* @brief Set datadir either from cmdline option or using autodetection * @brief Set datadir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --datadir=<something> * @param cmdline_param Value of cmdline parameter --datadir=<something>
* @param isService Value of cmdline parameter --service * @param isService Value of cmdline parameter --service
* *
* Examples of autodetected paths: * Examples of autodetected paths:
* *
* Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd\ * Windows < Vista: C:\Documents and Settings\Username\Application Data\i2pd\
* Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd\ * Windows >= Vista: C:\Users\Username\AppData\Roaming\i2pd\
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/ * Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/
* Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/ * Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/
*/ */
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false); void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/** /**
* @brief Create subdirectories inside datadir * @brief Create subdirectories inside datadir
*/ */
bool Init(); bool Init();
/** /**
* @brief Get list of files in directory * @brief Get list of files in directory
* @param path Path to directory * @param path Path to directory
* @param files Vector to store found files * @param files Vector to store found files
* @return true on success and false if directory not exists * @return true on success and false if directory not exists
*/ */
bool ReadDir(const std::string & path, std::vector<std::string> & files); bool ReadDir(const std::string & path, std::vector<std::string> & files);
/** /**
* @brief Remove file with given path * @brief Remove file with given path
* @param path Absolute path to file * @param path Absolute path to file
* @return true on success, false if file not exists, throws exception on error * @return true on success, false if file not exists, throws exception on error
*/ */
bool Remove(const std::string & path); bool Remove(const std::string & path);
/** /**
* @brief Check existence of file * @brief Check existence of file
* @param path Absolute path to file * @param path Absolute path to file
* @return true if file exists, false otherwise * @return true if file exists, false otherwise
*/ */
bool Exists(const std::string & path); bool Exists(const std::string & path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path); bool CreateDirectory (const std::string& path);
template<typename T> template<typename T>
void _ExpandPath(std::stringstream & path, T c) { void _ExpandPath(std::stringstream & path, T c) {
path << i2p::fs::dirSep << c; path << i2p::fs::dirSep << c;
} }
template<typename T, typename ... Other> template<typename T, typename ... Other>
void _ExpandPath(std::stringstream & path, T c, Other ... other) { void _ExpandPath(std::stringstream & path, T c, Other ... other) {
_ExpandPath(path, c); _ExpandPath(path, c);
_ExpandPath(path, other ...); _ExpandPath(path, other ...);
} }
/** /**
* @brief Get path relative to datadir * @brief Get path relative to datadir
* *
* Examples (with datadir = "/tmp/i2pd"): * Examples (with datadir = "/tmp/i2pd"):
* *
* i2p::fs::Path("test") -> '/tmp/i2pd/test' * i2p::fs::Path("test") -> '/tmp/i2pd/test'
* i2p::fs::Path("test", "file.txt") -> '/tmp/i2pd/test/file.txt' * i2p::fs::Path("test", "file.txt") -> '/tmp/i2pd/test/file.txt'
*/ */
template<typename ... Other> template<typename ... Other>
std::string DataDirPath(Other ... components) { std::string DataDirPath(Other ... components) {
std::stringstream s(""); std::stringstream s("");
s << i2p::fs::GetDataDir(); s << i2p::fs::GetDataDir();
_ExpandPath(s, components ...); _ExpandPath(s, components ...);
return s.str(); return s.str();
} }
template<typename Storage, typename... Filename> template<typename Storage, typename... Filename>
std::string StorageRootPath (const Storage& storage, Filename... filenames) std::string StorageRootPath (const Storage& storage, Filename... filenames)

@ -179,4 +179,3 @@ namespace data
} }
} }
} }

@ -38,9 +38,9 @@ namespace garlic
if (!m_SharedRoutingPath) return nullptr; if (!m_SharedRoutingPath) return nullptr;
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED || if (m_SharedRoutingPath->numTimesUsed >= ROUTING_PATH_MAX_NUM_TIMES_USED ||
!m_SharedRoutingPath->outboundTunnel->IsEstablished () || !m_SharedRoutingPath->outboundTunnel->IsEstablished () ||
ts*1000LL > m_SharedRoutingPath->remoteLease->endDate || ts*1000LL > m_SharedRoutingPath->remoteLease->endDate ||
ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT) ts > m_SharedRoutingPath->updateTime + ROUTING_PATH_EXPIRATION_TIMEOUT)
m_SharedRoutingPath = nullptr; m_SharedRoutingPath = nullptr;
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++; if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
return m_SharedRoutingPath; return m_SharedRoutingPath;
@ -68,7 +68,7 @@ namespace garlic
return true; return true;
} }
return false; return false;
} }
void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts) void GarlicRoutingSession::CleanupUnconfirmedLeaseSet (uint64_t ts)
{ {
@ -78,8 +78,8 @@ namespace garlic
GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); GetOwner ()->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
m_LeaseSetUpdateMsgID = 0; m_LeaseSetUpdateMsgID = 0;
} }
} }
std::shared_ptr<I2NPMessage> GarlicRoutingSession::CreateEncryptedDeliveryStatusMsg (uint32_t msgID) std::shared_ptr<I2NPMessage> GarlicRoutingSession::CreateEncryptedDeliveryStatusMsg (uint32_t msgID)
{ {
auto msg = CreateDeliveryStatusMsg (msgID); auto msg = CreateDeliveryStatusMsg (msgID);
@ -94,12 +94,12 @@ namespace garlic
msg = garlic.WrapSingleMessage (msg); msg = garlic.WrapSingleMessage (msg);
} }
return msg; return msg;
} }
ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner, ElGamalAESSession::ElGamalAESSession (GarlicDestination * owner,
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet): std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
GarlicRoutingSession (owner, attachLeaseSet), GarlicRoutingSession (owner, attachLeaseSet),
m_Destination (destination), m_NumTags (numTags) m_Destination (destination), m_NumTags (numTags)
{ {
// create new session tags and session key // create new session tags and session key
RAND_bytes (m_SessionKey, 32); RAND_bytes (m_SessionKey, 32);
@ -115,7 +115,7 @@ namespace garlic
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
} }
std::shared_ptr<I2NPMessage> ElGamalAESSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) std::shared_ptr<I2NPMessage> ElGamalAESSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
{ {
auto m = NewI2NPMessage (); auto m = NewI2NPMessage ();
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
@ -181,7 +181,7 @@ namespace garlic
return m; return m;
} }
size_t ElGamalAESSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg) size_t ElGamalAESSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg)
{ {
size_t blockSize = 0; size_t blockSize = 0;
bool createNewTags = GetOwner () && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3); bool createNewTags = GetOwner () && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3);
@ -329,10 +329,10 @@ namespace garlic
// create msg // create msg
auto msg = CreateEncryptedDeliveryStatusMsg (msgID); auto msg = CreateEncryptedDeliveryStatusMsg (msgID);
if (msg) if (msg)
{ {
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength (); size += msg->GetLength ();
} }
// fill clove // fill clove
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 8000; // 8 sec
uint32_t cloveID; uint32_t cloveID;
@ -353,7 +353,7 @@ namespace garlic
return size; return size;
} }
ElGamalAESSession::UnconfirmedTags * ElGamalAESSession::GenerateSessionTags () ElGamalAESSession::UnconfirmedTags * ElGamalAESSession::GenerateSessionTags ()
{ {
auto tags = new UnconfirmedTags (m_NumTags); auto tags = new UnconfirmedTags (m_NumTags);
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
@ -487,7 +487,7 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes"); LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
} }
else else
{ {
bool found = false; bool found = false;
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
{ {
@ -500,15 +500,15 @@ namespace garlic
found = true; found = true;
auto session = it1->second.tagset->GetSession (); auto session = it1->second.tagset->GetSession ();
if (!session || !session->HandleNextMessage (buf, length, it1->second.tagset, it1->second.index)) if (!session || !session->HandleNextMessage (buf, length, it1->second.tagset, it1->second.index))
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
m_ECIESx25519Tags.erase (it1); m_ECIESx25519Tags.erase (it1);
} }
} }
if (!found) // assume new session if (!found) // assume new session
{ {
// AES tag not found. Handle depending on encryption type // AES tag not found. Handle depending on encryption type
// try ElGamal/AES first if leading block is 514 // try ElGamal/AES first if leading block is 514
ElGamalBlock elGamal; ElGamalBlock elGamal;
if (mod == 2 && length >= 514 && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) && if (mod == 2 && length >= 514 && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) &&
Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)) Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
@ -521,16 +521,16 @@ namespace garlic
HandleAESBlock (buf + 514, length - 514, decryption, msg->from); HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
} }
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
{ {
// otherwise ECIESx25519 // otherwise ECIESx25519
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
if (!session->HandleNextMessage (buf, length, nullptr, 0)) if (!session->HandleNextMessage (buf, length, nullptr, 0))
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
} }
else else
LogPrint (eLogError, "Garlic: Failed to decrypt message"); LogPrint (eLogError, "Garlic: Failed to decrypt message");
} }
} }
} }
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
@ -703,41 +703,41 @@ namespace garlic
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession ( std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet) std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
{ {
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET &&
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
{ {
ECIESX25519AEADRatchetSessionPtr session; ECIESX25519AEADRatchetSessionPtr session;
uint8_t staticKey[32]; uint8_t staticKey[32];
destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key
auto it = m_ECIESx25519Sessions.find (staticKey); auto it = m_ECIESx25519Sessions.find (staticKey);
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
session = it->second; session = it->second;
if (!session) if (!session)
{ {
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true); session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
session->SetRemoteStaticKey (staticKey); session->SetRemoteStaticKey (staticKey);
} }
session->SetDestination (destination->GetIdentHash ()); // TODO: remove session->SetDestination (destination->GetIdentHash ()); // TODO: remove
return session; return session;
} }
else else
{ {
ElGamalAESSessionPtr session; ElGamalAESSessionPtr session;
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto it = m_Sessions.find (destination->GetIdentHash ()); auto it = m_Sessions.find (destination->GetIdentHash ());
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
session = it->second; session = it->second;
} }
if (!session) if (!session)
{ {
session = std::make_shared<ElGamalAESSession> (this, destination, session = std::make_shared<ElGamalAESSession> (this, destination,
attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[destination->GetIdentHash ()] = session; m_Sessions[destination->GetIdentHash ()] = session;
} }
return session; return session;
} }
} }
void GarlicDestination::CleanupExpiredTags () void GarlicDestination::CleanupExpiredTags ()
@ -791,7 +791,7 @@ namespace garlic
if (it->second.tagset->IsExpired (ts) || ts > it->second.creationTime + ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT) if (it->second.tagset->IsExpired (ts) || ts > it->second.creationTime + ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT)
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
else else
++it; ++it;
} }
for (auto it = m_ECIESx25519Sessions.begin (); it != m_ECIESx25519Sessions.end ();) for (auto it = m_ECIESx25519Sessions.begin (); it != m_ECIESx25519Sessions.end ();)
@ -800,7 +800,7 @@ namespace garlic
{ {
it->second->SetOwner (nullptr); it->second->SetOwner (nullptr);
it = m_ECIESx25519Sessions.erase (it); it = m_ECIESx25519Sessions.erase (it);
} }
else else
++it; ++it;
} }
@ -925,28 +925,28 @@ namespace garlic
std::vector<std::string> files; std::vector<std::string> files;
i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files); i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files);
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files) for (auto it: files)
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::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)
{ {
const uint8_t * buf1 = buf; const uint8_t * buf1 = buf;
uint8_t flag = buf[0]; buf++; // flag uint8_t flag = buf[0]; buf++; // flag
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
switch (deliveryType) switch (deliveryType)
{ {
case eGarlicDeliveryTypeDestination: case eGarlicDeliveryTypeDestination:
LogPrint (eLogDebug, "Garlic: type destination"); LogPrint (eLogDebug, "Garlic: type destination");
buf += 32; // TODO: check destination buf += 32; // TODO: check destination
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
#endif #endif
// no break here // no break here
case eGarlicDeliveryTypeLocal: case eGarlicDeliveryTypeLocal:
{ {
LogPrint (eLogDebug, "Garlic: type local"); LogPrint (eLogDebug, "Garlic: type local");
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
buf += (4 + 4); // msgID + expiration buf += (4 + 4); // msgID + expiration
ptrdiff_t offset = buf - buf1; ptrdiff_t offset = buf - buf1;
@ -957,8 +957,8 @@ namespace garlic
break; break;
} }
case eGarlicDeliveryTypeTunnel: case eGarlicDeliveryTypeTunnel:
{ {
LogPrint (eLogDebug, "Garlic: type tunnel"); LogPrint (eLogDebug, "Garlic: type tunnel");
// gwHash and gwTunnel sequence is reverted // gwHash and gwTunnel sequence is reverted
const uint8_t * gwHash = buf; const uint8_t * gwHash = buf;
buf += 32; buf += 32;
@ -968,47 +968,47 @@ namespace garlic
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: message is too short");
break; break;
} }
uint32_t gwTunnel = bufbe32toh (buf); buf += 4; uint32_t gwTunnel = bufbe32toh (buf); buf += 4;
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
buf += (4 + 4); // msgID + expiration buf += (4 + 4); // msgID + expiration
offset += 13; offset += 13;
if (GetTunnelPool ()) if (GetTunnelPool ())
{ {
auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel (); auto tunnel = GetTunnelPool ()->GetNextOutboundTunnel ();
if (tunnel) if (tunnel)
tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset)); tunnel->SendTunnelDataMsg (gwHash, gwTunnel, CreateI2NPMessage (typeID, buf, len - offset));
else else
LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove"); LogPrint (eLogWarning, "Garlic: No outbound tunnels available for garlic clove");
} }
else else
LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel"); LogPrint (eLogError, "Garlic: Tunnel pool is not set for inbound tunnel");
break; break;
} }
default: default:
LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType);
} }
} }
void GarlicDestination::AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset) void GarlicDestination::AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset)
{ {
auto index = tagset->GetNextIndex (); auto index = tagset->GetNextIndex ();
uint64_t tag = tagset->GetNextSessionTag (); uint64_t tag = tagset->GetNextSessionTag ();
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset, i2p::util::GetSecondsSinceEpoch ()}); m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset, i2p::util::GetSecondsSinceEpoch ()});
} }
void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session)
{ {
i2p::data::Tag<32> staticKeyTag (staticKey); i2p::data::Tag<32> staticKeyTag (staticKey);
auto it = m_ECIESx25519Sessions.find (staticKeyTag); auto it = m_ECIESx25519Sessions.find (staticKeyTag);
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ())) if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
m_ECIESx25519Sessions.erase (it); m_ECIESx25519Sessions.erase (it);
else else
{ {
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists"); LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
return; return;
} }
} }
m_ECIESx25519Sessions.emplace (staticKeyTag, session); m_ECIESx25519Sessions.emplace (staticKeyTag, session);
} }
@ -1020,7 +1020,7 @@ namespace garlic
{ {
it->second->SetOwner (nullptr); it->second->SetOwner (nullptr);
m_ECIESx25519Sessions.erase (it); m_ECIESx25519Sessions.erase (it);
} }
} }
} }
} }

@ -87,8 +87,8 @@ namespace garlic
class GarlicDestination; class GarlicDestination;
class GarlicRoutingSession class GarlicRoutingSession
{ {
protected: protected:
enum LeaseSetUpdateStatus enum LeaseSetUpdateStatus
{ {
eLeaseSetUpToDate = 0, eLeaseSetUpToDate = 0,
@ -103,10 +103,10 @@ namespace garlic
GarlicRoutingSession (); GarlicRoutingSession ();
virtual ~GarlicRoutingSession (); virtual ~GarlicRoutingSession ();
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0; virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
virtual bool MessageConfirmed (uint32_t msgID); virtual bool MessageConfirmed (uint32_t msgID);
virtual bool IsRatchets () const { return false; }; virtual bool IsRatchets () const { return false; };
void SetLeaseSetUpdated () void SetLeaseSetUpdated ()
{ {
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
@ -115,23 +115,23 @@ namespace garlic
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; }; bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; } uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
void CleanupUnconfirmedLeaseSet (uint64_t ts); void CleanupUnconfirmedLeaseSet (uint64_t ts);
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath (); std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path); void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
GarlicDestination * GetOwner () const { return m_Owner; } GarlicDestination * GetOwner () const { return m_Owner; }
void SetOwner (GarlicDestination * owner) { m_Owner = owner; } void SetOwner (GarlicDestination * owner) { m_Owner = owner; }
protected: protected:
LeaseSetUpdateStatus GetLeaseSetUpdateStatus () const { return m_LeaseSetUpdateStatus; } LeaseSetUpdateStatus GetLeaseSetUpdateStatus () const { return m_LeaseSetUpdateStatus; }
void SetLeaseSetUpdateStatus (LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; } void SetLeaseSetUpdateStatus (LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; }
uint32_t GetLeaseSetUpdateMsgID () const { return m_LeaseSetUpdateMsgID; } uint32_t GetLeaseSetUpdateMsgID () const { return m_LeaseSetUpdateMsgID; }
void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; } void SetLeaseSetUpdateMsgID (uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; }
void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; } void SetLeaseSetSubmissionTime (uint64_t ts) { m_LeaseSetSubmissionTime = ts; }
std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg (uint32_t msgID); std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg (uint32_t msgID);
private: private:
GarlicDestination * m_Owner; GarlicDestination * m_Owner;
@ -143,38 +143,39 @@ namespace garlic
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath; std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
public: public:
// for HTTP only // for HTTP only
virtual size_t GetNumOutgoingTags () const { return 0; }; virtual size_t GetNumOutgoingTags () const { return 0; };
}; };
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>; //using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8 typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
class ElGamalAESSession: public GarlicRoutingSession, public std::enable_shared_from_this<ElGamalAESSession> class ElGamalAESSession: public GarlicRoutingSession, public std::enable_shared_from_this<ElGamalAESSession>
{ {
struct UnconfirmedTags struct UnconfirmedTags
{ {
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; }; UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
~UnconfirmedTags () { delete[] sessionTags; }; ~UnconfirmedTags () { delete[] sessionTags; };
uint32_t msgID; uint32_t msgID;
int numTags; int numTags;
SessionTag * sessionTags; SessionTag * sessionTags;
uint32_t tagsCreationTime; uint32_t tagsCreationTime;
}; };
public: public:
ElGamalAESSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination, ElGamalAESSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
int numTags, bool attachLeaseSet); int numTags, bool attachLeaseSet);
ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption ElGamalAESSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
~ElGamalAESSession () {}; ~ElGamalAESSession () {};
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
bool MessageConfirmed (uint32_t msgID); bool MessageConfirmed (uint32_t msgID);
bool CleanupExpiredTags (); // returns true if something left bool CleanupExpiredTags (); // returns true if something left
bool CleanupUnconfirmedTags (); // returns true if something has been deleted bool CleanupUnconfirmedTags (); // returns true if something has been deleted
private: private:
size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg); size_t CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg);
size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags); size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags);
@ -183,32 +184,33 @@ namespace garlic
void TagsConfirmed (uint32_t msgID); void TagsConfirmed (uint32_t msgID);
UnconfirmedTags * GenerateSessionTags (); UnconfirmedTags * GenerateSessionTags ();
private:
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
i2p::crypto::AESKey m_SessionKey; private:
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
i2p::crypto::AESKey m_SessionKey;
std::list<SessionTag> m_SessionTags; std::list<SessionTag> m_SessionTags;
int m_NumTags; int m_NumTags;
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
public:
public:
// for HTTP only // for HTTP only
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
}; };
typedef std::shared_ptr<ElGamalAESSession> ElGamalAESSessionPtr; typedef std::shared_ptr<ElGamalAESSession> ElGamalAESSessionPtr;
class ECIESX25519AEADRatchetSession; class ECIESX25519AEADRatchetSession;
typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr; typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr;
class RatchetTagSet; class RatchetTagSet;
typedef std::shared_ptr<RatchetTagSet> RatchetTagSetPtr; typedef std::shared_ptr<RatchetTagSet> RatchetTagSetPtr;
struct ECIESX25519AEADRatchetIndexTagset struct ECIESX25519AEADRatchetIndexTagset
{ {
int index; int index;
RatchetTagSetPtr tagset; RatchetTagSetPtr tagset;
uint64_t creationTime; // seconds since epoch uint64_t creationTime; // seconds since epoch
}; };
@ -226,12 +228,12 @@ namespace garlic
void CleanupExpiredTags (); void CleanupExpiredTags ();
void RemoveDeliveryStatusSession (uint32_t msgID); void RemoveDeliveryStatusSession (uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination, std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false); std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
void AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset); void AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset);
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
void RemoveECIESx25519Session (const uint8_t * staticKey); void RemoveECIESx25519Session (const uint8_t * staticKey);
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
@ -266,10 +268,10 @@ namespace garlic
int m_NumTags; int m_NumTags;
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions; std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
// incoming // incoming
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags; std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
// DeliveryStatus // DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex; std::mutex m_DeliveryStatusSessionsMutex;
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session

@ -13,11 +13,11 @@ namespace crypto
enum GOSTR3410ParamSet enum GOSTR3410ParamSet
{ {
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1 eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
// XchA = A, XchB = C // XchA = A, XchB = C
//eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0 //eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0
//eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1 //eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1
eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1 eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1
eGOSTR3410NumParamSets eGOSTR3410NumParamSets
}; };

@ -40,13 +40,13 @@ namespace data
{ {
LogPrint (eLogError, "Gzip: Incorrect length"); LogPrint (eLogError, "Gzip: Incorrect length");
return 0; return 0;
} }
if (len > outLen) len = outLen; if (len > outLen) len = outLen;
memcpy (out, in + 15, len); memcpy (out, in + 15, len);
return len; return len;
} }
else else
{ {
if (m_IsDirty) inflateReset (&m_Inflator); if (m_IsDirty) inflateReset (&m_Inflator);
m_IsDirty = true; m_IsDirty = true;
m_Inflator.next_in = const_cast<uint8_t *>(in); m_Inflator.next_in = const_cast<uint8_t *>(in);
@ -59,7 +59,7 @@ namespace data
// else // else
LogPrint (eLogError, "Gzip: Inflate error ", err); LogPrint (eLogError, "Gzip: Inflate error ", err);
return 0; return 0;
} }
} }
void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os) void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os)
@ -126,7 +126,7 @@ namespace data
{ {
out[9] = 0xff; // OS is always unknown out[9] = 0xff; // OS is always unknown
return outLen - m_Deflator.avail_out; return outLen - m_Deflator.avail_out;
} }
// else // else
LogPrint (eLogError, "Gzip: Deflate error ", err); LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0; return 0;
@ -147,21 +147,21 @@ namespace data
auto flush = (it == bufs.back ()) ? Z_FINISH : Z_NO_FLUSH; auto flush = (it == bufs.back ()) ? Z_FINISH : Z_NO_FLUSH;
err = deflate (&m_Deflator, flush); err = deflate (&m_Deflator, flush);
if (err) if (err)
{ {
if (flush && err == Z_STREAM_END) if (flush && err == Z_STREAM_END)
{ {
out[9] = 0xff; // OS is always unknown out[9] = 0xff; // OS is always unknown
return outLen - m_Deflator.avail_out; return outLen - m_Deflator.avail_out;
} }
break; break;
} }
offset = outLen - m_Deflator.avail_out; offset = outLen - m_Deflator.avail_out;
} }
// else // else
LogPrint (eLogError, "Gzip: Deflate error ", err); LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0; return 0;
} }
size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen) size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen)
{ {
static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 }; static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 };
@ -176,7 +176,7 @@ namespace data
} }
size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen) size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen)
{ {
static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 }; static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 };
memcpy (out, gzipHeader, 11); memcpy (out, gzipHeader, 11);
uint32_t crc = 0; uint32_t crc = 0;
@ -186,9 +186,9 @@ namespace data
len1 = len; len1 = len;
len += it.second; len += it.second;
if (outLen < len + 23) return 0; if (outLen < len + 23) return 0;
memcpy (out + 15 + len1, it.first, it.second); memcpy (out + 15 + len1, it.first, it.second);
crc = crc32 (crc, it.first, it.second); crc = crc32 (crc, it.first, it.second);
} }
if (len > 0xffff) return 0; if (len > 0xffff) return 0;
htole32buf (out + len + 15, crc); htole32buf (out + len + 15, crc);
htole32buf (out + len + 19, len); htole32buf (out + len + 19, len);
@ -196,6 +196,6 @@ namespace data
htole16buf (out + 13, 0xffff - len); htole16buf (out + 13, 0xffff - len);
return len + 23; return len + 23;
} }
} // data } // data
} // i2p } // i2p

@ -4,9 +4,9 @@
#include <zlib.h> #include <zlib.h>
#include <vector> #include <vector>
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
class GzipInflator class GzipInflator
{ {
@ -45,7 +45,6 @@ namespace data
size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen); // for < 64K size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen); // for < 64K
size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen); // for total size < 64K size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen); // for total size < 64K
} // data } // data
} // i2p } // i2p

@ -180,9 +180,9 @@ namespace i2p
// excluded // excluded
if (cnt > 512) if (cnt > 512)
{ {
LogPrint (eLogWarning, "I2NP: Too many peers to exclude ", cnt, " for DatabaseLookup"); LogPrint (eLogWarning, "I2NP: Too many peers to exclude ", cnt, " for DatabaseLookup");
cnt = 0; cnt = 0;
} }
htobe16buf (buf, cnt); htobe16buf (buf, cnt);
buf += 2; buf += 2;
if (cnt > 0) if (cnt > 0)
@ -205,7 +205,7 @@ namespace i2p
} }
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::vector<i2p::data::IdentHash> routers) std::vector<i2p::data::IdentHash> routers)
{ {
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * buf = m->GetPayload (); uint8_t * buf = m->GetPayload ();
@ -268,7 +268,7 @@ namespace i2p
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, storeHash, 32); memcpy (payload + DATABASE_STORE_KEY_OFFSET, storeHash, 32);
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType (); // 1 for LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
size_t size = DATABASE_STORE_HEADER_SIZE; size_t size = DATABASE_STORE_HEADER_SIZE;
memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ()); memcpy (payload + size, leaseSet->GetBuffer (), leaseSet->GetBufferLen ());
@ -278,7 +278,7 @@ namespace i2p
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{ {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
@ -347,11 +347,11 @@ namespace i2p
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40); clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40);
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0; record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
} }
@ -386,7 +386,7 @@ namespace i2p
return; return;
} }
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
if (tunnel) if (tunnel)
{ {
// endpoint of inbound tunnel // endpoint of inbound tunnel
@ -414,7 +414,7 @@ namespace i2p
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len, eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
@ -440,7 +440,7 @@ namespace i2p
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPTunnelBuildReply, buf, len, eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
@ -592,13 +592,13 @@ namespace i2p
switch (typeID) switch (typeID)
{ {
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
HandleVariableTunnelBuildMsg (msgID, buf, size); HandleVariableTunnelBuildMsg (msgID, buf, size);
break; break;
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
HandleVariableTunnelBuildReplyMsg (msgID, buf, size); HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break; break;
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
HandleTunnelBuildMsg (buf, size); HandleTunnelBuildMsg (buf, size);
break; break;
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
// TODO: // TODO:
@ -667,7 +667,7 @@ namespace i2p
Flush (); Flush ();
} }
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg) void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {

@ -27,7 +27,7 @@ namespace i2p
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4; const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
// I2NP NTCP2 header // I2NP NTCP2 header
const size_t I2NP_NTCP2_HEADER_SIZE = I2NP_HEADER_EXPIRATION_OFFSET + 4; const size_t I2NP_NTCP2_HEADER_SIZE = I2NP_HEADER_EXPIRATION_OFFSET + 4;
// Tunnel Gateway header // Tunnel Gateway header
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0; const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0;
@ -75,7 +75,7 @@ namespace i2p
enum I2NPMessageType enum I2NPMessageType
{ {
eI2NPDummyMsg = 0, eI2NPDummyMsg = 0,
eI2NPDatabaseStore = 1, eI2NPDatabaseStore = 1,
eI2NPDatabaseLookup = 2, eI2NPDatabaseLookup = 2,
eI2NPDatabaseSearchReply = 3, eI2NPDatabaseSearchReply = 3,
@ -209,7 +209,7 @@ namespace tunnel
SetExpiration (bufbe32toh (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET)*1000LL); SetExpiration (bufbe32toh (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET)*1000LL);
SetSize (len - offset - I2NP_HEADER_SIZE); SetSize (len - offset - I2NP_HEADER_SIZE);
SetChks (0); SetChks (0);
} }
void ToNTCP2 () void ToNTCP2 ()
{ {

@ -356,7 +356,7 @@ namespace data
} }
return nullptr; return nullptr;
} }
void IdentityEx::CreateVerifier () const void IdentityEx::CreateVerifier () const
{ {
if (m_Verifier) return; // don't create again if (m_Verifier) return; // don't create again
@ -369,15 +369,15 @@ namespace data
else else
{ {
// for P521 // for P521
uint8_t * signingKey = new uint8_t[keyLen]; uint8_t * signingKey = new uint8_t[keyLen];
memcpy (signingKey, m_StandardIdentity.signingKey, 128); memcpy (signingKey, m_StandardIdentity.signingKey, 128);
size_t excessLen = keyLen - 128; size_t excessLen = keyLen - 128;
memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types
verifier->SetPublicKey (signingKey); verifier->SetPublicKey (signingKey);
delete[] signingKey; delete[] signingKey;
} }
} }
UpdateVerifier (verifier); UpdateVerifier (verifier);
} }
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
@ -390,7 +390,7 @@ namespace data
else else
del = true; del = true;
} }
if (del) if (del)
delete verifier; delete verifier;
} }
@ -426,7 +426,7 @@ namespace data
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)keyType); LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)keyType);
}; };
return nullptr; return nullptr;
} }
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (const uint8_t * key) const std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (const uint8_t * key) const
{ {
@ -460,9 +460,9 @@ namespace data
return *this; return *this;
} }
size_t PrivateKeys::GetFullLen () const size_t PrivateKeys::GetFullLen () const
{ {
size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen ();
if (IsOfflineSignature ()) if (IsOfflineSignature ())
ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen; ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen;
return ret; return ret;
@ -483,7 +483,7 @@ namespace data
// check if signing private key is all zeros // check if signing private key is all zeros
bool allzeros = true; bool allzeros = true;
for (size_t i = 0; i < signingPrivateKeySize; i++) for (size_t i = 0; i < signingPrivateKeySize; i++)
if (m_SigningPrivateKey[i]) if (m_SigningPrivateKey[i])
{ {
allzeros = false; allzeros = false;
break; break;
@ -500,7 +500,7 @@ namespace data
if (keyLen + ret > len) return 0; if (keyLen + ret > len) return 0;
transientVerifier->SetPublicKey (buf + ret); ret += keyLen; transientVerifier->SetPublicKey (buf + ret); ret += keyLen;
if (m_Public->GetSignatureLen () + ret > len) return 0; if (m_Public->GetSignatureLen () + ret > len) return 0;
if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret)) if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret))
{ {
LogPrint (eLogError, "Identity: offline signature verification failed"); LogPrint (eLogError, "Identity: offline signature verification failed");
return 0; return 0;
@ -511,7 +511,7 @@ namespace data
size_t offlineInfoLen = buf + ret - offlineInfo; size_t offlineInfoLen = buf + ret - offlineInfo;
m_OfflineSignature.resize (offlineInfoLen); m_OfflineSignature.resize (offlineInfoLen);
memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen); memcpy (m_OfflineSignature.data (), offlineInfo, offlineInfoLen);
// override signing private key // override signing private key
m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen (); m_TransientSigningPrivateKeyLen = transientVerifier->GetPrivateKeyLen ();
if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0; if (m_TransientSigningPrivateKeyLen + ret > len || m_TransientSigningPrivateKeyLen > 128) return 0;
memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen); memcpy (m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen);
@ -586,10 +586,10 @@ namespace data
else else
CreateSigner (m_Public->GetSigningKeyType ()); CreateSigner (m_Public->GetSigningKeyType ());
} }
void PrivateKeys::CreateSigner (SigningKeyType keyType) const void PrivateKeys::CreateSigner (SigningKeyType keyType) const
{ {
if (m_Signer) return; if (m_Signer) return;
if (keyType == SIGNING_KEY_TYPE_DSA_SHA1) if (keyType == SIGNING_KEY_TYPE_DSA_SHA1)
m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey)); m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey, m_Public->GetStandardIdentity ().signingKey));
else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ()) else if (keyType == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 && !IsOfflineSignature ())
@ -599,7 +599,7 @@ namespace data
// public key is not required // public key is not required
auto signer = CreateSigner (keyType, m_SigningPrivateKey); auto signer = CreateSigner (keyType, m_SigningPrivateKey);
if (signer) m_Signer.reset (signer); if (signer) m_Signer.reset (signer);
} }
} }
i2p::crypto::Signer * PrivateKeys::CreateSigner (SigningKeyType keyType, const uint8_t * priv) i2p::crypto::Signer * PrivateKeys::CreateSigner (SigningKeyType keyType, const uint8_t * priv)
@ -630,8 +630,8 @@ namespace data
return new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, priv); return new i2p::crypto::GOSTR3410_512_Signer (i2p::crypto::eGOSTR3410TC26A512, priv);
break; break;
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
return new i2p::crypto::RedDSA25519Signer (priv); return new i2p::crypto::RedDSA25519Signer (priv);
break; break;
default: default:
LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported"); LogPrint (eLogError, "Identity: Signing key type ", (int)keyType, " is not supported");
} }
@ -719,8 +719,8 @@ namespace data
case SIGNING_KEY_TYPE_RSA_SHA512_4096: case SIGNING_KEY_TYPE_RSA_SHA512_4096:
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA"); LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Creating EdDSA");
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
#endif #endif
// no break here // no break here
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub); i2p::crypto::CreateEDDSA25519RandomKeys (priv, pub);
@ -733,7 +733,7 @@ namespace data
break; break;
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
i2p::crypto::CreateRedDSA25519RandomKeys (priv, pub); i2p::crypto::CreateRedDSA25519RandomKeys (priv, pub);
break; break;
default: default:
LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); LogPrint (eLogWarning, "Identity: Signing key type ", (int)type, " is not supported. Create DSA-SHA1");
i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1 i2p::crypto::CreateDSARandomKeys (priv, pub); // DSA-SHA1
@ -765,7 +765,7 @@ namespace data
PrivateKeys PrivateKeys::CreateOfflineKeys (SigningKeyType type, uint32_t expires) const PrivateKeys PrivateKeys::CreateOfflineKeys (SigningKeyType type, uint32_t expires) const
{ {
PrivateKeys keys (*this); PrivateKeys keys (*this);
std::unique_ptr<i2p::crypto::Verifier> verifier (IdentityEx::CreateVerifier (type)); std::unique_ptr<i2p::crypto::Verifier> verifier (IdentityEx::CreateVerifier (type));
if (verifier) if (verifier)
{ {
size_t pubKeyLen = verifier->GetPublicKeyLen (); size_t pubKeyLen = verifier->GetPublicKeyLen ();
@ -775,7 +775,7 @@ namespace data
htobe32buf (keys.m_OfflineSignature.data (), expires); // expires htobe32buf (keys.m_OfflineSignature.data (), expires); // expires
htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
// recreate signer // recreate signer
keys.m_Signer = nullptr; keys.m_Signer = nullptr;
keys.CreateSigner (type); keys.CreateSigner (type);

@ -56,7 +56,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_RATCHET = 4; const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET = 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
@ -115,7 +115,7 @@ namespace data
void RecalculateIdentHash(uint8_t * buff=nullptr); void RecalculateIdentHash(uint8_t * buff=nullptr);
static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType); static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType);
static std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (CryptoKeyType keyType, const uint8_t * key); static std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (CryptoKeyType keyType, const uint8_t * key);
private: private:
@ -148,7 +148,7 @@ namespace data
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
size_t GetSignatureLen () const; // might not match identity size_t GetSignatureLen () const; // might not match identity
bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; }; bool IsOfflineSignature () const { return m_TransientSignatureLen > 0; };
uint8_t * GetPadding(); 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; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
@ -163,12 +163,12 @@ namespace data
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key); static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key);
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub); static void GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub);
static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long static void GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub); // priv and pub are 256 bytes long
static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv); static i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
// offline keys // offline keys
PrivateKeys CreateOfflineKeys (SigningKeyType type, uint32_t expires) const; PrivateKeys CreateOfflineKeys (SigningKeyType type, uint32_t expires) const;
const std::vector<uint8_t>& GetOfflineSignature () const { return m_OfflineSignature; }; const std::vector<uint8_t>& GetOfflineSignature () const { return m_OfflineSignature; };
private: private:
@ -204,7 +204,7 @@ namespace data
IdentHash CreateRoutingKey (const IdentHash& ident); IdentHash CreateRoutingKey (const IdentHash& ident);
XORMetric operator^(const IdentHash& key1, const IdentHash& key2); XORMetric operator^(const IdentHash& key1, const IdentHash& key2);
// destination for delivery instuctions // destination for delivery instructions
class RoutingDestination class RoutingDestination
{ {
public: public:
@ -235,5 +235,4 @@ namespace data
} }
} }
#endif #endif

@ -12,9 +12,8 @@ namespace i2p
{ {
namespace data namespace data
{ {
LeaseSet::LeaseSet (bool storeLeases): LeaseSet::LeaseSet (bool storeLeases):
m_IsValid (false), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr), m_IsValid (false), m_StoreLeases (storeLeases), m_ExpirationTime (0), m_EncryptionKey (nullptr),
m_Buffer (nullptr), m_BufferLen (0) m_Buffer (nullptr), m_BufferLen (0)
{ {
} }
@ -62,7 +61,7 @@ namespace data
{ {
if (!m_EncryptionKey) m_EncryptionKey = new uint8_t[256]; if (!m_EncryptionKey) m_EncryptionKey = new uint8_t[256];
memcpy (m_EncryptionKey, m_Buffer + size, 256); memcpy (m_EncryptionKey, m_Buffer + size, 256);
} }
size += 256; // encryption key size += 256; // encryption key
size += m_Identity->GetSigningPublicKeyLen (); // unused signing key size += m_Identity->GetSigningPublicKeyLen (); // unused signing key
uint8_t num = m_Buffer[size]; uint8_t num = m_Buffer[size];
@ -191,10 +190,10 @@ namespace data
return m_ExpirationTime - now <= dlt; return m_ExpirationTime - now <= dlt;
} }
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeases (bool withThreshold) const
{ {
return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold); return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold);
} }
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const
{ {
@ -249,19 +248,19 @@ namespace data
if (len <= m_BufferLen) m_BufferLen = len; if (len <= m_BufferLen) m_BufferLen = len;
else else
LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
} }
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto) LeaseSet (storeLeases), m_StoreType (storeType), m_EncryptionType (preferredCrypto)
{ {
SetBuffer (buf, len); SetBuffer (buf, len);
if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (storeType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
ReadFromBufferEncrypted (buf, len, nullptr, nullptr); ReadFromBufferEncrypted (buf, len, nullptr, nullptr);
else else
ReadFromBuffer (buf, len); ReadFromBuffer (buf, len);
} }
LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, LeaseSet2::LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
const uint8_t * secret, CryptoKeyType preferredCrypto): const uint8_t * secret, CryptoKeyType preferredCrypto):
LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto) LeaseSet (true), m_StoreType (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2), m_EncryptionType (preferredCrypto)
{ {
@ -269,10 +268,10 @@ namespace data
} }
void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature) void LeaseSet2::Update (const uint8_t * buf, size_t len, bool verifySignature)
{ {
SetBuffer (buf, len); SetBuffer (buf, len);
if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (GetStoreType () != NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
ReadFromBuffer (buf, len, false, verifySignature); ReadFromBuffer (buf, len, false, verifySignature);
// TODO: implement encrypted // TODO: implement encrypted
} }
@ -281,13 +280,13 @@ namespace data
uint64_t expiration; uint64_t expiration;
return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp; return ExtractPublishedTimestamp (buf, len, expiration) > m_PublishedTimestamp;
} }
void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature) void LeaseSet2::ReadFromBuffer (const uint8_t * buf, size_t len, bool readIdentity, bool verifySignature)
{ {
// standard LS2 header // standard LS2 header
std::shared_ptr<const IdentityEx> identity; std::shared_ptr<const IdentityEx> identity;
if (readIdentity) if (readIdentity)
{ {
identity = std::make_shared<IdentityEx>(buf, len); identity = std::make_shared<IdentityEx>(buf, len);
SetIdentity (identity); SetIdentity (identity);
} }
@ -304,7 +303,7 @@ namespace data
// transient key // transient key
m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset); m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
if (!m_TransientVerifier) if (!m_TransientVerifier)
{ {
LogPrint (eLogError, "LeaseSet2: offline signature failed"); LogPrint (eLogError, "LeaseSet2: offline signature failed");
return; return;
} }
@ -314,7 +313,7 @@ namespace data
{ {
m_IsPublishedEncrypted = true; m_IsPublishedEncrypted = true;
m_IsPublic = true; m_IsPublic = true;
} }
// type specific part // type specific part
size_t s = 0; size_t s = 0;
switch (m_StoreType) switch (m_StoreType)
@ -331,11 +330,11 @@ namespace data
if (!s) return; if (!s) return;
offset += s; offset += s;
if (verifySignature || m_TransientVerifier) if (verifySignature || m_TransientVerifier)
{ {
// verify signature // verify signature
bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) : bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
VerifySignature (identity, buf, len, offset); VerifySignature (identity, buf, len, offset);
SetIsValid (verified); SetIsValid (verified);
} }
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen (); offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : identity->GetSignatureLen ();
SetBufferLen (offset); SetBufferLen (offset);
@ -346,10 +345,10 @@ namespace data
{ {
if (signatureOffset + verifier->GetSignatureLen () > len) return false; if (signatureOffset + verifier->GetSignatureLen () > len) return false;
// we assume buf inside DatabaseStore message, so buf[-1] is valid memory // we assume buf inside DatabaseStore message, so buf[-1] is valid memory
// change it for signature verification, and restore back // change it for signature verification, and restore back
uint8_t c = buf[-1]; uint8_t c = buf[-1];
const_cast<uint8_t *>(buf)[-1] = m_StoreType; const_cast<uint8_t *>(buf)[-1] = m_StoreType;
bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset); bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset);
const_cast<uint8_t *>(buf)[-1] = c; const_cast<uint8_t *>(buf)[-1] = c;
if (!verified) if (!verified)
LogPrint (eLogWarning, "LeaseSet2: verification failed"); LogPrint (eLogWarning, "LeaseSet2: verification failed");
@ -360,7 +359,7 @@ namespace data
{ {
size_t offset = 0; size_t offset = 0;
// properties // properties
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
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
@ -371,7 +370,7 @@ namespace data
{ {
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption key type
if (offset + 2 >= len) return 0; if (offset + 2 >= len) return 0;
uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2; uint16_t encryptionKeyLen = bufbe16toh (buf + offset); offset += 2;
if (offset + encryptionKeyLen >= len) return 0; if (offset + encryptionKeyLen >= len) return 0;
if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only if (IsStoreLeases () && !preferredKeyFound) // create encryptor with leases only
{ {
@ -384,10 +383,10 @@ namespace data
if (keyType == preferredKeyType) preferredKeyFound = true; if (keyType == preferredKeyType) preferredKeyFound = true;
} }
} }
offset += encryptionKeyLen; offset += encryptionKeyLen;
} }
// leases // leases
if (offset + 1 >= len) return 0; if (offset + 1 >= len) return 0;
int numLeases = buf[offset]; offset++; int numLeases = buf[offset]; offset++;
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (IsStoreLeases ()) if (IsStoreLeases ())
@ -413,9 +412,9 @@ namespace data
{ {
size_t offset = 0; size_t offset = 0;
// properties // properties
uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2; uint16_t propertiesLen = bufbe16toh (buf + offset); offset += 2;
offset += propertiesLen; // skip for now. TODO: implement properties offset += propertiesLen; // skip for now. TODO: implement properties
// entries // entries
if (offset + 1 >= len) return 0; if (offset + 1 >= len) return 0;
int numEntries = buf[offset]; offset++; int numEntries = buf[offset]; offset++;
for (int i = 0; i < numEntries; i++) for (int i = 0; i < numEntries; i++)
@ -423,12 +422,12 @@ namespace data
if (offset + 40 >= len) return 0; if (offset + 40 >= len) return 0;
offset += 32; // hash offset += 32; // hash
offset += 3; // flags offset += 3; // flags
offset += 1; // cost offset += 1; // cost
offset += 4; // expires offset += 4; // expires
} }
// revocations // revocations
if (offset + 1 >= len) return 0; if (offset + 1 >= len) return 0;
int numRevocations = buf[offset]; offset++; int numRevocations = buf[offset]; offset++;
for (int i = 0; i < numRevocations; i++) for (int i = 0; i < numRevocations; i++)
{ {
if (offset + 32 > len) return 0; if (offset + 32 > len) return 0;
@ -446,7 +445,7 @@ namespace data
uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2; uint16_t blindedKeyType = bufbe16toh (stA1); offset += 2;
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType)); std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
if (!blindedVerifier) return; if (!blindedVerifier) return;
auto blindedKeyLen = blindedVerifier->GetPublicKeyLen (); auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
if (offset + blindedKeyLen >= len) return; if (offset + blindedKeyLen >= len) return;
const uint8_t * blindedPublicKey = buf + offset; const uint8_t * blindedPublicKey = buf + offset;
blindedVerifier->SetPublicKey (blindedPublicKey); offset += blindedKeyLen; blindedVerifier->SetPublicKey (blindedPublicKey); offset += blindedKeyLen;
@ -461,7 +460,7 @@ namespace data
{ {
// transient key // transient key
m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset); m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
if (!m_TransientVerifier) if (!m_TransientVerifier)
{ {
LogPrint (eLogError, "LeaseSet2: offline signature failed"); LogPrint (eLogError, "LeaseSet2: offline signature failed");
return; return;
@ -470,16 +469,16 @@ namespace data
// outer ciphertext // outer ciphertext
if (offset + 2 > len) return; if (offset + 2 > len) return;
uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2; uint16_t lenOuterCiphertext = bufbe16toh (buf + offset); offset += 2;
const uint8_t * outerCiphertext = buf + offset; const uint8_t * outerCiphertext = buf + offset;
offset += lenOuterCiphertext; offset += lenOuterCiphertext;
// verify signature // verify signature
bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) : bool verified = m_TransientVerifier ? VerifySignature (m_TransientVerifier, buf, len, offset) :
VerifySignature (blindedVerifier, buf, len, offset); VerifySignature (blindedVerifier, buf, len, offset);
SetIsValid (verified); SetIsValid (verified);
// handle ciphertext // handle ciphertext
if (verified && key && lenOuterCiphertext >= 32) if (verified && key && lenOuterCiphertext >= 32)
{ {
SetIsValid (false); // we must verify it again in Layer 2 SetIsValid (false); // we must verify it again in Layer 2
if (blindedKeyType == key->GetBlindedSigType ()) if (blindedKeyType == key->GetBlindedSigType ())
{ {
// verify blinding // verify blinding
@ -491,13 +490,13 @@ namespace data
{ {
LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match"); LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match");
return; return;
} }
} }
else else
{ {
LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ()); LogPrint (eLogError, "LeaseSet2: Unexpected blinded key type ", blindedKeyType, " instead ", key->GetBlindedSigType ());
return; return;
} }
// outer key // outer key
// outerInput = subcredential || publishedTimestamp // outerInput = subcredential || publishedTimestamp
uint8_t subcredential[36]; uint8_t subcredential[36];
@ -518,10 +517,10 @@ namespace data
// innerSalt = innerCiphertext[0:32] // innerSalt = innerCiphertext[0:32]
// keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44) // keys = HKDF(innerSalt, innerInput, "ELS2_L2K", 44)
uint8_t innerInput[68]; uint8_t innerInput[68];
size_t authDataLen = ExtractClientAuthData (outerPlainText.data (), lenOuterPlaintext, secret, subcredential, innerInput); size_t authDataLen = ExtractClientAuthData (outerPlainText.data (), lenOuterPlaintext, secret, subcredential, innerInput);
if (authDataLen > 0) if (authDataLen > 0)
{ {
memcpy (innerInput + 32, subcredential, 36); memcpy (innerInput + 32, subcredential, 36);
i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys); i2p::crypto::HKDF (outerPlainText.data () + 1 + authDataLen, innerInput, 68, "ELS2_L2K", keys);
} }
else else
@ -537,20 +536,20 @@ namespace data
if (innerPlainText[0] == NETDB_STORE_TYPE_STANDARD_LEASESET2 || innerPlainText[0] == NETDB_STORE_TYPE_META_LEASESET2) if (innerPlainText[0] == NETDB_STORE_TYPE_STANDARD_LEASESET2 || innerPlainText[0] == NETDB_STORE_TYPE_META_LEASESET2)
{ {
// override store type and buffer // override store type and buffer
m_StoreType = innerPlainText[0]; m_StoreType = innerPlainText[0];
SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); SetBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
// parse and verify Layer 2 // parse and verify Layer 2
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
} }
else else
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
} }
else else
{ {
// we set actual length of encrypted buffer // we set actual length of encrypted buffer
offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : blindedVerifier->GetSignatureLen (); offset += m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : blindedVerifier->GetSignatureLen ();
SetBufferLen (offset); SetBufferLen (offset);
} }
} }
// helper for ExtractClientAuthData // helper for ExtractClientAuthData
@ -563,12 +562,12 @@ namespace data
{ {
// clientKey_i = okm[0:31] // clientKey_i = okm[0:31]
// clientIV_i = okm[32:43] // clientIV_i = okm[32:43]
i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i i2p::crypto::ChaCha20 (authClients + i*40 + 8, 32, okm, okm + 32, authCookie); // clientCookie_i
return true; return true;
} }
} }
return false; return false;
} }
size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const size_t LeaseSet2::ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const
{ {
@ -581,7 +580,7 @@ namespace data
const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len) if (offset > len)
{ {
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data"); LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
return 0; return 0;
@ -595,19 +594,19 @@ namespace data
memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i memcpy (authInput + 32, ck.GetPublicKey (), 32); // cpk_i
memcpy (authInput + 64, subcredential, 36); memcpy (authInput + 64, subcredential, 36);
uint8_t okm[64]; // 52 actual data uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm); i2p::crypto::HKDF (ephemeralPublicKey, authInput, 100, "ELS2_XCA", okm);
if (!GetAuthCookie (authClients, numClients, okm, authCookie)) if (!GetAuthCookie (authClients, numClients, okm, authCookie))
LogPrint (eLogError, "LeaseSet2: Client cookie DH not found"); LogPrint (eLogError, "LeaseSet2: Client cookie DH not found");
} }
else else
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided"); LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: csk_i is not provided");
} }
else if (flag & 0x02) // PSK, bit 1 is set to 1 else if (flag & 0x02) // PSK, bit 1 is set to 1
{ {
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len) if (offset > len)
{ {
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data"); LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
return 0; return 0;
@ -619,7 +618,7 @@ namespace data
memcpy (authInput, secret, 32); memcpy (authInput, secret, 32);
memcpy (authInput + 32, subcredential, 36); memcpy (authInput + 32, subcredential, 36);
uint8_t okm[64]; // 52 actual data uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
if (!GetAuthCookie (authClients, numClients, okm, authCookie)) if (!GetAuthCookie (authClients, numClients, okm, authCookie))
LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found"); LogPrint (eLogError, "LeaseSet2: Client cookie PSK not found");
} }
@ -627,7 +626,7 @@ namespace data
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided"); LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
} }
else else
LogPrint (eLogError, "LeaseSet2: unknown client auth type ", (int)flag); LogPrint (eLogError, "LeaseSet2: unknown client auth type ", (int)flag);
} }
return offset - 1; return offset - 1;
} }
@ -636,7 +635,7 @@ namespace data
{ {
auto encryptor = m_Encryptor; // TODO: atomic auto encryptor = m_Encryptor; // TODO: atomic
if (encryptor) if (encryptor)
encryptor->Encrypt (data, encrypted, ctx, true); encryptor->Encrypt (data, encrypted, ctx, true);
} }
uint64_t LeaseSet2::ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const uint64_t LeaseSet2::ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const
@ -648,7 +647,7 @@ namespace data
uint64_t LeaseSet2::ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const uint64_t LeaseSet2::ExtractPublishedTimestamp (const uint8_t * buf, size_t len, uint64_t& expiration) const
{ {
if (len < 8) return 0; if (len < 8) return 0;
if (m_StoreType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (m_StoreType == NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{ {
// encrypted LS2 // encrypted LS2
@ -656,11 +655,11 @@ namespace data
uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2; uint16_t blindedKeyType = bufbe16toh (buf + offset); offset += 2;
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType)); std::unique_ptr<i2p::crypto::Verifier> blindedVerifier (i2p::data::IdentityEx::CreateVerifier (blindedKeyType));
if (!blindedVerifier) return 0 ; if (!blindedVerifier) return 0 ;
auto blindedKeyLen = blindedVerifier->GetPublicKeyLen (); auto blindedKeyLen = blindedVerifier->GetPublicKeyLen ();
if (offset + blindedKeyLen + 6 >= len) return 0; if (offset + blindedKeyLen + 6 >= len) return 0;
offset += blindedKeyLen; offset += blindedKeyLen;
uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; uint32_t timestamp = bufbe32toh (buf + offset); offset += 4;
uint16_t expires = bufbe16toh (buf + offset); offset += 2; uint16_t expires = bufbe16toh (buf + offset); offset += 2;
expiration = (timestamp + expires)* 1000LL; expiration = (timestamp + expires)* 1000LL;
return timestamp; return timestamp;
} }
@ -670,13 +669,13 @@ namespace data
if (!identity) return 0; if (!identity) return 0;
size_t offset = identity->GetFullLen (); size_t offset = identity->GetFullLen ();
if (offset + 6 >= len) return 0; if (offset + 6 >= len) return 0;
uint32_t timestamp = bufbe32toh (buf + offset); offset += 4; uint32_t timestamp = bufbe32toh (buf + offset); offset += 4;
uint16_t expires = bufbe16toh (buf + offset); offset += 2; uint16_t expires = bufbe16toh (buf + offset); offset += 2;
expiration = (timestamp + expires)* 1000LL; expiration = (timestamp + expires)* 1000LL;
return timestamp; return timestamp;
} }
} }
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels): LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels):
m_ExpirationTime (0), m_Identity (identity) m_ExpirationTime (0), m_Identity (identity)
{ {
@ -770,36 +769,35 @@ namespace data
return ident.Verify(ptr, leases - ptr, leases); return ident.Verify(ptr, leases - ptr, leases);
} }
LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, LocalLeaseSet2::LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
const KeySections& encryptionKeys, const KeySections& encryptionKeys, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
bool isPublic, bool isPublishedEncrypted): bool isPublic, bool isPublishedEncrypted):
LocalLeaseSet (keys.GetPublic (), nullptr, 0) LocalLeaseSet (keys.GetPublic (), nullptr, 0)
{ {
auto identity = keys.GetPublic (); auto identity = keys.GetPublic ();
// assume standard LS2 // assume standard LS2
int num = tunnels.size (); int num = tunnels.size ();
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
size_t keySectionsLen = 0; size_t keySectionsLen = 0;
for (const auto& it: encryptionKeys) for (const auto& it: encryptionKeys)
keySectionsLen += 2/*key type*/ + 2/*key len*/ + it.keyLen/*key*/; keySectionsLen += 2/*key type*/ + 2/*key len*/ + it.keyLen/*key*/;
m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ + m_BufferLen = identity->GetFullLen () + 4/*published*/ + 2/*expires*/ + 2/*flag*/ + 2/*properties len*/ +
1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen (); 1/*num keys*/ + keySectionsLen + 1/*num leases*/ + num*LEASE2_SIZE + keys.GetSignatureLen ();
uint16_t flags = 0; uint16_t flags = 0;
if (keys.IsOfflineSignature ()) if (keys.IsOfflineSignature ())
{ {
flags |= LEASESET2_FLAG_OFFLINE_KEYS; flags |= LEASESET2_FLAG_OFFLINE_KEYS;
m_BufferLen += keys.GetOfflineSignature ().size (); m_BufferLen += keys.GetOfflineSignature ().size ();
} }
if (isPublishedEncrypted) if (isPublishedEncrypted)
{ {
flags |= LEASESET2_FLAG_PUBLISHED_ENCRYPTED; flags |= LEASESET2_FLAG_PUBLISHED_ENCRYPTED;
isPublic = true; isPublic = true;
} }
if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET; if (!isPublic) flags |= LEASESET2_FLAG_UNPUBLISHED_LEASESET;
m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer = new uint8_t[m_BufferLen + 1];
m_Buffer[0] = storeType; m_Buffer[0] = storeType;
// LS2 header // LS2 header
auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1; auto offset = identity->ToBuffer (m_Buffer + 1, m_BufferLen) + 1;
auto timestamp = i2p::util::GetSecondsSinceEpoch (); auto timestamp = i2p::util::GetSecondsSinceEpoch ();
@ -814,14 +812,14 @@ namespace data
offset += offlineSignature.size (); offset += offlineSignature.size ();
} }
htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len htobe16buf (m_Buffer + offset, 0); offset += 2; // properties len
// keys // keys
m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key m_Buffer[offset] = encryptionKeys.size (); offset++; // 1 key
for (const auto& it: encryptionKeys) for (const auto& it: encryptionKeys)
{ {
htobe16buf (m_Buffer + offset, it.keyType); offset += 2; // key type htobe16buf (m_Buffer + offset, it.keyType); offset += 2; // key type
htobe16buf (m_Buffer + offset, it.keyLen); offset += 2; // key len htobe16buf (m_Buffer + offset, it.keyLen); offset += 2; // key len
memcpy (m_Buffer + offset, it.encryptionPublicKey, it.keyLen); offset += it.keyLen; // key memcpy (m_Buffer + offset, it.encryptionPublicKey, it.keyLen); offset += it.keyLen; // key
} }
// leases // leases
uint32_t expirationTime = 0; // in seconds uint32_t expirationTime = 0; // in seconds
m_Buffer[offset] = num; offset++; // num leases m_Buffer[offset] = num; offset++; // num leases
@ -835,11 +833,11 @@ namespace data
if (ts > expirationTime) expirationTime = ts; if (ts > expirationTime) expirationTime = ts;
htobe32buf (m_Buffer + offset, ts); htobe32buf (m_Buffer + offset, ts);
offset += 4; // end date offset += 4; // end date
} }
// update expiration // update expiration
SetExpirationTime (expirationTime*1000LL); SetExpirationTime (expirationTime*1000LL);
auto expires = expirationTime - timestamp; auto expires = expirationTime - timestamp;
htobe16buf (expiresBuf, expires > 0 ? expires : 0); htobe16buf (expiresBuf, expires > 0 ? expires : 0);
// sign // sign
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
} }
@ -853,7 +851,7 @@ namespace data
m_Buffer[0] = storeType; m_Buffer[0] = storeType;
} }
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys,
int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys): int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys):
LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls) LocalLeaseSet2 (ls->GetIdentity ()), m_InnerLeaseSet (ls)
{ {
@ -863,16 +861,16 @@ namespace data
{ {
if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1 if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) layer1Flags |= 0x01; // DH, authentication scheme 0, auth bit 1
else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1 else if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_PSK) layer1Flags |= 0x03; // PSK, authentication scheme 1, auth bit 1
if (layer1Flags) if (layer1Flags)
lenOuterPlaintext += 32 + 2 + authKeys->size ()*40; // auth data len lenOuterPlaintext += 32 + 2 + authKeys->size ()*40; // auth data len
} }
size_t lenOuterCiphertext = lenOuterPlaintext + 32; size_t lenOuterCiphertext = lenOuterPlaintext + 32;
m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/; m_BufferLen = 2/*blinded sig type*/ + 32/*blinded pub key*/ + 4/*published*/ + 2/*expires*/ + 2/*flags*/ + 2/*lenOuterCiphertext*/ + lenOuterCiphertext + 64/*signature*/;
m_Buffer = new uint8_t[m_BufferLen + 1]; m_Buffer = new uint8_t[m_BufferLen + 1];
m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; m_Buffer[0] = NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
BlindedPublicKey blindedKey (ls->GetIdentity ()); BlindedPublicKey blindedKey (ls->GetIdentity ());
auto timestamp = i2p::util::GetSecondsSinceEpoch (); auto timestamp = i2p::util::GetSecondsSinceEpoch ();
char date[9]; char date[9];
i2p::util::GetDateString (timestamp, date); i2p::util::GetDateString (timestamp, date);
uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max uint8_t blindedPriv[64], blindedPub[128]; // 64 and 128 max
@ -883,25 +881,25 @@ namespace data
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds) htobe32buf (m_Buffer + offset, timestamp); offset += 4; // published timestamp (seconds)
auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds auto nextMidnight = (timestamp/86400LL + 1)*86400LL; // 86400 = 24*3600 seconds
auto expirationTime = ls->GetExpirationTime ()/1000LL; auto expirationTime = ls->GetExpirationTime ()/1000LL;
if (expirationTime > nextMidnight) expirationTime = nextMidnight; if (expirationTime > nextMidnight) expirationTime = nextMidnight;
SetExpirationTime (expirationTime*1000LL); SetExpirationTime (expirationTime*1000LL);
htobe16buf (m_Buffer + offset, expirationTime > timestamp ? expirationTime - timestamp : 0); offset += 2; // expires htobe16buf (m_Buffer + offset, expirationTime > timestamp ? expirationTime - timestamp : 0); offset += 2; // expires
uint16_t flags = 0; uint16_t flags = 0;
htobe16buf (m_Buffer + offset, flags); offset += 2; // flags htobe16buf (m_Buffer + offset, flags); offset += 2; // flags
htobe16buf (m_Buffer + offset, lenOuterCiphertext); offset += 2; // lenOuterCiphertext htobe16buf (m_Buffer + offset, lenOuterCiphertext); offset += 2; // lenOuterCiphertext
// outerChipherText // outerChipherText
// Layer 1 // Layer 1
uint8_t subcredential[36]; uint8_t subcredential[36];
blindedKey.GetSubcredential (blindedPub, 32, subcredential); blindedKey.GetSubcredential (blindedPub, 32, subcredential);
htobe32buf (subcredential + 32, timestamp); // outerInput = subcredential || publishedTimestamp htobe32buf (subcredential + 32, timestamp); // outerInput = subcredential || publishedTimestamp
// keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44) // keys = HKDF(outerSalt, outerInput, "ELS2_L1K", 44)
uint8_t keys1[64]; // 44 bytes actual data uint8_t keys1[64]; // 44 bytes actual data
RAND_bytes (m_Buffer + offset, 32); // outerSalt = CSRNG(32) RAND_bytes (m_Buffer + offset, 32); // outerSalt = CSRNG(32)
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1); i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L1K", keys1);
offset += 32; // outerSalt offset += 32; // outerSalt
uint8_t * outerPlainText = m_Buffer + offset; uint8_t * outerPlainText = m_Buffer + offset;
m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags m_Buffer[offset] = layer1Flags; offset++; // layer 1 flags
// auth data // auth data
uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp uint8_t innerInput[68]; // authCookie || subcredential || publishedTimestamp
if (layer1Flags) if (layer1Flags)
@ -909,20 +907,20 @@ namespace data
RAND_bytes (innerInput, 32); // authCookie RAND_bytes (innerInput, 32); // authCookie
CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset); CreateClientAuthData (subcredential, authType, authKeys, innerInput, m_Buffer + offset);
offset += 32 + 2 + authKeys->size ()*40; // auth clients offset += 32 + 2 + authKeys->size ()*40; // auth clients
} }
// Layer 2 // Layer 2
// keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44) // keys = HKDF(outerSalt, outerInput, "ELS2_L2K", 44)
uint8_t keys2[64]; // 44 bytes actual data uint8_t keys2[64]; // 44 bytes actual data
RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32) RAND_bytes (m_Buffer + offset, 32); // innerSalt = CSRNG(32)
if (layer1Flags) if (layer1Flags)
{ {
memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp memcpy (innerInput + 32, subcredential, 36); // + subcredential || publishedTimestamp
i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2); i2p::crypto::HKDF (m_Buffer + offset, innerInput, 68, "ELS2_L2K", keys2);
} }
else else
i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie i2p::crypto::HKDF (m_Buffer + offset, subcredential, 36, "ELS2_L2K", keys2); // no authCookie
offset += 32; // innerSalt offset += 32; // innerSalt
m_Buffer[offset] = ls->GetStoreType (); m_Buffer[offset] = ls->GetStoreType ();
memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ()); memcpy (m_Buffer + offset + 1, ls->GetBuffer (), ls->GetBufferLen ());
i2p::crypto::ChaCha20 (m_Buffer + offset, lenInnerPlaintext, keys2, keys2 + 32, m_Buffer + offset); // encrypt Layer 2 i2p::crypto::ChaCha20 (m_Buffer + offset, lenInnerPlaintext, keys2, keys2 + 32, m_Buffer + offset); // encrypt Layer 2
offset += lenInnerPlaintext; offset += lenInnerPlaintext;
@ -930,14 +928,14 @@ namespace data
// signature // signature
blindedSigner->Sign (m_Buffer, offset, m_Buffer + offset); blindedSigner->Sign (m_Buffer, offset, m_Buffer + offset);
// store hash // store hash
m_StoreHash = blindedKey.GetStoreHash (date); m_StoreHash = blindedKey.GetStoreHash (date);
} }
LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len): LocalEncryptedLeaseSet2::LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
LocalLeaseSet2 (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, identity, buf, len) LocalLeaseSet2 (NETDB_STORE_TYPE_ENCRYPTED_LEASESET2, identity, buf, len)
{ {
// fill inner LeaseSet2 // fill inner LeaseSet2
auto blindedKey = std::make_shared<BlindedPublicKey>(identity); auto blindedKey = std::make_shared<BlindedPublicKey>(identity);
i2p::data::LeaseSet2 ls (buf, len, blindedKey); // inner layer i2p::data::LeaseSet2 ls (buf, len, blindedKey); // inner layer
if (ls.IsValid ()) if (ls.IsValid ())
{ {
@ -945,10 +943,10 @@ namespace data
m_StoreHash = blindedKey->GetStoreHash (); m_StoreHash = blindedKey->GetStoreHash ();
} }
else else
LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer"); LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer");
} }
void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const
{ {
if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH) if (authType == ENCRYPTED_LEASESET_AUTH_TYPE_DH)
{ {
@ -963,9 +961,9 @@ namespace data
ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i) ek.Agree (it, authInput); // sharedSecret = DH(esk, cpk_i)
memcpy (authInput + 32, it, 32); memcpy (authInput + 32, it, 32);
uint8_t okm[64]; // 52 actual data uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm); i2p::crypto::HKDF (ek.GetPublicKey (), authInput, 100, "ELS2_XCA", okm);
memcpy (authData, okm + 44, 8); authData += 8; // clientID_i memcpy (authData, okm + 44, 8); authData += 8; // clientID_i
i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i
} }
} }
else // assume PSK else // assume PSK
@ -980,10 +978,10 @@ namespace data
{ {
memcpy (authInput, it, 32); memcpy (authInput, it, 32);
uint8_t okm[64]; // 52 actual data uint8_t okm[64]; // 52 actual data
i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm); i2p::crypto::HKDF (authSalt, authInput, 68, "ELS2PSKA", okm);
memcpy (authData, okm + 44, 8); authData += 8; // clientID_i memcpy (authData, okm + 44, 8); authData += 8; // clientID_i
i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i i2p::crypto::ChaCha20 (authCookie, 32, okm, okm + 32, authData); authData += 32; // clientCookie_i
} }
} }
} }
} }

@ -48,11 +48,11 @@ namespace data
}; };
}; };
typedef std::function<bool(const Lease & l)> LeaseInspectFunc; typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
const size_t MAX_LS_BUFFER_SIZE = 3072; const size_t MAX_LS_BUFFER_SIZE = 3072;
const size_t LEASE_SIZE = 44; // 32 + 4 + 8 const size_t LEASE_SIZE = 44; // 32 + 4 + 8
const size_t LEASE2_SIZE = 40; // 32 + 4 + 4 const size_t LEASE2_SIZE = 40; // 32 + 4 + 4
const uint8_t MAX_NUM_LEASES = 16; const uint8_t MAX_NUM_LEASES = 16;
const uint8_t NETDB_STORE_TYPE_LEASESET = 1; const uint8_t NETDB_STORE_TYPE_LEASESET = 1;
@ -70,7 +70,7 @@ namespace data
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
bool IsValid () const { return m_IsValid; }; bool IsValid () const { return m_IsValid; };
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const; const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const; const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const;
bool HasExpiredLeases () const; bool HasExpiredLeases () const;
bool IsExpired () const; bool IsExpired () const;
bool IsEmpty () const { return m_Leases.empty (); }; bool IsEmpty () const { return m_Leases.empty (); };
@ -80,7 +80,7 @@ namespace data
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; }; virtual uint8_t GetStoreType () const { return NETDB_STORE_TYPE_LEASESET; };
virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only virtual uint32_t GetPublishedTimestamp () const { return 0; }; // should be set for LeaseSet2 only
virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; }; virtual std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier () const { return nullptr; };
virtual bool IsPublishedEncrypted () const { return false; }; virtual bool IsPublishedEncrypted () const { return false; };
// implements RoutingDestination // implements RoutingDestination
@ -97,7 +97,7 @@ namespace data
// called from LeaseSet2 // called from LeaseSet2
LeaseSet (bool storeLeases); LeaseSet (bool storeLeases);
void SetBuffer (const uint8_t * buf, size_t len); void SetBuffer (const uint8_t * buf, size_t len);
void SetBufferLen (size_t len); void SetBufferLen (size_t len);
void SetIdentity (std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; }; void SetIdentity (std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; };
void SetExpirationTime (uint64_t t) { m_ExpirationTime = t; }; void SetExpirationTime (uint64_t t) { m_ExpirationTime = t; };
void SetIsValid (bool isValid) { m_IsValid = isValid; }; void SetIsValid (bool isValid) { m_IsValid = isValid; };
@ -130,7 +130,7 @@ namespace data
const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7; const uint8_t NETDB_STORE_TYPE_META_LEASESET2 = 7;
const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001; const uint16_t LEASESET2_FLAG_OFFLINE_KEYS = 0x0001;
const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002; const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002;
const uint16_t LEASESET2_FLAG_PUBLISHED_ENCRYPTED = 0x0004; const uint16_t LEASESET2_FLAG_PUBLISHED_ENCRYPTED = 0x0004;
class LeaseSet2: public LeaseSet class LeaseSet2: public LeaseSet
@ -167,7 +167,7 @@ namespace data
private: private:
uint8_t m_StoreType; uint8_t m_StoreType;
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;
@ -175,7 +175,7 @@ namespace data
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2 std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> m_Encryptor; // for standardLS2
}; };
// also called from Streaming.cpp // also called from Streaming.cpp
template<typename Verifier> template<typename Verifier>
std::shared_ptr<i2p::crypto::Verifier> ProcessOfflineSignature (const Verifier& verifier, const uint8_t * buf, size_t len, size_t& offset) std::shared_ptr<i2p::crypto::Verifier> ProcessOfflineSignature (const Verifier& verifier, const uint8_t * buf, size_t len, size_t& offset)
{ {
@ -191,7 +191,7 @@ namespace data
transientVerifier->SetPublicKey (buf + offset); offset += keyLen; transientVerifier->SetPublicKey (buf + offset); offset += keyLen;
if (offset + verifier->GetSignatureLen () >= len) return nullptr; if (offset + verifier->GetSignatureLen () >= len) return nullptr;
if (!verifier->Verify (signedData, keyLen + 6, buf + offset)) return nullptr; if (!verifier->Verify (signedData, keyLen + 6, buf + offset)) return nullptr;
offset += verifier->GetSignatureLen (); offset += verifier->GetSignatureLen ();
return transientVerifier; return transientVerifier;
} }
@ -238,17 +238,18 @@ namespace data
{ {
uint16_t keyType, keyLen; uint16_t keyType, keyLen;
const uint8_t * encryptionPublicKey; const uint8_t * encryptionPublicKey;
}; };
typedef std::vector<KeySection> KeySections; typedef std::vector<KeySection> KeySections;
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys, LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
const KeySections& encryptionKeys, const KeySections& encryptionKeys,
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels,
bool isPublic, bool isPublishedEncrypted = false); bool isPublic, bool isPublishedEncrypted = false);
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
LocalLeaseSet2 (uint8_t storeType, std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP
virtual ~LocalLeaseSet2 () { delete[] m_Buffer; }; virtual ~LocalLeaseSet2 () { delete[] m_Buffer; };
uint8_t * GetBuffer () const { return m_Buffer + 1; }; uint8_t * GetBuffer () const { return m_Buffer + 1; };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
@ -269,13 +270,13 @@ namespace data
const int ENCRYPTED_LEASESET_AUTH_TYPE_DH = 1; const int ENCRYPTED_LEASESET_AUTH_TYPE_DH = 1;
const int ENCRYPTED_LEASESET_AUTH_TYPE_PSK = 2; const int ENCRYPTED_LEASESET_AUTH_TYPE_PSK = 2;
typedef i2p::data::Tag<32> AuthPublicKey; typedef i2p::data::Tag<32> AuthPublicKey;
class LocalEncryptedLeaseSet2: public LocalLeaseSet2 class LocalEncryptedLeaseSet2: public LocalLeaseSet2
{ {
public: public:
LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, int authType = ENCRYPTED_LEASESET_AUTH_TYPE_NONE, std::shared_ptr<std::vector<AuthPublicKey> > authKeys = nullptr); LocalEncryptedLeaseSet2 (std::shared_ptr<const LocalLeaseSet2> ls, const i2p::data::PrivateKeys& keys, int authType = ENCRYPTED_LEASESET_AUTH_TYPE_NONE, std::shared_ptr<std::vector<AuthPublicKey> > authKeys = nullptr);
LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP LocalEncryptedLeaseSet2 (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len); // from I2CP

@ -29,35 +29,35 @@ struct BigEndian;
template<typename T> template<typename T>
struct LittleEndian struct LittleEndian
{ {
union union
{ {
unsigned char bytes[sizeof(T)]; unsigned char bytes[sizeof(T)];
T raw_value; T raw_value;
}; };
LittleEndian(T t = T()) LittleEndian(T t = T())
{ {
operator =(t); operator =(t);
} }
LittleEndian(const LittleEndian<T> & t) LittleEndian(const LittleEndian<T> & t)
{ {
raw_value = t.raw_value; raw_value = t.raw_value;
} }
LittleEndian(const BigEndian<T> & t) LittleEndian(const BigEndian<T> & t)
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
bytes[i] = t.bytes[sizeof(T)-1-i]; bytes[i] = t.bytes[sizeof(T)-1-i];
} }
operator const T() const operator const T() const
{ {
T t = T(); T t = T();
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
t |= T(bytes[i]) << (i << 3); t |= T(bytes[i]) << (i << 3);
return t; return t;
} }
const T operator = (const T t) const T operator = (const T t)
{ {
@ -66,68 +66,68 @@ struct LittleEndian
return t; return t;
} }
// operators // operators
const T operator += (const T t) const T operator += (const T t)
{ {
return (*this = *this + t); return (*this = *this + t);
} }
const T operator -= (const T t) const T operator -= (const T t)
{ {
return (*this = *this - t); return (*this = *this - t);
} }
const T operator *= (const T t) const T operator *= (const T t)
{ {
return (*this = *this * t); return (*this = *this * t);
} }
const T operator /= (const T t) const T operator /= (const T t)
{ {
return (*this = *this / t); return (*this = *this / t);
} }
const T operator %= (const T t) const T operator %= (const T t)
{ {
return (*this = *this % t); return (*this = *this % t);
} }
LittleEndian<T> operator ++ (int) LittleEndian<T> operator ++ (int)
{ {
LittleEndian<T> tmp(*this); LittleEndian<T> tmp(*this);
operator ++ (); operator ++ ();
return tmp; return tmp;
} }
LittleEndian<T> & operator ++ () LittleEndian<T> & operator ++ ()
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
{ {
++bytes[i]; ++bytes[i];
if (bytes[i] != 0) if (bytes[i] != 0)
break; break;
} }
return (*this); return (*this);
} }
LittleEndian<T> operator -- (int) LittleEndian<T> operator -- (int)
{ {
LittleEndian<T> tmp(*this); LittleEndian<T> tmp(*this);
operator -- (); operator -- ();
return tmp; return tmp;
} }
LittleEndian<T> & operator -- () LittleEndian<T> & operator -- ()
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
{ {
--bytes[i]; --bytes[i];
if (bytes[i] != (T)(-1)) if (bytes[i] != (T)(-1))
break; break;
} }
return (*this); return (*this);
} }
}; };
#pragma pack(pop) #pragma pack(pop)
@ -137,105 +137,105 @@ struct LittleEndian
template<typename T> template<typename T>
struct BigEndian struct BigEndian
{ {
union union
{ {
unsigned char bytes[sizeof(T)]; unsigned char bytes[sizeof(T)];
T raw_value; T raw_value;
}; };
BigEndian(T t = T()) BigEndian(T t = T())
{ {
operator =(t); operator =(t);
} }
BigEndian(const BigEndian<T> & t) BigEndian(const BigEndian<T> & t)
{ {
raw_value = t.raw_value; raw_value = t.raw_value;
} }
BigEndian(const LittleEndian<T> & t) BigEndian(const LittleEndian<T> & t)
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
bytes[i] = t.bytes[sizeof(T)-1-i]; bytes[i] = t.bytes[sizeof(T)-1-i];
} }
operator const T() const operator const T() const
{ {
T t = T(); T t = T();
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
t |= T(bytes[sizeof(T) - 1 - i]) << (i << 3); t |= T(bytes[sizeof(T) - 1 - i]) << (i << 3);
return t; return t;
} }
const T operator = (const T t) const T operator = (const T t)
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
bytes[sizeof(T) - 1 - i] = t >> (i << 3); bytes[sizeof(T) - 1 - i] = t >> (i << 3);
return t; return t;
} }
// operators // operators
const T operator += (const T t) const T operator += (const T t)
{ {
return (*this = *this + t); return (*this = *this + t);
} }
const T operator -= (const T t) const T operator -= (const T t)
{ {
return (*this = *this - t); return (*this = *this - t);
} }
const T operator *= (const T t) const T operator *= (const T t)
{ {
return (*this = *this * t); return (*this = *this * t);
} }
const T operator /= (const T t) const T operator /= (const T t)
{ {
return (*this = *this / t); return (*this = *this / t);
} }
const T operator %= (const T t) const T operator %= (const T t)
{ {
return (*this = *this % t); return (*this = *this % t);
} }
BigEndian<T> operator ++ (int) BigEndian<T> operator ++ (int)
{ {
BigEndian<T> tmp(*this); BigEndian<T> tmp(*this);
operator ++ (); operator ++ ();
return tmp; return tmp;
} }
BigEndian<T> & operator ++ () BigEndian<T> & operator ++ ()
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
{ {
++bytes[sizeof(T) - 1 - i]; ++bytes[sizeof(T) - 1 - i];
if (bytes[sizeof(T) - 1 - i] != 0) if (bytes[sizeof(T) - 1 - i] != 0)
break; break;
} }
return (*this); return (*this);
} }
BigEndian<T> operator -- (int) BigEndian<T> operator -- (int)
{ {
BigEndian<T> tmp(*this); BigEndian<T> tmp(*this);
operator -- (); operator -- ();
return tmp; return tmp;
} }
BigEndian<T> & operator -- () BigEndian<T> & operator -- ()
{ {
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
{ {
--bytes[sizeof(T) - 1 - i]; --bytes[sizeof(T) - 1 - i];
if (bytes[sizeof(T) - 1 - i] != (T)(-1)) if (bytes[sizeof(T) - 1 - i] != (T)(-1))
break; break;
} }
return (*this); return (*this);
} }
}; };
#pragma pack(pop) #pragma pack(pop)

@ -110,18 +110,18 @@ namespace log {
} }
} }
std::string str_tolower(std::string s) { std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), std::transform(s.begin(), s.end(), s.begin(),
// static_cast<int(*)(int)>(std::tolower) // wrong // static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong // [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong // [](char c){ return std::tolower(c); } // wrong
[](unsigned char c){ return std::tolower(c); } // correct [](unsigned char c){ return std::tolower(c); } // correct
); );
return s; return s;
} }
void Log::SetLogLevel (const std::string& level_) { void Log::SetLogLevel (const std::string& level_) {
std::string level=str_tolower(level_); std::string level=str_tolower(level_);
if (level == "none") { m_MinLevel = eLogNone; } if (level == "none") { m_MinLevel = eLogNone; }
else if (level == "error") { m_MinLevel = eLogError; } else if (level == "error") { m_MinLevel = eLogError; }
else if (level == "warn") { m_MinLevel = eLogWarning; } else if (level == "warn") { m_MinLevel = eLogWarning; }
@ -240,7 +240,7 @@ namespace log {
static ThrowFunction g_ThrowFunction; static ThrowFunction g_ThrowFunction;
ThrowFunction GetThrowFunction () { return g_ThrowFunction; } ThrowFunction GetThrowFunction () { return g_ThrowFunction; }
void SetThrowFunction (ThrowFunction f) { g_ThrowFunction = f; } void SetThrowFunction (ThrowFunction f) { g_ThrowFunction = f; }
} // log } // log
} // i2p } // i2p

@ -155,9 +155,9 @@ namespace log {
typedef std::function<void (const std::string&)> ThrowFunction; typedef std::function<void (const std::string&)> ThrowFunction;
ThrowFunction GetThrowFunction (); ThrowFunction GetThrowFunction ();
void SetThrowFunction (ThrowFunction f); void SetThrowFunction (ThrowFunction f);
} // log } // log
} } // i2p
/** internal usage only -- folding args array to single string */ /** internal usage only -- folding args array to single string */
template<typename TValue> template<typename TValue>
@ -203,7 +203,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
} }
/** /**
* @brief Throw fatal error message with the list of arguments * @brief Throw fatal error message with the list of arguments
* @param args Array of message parts * @param args Array of message parts
*/ */
template<typename... TArgs> template<typename... TArgs>

@ -114,7 +114,7 @@ namespace transport
void NTCP2Establisher::KDF2Bob () void NTCP2Establisher::KDF2Bob ()
{ {
KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ()); KeyDerivationFunction2 (m_SessionRequestBuffer, m_SessionRequestBufferLen, GetPub ());
} }
void NTCP2Establisher::KDF3Alice () void NTCP2Establisher::KDF3Alice ()
@ -707,7 +707,7 @@ namespace transport
auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already auto existing = i2p::data::netdb.FindRouter (ri.GetRouterIdentity ()->GetIdentHash ()); // check if exists already
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
if (m_Server.AddNTCP2Session (shared_from_this (), true)) if (m_Server.AddNTCP2Session (shared_from_this (), true))
{ {
Established (); Established ();
ReceiveLength (); ReceiveLength ();
} }
@ -1200,7 +1200,7 @@ namespace transport
continue; continue;
} }
LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port); LogPrint (eLogInfo, "NTCP2: Start listening v4 TCP port ", address->port);
auto conn = std::make_shared<NTCP2Session>(*this); auto conn = std::make_shared<NTCP2Session>(*this);
m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1)); m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
} }
@ -1218,8 +1218,8 @@ namespace transport
LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port); LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port);
auto conn = std::make_shared<NTCP2Session> (*this); auto conn = std::make_shared<NTCP2Session> (*this);
m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1)); m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1));
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogError, "NTCP2: failed to bind to v6 port ", address->port, ": ", ex.what()); LogPrint(eLogError, "NTCP2: failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ()); ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
@ -1485,7 +1485,7 @@ namespace transport
} }
}); });
auto readbuff = std::make_shared<std::vector<uint8_t> >(2); auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2), boost::asio::async_read(conn->GetSocket(), boost::asio::buffer(readbuff->data (), 2),
[this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred) [this, readbuff, timer, conn, host, port, addrtype](const boost::system::error_code & ec, std::size_t transferred)
{ {
if(ec) if(ec)
@ -1531,8 +1531,8 @@ namespace transport
std::ostream out(&writebuff); std::ostream out(&writebuff);
out << req.to_string(); out << req.to_string();
boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(), boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(),
[](const boost::system::error_code & ec, std::size_t transferred) [](const boost::system::error_code & ec, std::size_t transferred)
{ {
(void) transferred; (void) transferred;
if(ec) if(ec)
@ -1540,8 +1540,8 @@ namespace transport
}); });
boost::asio::streambuf * readbuff = new boost::asio::streambuf; boost::asio::streambuf * readbuff = new boost::asio::streambuf;
boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n", boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n",
[this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred) [this, readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred)
{ {
if(ec) if(ec)
{ {

@ -126,7 +126,6 @@ namespace transport
{ {
public: public:
NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr); NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr);
~NTCP2Session (); ~NTCP2Session ();
void Terminate (); void Terminate ();

@ -26,7 +26,7 @@ namespace transport
{ {
std::shared_ptr<NTCPSession> session; std::shared_ptr<NTCPSession> session;
}; };
NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter): NTCPSession::NTCPSession (NTCPServer& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter, NTCP_ESTABLISH_TIMEOUT), TransportSession (in_RemoteRouter, NTCP_ESTABLISH_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()), m_Server (server), m_Socket (m_Server.GetService ()),
@ -468,7 +468,7 @@ namespace transport
LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock"); LogPrint (eLogError, "NTCP: Phase 4 read error: ", ecode.message (), ". Check your clock");
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
// this router doesn't like us // this router doesn't like us
i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true);
Terminate (); Terminate ();
} }
@ -736,13 +736,11 @@ namespace transport
} }
} }
void NTCPSession::SendTimeSyncMessage () void NTCPSession::SendTimeSyncMessage ()
{ {
Send (nullptr); Send (nullptr);
} }
void NTCPSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) void NTCPSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{ {
m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs)); m_Server.GetService ().post (std::bind (&NTCPSession::PostI2NPMessages, shared_from_this (), msgs));
@ -821,8 +819,8 @@ namespace transport
{ {
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port)); m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
LogPrint (eLogInfo, "NTCP: Start listening v6 TCP port ", address->port); LogPrint (eLogInfo, "NTCP: Start listening v6 TCP port ", address->port);
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
/** fail to bind ip4 */ /** fail to bind ip4 */
LogPrint(eLogError, "NTCP: Failed to bind to v4 port ", address->port, ": ", ex.what()); LogPrint(eLogError, "NTCP: Failed to bind to v4 port ", address->port, ": ", ex.what());
@ -848,8 +846,8 @@ namespace transport
LogPrint (eLogInfo, "NTCP: Start listening v6 TCP port ", address->port); LogPrint (eLogInfo, "NTCP: Start listening v6 TCP port ", address->port);
auto conn = std::make_shared<NTCPSession> (*this); auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1)); m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1));
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogError, "NTCP: failed to bind to v6 port ", address->port, ": ", ex.what()); LogPrint(eLogError, "NTCP: failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal (eLogError, "Unable to start IPv6 NTCP transport at port ", address->port, ": ", ex.what ()); ThrowFatal (eLogError, "Unable to start IPv6 NTCP transport at port ", address->port, ": ", ex.what ());
@ -904,7 +902,6 @@ namespace transport
} }
} }
void NTCPServer::Run () void NTCPServer::Run ()
{ {
while (m_IsRunning) while (m_IsRunning)

@ -216,10 +216,10 @@ namespace data
LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64()); LogPrint (eLogDebug, "NetDb: RouterInfo floodfill status updated: ", ident.ToBase64());
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
if (wasFloodfill) if (wasFloodfill)
m_Floodfills.remove (r); m_Floodfills.remove (r);
else else
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
} }
} }
else else
{ {
@ -390,7 +390,7 @@ namespace data
} }
} }
m_Reseeder->Bootstrap (); m_Reseeder->Bootstrap ();
} }
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
@ -532,12 +532,12 @@ namespace data
auto total = m_RouterInfos.size (); auto total = m_RouterInfos.size ();
uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL; uint64_t expirationTimeout = NETDB_MAX_EXPIRATION_TIMEOUT*1000LL;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
auto uptime = i2p::context.GetUptime (); auto uptime = i2p::context.GetUptime ();
// routers don't expire if less than 90 or uptime is less than 1 hour // routers don't expire if less than 90 or uptime is less than 1 hour
bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes bool checkForExpiration = total > NETDB_MIN_ROUTERS && uptime > 600; // 10 minutes
if (checkForExpiration && uptime > 3600) // 1 hour if (checkForExpiration && uptime > 3600) // 1 hour
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
for (auto& it: m_RouterInfos) for (auto& it: m_RouterInfos)
{ {
@ -555,7 +555,7 @@ namespace data
// find & mark expired routers // find & mark expired routers
if (it.second->UsesIntroducer ()) if (it.second->UsesIntroducer ())
{ {
if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL) if (ts > it.second->GetTimestamp () + NETDB_INTRODUCEE_EXPIRATION_TIMEOUT*1000LL)
// RouterInfo expires after 1 hour if uses introducer // RouterInfo expires after 1 hour if uses introducer
it.second->SetUnreachable (true); it.second->SetUnreachable (true);
} }
@ -873,7 +873,7 @@ namespace data
std::shared_ptr<I2NPMessage> replyMsg; std::shared_ptr<I2NPMessage> replyMsg;
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP) if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
{ {
LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded"); LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters; std::set<IdentHash> excludedRouters;
for (int i = 0; i < numExcluded; i++) for (int i = 0; i < numExcluded; i++)
{ {
@ -894,7 +894,7 @@ namespace data
} }
else else
{ {
if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP || if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{ {
auto router = FindRouter (ident); auto router = FindRouter (ident);
@ -907,7 +907,7 @@ namespace data
} }
} }
if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP || if (!replyMsg && (lookupType == DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP))
{ {
auto leaseSet = FindLeaseSet (ident); auto leaseSet = FindLeaseSet (ident);
@ -957,12 +957,12 @@ namespace data
replyMsg = i2p::garlic::WrapECIESX25519AEADRatchetMessage (replyMsg, sessionKey, tag); replyMsg = i2p::garlic::WrapECIESX25519AEADRatchetMessage (replyMsg, sessionKey, tag);
} }
else else
{ {
const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag const i2p::garlic::SessionTag sessionTag(excluded + 33); // take first tag
i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag); i2p::garlic::ElGamalAESSession garlic (sessionKey, sessionTag);
replyMsg = garlic.WrapSingleMessage (replyMsg); replyMsg = garlic.WrapSingleMessage (replyMsg);
} }
if (!replyMsg) if (!replyMsg)
LogPrint (eLogError, "NetDb: failed to wrap message"); LogPrint (eLogError, "NetDb: failed to wrap message");
} }
else else
@ -1103,7 +1103,7 @@ namespace data
{ {
return !router->IsHidden () && router->IsSSUV6 (); return !router->IsHidden () && router->IsSSUV6 ();
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer () const std::shared_ptr<const RouterInfo> NetDb::GetRandomIntroducer () const
{ {

@ -28,12 +28,12 @@ namespace i2p
namespace data namespace data
{ {
const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_ROUTERS = 90;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60; const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90*60; // 1.5 hours const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27*60*60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_PUBLISH_INTERVAL = 60*40; const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0,9,36); // 0.9.36 const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
/** function for visiting a leaseset stored in a floodfill */ /** function for visiting a leaseset stored in a floodfill */
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor; typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
@ -63,13 +63,13 @@ namespace data
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const; std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m); void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
@ -80,13 +80,13 @@ namespace data
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */ /** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide); void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
@ -119,12 +119,13 @@ namespace data
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); void ReseedFromFloodfill(const RouterInfo & ri, int numRouters = 40, int numFloodfills = 20);
std::shared_ptr<const RouterInfo> AddRouterInfo (const uint8_t * buf, int len, bool& updated); std::shared_ptr<const RouterInfo> AddRouterInfo (const uint8_t * buf, int len, bool& updated);
std::shared_ptr<const RouterInfo> AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated); std::shared_ptr<const RouterInfo> AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated);
template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private: private:
@ -150,12 +151,12 @@ namespace data
bool m_PersistProfiles; bool m_PersistProfiles;
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */ /** true if in hidden mode */
bool m_HiddenMode; bool m_HiddenMode;
}; };
extern NetDb netdb; extern NetDb netdb;

@ -14,8 +14,8 @@ namespace data
std::shared_ptr<I2NPMessage> msg; std::shared_ptr<I2NPMessage> msg;
if(replyTunnel) if(replyTunnel)
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
&m_ExcludedPeers); &m_ExcludedPeers);
else else
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
if(router) if(router)
@ -158,4 +158,3 @@ namespace data
} }
} }
} }

@ -66,4 +66,3 @@ namespace data
} }
#endif #endif

@ -7,12 +7,11 @@
*/ */
#if !OPENSSL_AEAD_CHACHA20_POLY1305 #if !OPENSSL_AEAD_CHACHA20_POLY1305
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
{ {
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz) void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz)
{ {
Poly1305 p(key); Poly1305 p(key);

@ -1,9 +1,9 @@
/** /**
This code is licensed under the MCGSI Public License * This code is licensed under the MCGSI Public License
Copyright 2018 Jeff Becker * Copyright 2018 Jeff Becker
*
Kovri go write your own code * Kovri go write your own code
*
*/ */
#ifndef LIBI2PD_POLY1305_H #ifndef LIBI2PD_POLY1305_H
#define LIBI2PD_POLY1305_H #define LIBI2PD_POLY1305_H
@ -11,7 +11,7 @@
#include <cstring> #include <cstring>
#include "Crypto.h" #include "Crypto.h"
#if !OPENSSL_AEAD_CHACHA20_POLY1305 #if !OPENSSL_AEAD_CHACHA20_POLY1305
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -24,7 +24,6 @@ namespace crypto
namespace poly1305 namespace poly1305
{ {
struct LongBlock struct LongBlock
{ {
unsigned long data[17]; unsigned long data[17];
@ -252,8 +251,8 @@ namespace crypto
poly1305::LongBlock m_HR; poly1305::LongBlock m_HR;
uint8_t m_Final; uint8_t m_Final;
}; };
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
} }
} }
#endif #endif

@ -32,73 +32,76 @@ namespace data
{ {
} }
/** @brief tries to bootstrap into I2P network (from local files and servers, with respect of options) /**
*/ @brief tries to bootstrap into I2P network (from local files and servers, with respect of options)
void Reseeder::Bootstrap () */
{ void Reseeder::Bootstrap ()
std::string su3FileName; i2p::config::GetOption("reseed.file", su3FileName); {
std::string zipFileName; i2p::config::GetOption("reseed.zipfile", zipFileName); std::string su3FileName; i2p::config::GetOption("reseed.file", su3FileName);
std::string zipFileName; i2p::config::GetOption("reseed.zipfile", zipFileName);
if (su3FileName.length() > 0) // bootstrap from SU3 file or URL
{ if (su3FileName.length() > 0) // bootstrap from SU3 file or URL
int num; {
if (su3FileName.length() > 8 && su3FileName.substr(0, 8) == "https://") int num;
{ if (su3FileName.length() > 8 && su3FileName.substr(0, 8) == "https://")
num = ReseedFromSU3Url (su3FileName); // from https URL {
} num = ReseedFromSU3Url (su3FileName); // from https URL
else }
{ else
num = ProcessSU3File (su3FileName.c_str ()); {
} num = ProcessSU3File (su3FileName.c_str ());
if (num == 0) }
LogPrint (eLogWarning, "Reseed: failed to reseed from ", su3FileName); if (num == 0)
} LogPrint (eLogWarning, "Reseed: failed to reseed from ", su3FileName);
else if (zipFileName.length() > 0) // bootstrap from ZIP file }
{ else if (zipFileName.length() > 0) // bootstrap from ZIP file
int num = ProcessZIPFile (zipFileName.c_str ()); {
if (num == 0) int num = ProcessZIPFile (zipFileName.c_str ());
LogPrint (eLogWarning, "Reseed: failed to reseed from ", zipFileName); if (num == 0)
} LogPrint (eLogWarning, "Reseed: failed to reseed from ", zipFileName);
else // bootstrap from reseed servers }
{ else // bootstrap from reseed servers
int num = ReseedFromServers (); {
if (num == 0) int num = ReseedFromServers ();
LogPrint (eLogWarning, "Reseed: failed to reseed from servers"); if (num == 0)
} LogPrint (eLogWarning, "Reseed: failed to reseed from servers");
} }
}
/** @brief bootstrap from random server, retry 10 times
* @return number of entries added to netDb /**
*/ * @brief bootstrap from random server, retry 10 times
* @return number of entries added to netDb
*/
int Reseeder::ReseedFromServers () int Reseeder::ReseedFromServers ()
{ {
std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs); std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs);
std::vector<std::string> httpsReseedHostList; std::vector<std::string> httpsReseedHostList;
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
if (reseedURLs.length () == 0) if (reseedURLs.length () == 0)
{ {
LogPrint (eLogWarning, "Reseed: No reseed servers specified"); LogPrint (eLogWarning, "Reseed: No reseed servers specified");
return 0; return 0;
} }
int reseedRetries = 0; int reseedRetries = 0;
while (reseedRetries < 10) while (reseedRetries < 10)
{ {
auto ind = rand () % httpsReseedHostList.size (); auto ind = rand () % httpsReseedHostList.size ();
std::string reseedUrl = httpsReseedHostList[ind] + "i2pseeds.su3"; std::string reseedUrl = httpsReseedHostList[ind] + "i2pseeds.su3";
auto num = ReseedFromSU3Url (reseedUrl); auto num = ReseedFromSU3Url (reseedUrl);
if (num > 0) return num; // success if (num > 0) return num; // success
reseedRetries++; reseedRetries++;
} }
LogPrint (eLogWarning, "Reseed: failed to reseed from servers after 10 attempts"); LogPrint (eLogWarning, "Reseed: failed to reseed from servers after 10 attempts");
return 0; return 0;
} }
/** @brief bootstrap from HTTPS URL with SU3 file /**
* @param url * @brief bootstrap from HTTPS URL with SU3 file
* @return number of entries added to netDb * @param url
*/ * @return number of entries added to netDb
*/
int Reseeder::ReseedFromSU3Url (const std::string& url) int Reseeder::ReseedFromSU3Url (const std::string& url)
{ {
LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", url); LogPrint (eLogInfo, "Reseed: Downloading SU3 from ", url);
@ -702,4 +705,3 @@ namespace data
} }
} }
} }

@ -21,7 +21,7 @@ namespace data
Reseeder(); Reseeder();
~Reseeder(); ~Reseeder();
void Bootstrap (); void Bootstrap ();
int ReseedFromServers (); int ReseedFromServers ();
int ReseedFromSU3Url (const std::string& url); int ReseedFromSU3Url (const std::string& url);
int ProcessSU3File (const char * filename); int ProcessSU3File (const char * filename);

@ -338,10 +338,10 @@ namespace i2p
{ {
case low : /* not set */; break; case low : /* not set */; break;
case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P' case extra : caps |= i2p::data::RouterInfo::eExtraBandwidth; break; // 'P'
case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth; case unlim : caps |= i2p::data::RouterInfo::eExtraBandwidth;
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
#endif #endif
// no break here, extra + high means 'X' // no break here, extra + high means 'X'
case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break; case high : caps |= i2p::data::RouterInfo::eHighBandwidth; break;
} }

@ -15,7 +15,7 @@ namespace i2p
{ {
const char ROUTER_INFO[] = "router.info"; const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys"; const char ROUTER_KEYS[] = "router.keys";
const char NTCP2_KEYS[] = "ntcp2.keys"; const char NTCP2_KEYS[] = "ntcp2.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
enum RouterStatus enum RouterStatus
@ -36,12 +36,12 @@ namespace i2p
{ {
private: private:
struct NTCP2PrivateKeys struct NTCP2PrivateKeys
{ {
uint8_t staticPublicKey[32]; uint8_t staticPublicKey[32];
uint8_t staticPrivateKey[32]; uint8_t staticPrivateKey[32];
uint8_t iv[16]; uint8_t iv[16];
}; };
public: public:
@ -63,7 +63,7 @@ namespace i2p
const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; }; const uint8_t * GetNTCP2StaticPublicKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; }; const uint8_t * GetNTCP2StaticPrivateKey () const { return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr; };
const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; }; const uint8_t * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
i2p::crypto::X25519Keys& GetStaticKeys (); i2p::crypto::X25519Keys& GetStaticKeys ();
uint32_t GetUptime () const; // in seconds uint32_t GetUptime () const; // in seconds
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
@ -77,7 +77,7 @@ namespace i2p
void SetNetID (int netID) { m_NetID = netID; }; void SetNetID (int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
void PublishNTCP2Address (int port, bool publish = true, bool v4only = false); void PublishNTCP2Address (int port, bool publish = true, bool v4only = false);
void UpdateNTCP2Address (bool enable); void UpdateNTCP2Address (bool enable);
@ -124,7 +124,7 @@ namespace i2p
// implements GarlicDestination // implements GarlicDestination
void HandleI2NPMessage (const uint8_t * buf, size_t len); void HandleI2NPMessage (const uint8_t * buf, size_t len);
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented
private: private:
@ -141,7 +141,7 @@ namespace i2p
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
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;
std::chrono::time_point<std::chrono::steady_clock> m_StartupTime; std::chrono::time_point<std::chrono::steady_clock> m_StartupTime;
uint64_t m_BandwidthLimit; // allowed bandwidth uint64_t m_BandwidthLimit; // allowed bandwidth
int m_ShareRatio; int m_ShareRatio;

@ -35,12 +35,12 @@ namespace data
} }
RouterInfo::RouterInfo (const uint8_t * buf, int len): RouterInfo::RouterInfo (const uint8_t * buf, int len):
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0),
m_Caps (0), m_Version (0) m_Caps (0), m_Version (0)
{ {
m_Addresses = boost::make_shared<Addresses>(); // create empty list m_Addresses = boost::make_shared<Addresses>(); // create empty list
if (len <= MAX_RI_BUFFER_SIZE) if (len <= MAX_RI_BUFFER_SIZE)
{ {
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
@ -173,7 +173,6 @@ namespace data
LogPrint (eLogError, "RouterInfo: malformed message"); LogPrint (eLogError, "RouterInfo: malformed message");
m_IsUnreachable = true; m_IsUnreachable = true;
} }
} }
void RouterInfo::ReadFromStream (std::istream& s) void RouterInfo::ReadFromStream (std::istream& s)
@ -192,7 +191,7 @@ namespace data
s.read ((char *)&address->cost, sizeof (address->cost)); s.read ((char *)&address->cost, sizeof (address->cost));
s.read ((char *)&address->date, sizeof (address->date)); s.read ((char *)&address->date, sizeof (address->date));
bool isNTCP2Only = false; bool isNTCP2Only = false;
char transportStyle[6]; char transportStyle[6];
auto transportStyleLen = ReadString (transportStyle, 6, s) - 1; auto transportStyleLen = ReadString (transportStyle, 6, s) - 1;
if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2 if (!strncmp (transportStyle, "NTCP", 4)) // NTCP or NTCP2
{ {
@ -231,13 +230,13 @@ namespace data
address->host.to_string (ecode); address->host.to_string (ecode);
if (!ecode) if (!ecode)
#endif #endif
{ {
// add supported protocol // add supported protocol
if (address->host.is_v4 ()) if (address->host.is_v4 ())
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
else else
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
} }
} }
} }
else if (!strcmp (key, "port")) else if (!strcmp (key, "port"))
@ -262,15 +261,15 @@ namespace data
{ {
if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ());
supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6;
Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32); Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32);
} }
else if (!strcmp (key, "i")) // ntcp2 iv else if (!strcmp (key, "i")) // ntcp2 iv
{ {
if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ()); if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ());
supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6; supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6;
Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16);
address->ntcp2->isPublished = true; // presence if "i" means "published" address->ntcp2->isPublished = true; // presence if "i" means "published"
} }
else if (key[0] == 'i') else if (key[0] == 'i')
{ {
// introducers // introducers
@ -278,7 +277,7 @@ namespace data
{ {
LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped"); LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped");
continue; continue;
} }
introducers = true; introducers = true;
size_t l = strlen(key); size_t l = strlen(key);
unsigned char index = key[l-1] - '0'; // TODO: unsigned char index = key[l-1] - '0'; // TODO:
@ -309,7 +308,7 @@ namespace data
} }
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
if (isNTCP2Only && address->ntcp2) address->ntcp2->isNTCP2Only = true; if (isNTCP2Only && address->ntcp2) address->ntcp2->isNTCP2Only = true;
if (supportedTransports) if (supportedTransports)
{ {
addresses->push_back(address); addresses->push_back(address);
m_SupportedTransports |= supportedTransports; m_SupportedTransports |= supportedTransports;
@ -349,13 +348,13 @@ namespace data
while (*ch) while (*ch)
{ {
if (*ch >= '0' && *ch <= '9') if (*ch >= '0' && *ch <= '9')
{ {
m_Version *= 10; m_Version *= 10;
m_Version += (*ch - '0'); m_Version += (*ch - '0');
} }
ch++; ch++;
} }
} }
// check netId // check netId
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ()) else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ())
{ {
@ -384,9 +383,10 @@ namespace data
SetUnreachable (true); SetUnreachable (true);
} }
bool RouterInfo::IsFamily(const std::string & fam) const { bool RouterInfo::IsFamily(const std::string & fam) const
return m_Family == fam; {
} return m_Family == fam;
}
void RouterInfo::ExtractCaps (const char * value) void RouterInfo::ExtractCaps (const char * value)
{ {
@ -580,7 +580,7 @@ namespace data
properties << '='; properties << '=';
WriteString (boost::lexical_cast<std::string>(address.port), properties); WriteString (boost::lexical_cast<std::string>(address.port), properties);
properties << ';'; properties << ';';
} }
if (address.IsNTCP2 ()) if (address.IsNTCP2 ())
{ {
// publish s and v for NTCP2 // publish s and v for NTCP2
@ -588,7 +588,7 @@ namespace data
WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';'; WriteString (address.ntcp2->staticKey.ToBase64 (), properties); properties << ';';
WriteString ("v", properties); properties << '='; WriteString ("v", properties); properties << '=';
WriteString ("2", properties); properties << ';'; WriteString ("2", properties); properties << ';';
} }
uint16_t size = htobe16 (properties.str ().size ()); uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size)); s.write ((char *)&size, sizeof (size));
@ -742,7 +742,7 @@ namespace data
addr->ntcp2->isNTCP2Only = true; // NTCP2 only address addr->ntcp2->isNTCP2Only = true; // NTCP2 only address
if (port) addr->ntcp2->isPublished = true; if (port) addr->ntcp2->isPublished = true;
memcpy (addr->ntcp2->staticKey, staticKey, 32); memcpy (addr->ntcp2->staticKey, staticKey, 32);
memcpy (addr->ntcp2->iv, iv, 16); memcpy (addr->ntcp2->iv, iv, 16);
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }
@ -854,7 +854,7 @@ namespace data
m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6; m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6;
} }
void RouterInfo::EnableV4 () void RouterInfo::EnableV4 ()
{ {
if (!IsV4 ()) if (!IsV4 ())
m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4; m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4;
@ -877,7 +877,7 @@ namespace data
} }
} }
void RouterInfo::DisableV4 () void RouterInfo::DisableV4 ()
{ {
if (IsV4 ()) if (IsV4 ())
{ {
@ -926,7 +926,7 @@ namespace data
}); });
} }
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (Filter filter) const
{ {
// TODO: make it more generic using comparator // TODO: make it more generic using comparator
@ -937,7 +937,7 @@ namespace data
#endif #endif
for (const auto& address : *addresses) for (const auto& address : *addresses)
if (filter (address)) return address; if (filter (address)) return address;
return nullptr; return nullptr;
} }

@ -203,8 +203,8 @@ namespace data
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const; bool IsNewer (const uint8_t * buf, size_t len) const;
/** return true if we are in a router family and the signature is valid */ /** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const; bool IsFamily(const std::string & fam) const;
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; }; std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };

@ -45,15 +45,15 @@ namespace transport
void SSUServer::OpenSocket () void SSUServer::OpenSocket ()
{ {
try try
{ {
m_Socket.open (boost::asio::ip::udp::v4()); m_Socket.open (boost::asio::ip::udp::v4());
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_Socket.bind (m_Endpoint); m_Socket.bind (m_Endpoint);
LogPrint (eLogInfo, "SSU: Start listening v4 port ", m_Endpoint.port()); LogPrint (eLogInfo, "SSU: Start listening v4 port ", m_Endpoint.port());
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint (eLogError, "SSU: failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what()); LogPrint (eLogError, "SSU: failed to bind to v4 port ", m_Endpoint.port(), ": ", ex.what());
ThrowFatal ("Unable to start IPv4 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ()); ThrowFatal ("Unable to start IPv4 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
@ -62,7 +62,7 @@ namespace transport
void SSUServer::OpenSocketV6 () void SSUServer::OpenSocketV6 ()
{ {
try try
{ {
m_SocketV6.open (boost::asio::ip::udp::v6()); m_SocketV6.open (boost::asio::ip::udp::v6());
m_SocketV6.set_option (boost::asio::ip::v6_only (true)); m_SocketV6.set_option (boost::asio::ip::v6_only (true));
@ -70,8 +70,8 @@ namespace transport
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_SocketV6.bind (m_EndpointV6); m_SocketV6.bind (m_EndpointV6);
LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port()); LogPrint (eLogInfo, "SSU: Start listening v6 port ", m_EndpointV6.port());
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint (eLogError, "SSU: failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what()); LogPrint (eLogError, "SSU: failed to bind to v6 port ", m_EndpointV6.port(), ": ", ex.what());
ThrowFatal ("Unable to start IPv6 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ()); ThrowFatal ("Unable to start IPv6 SSU transport at port ", m_Endpoint.port(), ": ", ex.what ());
@ -184,7 +184,7 @@ namespace transport
m_Socket.close (); m_Socket.close ();
OpenSocket (); OpenSocket ();
Receive (); Receive ();
} }
} }
} }
} }
@ -359,10 +359,10 @@ namespace transport
{ {
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
{ {
if (session) if (session)
{ {
session->FlushData (); session->FlushData ();
session = nullptr; session = nullptr;
} }
auto it = sessions->find (packet->from); auto it = sessions->find (packet->from);
if (it != sessions->end ()) if (it != sessions->end ())
@ -826,4 +826,3 @@ namespace transport
} }
} }
} }

@ -40,7 +40,7 @@ namespace transport
public: public:
SSUServer (int port); SSUServer (int port);
SSUServer (const boost::asio::ip::address & addr, int port); // ipv6 only constructor SSUServer (const boost::asio::ip::address & addr, int port); // ipv6 only constructor
~SSUServer (); ~SSUServer ();
void Start (); void Start ();
void Stop (); void Stop ();
@ -135,4 +135,3 @@ namespace transport
} }
#endif #endif

@ -496,7 +496,7 @@ namespace transport
} }
// decay // decay
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL) i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
m_ReceivedMessages.clear (); m_ReceivedMessages.clear ();
ScheduleIncompleteMessagesCleanup (); ScheduleIncompleteMessagesCleanup ();
@ -504,4 +504,3 @@ namespace transport
} }
} }
} }

@ -128,4 +128,3 @@ namespace transport
} }
#endif #endif

@ -336,7 +336,7 @@ namespace transport
m_SignedData->Insert (payload, 4); // insert Alice's signed on time m_SignedData->Insert (payload, 4); // insert Alice's signed on time
payload += 4; // signed-on time payload += 4; // signed-on time
size_t paddingSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen (); size_t paddingSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen ();
paddingSize &= 0x0F; // %16 paddingSize &= 0x0F; // %16
if (paddingSize > 0) paddingSize = 16 - paddingSize; if (paddingSize > 0) paddingSize = 16 - paddingSize;
payload += paddingSize; payload += paddingSize;
// verify signature // verify signature
@ -934,7 +934,7 @@ namespace transport
for (const auto& it: msgs) for (const auto& it: msgs)
if (it) if (it)
{ {
if (it->GetLength () <= SSU_MAX_I2NP_MESSAGE_SIZE) if (it->GetLength () <= SSU_MAX_I2NP_MESSAGE_SIZE)
m_Data.Send (it); m_Data.Send (it);
else else
LogPrint (eLogError, "SSU: I2NP message of size ", it->GetLength (), " can't be sent. Dropped"); LogPrint (eLogError, "SSU: I2NP message of size ", it->GetLength (), " can't be sent. Dropped");
@ -1206,4 +1206,3 @@ namespace transport
} }
} }
} }

@ -28,7 +28,7 @@ namespace transport
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU_CLOCK_SKEW = 60; // in seconds const int SSU_CLOCK_SKEW = 60; // in seconds
const size_t SSU_MAX_I2NP_MESSAGE_SIZE = 32768; const size_t SSU_MAX_I2NP_MESSAGE_SIZE = 32768;
// payload types (4 bits) // payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
@ -81,12 +81,12 @@ namespace transport
void Done (); void Done ();
void Failed (); void Failed ();
const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendPeerTest (); // Alice void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; }; SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
@ -158,10 +158,7 @@ namespace transport
std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
std::map<uint32_t, std::shared_ptr<const i2p::data::RouterInfo> > m_RelayRequests; // nonce->Charlie std::map<uint32_t, std::shared_ptr<const i2p::data::RouterInfo> > m_RelayRequests; // nonce->Charlie
}; };
} }
} }
#endif #endif

@ -6,11 +6,11 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
EDDSA25519Verifier::EDDSA25519Verifier (): EDDSA25519Verifier::EDDSA25519Verifier ():
m_Pkey (nullptr) m_Pkey (nullptr)
{ {
m_MDCtx = EVP_MD_CTX_create (); m_MDCtx = EVP_MD_CTX_create ();
} }
EDDSA25519Verifier::~EDDSA25519Verifier () EDDSA25519Verifier::~EDDSA25519Verifier ()
@ -23,21 +23,21 @@ namespace crypto
{ {
m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32); m_Pkey = EVP_PKEY_new_raw_public_key (EVP_PKEY_ED25519, NULL, signingKey, 32);
EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey); EVP_DigestVerifyInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
} }
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len); return EVP_DigestVerify (m_MDCtx, signature, 64, buf, len);
} }
#else #else
EDDSA25519Verifier::EDDSA25519Verifier () EDDSA25519Verifier::EDDSA25519Verifier ()
{ {
} }
EDDSA25519Verifier::~EDDSA25519Verifier () EDDSA25519Verifier::~EDDSA25519Verifier ()
{ {
} }
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey)
{ {
@ -45,8 +45,8 @@ namespace crypto
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
uint8_t digest[64]; uint8_t digest[64];
@ -83,19 +83,19 @@ namespace crypto
EDDSA25519SignerCompat::~EDDSA25519SignerCompat () EDDSA25519SignerCompat::~EDDSA25519SignerCompat ()
{ {
} }
void EDDSA25519SignerCompat::Sign (const uint8_t * buf, int len, uint8_t * signature) const void EDDSA25519SignerCompat::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature); GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
} }
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey): EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey):
m_Fallback (nullptr) m_Fallback (nullptr)
{ {
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32); m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_ED25519, NULL, signingPrivateKey, 32);
uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t publicKey[EDDSA25519_PUBLIC_KEY_LENGTH];
size_t len = EDDSA25519_PUBLIC_KEY_LENGTH; size_t len = EDDSA25519_PUBLIC_KEY_LENGTH;
EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len); EVP_PKEY_get_raw_public_key (m_Pkey, publicKey, &len);
if (signingPublicKey && memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH)) if (signingPublicKey && memcmp (publicKey, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
@ -105,10 +105,10 @@ namespace crypto
m_Fallback = new EDDSA25519SignerCompat (signingPrivateKey, signingPublicKey); m_Fallback = new EDDSA25519SignerCompat (signingPrivateKey, signingPublicKey);
} }
else else
{ {
m_MDCtx = EVP_MD_CTX_create (); m_MDCtx = EVP_MD_CTX_create ();
EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, m_Pkey); EVP_DigestSignInit (m_MDCtx, NULL, NULL, NULL, m_Pkey);
} }
} }
EDDSA25519Signer::~EDDSA25519Signer () EDDSA25519Signer::~EDDSA25519Signer ()
@ -118,22 +118,20 @@ namespace crypto
{ {
EVP_MD_CTX_destroy (m_MDCtx); EVP_MD_CTX_destroy (m_MDCtx);
EVP_PKEY_free (m_Pkey); EVP_PKEY_free (m_Pkey);
} }
} }
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
if (m_Fallback) return m_Fallback->Sign (buf, len, signature); if (m_Fallback) return m_Fallback->Sign (buf, len, signature);
else else
{ {
size_t l = 64; size_t l = 64;
uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232 uint8_t sig[64]; // temporary buffer for signature. openssl issue #7232
EVP_DigestSign (m_MDCtx, sig, &l, buf, len); EVP_DigestSign (m_MDCtx, sig, &l, buf, len);
memcpy (signature, sig, 64); memcpy (signature, sig, 64);
} }
} }
#endif #endif
} }
} }

@ -46,9 +46,9 @@ namespace crypto
{ {
m_PublicKey = CreateDSA (); m_PublicKey = CreateDSA ();
} }
void SetPublicKey (const uint8_t * signingKey) void SetPublicKey (const uint8_t * signingKey)
{ {
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
} }
@ -163,9 +163,9 @@ namespace crypto
{ {
m_PublicKey = EC_KEY_new_by_curve_name (curve); m_PublicKey = EC_KEY_new_by_curve_name (curve);
} }
void SetPublicKey (const uint8_t * signingKey) void SetPublicKey (const uint8_t * signingKey)
{ {
BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL); BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL);
BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL); BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL);
EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y); EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y);
@ -287,7 +287,7 @@ namespace crypto
EDDSA25519Verifier (); EDDSA25519Verifier ();
void SetPublicKey (const uint8_t * signingKey); void SetPublicKey (const uint8_t * signingKey);
~EDDSA25519Verifier (); ~EDDSA25519Verifier ();
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; }; size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
@ -298,10 +298,10 @@ namespace crypto
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
EVP_PKEY * m_Pkey; EVP_PKEY * m_Pkey;
EVP_MD_CTX * m_MDCtx; EVP_MD_CTX * m_MDCtx;
#else #else
EDDSAPoint m_PublicKey; EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
#endif #endif
}; };
class EDDSA25519SignerCompat: public Signer class EDDSA25519SignerCompat: public Signer
@ -311,17 +311,17 @@ namespace crypto
EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr); EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key // we pass signingPublicKey to check if it matches private key
~EDDSA25519SignerCompat (); ~EDDSA25519SignerCompat ();
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
private: private:
uint8_t m_ExpandedPrivateKey[64]; uint8_t m_ExpandedPrivateKey[64];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
}; };
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
class EDDSA25519Signer: public Signer class EDDSA25519Signer: public Signer
{ {
public: public:
@ -329,23 +329,23 @@ namespace crypto
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr); EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key // we pass signingPublicKey to check if it matches private key
~EDDSA25519Signer (); ~EDDSA25519Signer ();
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
private: private:
EVP_PKEY * m_Pkey; EVP_PKEY * m_Pkey;
EVP_MD_CTX * m_MDCtx; EVP_MD_CTX * m_MDCtx;
EDDSA25519SignerCompat * m_Fallback; EDDSA25519SignerCompat * m_Fallback;
}; };
#else #else
typedef EDDSA25519SignerCompat EDDSA25519Signer; typedef EDDSA25519SignerCompat EDDSA25519Signer;
#endif #endif
inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
EVP_PKEY *pkey = NULL; EVP_PKEY *pkey = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL); EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL);
EVP_PKEY_keygen_init (pctx); EVP_PKEY_keygen_init (pctx);
@ -355,12 +355,12 @@ namespace crypto
EVP_PKEY_get_raw_public_key (pkey, signingPublicKey, &len); EVP_PKEY_get_raw_public_key (pkey, signingPublicKey, &len);
len = EDDSA25519_PRIVATE_KEY_LENGTH; len = EDDSA25519_PRIVATE_KEY_LENGTH;
EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len); EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len);
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
#else #else
RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
EDDSA25519Signer signer (signingPrivateKey); EDDSA25519Signer signer (signingPrivateKey);
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
#endif #endif
} }
@ -399,18 +399,18 @@ namespace crypto
GOSTR3410Verifier (GOSTR3410ParamSet paramSet): GOSTR3410Verifier (GOSTR3410ParamSet paramSet):
m_ParamSet (paramSet), m_PublicKey (nullptr) m_ParamSet (paramSet), m_PublicKey (nullptr)
{ {
} }
void SetPublicKey (const uint8_t * signingKey) void SetPublicKey (const uint8_t * signingKey)
{ {
BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL); BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL);
BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL); BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL);
m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y); m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
~GOSTR3410Verifier () ~GOSTR3410Verifier ()
{ {
if (m_PublicKey) EC_POINT_free (m_PublicKey); if (m_PublicKey) EC_POINT_free (m_PublicKey);
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
@ -501,18 +501,18 @@ namespace crypto
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_PrivateKey, ctx); auto publicKey = GetEd25519 ()->GeneratePublicKey (m_PrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx); GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
~RedDSA25519Signer () {}; ~RedDSA25519Signer () {};
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature); GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature);
} }
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
private: private:
uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH]; uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
}; };
@ -521,10 +521,9 @@ namespace crypto
{ {
GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey); GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey);
RedDSA25519Signer signer (signingPrivateKey); RedDSA25519Signer signer (signingPrivateKey);
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
} }
} }
} }
#endif #endif

@ -1,9 +1,9 @@
/** /**
This code is licensed under the MCGSI Public License * This code is licensed under the MCGSI Public License
Copyright 2018 Jeff Becker * Copyright 2018 Jeff Becker
*
Kovri go write your own code * Kovri go write your own code
*
*/ */
#ifndef SIPHASH_H #ifndef SIPHASH_H
#define SIPHASH_H #define SIPHASH_H
@ -14,140 +14,140 @@
#if !OPENSSL_SIPHASH #if !OPENSSL_SIPHASH
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
{ {
namespace siphash namespace siphash
{ {
constexpr int crounds = 2; constexpr int crounds = 2;
constexpr int drounds = 4; constexpr int drounds = 4;
inline uint64_t rotl(const uint64_t & x, int b) inline uint64_t rotl(const uint64_t & x, int b)
{ {
uint64_t ret = x << b; uint64_t ret = x << b;
ret |= x >> (64 - b); ret |= x >> (64 - b);
return ret; return ret;
} }
inline void u32to8le(const uint32_t & v, uint8_t * p) inline void u32to8le(const uint32_t & v, uint8_t * p)
{ {
p[0] = (uint8_t) v; p[0] = (uint8_t) v;
p[1] = (uint8_t) (v >> 8); p[1] = (uint8_t) (v >> 8);
p[2] = (uint8_t) (v >> 16); p[2] = (uint8_t) (v >> 16);
p[3] = (uint8_t) (v >> 24); p[3] = (uint8_t) (v >> 24);
} }
inline void u64to8le(const uint64_t & v, uint8_t * p) inline void u64to8le(const uint64_t & v, uint8_t * p)
{ {
p[0] = v & 0xff; p[0] = v & 0xff;
p[1] = (v >> 8) & 0xff; p[1] = (v >> 8) & 0xff;
p[2] = (v >> 16) & 0xff; p[2] = (v >> 16) & 0xff;
p[3] = (v >> 24) & 0xff; p[3] = (v >> 24) & 0xff;
p[4] = (v >> 32) & 0xff; p[4] = (v >> 32) & 0xff;
p[5] = (v >> 40) & 0xff; p[5] = (v >> 40) & 0xff;
p[6] = (v >> 48) & 0xff; p[6] = (v >> 48) & 0xff;
p[7] = (v >> 56) & 0xff; p[7] = (v >> 56) & 0xff;
} }
inline uint64_t u8to64le(const uint8_t * p) inline uint64_t u8to64le(const uint8_t * p)
{ {
uint64_t i = 0; uint64_t i = 0;
int idx = 0; int idx = 0;
while(idx < 8) while(idx < 8)
{ {
i |= ((uint64_t) p[idx]) << (idx * 8); i |= ((uint64_t) p[idx]) << (idx * 8);
++idx; ++idx;
} }
return i; return i;
} }
inline void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3) inline void round(uint64_t & _v0, uint64_t & _v1, uint64_t & _v2, uint64_t & _v3)
{ {
_v0 += _v1; _v0 += _v1;
_v1 = rotl(_v1, 13); _v1 = rotl(_v1, 13);
_v1 ^= _v0; _v1 ^= _v0;
_v0 = rotl(_v0, 32); _v0 = rotl(_v0, 32);
_v2 += _v3; _v2 += _v3;
_v3 = rotl(_v3, 16); _v3 = rotl(_v3, 16);
_v3 ^= _v2; _v3 ^= _v2;
_v0 += _v3; _v0 += _v3;
_v3 = rotl(_v3, 21); _v3 = rotl(_v3, 21);
_v3 ^= _v0; _v3 ^= _v0;
_v2 += _v1; _v2 += _v1;
_v1 = rotl(_v1, 17); _v1 = rotl(_v1, 17);
_v1 ^= _v2; _v1 ^= _v2;
_v2 = rotl(_v2, 32); _v2 = rotl(_v2, 32);
} }
} }
/** hashsz must be 8 or 16 */ /** hashsz must be 8 or 16 */
template<std::size_t hashsz> template<std::size_t hashsz>
inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key) inline void Siphash(uint8_t * h, const uint8_t * buf, std::size_t bufsz, const uint8_t * key)
{ {
uint64_t v0 = 0x736f6d6570736575ULL; uint64_t v0 = 0x736f6d6570736575ULL;
uint64_t v1 = 0x646f72616e646f6dULL; uint64_t v1 = 0x646f72616e646f6dULL;
uint64_t v2 = 0x6c7967656e657261ULL; uint64_t v2 = 0x6c7967656e657261ULL;
uint64_t v3 = 0x7465646279746573ULL; uint64_t v3 = 0x7465646279746573ULL;
const uint64_t k0 = siphash::u8to64le(key); const uint64_t k0 = siphash::u8to64le(key);
const uint64_t k1 = siphash::u8to64le(key + 8); const uint64_t k1 = siphash::u8to64le(key + 8);
uint64_t msg; uint64_t msg;
int i; int i;
const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t)); const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t));
auto left = bufsz & 7; auto left = bufsz & 7;
uint64_t b = ((uint64_t)bufsz) << 56; uint64_t b = ((uint64_t)bufsz) << 56;
v3 ^= k1; v3 ^= k1;
v2 ^= k0; v2 ^= k0;
v1 ^= k1; v1 ^= k1;
v0 ^= k0; v0 ^= k0;
if(hashsz == 16) v1 ^= 0xee; if(hashsz == 16) v1 ^= 0xee;
while(buf != end) while(buf != end)
{ {
msg = siphash::u8to64le(buf); msg = siphash::u8to64le(buf);
v3 ^= msg; v3 ^= msg;
for(i = 0; i < siphash::crounds; ++i) for(i = 0; i < siphash::crounds; ++i)
siphash::round(v0, v1, v2, v3); siphash::round(v0, v1, v2, v3);
v0 ^= msg; v0 ^= msg;
buf += 8; buf += 8;
} }
while(left) while(left)
{ {
--left; --left;
b |= ((uint64_t)(buf[left])) << (left * 8); b |= ((uint64_t)(buf[left])) << (left * 8);
} }
v3 ^= b; v3 ^= b;
for(i = 0; i < siphash::crounds; ++i) for(i = 0; i < siphash::crounds; ++i)
siphash::round(v0, v1, v2, v3); siphash::round(v0, v1, v2, v3);
v0 ^= b; v0 ^= b;
if(hashsz == 16) if(hashsz == 16)
v2 ^= 0xee; v2 ^= 0xee;
else else
v2 ^= 0xff; v2 ^= 0xff;
for(i = 0; i < siphash::drounds; ++i) for(i = 0; i < siphash::drounds; ++i)
siphash::round(v0, v1, v2, v3); siphash::round(v0, v1, v2, v3);
b = v0 ^ v1 ^ v2 ^ v3; b = v0 ^ v1 ^ v2 ^ v3;
siphash::u64to8le(b, h); siphash::u64to8le(b, h);
if(hashsz == 8) return; if(hashsz == 8) return;
v1 ^= 0xdd; v1 ^= 0xdd;
for (i = 0; i < siphash::drounds; ++i) for (i = 0; i < siphash::drounds; ++i)
siphash::round(v0, v1, v2, v3); siphash::round(v0, v1, v2, v3);
b = v0 ^ v1 ^ v2 ^ v3; b = v0 ^ v1 ^ v2 ^ v3;
siphash::u64to8le(b, h + 8); siphash::u64to8le(b, h + 8);
} }
} }
} }
#endif #endif

@ -34,7 +34,7 @@ namespace stream
else else
{ {
// partially // partially
rem = len - offset; rem = len - offset;
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset); memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
nextBuffer->offset += (len - offset); nextBuffer->offset += (len - offset);
offset = len; // break offset = len; // break
@ -60,7 +60,7 @@ namespace stream
m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_RemoteLeaseSet (remote), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service),
m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port), m_AckSendTimer (m_Service), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (port),
m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO),
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU)
@ -73,7 +73,7 @@ namespace stream
m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_Service (service), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local), m_Status (eStreamStatusNew), m_IsAckSendScheduled (false), m_LocalDestination (local),
m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service), m_ReceiveTimer (m_Service), m_ResendTimer (m_Service), m_AckSendTimer (m_Service),
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE),
m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU) m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0), m_MTU (STREAMING_MTU)
{ {
@ -228,7 +228,7 @@ namespace stream
Terminate (); Terminate ();
return; return;
} }
packet->offset = packet->GetPayload () - packet->buf; packet->offset = packet->GetPayload () - packet->buf;
if (packet->GetLength () > 0) if (packet->GetLength () > 0)
{ {
@ -258,7 +258,7 @@ namespace stream
bool Stream::ProcessOptions (uint16_t flags, Packet * packet) bool Stream::ProcessOptions (uint16_t flags, Packet * packet)
{ {
const uint8_t * optionData = packet->GetOptionData (); const uint8_t * optionData = packet->GetOptionData ();
size_t optionSize = packet->GetOptionSize (); size_t optionSize = packet->GetOptionSize ();
if (flags & PACKET_FLAG_DELAY_REQUESTED) if (flags & PACKET_FLAG_DELAY_REQUESTED)
optionData += 2; optionData += 2;
@ -269,7 +269,7 @@ namespace stream
m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, optionSize); m_RemoteIdentity = std::make_shared<i2p::data::IdentityEx>(optionData, optionSize);
if (m_RemoteIdentity->IsRSA ()) if (m_RemoteIdentity->IsRSA ())
{ {
LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded"); LogPrint (eLogInfo, "Streaming: Incoming stream from RSA destination ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " Discarded");
return false; return false;
} }
optionData += m_RemoteIdentity->GetFullLen (); optionData += m_RemoteIdentity->GetFullLen ();
@ -306,11 +306,11 @@ namespace stream
size_t offset = 0; size_t offset = 0;
m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset); m_TransientVerifier = i2p::data::ProcessOfflineSignature (m_RemoteIdentity, optionData, optionSize - (optionData - packet->GetOptionData ()), offset);
optionData += offset; optionData += offset;
if (!m_TransientVerifier) if (!m_TransientVerifier)
{ {
LogPrint (eLogError, "Streaming: offline signature failed"); LogPrint (eLogError, "Streaming: offline signature failed");
return false; return false;
} }
} }
} }
@ -322,7 +322,7 @@ namespace stream
{ {
memcpy (signature, optionData, signatureLen); memcpy (signature, optionData, signatureLen);
memset (const_cast<uint8_t *>(optionData), 0, signatureLen); memset (const_cast<uint8_t *>(optionData), 0, signatureLen);
bool verified = m_TransientVerifier ? bool verified = m_TransientVerifier ?
m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) : m_TransientVerifier->Verify (packet->GetBuffer (), packet->GetLength (), signature) :
m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature); m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature);
if (!verified) if (!verified)
@ -340,7 +340,7 @@ namespace stream
return false; return false;
} }
} }
return true; return true;
} }
void Stream::ProcessAck (Packet * packet) void Stream::ProcessAck (Packet * packet)
@ -435,7 +435,7 @@ namespace stream
m_SendBuffer.Add (buf, len, handler); m_SendBuffer.Add (buf, len, handler);
} }
else if (handler) else if (handler)
handler(boost::system::error_code ()); handler(boost::system::error_code ());
m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ())); m_Service.post (std::bind (&Stream::SendBuffer, shared_from_this ()));
} }
@ -471,14 +471,14 @@ namespace stream
size++; // resend delay size++; // resend delay
if (m_Status == eStreamStatusNew) if (m_Status == eStreamStatusNew)
{ {
// initial packet // initial packet
m_Status = eStreamStatusOpen; m_Status = eStreamStatusOpen;
if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());; if (!m_RemoteLeaseSet) m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ());;
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet)
{ {
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU; m_MTU = m_RoutingSession->IsRatchets () ? STREAMING_MTU_RATCHETS : STREAMING_MTU;
} }
uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED | uint16_t flags = PACKET_FLAG_SYNCHRONIZE | PACKET_FLAG_FROM_INCLUDED |
PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED; PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED;
if (isNoAck) flags |= PACKET_FLAG_NO_ACK; if (isNoAck) flags |= PACKET_FLAG_NO_ACK;
@ -488,7 +488,7 @@ namespace stream
size += 2; // flags size += 2; // flags
size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen (); size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen ();
size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen (); size_t signatureLen = m_LocalDestination.GetOwner ()->GetPrivateKeys ().GetSignatureLen ();
uint8_t * optionsSize = packet + size; // set options size later uint8_t * optionsSize = packet + size; // set options size later
size += 2; // options size size += 2; // options size
m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen); m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen);
size += identityLen; // from size += identityLen; // from
@ -654,7 +654,7 @@ namespace stream
size += 4; // receiveStreamID size += 4; // receiveStreamID
htobe32buf (packet + size, m_SequenceNumber++); htobe32buf (packet + size, m_SequenceNumber++);
size += 4; // sequenceNum size += 4; // sequenceNum
htobe32buf (packet + size, m_LastReceivedSequenceNumber >= 0 ? m_LastReceivedSequenceNumber : 0); htobe32buf (packet + size, m_LastReceivedSequenceNumber >= 0 ? m_LastReceivedSequenceNumber : 0);
size += 4; // ack Through size += 4; // ack Through
packet[size] = 0; packet[size] = 0;
size++; // NACK count size++; // NACK count
@ -748,7 +748,7 @@ namespace stream
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet if (!m_CurrentRemoteLease || !m_CurrentRemoteLease->endDate || // excluded from LeaseSet
ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD) ts >= m_CurrentRemoteLease->endDate - i2p::data::LEASE_ENDDATE_THRESHOLD)
UpdateCurrentRemoteLease (true); UpdateCurrentRemoteLease (true);
if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD) if (m_CurrentRemoteLease && ts < m_CurrentRemoteLease->endDate + i2p::data::LEASE_ENDDATE_THRESHOLD)
{ {
@ -785,7 +785,7 @@ namespace stream
if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASET_CONFIRMATION_TIMEOUT) if (ts > m_RoutingSession->GetLeaseSetSubmissionTime () + i2p::garlic::LEASET_CONFIRMATION_TIMEOUT)
{ {
// LeaseSet was not confirmed, should try other tunnels // LeaseSet was not confirmed, should try other tunnels
LogPrint (eLogWarning, "Streaming: LeaseSet was not confirmed in ", i2p::garlic::LEASET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit"); LogPrint (eLogWarning, "Streaming: LeaseSet was not confirmed in ", i2p::garlic::LEASET_CONFIRMATION_TIMEOUT, " milliseconds. Trying to resubmit");
m_RoutingSession->SetSharedRoutingPath (nullptr); m_RoutingSession->SetSharedRoutingPath (nullptr);
m_CurrentOutboundTunnel = nullptr; m_CurrentOutboundTunnel = nullptr;
m_CurrentRemoteLease = nullptr; m_CurrentRemoteLease = nullptr;
@ -848,9 +848,9 @@ namespace stream
break; break;
case 2: case 2:
m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time m_RTO = INITIAL_RTO; // drop RTO to initial upon tunnels pair change first time
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
#endif #endif
// no break here // no break here
case 4: case 4:
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
@ -911,7 +911,7 @@ namespace stream
// LeaseSet updated // LeaseSet updated
m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity (); m_RemoteIdentity = m_RemoteLeaseSet->GetIdentity ();
m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier (); m_TransientVerifier = m_RemoteLeaseSet->GetTransientVerifier ();
} }
} }
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet)
{ {
@ -926,7 +926,7 @@ namespace stream
m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet ( m_LocalDestination.GetOwner ()->RequestDestinationWithEncryptedLeaseSet (
std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity)); std::make_shared<i2p::data::BlindedPublicKey>(m_RemoteIdentity));
else else
m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ());
leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold
} }
if (!leases.empty ()) if (!leases.empty ())
@ -994,7 +994,7 @@ namespace stream
{ {
std::unique_lock<std::mutex> l(m_StreamsMutex); std::unique_lock<std::mutex> l(m_StreamsMutex);
for (auto it: m_Streams) for (auto it: m_Streams)
it.second->Terminate (false); // we delete here it.second->Terminate (false); // we delete here
m_Streams.clear (); m_Streams.clear ();
m_IncomingStreams.clear (); m_IncomingStreams.clear ();
} }
@ -1136,8 +1136,8 @@ namespace stream
return false; return false;
DeleteStream (it->second); DeleteStream (it->second);
return true; return true;
} }
void StreamingDestination::SetAcceptor (const Acceptor& acceptor) void StreamingDestination::SetAcceptor (const Acceptor& acceptor)
{ {
m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet m_Acceptor = acceptor; // we must set it immediately for IsAcceptorSet
@ -1164,7 +1164,7 @@ namespace stream
m_Owner->GetService ().post([acceptor, this](void) m_Owner->GetService ().post([acceptor, this](void)
{ {
if (!m_PendingIncomingStreams.empty ()) if (!m_PendingIncomingStreams.empty ())
{ {
acceptor (m_PendingIncomingStreams.front ()); acceptor (m_PendingIncomingStreams.front ());
m_PendingIncomingStreams.pop_front (); m_PendingIncomingStreams.pop_front ();
if (m_PendingIncomingStreams.empty ()) if (m_PendingIncomingStreams.empty ())

@ -16,93 +16,91 @@
namespace i2p { namespace i2p {
namespace data { namespace data {
template<size_t sz>
template<size_t sz> class Tag
class Tag
{
BOOST_STATIC_ASSERT_MSG(sz % 8 == 0, "Tag size must be multiple of 8 bytes");
public:
Tag () = default;
Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }
bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }
bool operator!= (const Tag& other) const { return !(*this == other); }
bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }
uint8_t * operator()() { return m_Buf; }
const uint8_t * operator()() const { return m_Buf; }
operator uint8_t * () { return m_Buf; }
operator const uint8_t * () const { return m_Buf; }
const uint8_t * data() const { return m_Buf; }
const uint64_t * GetLL () const { return ll; }
bool IsZero () const
{
for (size_t i = 0; i < sz/8; ++i)
if (ll[i]) return false;
return true;
}
void Fill(uint8_t c)
{ {
memset(m_Buf, c, sz); BOOST_STATIC_ASSERT_MSG(sz % 8 == 0, "Tag size must be multiple of 8 bytes");
}
public:
void Randomize()
{ Tag () = default;
RAND_bytes(m_Buf, sz); Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }
}
bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }
std::string ToBase64 () const bool operator!= (const Tag& other) const { return !(*this == other); }
{ bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }
char str[sz*2];
size_t l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); uint8_t * operator()() { return m_Buf; }
return std::string (str, str + l); const uint8_t * operator()() const { return m_Buf; }
}
operator uint8_t * () { return m_Buf; }
std::string ToBase32 () const operator const uint8_t * () const { return m_Buf; }
{
char str[sz*2]; const uint8_t * data() const { return m_Buf; }
size_t l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); const uint64_t * GetLL () const { return ll; }
return std::string (str, str + l);
} bool IsZero () const
{
size_t FromBase32 (const std::string& s) for (size_t i = 0; i < sz/8; ++i)
{ if (ll[i]) return false;
return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); return true;
} }
size_t FromBase64 (const std::string& s) void Fill(uint8_t c)
{ {
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); memset(m_Buf, c, sz);
} }
private: void Randomize()
{
union // 8 bytes aligned RAND_bytes(m_Buf, sz);
{ }
uint8_t m_Buf[sz];
uint64_t ll[sz/8]; std::string ToBase64 () const
{
char str[sz*2];
size_t l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2);
return std::string (str, str + l);
}
std::string ToBase32 () const
{
char str[sz*2];
size_t l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2);
return std::string (str, str + l);
}
size_t FromBase32 (const std::string& s)
{
return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
}
size_t FromBase64 (const std::string& s)
{
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
}
private:
union // 8 bytes aligned
{
uint8_t m_Buf[sz];
uint64_t ll[sz/8];
};
}; };
};
} // data } // data
} // i2p } // i2p
namespace std namespace std
{ {
// hash for std::unordered_map // hash for std::unordered_map
template<size_t sz> struct hash<i2p::data::Tag<sz> > template<size_t sz> struct hash<i2p::data::Tag<sz> >
{ {
size_t operator()(const i2p::data::Tag<sz>& s) const size_t operator()(const i2p::data::Tag<sz>& s) const
{ {
return s.GetLL ()[0]; return s.GetLL ()[0];
} }
}; };
} }
#endif /* TAG_H__ */ #endif /* TAG_H__ */

@ -24,26 +24,26 @@ namespace util
static uint64_t GetLocalMillisecondsSinceEpoch () static uint64_t GetLocalMillisecondsSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
static uint32_t GetLocalHoursSinceEpoch () static uint32_t GetLocalHoursSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::hours>( return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
static uint64_t GetLocalSecondsSinceEpoch () static uint64_t GetLocalSecondsSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::seconds>( return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
static int64_t g_TimeOffset = 0; // in seconds static int64_t g_TimeOffset = 0; // in seconds
static void SyncTimeWithNTP (const std::string& address) static void SyncTimeWithNTP (const std::string& address)
{ {
LogPrint (eLogInfo, "Timestamp: NTP request to ", address); LogPrint (eLogInfo, "Timestamp: NTP request to ", address);
boost::asio::io_service service; boost::asio::io_service service;
boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp"); boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp");
boost::system::error_code ec; boost::system::error_code ec;
@ -148,11 +148,11 @@ namespace util
} }
void NTPTimeSync::Sync () void NTPTimeSync::Sync ()
{ {
if (m_NTPServersList.size () > 0) if (m_NTPServersList.size () > 0)
SyncTimeWithNTP (m_NTPServersList[rand () % m_NTPServersList.size ()]); SyncTimeWithNTP (m_NTPServersList[rand () % m_NTPServersList.size ()]);
else else
m_IsRunning = false; m_IsRunning = false;
if (m_IsRunning) if (m_IsRunning)
{ {
@ -200,4 +200,3 @@ namespace util
} }
} }
} }

@ -15,8 +15,8 @@ namespace util
uint32_t GetHoursSinceEpoch (); uint32_t GetHoursSinceEpoch ();
uint64_t GetSecondsSinceEpoch (); uint64_t GetSecondsSinceEpoch ();
void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes void GetCurrentDate (char * date); // returns date as YYYYMMDD string, 9 bytes
void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes void GetDateString (uint64_t timestamp, char * date); // timestap is seconds since epoch, returns date as YYYYMMDD string, 9 bytes
class NTPTimeSync class NTPTimeSync
{ {
@ -26,17 +26,17 @@ namespace util
~NTPTimeSync (); ~NTPTimeSync ();
void Start (); void Start ();
void Stop (); void Stop ();
private: private:
void Run (); void Run ();
void Sync (); void Sync ();
private: private:
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
int m_SyncInterval; int m_SyncInterval;
@ -46,4 +46,3 @@ namespace util
} }
#endif #endif

@ -12,7 +12,7 @@ namespace i2p
namespace tunnel namespace tunnel
{ {
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID, TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey): const uint8_t * layerKey,const uint8_t * ivKey):
TunnelBase (receiveTunnelID, nextTunnelID, nextIdent) TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
{ {
@ -88,7 +88,7 @@ namespace tunnel
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID, std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey, const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint) bool isGateway, bool isEndpoint)
{ {
if (isEndpoint) if (isEndpoint)

@ -68,15 +68,15 @@ namespace transport
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; } std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity ()
{ {
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex); std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
return m_RemoteIdentity; return m_RemoteIdentity;
} }
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident)
{ {
std::lock_guard<std::mutex> l(m_RemoteIdentityMutex); std::lock_guard<std::mutex> l(m_RemoteIdentityMutex);
m_RemoteIdentity = ident; m_RemoteIdentity = ident;
} }
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };

@ -220,10 +220,10 @@ namespace transport
return; return;
} }
else else
{ {
m_NTCP2Server = new NTCP2Server (); m_NTCP2Server = new NTCP2Server ();
m_NTCP2Server->Start (); m_NTCP2Server->Start ();
} }
} }
// create acceptors // create acceptors
@ -390,7 +390,7 @@ namespace transport
{ {
auto r = netdb.FindRouter (ident); auto r = netdb.FindRouter (ident);
{ {
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {}, it = m_Peers.insert (std::pair<i2p::data::IdentHash, Peer>(ident, { 0, r, {},
i2p::util::GetSecondsSinceEpoch (), {} })).first; i2p::util::GetSecondsSinceEpoch (), {} })).first;
} }
@ -553,13 +553,13 @@ namespace transport
{ {
auto router = i2p::data::netdb.GetRandomPeerTestRouter (isv4); // v4 only if v4 auto router = i2p::data::netdb.GetRandomPeerTestRouter (isv4); // v4 only if v4
if (router) if (router)
m_SSUServer->CreateSession (router, true, isv4); // peer test m_SSUServer->CreateSession (router, true, isv4); // peer test
else else
{ {
// if not peer test capable routers found pick any // if not peer test capable routers found pick any
router = i2p::data::netdb.GetRandomRouter (); router = i2p::data::netdb.GetRandomRouter ();
if (router && router->IsSSU ()) if (router && router->IsSSU ())
m_SSUServer->CreateSession (router); // no peer test m_SSUServer->CreateSession (router); // no peer test
} }
} }
if (i2p::context.SupportsV6 ()) if (i2p::context.SupportsV6 ())
@ -574,7 +574,7 @@ namespace transport
if (addr) if (addr)
m_SSUServer->GetServiceV6 ().post ([this, router, addr] m_SSUServer->GetServiceV6 ().post ([this, router, addr]
{ {
m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false); m_SSUServer->CreateDirectSession (router, { addr->host, (uint16_t)addr->port }, false);
}); });
} }
} }
@ -713,7 +713,7 @@ namespace transport
{ {
profile->TunnelNonReplied(); profile->TunnelNonReplied();
} }
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it); it = m_Peers.erase (it);
} }
else else

@ -103,7 +103,7 @@ namespace transport
uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; }; uint64_t GetTotalReceivedBytes () const { return m_TotalReceivedBytes; };
uint64_t GetTotalTransitTransmittedBytes () const { return m_TotalTransitTransmittedBytes; } uint64_t GetTotalTransitTransmittedBytes () const { return m_TotalTransitTransmittedBytes; }
void UpdateTotalTransitTransmittedBytes (uint32_t add) { m_TotalTransitTransmittedBytes += add; }; void UpdateTotalTransitTransmittedBytes (uint32_t add) { m_TotalTransitTransmittedBytes += add; };
uint32_t GetInBandwidth () const { return m_InBandwidth; }; uint32_t GetInBandwidth () const { return m_InBandwidth; };
uint32_t GetOutBandwidth () const { return m_OutBandwidth; }; uint32_t GetOutBandwidth () const { return m_OutBandwidth; };
uint32_t GetTransitBandwidth () const { return m_TransitBandwidth; }; uint32_t GetTransitBandwidth () const { return m_TransitBandwidth; };
bool IsBandwidthExceeded () const; bool IsBandwidthExceeded () const;
@ -111,16 +111,16 @@ namespace transport
size_t GetNumPeers () const { return m_Peers.size (); }; size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const; std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer () const;
/** get a trusted first hop for restricted routes */ /** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const; std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer() const;
/** do we want to use restricted routes? */ /** do we want to use restricted routes? */
bool RoutesRestricted() const; bool RoutesRestricted() const;
/** restrict routes to use only these router families for first hops */ /** restrict routes to use only these router families for first hops */
void RestrictRoutesToFamilies(std::set<std::string> families); void RestrictRoutesToFamilies(std::set<std::string> families);
/** restrict routes to use only these routers for first hops */ /** restrict routes to use only these routers for first hops */
void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers); void RestrictRoutesToRouters(std::set<i2p::data::IdentHash> routers);
bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const;
void PeerTest (); void PeerTest ();

@ -64,8 +64,7 @@ namespace tunnel
m.hash = i2p::data::IdentHash (fragment); m.hash = i2p::data::IdentHash (fragment);
fragment += 32; // to hash fragment += 32; // to hash
break; break;
default: default: ;
;
} }
bool isFragmented = flag & 0x08; bool isFragmented = flag & 0x08;

@ -51,7 +51,7 @@ namespace tunnel
// create fragments // create fragments
const std::shared_ptr<I2NPMessage> & msg = block.data; const std::shared_ptr<I2NPMessage> & msg = block.data;
size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length size_t fullMsgLen = diLen + msg->GetLength () + 2; // delivery instructions + payload + 2 bytes length
if (!messageCreated && fullMsgLen > m_RemainingSize) // check if we should complete previous message if (!messageCreated && fullMsgLen > m_RemainingSize) // check if we should complete previous message
{ {
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE; size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
@ -172,7 +172,7 @@ namespace tunnel
SHA256(payload, size+16, hash); SHA256(payload, size+16, hash);
memcpy (buf+20, hash, 4); // checksum memcpy (buf+20, hash, 4); // checksum
payload[-1] = 0; // zero payload[-1] = 0; // zero
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
if (paddingSize > 0) if (paddingSize > 0)
{ {
// non-zero padding // non-zero padding
@ -219,4 +219,3 @@ namespace tunnel
} }
} }
} }

@ -16,7 +16,6 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true), m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true),
@ -67,7 +66,8 @@ namespace tunnel
m_Tests.clear (); m_Tests.clear ();
} }
bool TunnelPool::Reconfigure(int inHops, int outHops, int inQuant, int outQuant) { bool TunnelPool::Reconfigure(int inHops, int outHops, int inQuant, int outQuant)
{
if( inHops >= 0 && outHops >= 0 && inQuant > 0 && outQuant > 0) if( inHops >= 0 && outHops >= 0 && inQuant > 0 && outQuant > 0)
{ {
m_NumInboundHops = inHops; m_NumInboundHops = inHops;
@ -78,7 +78,7 @@ namespace tunnel
} }
return false; return false;
} }
void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel) void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel)
{ {
if (!m_IsActive) return; if (!m_IsActive) return;
@ -180,8 +180,8 @@ namespace tunnel
{ {
if (it->IsEstablished () && it != excluded) if (it->IsEstablished () && it != excluded)
{ {
tunnel = it; tunnel = it;
i++; i++;
} }
if (i > ind && tunnel) break; if (i > ind && tunnel) break;
} }
@ -411,7 +411,7 @@ namespace tunnel
{ {
std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex);
if (m_CustomPeerSelector) if (m_CustomPeerSelector)
return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound); return m_CustomPeerSelector->SelectPeers(peers, numHops, isInbound);
} }
// explicit peers in use // explicit peers in use
if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound); if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound);

@ -75,23 +75,23 @@ namespace tunnel
/** i2cp reconfigure */ /** i2cp reconfigure */
bool Reconfigure(int inboundHops, int outboundHops, int inboundQuant, int outboundQuant); bool Reconfigure(int inboundHops, int outboundHops, int inboundQuant, int outboundQuant);
void SetCustomPeerSelector(ITunnelPeerSelector * selector); void SetCustomPeerSelector(ITunnelPeerSelector * selector);
void UnsetCustomPeerSelector(); void UnsetCustomPeerSelector();
bool HasCustomPeerSelector(); bool HasCustomPeerSelector();
/** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */ /** @brief make this tunnel pool yield tunnels that fit latency range [min, max] */
void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; } void RequireLatency(uint64_t min, uint64_t max) { m_MinLatency = min; m_MaxLatency = max; }
/** @brief return true if this tunnel pool has a latency requirement */ /** @brief return true if this tunnel pool has a latency requirement */
bool HasLatencyRequirement() const { return m_MinLatency > 0 && m_MaxLatency > 0; } bool HasLatencyRequirement() const { return m_MinLatency > 0 && m_MaxLatency > 0; }
/** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */ /** @brief get the lowest latency tunnel in this tunnel pool regardless of latency requirements */
std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude=nullptr) const; std::shared_ptr<InboundTunnel> GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude = nullptr) const;
std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude=nullptr) const; std::shared_ptr<OutboundTunnel> GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude = nullptr) const;
// for overriding tunnel peer selection // for overriding tunnel peer selection
std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const; std::shared_ptr<const i2p::data::RouterInfo> SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop) const;
private: private:
@ -118,8 +118,8 @@ namespace tunnel
std::mutex m_CustomPeerSelectorMutex; std::mutex m_CustomPeerSelectorMutex;
ITunnelPeerSelector * m_CustomPeerSelector; ITunnelPeerSelector * m_CustomPeerSelector;
uint64_t m_MinLatency=0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms uint64_t m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
uint64_t m_MaxLatency=0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms uint64_t m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms
public: public:

@ -31,8 +31,8 @@ namespace api
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
i2p::crypto::InitCrypto (precomputation); i2p::crypto::InitCrypto (precomputation);
int netID; i2p::config::GetOption("netid", netID); int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID); i2p::context.SetNetID (netID);
i2p::context.Init (); i2p::context.Init ();
} }
@ -133,4 +133,3 @@ namespace api
} }
} }
} }

@ -35,4 +35,3 @@ namespace api
} }
#endif #endif

@ -64,9 +64,9 @@ namespace util
{ {
m_IsRunning = true; m_IsRunning = true;
m_Thread.reset (new std::thread (std::bind (& RunnableService::Run, this))); m_Thread.reset (new std::thread (std::bind (& RunnableService::Run, this)));
} }
} }
void RunnableService::StopIOService () void RunnableService::StopIOService ()
{ {
if (m_IsRunning) if (m_IsRunning)
@ -79,7 +79,7 @@ namespace util
m_Thread = nullptr; m_Thread = nullptr;
} }
} }
} }
void RunnableService::Run () void RunnableService::Run ()
{ {
@ -94,28 +94,28 @@ namespace util
LogPrint (eLogError, m_Name, ": runtime exception: ", ex.what ()); LogPrint (eLogError, m_Name, ": runtime exception: ", ex.what ());
} }
} }
} }
namespace net namespace net
{ {
#ifdef WIN32 #ifdef WIN32
bool IsWindowsXPorLater() bool IsWindowsXPorLater()
{ {
static bool isRequested = false; static bool isRequested = false;
static bool isXP = false; static bool isXP = false;
if (!isRequested) if (!isRequested)
{ {
// request // request
OSVERSIONINFO osvi; OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi); GetVersionEx(&osvi);
isXP = osvi.dwMajorVersion <= 5; isXP = osvi.dwMajorVersion <= 5;
isRequested = true; isRequested = true;
} }
return isXP; return isXP;
} }
int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback) int GetMTUWindowsIpv4(sockaddr_in inputAddress, int fallback)
@ -246,22 +246,24 @@ namespace net
std::string localAddressUniversal = localAddress.to_string(); std::string localAddressUniversal = localAddress.to_string();
#endif #endif
typedef int (* IPN)(int af, const char *src, void *dst); typedef int (* IPN)(int af, const char *src, void *dst);
IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton"); IPN inetpton = (IPN)GetProcAddress (GetModuleHandle ("ws2_32.dll"), "InetPton");
if (!inetpton) inetpton = inet_pton_xp; // use own implementation if not found 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;
inetpton(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;
inetpton(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");
return fallback; return fallback;
} }
@ -355,7 +357,7 @@ 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[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
memset (addr, 0, 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);
@ -379,7 +381,6 @@ namespace net
LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname); LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname);
} }
return boost::asio::ip::address::from_string(fallback); return boost::asio::ip::address::from_string(fallback);
#endif #endif
} }
} }

@ -132,34 +132,34 @@ namespace util
boost::asio::io_service& GetIOService () { return m_Service; } boost::asio::io_service& GetIOService () { return m_Service; }
bool IsRunning () const { return m_IsRunning; }; bool IsRunning () const { return m_IsRunning; };
void StartIOService (); void StartIOService ();
void StopIOService (); void StopIOService ();
private: private:
void Run (); void Run ();
private: private:
std::string m_Name; std::string m_Name;
volatile bool m_IsRunning; volatile bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
}; };
class RunnableServiceWithWork: public RunnableService class RunnableServiceWithWork: public RunnableService
{ {
protected: protected:
RunnableServiceWithWork (const std::string& name): RunnableServiceWithWork (const std::string& name):
RunnableService (name), m_Work (GetIOService ()) {} RunnableService (name), m_Work (GetIOService ()) {}
private: private:
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;
}; };
namespace net namespace net
{ {
int GetMTU (const boost::asio::ip::address& localAddress); int GetMTU (const boost::asio::ip::address& localAddress);

@ -31,7 +31,7 @@ namespace client
std::string etagsPath, indexPath, localPath; std::string etagsPath, indexPath, localPath;
public: public:
AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32") AddressBookFilesystemStorage (): storage("addressbook", "b", "", "b32")
{ {
i2p::config::GetOption("persist.addressbook", m_IsPersist); i2p::config::GetOption("persist.addressbook", m_IsPersist);
} }
@ -77,10 +77,10 @@ namespace client
std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const std::shared_ptr<const i2p::data::IdentityEx> AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const
{ {
if (!m_IsPersist) if (!m_IsPersist)
{ {
LogPrint(eLogDebug, "Addressbook: Persistence is disabled"); LogPrint(eLogDebug, "Addressbook: Persistence is disabled");
return nullptr; return nullptr;
} }
std::string filename = storage.Path(ident.ToBase32()); std::string filename = storage.Path(ident.ToBase32());
std::ifstream f(filename, std::ifstream::binary); std::ifstream f(filename, std::ifstream::binary);
@ -121,7 +121,7 @@ namespace client
void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident) void AddressBookFilesystemStorage::RemoveAddress (const i2p::data::IdentHash& ident)
{ {
if (!m_IsPersist) return; if (!m_IsPersist) return;
storage.Remove( ident.ToBase32() ); storage.Remove( ident.ToBase32() );
} }
@ -189,7 +189,7 @@ namespace client
} }
for (const auto& it: addresses) for (const auto& it: addresses)
{ {
f << it.first << ","; f << it.first << ",";
if (it.second->IsIdentHash ()) if (it.second->IsIdentHash ())
f << it.second->identHash.ToBase32 (); f << it.second->identHash.ToBase32 ();
@ -251,12 +251,12 @@ namespace client
if (blindedPublicKey->IsValid ()) if (blindedPublicKey->IsValid ())
addressType = eAddressBlindedPublicKey; addressType = eAddressBlindedPublicKey;
} }
} }
Address::Address (const i2p::data::IdentHash& hash) Address::Address (const i2p::data::IdentHash& hash)
{ {
addressType = eAddressIndentHash; addressType = eAddressIndentHash;
identHash = hash; identHash = hash;
} }
AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false), AddressBook::AddressBook (): m_Storage(nullptr), m_IsLoaded (false), m_IsDownloading (false),
@ -322,7 +322,7 @@ namespace client
{ {
auto pos = address.find(".b32.i2p"); auto pos = address.find(".b32.i2p");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
auto addr = std::make_shared<const Address>(address.substr (0, pos)); auto addr = std::make_shared<const Address>(address.substr (0, pos));
return addr->IsValid () ? addr : nullptr; return addr->IsValid () ? addr : nullptr;
} }
@ -333,10 +333,10 @@ namespace client
{ {
auto addr = FindAddress (address); auto addr = FindAddress (address);
if (!addr) if (!addr)
LookupAddress (address); // TODO: LookupAddress (address); // TODO:
return addr; return addr;
} }
} }
// if not .b32 we assume full base64 address // if not .b32 we assume full base64 address
i2p::data::IdentityEx dest; i2p::data::IdentityEx dest;
if (!dest.FromBase64 (address)) if (!dest.FromBase64 (address))
@ -359,10 +359,10 @@ namespace client
{ {
m_Addresses[address] = std::make_shared<Address>(jump.substr (0, pos)); m_Addresses[address] = std::make_shared<Address>(jump.substr (0, pos));
LogPrint (eLogInfo, "Addressbook: added ", address," -> ", jump); LogPrint (eLogInfo, "Addressbook: added ", address," -> ", jump);
} }
else else
{ {
// assume base64 // assume base64
auto ident = std::make_shared<i2p::data::IdentityEx>(); auto ident = std::make_shared<i2p::data::IdentityEx>();
if (ident->FromBase64 (jump)) if (ident->FromBase64 (jump))
{ {
@ -487,18 +487,18 @@ namespace client
LogPrint (eLogWarning, "Addressbook: subscriptions.txt usage is deprecated, use config file instead"); LogPrint (eLogWarning, "Addressbook: subscriptions.txt usage is deprecated, use config file instead");
} }
else if (!i2p::config::IsDefault("addressbook.subscriptions")) else if (!i2p::config::IsDefault("addressbook.subscriptions"))
{ {
// using config file items // using config file items
std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs); std::string subscriptionURLs; i2p::config::GetOption("addressbook.subscriptions", subscriptionURLs);
std::vector<std::string> subsList; std::vector<std::string> subsList;
boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(subsList, subscriptionURLs, boost::is_any_of(","), boost::token_compress_on);
for (size_t i = 0; i < subsList.size (); i++) for (size_t i = 0; i < subsList.size (); i++)
{ {
m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, subsList[i])); m_Subscriptions.push_back (std::make_shared<AddressBookSubscription> (*this, subsList[i]));
} }
LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded"); LogPrint (eLogInfo, "Addressbook: ", m_Subscriptions.size (), " subscriptions urls loaded");
} }
} }
else else
LogPrint (eLogError, "Addressbook: subscriptions already loaded"); LogPrint (eLogError, "Addressbook: subscriptions already loaded");
@ -515,7 +515,7 @@ namespace client
if (dot != std::string::npos) if (dot != std::string::npos)
{ {
auto domain = it.first.substr (dot + 1); auto domain = it.first.substr (dot + 1);
auto it1 = m_Addresses.find (domain); // find domain in our addressbook auto it1 = m_Addresses.find (domain); // find domain in our addressbook
if (it1 != m_Addresses.end () && it1->second->IsIdentHash ()) if (it1 != m_Addresses.end () && it1->second->IsIdentHash ())
{ {
auto dest = context.FindLocalDestination (it1->second->identHash); auto dest = context.FindLocalDestination (it1->second->identHash);
@ -610,7 +610,7 @@ namespace client
{ {
// download it from default subscription // download it from default subscription
LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription."); LogPrint (eLogInfo, "Addressbook: trying to download it from default subscription.");
std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL); std::string defaultSubURL; i2p::config::GetOption("addressbook.defaulturl", defaultSubURL);
if (!m_DefaultSubscription) if (!m_DefaultSubscription)
m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL); m_DefaultSubscription = std::make_shared<AddressBookSubscription>(*this, defaultSubURL);
m_IsDownloading = true; m_IsDownloading = true;
@ -743,13 +743,13 @@ namespace client
i2p::http::URL url; i2p::http::URL url;
// must be run in separate thread // must be run in separate thread
LogPrint (eLogInfo, "Addressbook: Downloading hosts database from ", m_Link); LogPrint (eLogInfo, "Addressbook: Downloading hosts database from ", m_Link);
if (!url.parse(m_Link)) if (!url.parse(m_Link))
{ {
LogPrint(eLogError, "Addressbook: failed to parse url: ", m_Link); LogPrint(eLogError, "Addressbook: failed to parse url: ", m_Link);
return false; return false;
} }
auto addr = m_Book.GetAddress (url.host); auto addr = m_Book.GetAddress (url.host);
if (!addr || !addr->IsIdentHash ()) if (!addr || !addr->IsIdentHash ())
{ {
LogPrint (eLogError, "Addressbook: Can't resolve ", url.host); LogPrint (eLogError, "Addressbook: Can't resolve ", url.host);
return false; return false;
@ -802,7 +802,7 @@ namespace client
/* convert url to relative */ /* convert url to relative */
url.schema = ""; url.schema = "";
url.host = ""; url.host = "";
req.uri = url.to_string(); req.uri = url.to_string();
auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, dest_port); auto stream = i2p::client::context.GetSharedLocalDestination ()->CreateStream (leaseSet, dest_port);
std::string request = req.to_string(); std::string request = req.to_string();
stream->Send ((const uint8_t *) request.data(), request.length()); stream->Send ((const uint8_t *) request.data(), request.length());
@ -920,7 +920,7 @@ namespace client
{ {
auto datagram = m_LocalDestination->GetDatagramDestination (); auto datagram = m_LocalDestination->GetDatagramDestination ();
if (datagram) if (datagram)
datagram->ResetReceiver (ADDRESS_RESOLVER_DATAGRAM_PORT); datagram->ResetReceiver (ADDRESS_RESOLVER_DATAGRAM_PORT);
} }
} }

@ -37,8 +37,8 @@ namespace client
i2p::data::IdentHash identHash; i2p::data::IdentHash identHash;
std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey; std::shared_ptr<i2p::data::BlindedPublicKey> blindedPublicKey;
Address (const std::string& b32); Address (const std::string& b32);
Address (const i2p::data::IdentHash& hash); Address (const i2p::data::IdentHash& hash);
bool IsIdentHash () const { return addressType == eAddressIndentHash; }; bool IsIdentHash () const { return addressType == eAddressIndentHash; };
bool IsValid () const { return addressType != eAddressInvalid; }; bool IsValid () const { return addressType != eAddressInvalid; };
}; };
@ -160,5 +160,3 @@ namespace client
} }
#endif #endif

@ -50,10 +50,10 @@ namespace client
void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver) void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
{ {
receiver->socket->async_read_some (boost::asio::buffer( receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset, receiver->buffer + receiver->bufferOffset,
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset), BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this, std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
std::placeholders::_1, std::placeholders::_2, receiver)); std::placeholders::_1, std::placeholders::_2, receiver));
} }
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
@ -255,7 +255,7 @@ namespace client
std::bind(&BOBCommandSession::HandleReceivedLine, shared_from_this(), std::bind(&BOBCommandSession::HandleReceivedLine, shared_from_this(),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} }
void BOBCommandSession::HandleReceivedLine(const boost::system::error_code& ecode, std::size_t bytes_transferred) void BOBCommandSession::HandleReceivedLine(const boost::system::error_code& ecode, std::size_t bytes_transferred)
{ {
if(ecode) if(ecode)
@ -267,14 +267,14 @@ namespace client
else else
{ {
std::string line; std::string line;
std::istream is(&m_ReceiveBuffer); std::istream is(&m_ReceiveBuffer);
std::getline(is, line); std::getline(is, line);
std::string command, operand; std::string command, operand;
std::istringstream iss(line); std::istringstream iss(line);
iss >> command >> operand; iss >> command >> operand;
// process command // process command
auto& handlers = m_Owner.GetCommandHandlers(); auto& handlers = m_Owner.GetCommandHandlers();
auto it = handlers.find(command); auto it = handlers.find(command);
@ -346,7 +346,7 @@ namespace client
std::ostream os(&m_SendBuffer); std::ostream os(&m_SendBuffer);
os << data << std::endl; os << data << std::endl;
} }
void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out) void BOBCommandSession::BuildStatusLine(bool currentTunnel, BOBDestination *dest, std::string &out)
{ {
// helper lambdas // helper lambdas
@ -355,7 +355,7 @@ namespace client
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; }; const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); }; const auto destReady = [](const BOBDestination * const dest) { return dest->GetLocalDestination()->IsReady(); };
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
// tunnel info // tunnel info
const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname(); const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname();
const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet(); const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet();
@ -367,7 +367,7 @@ namespace client
const bool starting = destExists(dest) && !destReady(dest); const bool starting = destExists(dest) && !destReady(dest);
const bool running = destExists(dest) && destReady(dest); const bool running = destExists(dest) && destReady(dest);
const bool stopping = false; const bool stopping = false;
// build line // build line
std::stringstream ss; std::stringstream ss;
ss << "DATA " ss << "DATA "
@ -433,11 +433,11 @@ namespace client
return; return;
} }
} }
if (!m_CurrentDestination) if (!m_CurrentDestination)
{ {
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet); m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet);
m_Owner.AddDestination (m_Nickname, m_CurrentDestination); m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
} }
if (m_InPort) if (m_InPort)
@ -613,25 +613,24 @@ namespace client
} }
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination (); auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
if (addr->IsIdentHash ()) if (addr->IsIdentHash ())
{ {
// we might have leaseset already // we might have leaseset already
auto leaseSet = localDestination->FindLeaseSet (addr->identHash); auto leaseSet = localDestination->FindLeaseSet (addr->identHash);
if (leaseSet) if (leaseSet)
{ {
SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ()); SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ());
return; return;
} }
} }
// trying to request // trying to request
auto s = shared_from_this (); auto s = shared_from_this ();
auto requstCallback = auto requstCallback = [s](std::shared_ptr<i2p::data::LeaseSet> ls)
[s](std::shared_ptr<i2p::data::LeaseSet> ls) {
{ if (ls)
if (ls) s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ()); else
else s->SendReplyError ("LeaseSet Not found");
s->SendReplyError ("LeaseSet Not found"); };
};
if (addr->IsIdentHash ()) if (addr->IsIdentHash ())
localDestination->RequestDestination (addr->identHash, requstCallback); localDestination->RequestDestination (addr->identHash, requstCallback);
else else
@ -794,7 +793,7 @@ namespace client
BOBCommandChannel::~BOBCommandChannel () BOBCommandChannel::~BOBCommandChannel ()
{ {
if (IsRunning ()) if (IsRunning ())
Stop (); Stop ();
for (const auto& it: m_Destinations) for (const auto& it: m_Destinations)
delete it.second; delete it.second;
@ -856,8 +855,7 @@ namespace client
session->SendVersion (); session->SendVersion ();
} }
else else
LogPrint (eLogError, "BOB: accept error: ", ecode.message ()); LogPrint (eLogError, "BOB: accept error: ", ecode.message ());
} }
} }
} }

@ -39,7 +39,7 @@ namespace client
const char BOB_COMMAND_OPTION[] = "option"; const char BOB_COMMAND_OPTION[] = "option";
const char BOB_COMMAND_STATUS[] = "status"; const char BOB_COMMAND_STATUS[] = "status";
const char BOB_COMMAND_HELP[] = "help"; const char BOB_COMMAND_HELP[] = "help";
const char BOB_HELP_ZAP[] = "zap - Shuts down BOB."; const char BOB_HELP_ZAP[] = "zap - Shuts down BOB.";
const char BOB_HELP_QUIT[] = "quit - Quits this session with BOB."; const char BOB_HELP_QUIT[] = "quit - Quits this session with BOB.";
const char BOB_HELP_START[] = "start - Starts the current nicknamed tunnel."; const char BOB_HELP_START[] = "start - Starts the current nicknamed tunnel.";
@ -75,15 +75,15 @@ namespace client
class BOBI2PInboundTunnel: public BOBI2PTunnel class BOBI2PInboundTunnel: public BOBI2PTunnel
{ {
struct AddressReceiver struct AddressReceiver
{ {
std::shared_ptr<boost::asio::ip::tcp::socket> socket; std::shared_ptr<boost::asio::ip::tcp::socket> socket;
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
uint8_t * data; // pointer to buffer uint8_t * data; // pointer to buffer
size_t dataLen, bufferOffset; size_t dataLen, bufferOffset;
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {}; AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
}; };
public: public:
@ -115,7 +115,7 @@ namespace client
{ {
public: public:
BOBI2POutboundTunnel (const std::string& outhost, int port, std::shared_ptr<ClientDestination> localDestination, bool quiet); BOBI2POutboundTunnel (const std::string& outhost, int port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
void Start (); void Start ();
void Stop (); void Stop ();
@ -162,7 +162,7 @@ namespace client
std::shared_ptr<ClientDestination> m_LocalDestination; std::shared_ptr<ClientDestination> m_LocalDestination;
BOBI2POutboundTunnel * m_OutboundTunnel; BOBI2POutboundTunnel * m_OutboundTunnel;
BOBI2PInboundTunnel * m_InboundTunnel; BOBI2PInboundTunnel * m_InboundTunnel;
std::string m_Nickname; std::string m_Nickname;
std::string m_InHost, m_OutHost; std::string m_InHost, m_OutHost;
int m_InPort, m_OutPort; int m_InPort, m_OutPort;
@ -215,14 +215,14 @@ namespace client
void SendReplyOK (const char * msg = nullptr); void SendReplyOK (const char * msg = nullptr);
void SendReplyError (const char * msg); void SendReplyError (const char * msg);
void SendRaw (const char * data); void SendRaw (const char * data);
void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out); void BuildStatusLine(bool currentTunnel, BOBDestination *destination, std::string &out);
private: private:
BOBCommandChannel& m_Owner; BOBCommandChannel& m_Owner;
boost::asio::ip::tcp::socket m_Socket; boost::asio::ip::tcp::socket m_Socket;
boost::asio::streambuf m_ReceiveBuffer, m_SendBuffer; boost::asio::streambuf m_ReceiveBuffer, m_SendBuffer;
bool m_IsOpen, m_IsQuiet, m_IsActive; bool m_IsOpen, m_IsQuiet, m_IsActive;
std::string m_Nickname, m_InHost, m_OutHost; std::string m_Nickname, m_InHost, m_OutHost;
int m_InPort, m_OutPort; int m_InPort, m_OutPort;
@ -269,4 +269,3 @@ namespace client
} }
#endif #endif

@ -52,18 +52,18 @@ namespace client
// SAM // SAM
bool sam; i2p::config::GetOption("sam.enabled", sam); bool sam; i2p::config::GetOption("sam.enabled", sam);
if (sam) if (sam)
{ {
std::string samAddr; i2p::config::GetOption("sam.address", samAddr); std::string samAddr; i2p::config::GetOption("sam.address", samAddr);
uint16_t samPort; i2p::config::GetOption("sam.port", samPort); uint16_t samPort; i2p::config::GetOption("sam.port", samPort);
bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread); bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread);
LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort); LogPrint(eLogInfo, "Clients: starting SAM bridge at ", samAddr, ":", samPort);
try try
{ {
m_SamBridge = new SAMBridge (samAddr, samPort, singleThread); m_SamBridge = new SAMBridge (samAddr, samPort, singleThread);
m_SamBridge->Start (); m_SamBridge->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what()); LogPrint(eLogError, "Clients: Exception in SAM bridge: ", e.what());
ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ()); ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":", samPort, ": ", e.what ());
@ -76,12 +76,12 @@ namespace client
std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr); std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr);
uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort); uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort);
LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort); LogPrint(eLogInfo, "Clients: starting BOB command channel at ", bobAddr, ":", bobPort);
try try
{ {
m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort);
m_BOBCommandChannel->Start (); m_BOBCommandChannel->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what()); LogPrint(eLogError, "Clients: Exception in BOB bridge: ", e.what());
ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ()); ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ());
@ -95,12 +95,12 @@ namespace client
std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr); std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr);
uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort); uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort);
LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort); LogPrint(eLogInfo, "Clients: starting I2CP at ", i2cpAddr, ":", i2cpPort);
try try
{ {
m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort); m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort);
m_I2CPServer->Start (); m_I2CPServer->Start ();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what()); LogPrint(eLogError, "Clients: Exception in I2CP: ", e.what());
ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ()); ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ());
@ -407,13 +407,13 @@ namespace client
template<typename Section, typename Type> template<typename Section, typename Type>
std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const
{ {
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value)); return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value));
} }
template<typename Section> template<typename Section>
std::string ClientContext::GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const std::string ClientContext::GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const
{ {
return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value); return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value);
} }
template<typename Section> template<typename Section>
@ -423,13 +423,13 @@ namespace client
{ {
if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group)) if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group))
options[it.first] = it.second.get_value (""); options[it.first] = it.second.get_value ("");
} }
} }
template<typename Section> template<typename Section>
void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const void ClientContext::ReadI2CPOptions (const Section& section, std::map<std::string, std::string>& options) const
{ {
options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH); options[I2CP_PARAM_INBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH);
options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH); options[I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH);
options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY); options[I2CP_PARAM_INBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY);
options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY); options[I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY] = GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY);
@ -528,10 +528,10 @@ namespace client
{ {
std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE); std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE);
if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT
|| type == I2P_TUNNELS_SECTION_TYPE_SOCKS || type == I2P_TUNNELS_SECTION_TYPE_SOCKS
|| type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS || type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS
|| type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY || type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY
|| type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT)
{ {
// mandatory params // mandatory params
std::string dest; std::string dest;
@ -640,9 +640,9 @@ namespace client
} }
} }
else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER
|| type == I2P_TUNNELS_SECTION_TYPE_HTTP || type == I2P_TUNNELS_SECTION_TYPE_HTTP
|| type == I2P_TUNNELS_SECTION_TYPE_IRC || type == I2P_TUNNELS_SECTION_TYPE_IRC
|| type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER)
{ {
// mandatory params // mandatory params
std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST); std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST);
@ -699,7 +699,7 @@ namespace client
continue; continue;
} }
std::shared_ptr<I2PServerTunnel> serverTunnel; std::shared_ptr<I2PServerTunnel> serverTunnel;
if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) if (type == I2P_TUNNELS_SECTION_TYPE_HTTP)
serverTunnel = std::make_shared<I2PServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip); serverTunnel = std::make_shared<I2PServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip);
else if (type == I2P_TUNNELS_SECTION_TYPE_IRC) else if (type == I2P_TUNNELS_SECTION_TYPE_IRC)
@ -745,7 +745,7 @@ namespace client
ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ());
} }
ins.first->second->isUpdated = true; ins.first->second->isUpdated = true;
LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists");
} }
} }
@ -769,9 +769,9 @@ namespace client
std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys);
std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr);
uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort);
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL); std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL);
bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper); bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper);
i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType);
LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); LogPrint(eLogInfo, "Clients: starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort);
if (httpProxyKeys.length () > 0) if (httpProxyKeys.length () > 0)
{ {
@ -786,12 +786,12 @@ namespace client
else else
LogPrint(eLogError, "Clients: failed to load HTTP Proxy key"); LogPrint(eLogError, "Clients: failed to load HTTP Proxy key");
} }
try try
{ {
m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, localDestination); m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, httpOutProxyURL, httpAddresshelper, localDestination);
m_HttpProxy->Start(); m_HttpProxy->Start();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what()); LogPrint(eLogError, "Clients: Exception in HTTP Proxy: ", e.what());
ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ()); ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ());
@ -826,13 +826,13 @@ namespace client
else else
LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key"); LogPrint(eLogError, "Clients: failed to load SOCKS Proxy key");
} }
try try
{ {
m_SocksProxy = new i2p::proxy::SOCKSProxy("SOCKS", socksProxyAddr, socksProxyPort, m_SocksProxy = new i2p::proxy::SOCKSProxy("SOCKS", socksProxyAddr, socksProxyPort,
socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination); socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination);
m_SocksProxy->Start(); m_SocksProxy->Start();
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what()); LogPrint(eLogError, "Clients: Exception in SOCKS Proxy: ", e.what());
ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ()); ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ());

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save