Compare commits

...

12 Commits

Author SHA1 Message Date
orignal
dcbe6cfaf2 Update RTO calculation and windows reseting algorithm 2024-12-10 17:49:11 -05:00
orignal
3534b9c499 don't create EVP_CIPHER_CTX for each AEAD/Chacha20/Poly1305 message 2024-12-09 20:59:59 -05:00
orignal
a7021a8283 Merge pull request #2136 from Vort/xp_fix
fix Windows XP build
2024-12-09 08:00:01 -05:00
Vort
946e523554 fix Windows XP build 2024-12-09 02:49:43 +02:00
r4sas
cdd528c51f [gha] disable winxp build
Signed-off-by: r4sas <r4sas@i2pmail.org>
2024-12-08 23:50:16 +03:00
orignal
1a748aebf1 removed depereated section from config 2024-12-08 11:33:30 -05:00
orignal
f23a7f569b pass iv to AES Encrypt/Decrypt directly. aes-test added 2024-12-08 11:08:17 -05:00
orignal
48b62340cc exclude AESNI option 2024-12-07 15:27:23 -05:00
orignal
65da550d19 fix bug with unexpected stream closing 2024-12-07 15:03:18 -05:00
orignal
786da057f2 always use openssl for AES 2024-12-06 20:25:22 -05:00
orignal
097813a6ca Merge pull request #2131 from rex4539/typos
Fix typos
2024-12-06 20:15:25 -05:00
Dimitris Apostolou
226257aa71 Fix typos 2024-12-06 17:11:31 +02:00
34 changed files with 410 additions and 736 deletions

View File

@@ -230,8 +230,10 @@ jobs:
run: | run: |
cd MINGW-packages/mingw-w64-boost cd MINGW-packages/mingw-w64-boost
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm --nocheck
- name: Remove boost packages
run: pacman --noconfirm -R mingw-w64-i686-boost mingw-w64-i686-boost-libs
- name: Install boost package - name: Install boost package
run: pacman --noconfirm -U --overwrite MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst run: pacman --noconfirm -U MINGW-packages/mingw-w64-boost/mingw-w64-i686-*-any.pkg.tar.zst
# Building i2pd # Building i2pd
- name: Build application - name: Build application

View File

@@ -29,7 +29,6 @@ DAEMON_SRC_DIR := daemon
# import source files lists # import source files lists
include filelist.mk include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no) USE_STATIC := $(or $(USE_STATIC),no)
USE_UPNP := $(or $(USE_UPNP),no) USE_UPNP := $(or $(USE_UPNP),no)
DEBUG := $(or $(DEBUG),yes) DEBUG := $(or $(DEBUG),yes)

View File

@@ -30,13 +30,6 @@ ifeq ($(USE_UPNP),yes)
INCFLAGS += -I${UPNPROOT}/include INCFLAGS += -I${UPNPROOT}/include
endif endif
ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
NEEDED_CXXFLAGS += -maes
DEFINES += -D__AES__
endif
endif
install: all install: all
install -d ${PREFIX}/bin install -d ${PREFIX}/bin
install -m 755 ${I2PD} ${PREFIX}/bin install -m 755 ${I2PD} ${PREFIX}/bin

View File

@@ -51,13 +51,6 @@ ifeq ($(USE_UPNP),yes)
DEFINES += -DUSE_UPNP DEFINES += -DUSE_UPNP
endif endif
ifeq ($(USE_AESNI),yes)
ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64, $(SYS))) # only x86-based CPU supports that
NEEDED_CXXFLAGS += -maes
DEFINES += -D__AES__
endif
endif
install: all install: all
install -d ${PREFIX}/bin install -d ${PREFIX}/bin
install -m 755 ${I2PD} ${PREFIX}/bin install -m 755 ${I2PD} ${PREFIX}/bin

View File

@@ -42,12 +42,6 @@ ifeq ($(USE_WIN32_APP), yes)
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
endif endif
ifeq ($(USE_AESNI),yes)
NEEDED_CXXFLAGS += -maes
LDFLAGS += -maes
DEFINES += -D__AES__
endif
ifeq ($(USE_ASLR),yes) ifeq ($(USE_ASLR),yes)
LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols LDFLAGS += -Wl,--nxcompat -Wl,--high-entropy-va -Wl,--dynamicbase,--export-all-symbols
endif endif

View File

@@ -25,9 +25,5 @@ endif
OSARCH = $(shell uname -p) OSARCH = $(shell uname -p)
ifneq ($(OSARCH),powerpc) ifneq ($(OSARCH),powerpc)
ifeq ($(USE_AESNI),yes)
CXXFLAGS += -D__AES__ -maes
else
CXXFLAGS += -msse CXXFLAGS += -msse
endif
endif endif

View File

@@ -29,7 +29,6 @@ project(
) )
# configurable options # configurable options
option(WITH_AESNI "Use AES-NI instructions set" ON)
option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_HARDENING "Use hardening compiler flags" OFF)
option(WITH_LIBRARY "Build library" ON) option(WITH_LIBRARY "Build library" ON)
option(WITH_BINARY "Build binary" ON) option(WITH_BINARY "Build binary" ON)
@@ -185,16 +184,6 @@ if(UNIX)
endif() endif()
endif() endif()
# Note: AES-NI and AVX is available on x86-based CPU's.
# Here also ARM64 implementation, but currently we don't support it.
# MSVC is not supported due to different ASM processing, so we hope OpenSSL has its own checks to run optimized code.
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
endif()
add_definitions(-D__AES__)
endif()
if(WITH_ADDRSANITIZER) if(WITH_ADDRSANITIZER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
@@ -335,7 +324,6 @@ message(STATUS "Architecture : ${ARCHITECTURE}")
message(STATUS "Compiler flags : ${CMAKE_CXX_FLAGS}") message(STATUS "Compiler flags : ${CMAKE_CXX_FLAGS}")
message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
message(STATUS "Options:") message(STATUS "Options:")
message(STATUS " AESNI : ${WITH_AESNI}")
message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " HARDENING : ${WITH_HARDENING}")
message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " BINARY : ${WITH_BINARY}") message(STATUS " BINARY : ${WITH_BINARY}")

View File

@@ -277,9 +277,3 @@ verify = true
## Save full addresses on disk (default: true) ## Save full addresses on disk (default: true)
# addressbook = true # addressbook = true
[cpuext]
## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
# aesni = true
## Force usage of CPU instructions set, even if they not found (default: false)
## DO NOT TOUCH that option if you really don't know what are you doing!
# force = false

View File

@@ -149,12 +149,10 @@ namespace util
LogPrint(eLogDebug, "FS: Certificates directory: ", certsdir); LogPrint(eLogDebug, "FS: Certificates directory: ", certsdir);
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
bool ssu; i2p::config::GetOption("ssu", ssu); bool ssu; i2p::config::GetOption("ssu", ssu);
if (!ssu && i2p::config::IsDefault ("precomputation.elgamal")) if (!ssu && i2p::config::IsDefault ("precomputation.elgamal"))
precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly precomputation = false; // we don't elgamal table if no ssu, unless it's specified explicitly
i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt); i2p::crypto::InitCrypto (precomputation);
i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces i2p::transport::InitAddressFromIface (); // get address4/6 from interfaces

View File

@@ -1,68 +0,0 @@
/*
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include "CPU.h"
#include "Log.h"
#ifndef bit_AES
#define bit_AES (1 << 25)
#endif
#if defined(__GNUC__) && __GNUC__ < 6 && IS_X86
#include <cpuid.h>
#endif
#ifdef _MSC_VER
#include <intrin.h>
#endif
namespace i2p
{
namespace cpu
{
bool aesni = false;
inline bool cpu_support_aes()
{
#if IS_X86
#if defined(__clang__)
# if (__clang_major__ >= 6)
__builtin_cpu_init();
# endif
return __builtin_cpu_supports("aes");
#elif (defined(__GNUC__) && __GNUC__ >= 6)
__builtin_cpu_init();
return __builtin_cpu_supports("aes");
#elif (defined(__GNUC__) && __GNUC__ < 6)
int cpu_info[4];
bool flag = false;
__cpuid(0, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
if (cpu_info[0] >= 0x00000001) {
__cpuid(0x00000001, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
flag = ((cpu_info[2] & bit_AES) != 0);
}
return flag;
#elif defined(_MSC_VER)
int cpu_info[4];
__cpuid(cpu_info, 1);
return ((cpu_info[2] & bit_AES) != 0);
#endif
#endif
return false;
}
void Detect(bool AesSwitch, bool force)
{
if ((cpu_support_aes() && AesSwitch) || (AesSwitch && force)) {
aesni = true;
}
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
}
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2023, The PurpleI2P Project * Copyright (c) 2013-2024, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@@ -21,20 +21,4 @@
# define IS_X86_64 0 # define IS_X86_64 0
#endif #endif
#if defined(__AES__) && !defined(_MSC_VER) && IS_X86
# define SUPPORTS_AES 1
#else
# define SUPPORTS_AES 0
#endif
namespace i2p
{
namespace cpu
{
extern bool aesni;
void Detect(bool AesSwitch, bool force);
}
}
#endif #endif

View File

@@ -117,7 +117,7 @@ namespace config {
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url") ("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper") ("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper")
("httpproxy.senduseragent", value<bool>()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by deafult") ("httpproxy.senduseragent", value<bool>()->default_value(false), "Pass through user's User-Agent if enabled. Disabled by default")
("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type")
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type") ("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key") ("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key")
@@ -315,11 +315,11 @@ namespace config {
("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)") ("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)")
; ;
options_description cpuext("CPU encryption extensions options"); options_description cpuext("CPU encryption extensions options. Deprecated");
cpuext.add_options() cpuext.add_options()
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") ("cpuext.aesni", bool_switch()->default_value(true), "Deprecated option")
("cpuext.avx", bool_switch()->default_value(false), "Deprecated option") ("cpuext.avx", bool_switch()->default_value(false), "Deprecated option")
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") ("cpuext.force", bool_switch()->default_value(false), "Deprecated option")
; ;
options_description meshnets("Meshnet transports options"); options_description meshnets("Meshnet transports options");

View File

@@ -19,6 +19,7 @@
#if OPENSSL_HKDF #if OPENSSL_HKDF
#include <openssl/kdf.h> #include <openssl/kdf.h>
#endif #endif
#include "CPU.h"
#include "Crypto.h" #include "Crypto.h"
#include "Ed25519.h" #include "Ed25519.h"
#include "I2PEndian.h" #include "I2PEndian.h"
@@ -441,9 +442,8 @@ namespace crypto
// encrypt // encrypt
CBCEncryption encryption; CBCEncryption encryption;
encryption.SetKey (shared); encryption.SetKey (shared);
encryption.SetIV (iv);
encrypted[257] = 0; encrypted[257] = 0;
encryption.Encrypt (m, 256, encrypted + 258); encryption.Encrypt (m, 256, iv, encrypted + 258);
EC_POINT_free (p); EC_POINT_free (p);
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
@@ -476,8 +476,7 @@ namespace crypto
uint8_t m[256]; uint8_t m[256];
CBCDecryption decryption; CBCDecryption decryption;
decryption.SetKey (shared); decryption.SetKey (shared);
decryption.SetIV (iv); decryption.Decrypt (encrypted + 258, 256, iv, m);
decryption.Decrypt (encrypted + 258, 256, m);
// verify and copy // verify and copy
uint8_t hash[32]; uint8_t hash[32];
SHA256 (m + 33, 222, hash); SHA256 (m + 33, 222, hash);
@@ -515,440 +514,114 @@ namespace crypto
} }
// AES // AES
#if SUPPORTS_AES ECBEncryption::ECBEncryption ()
#define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pxor %%xmm2, %%xmm1 \n" \
"movaps %%xmm1, "#round0"(%[sched]) \n" \
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
"movaps %%xmm3, %%xmm4 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pxor %%xmm2, %%xmm3 \n" \
"movaps %%xmm3, "#round1"(%[sched]) \n"
#endif
#if SUPPORTS_AES
void ECBCryptoAESNI::ExpandKey (const AESKey& key)
{ {
__asm__ m_Ctx = EVP_CIPHER_CTX_new ();
(
"movups (%[key]), %%xmm1 \n"
"movups 16(%[key]), %%xmm3 \n"
"movaps %%xmm1, (%[sched]) \n"
"movaps %%xmm3, 16(%[sched]) \n"
"aeskeygenassist $1, %%xmm3, %%xmm2 \n"
KeyExpansion256(32,48)
"aeskeygenassist $2, %%xmm3, %%xmm2 \n"
KeyExpansion256(64,80)
"aeskeygenassist $4, %%xmm3, %%xmm2 \n"
KeyExpansion256(96,112)
"aeskeygenassist $8, %%xmm3, %%xmm2 \n"
KeyExpansion256(128,144)
"aeskeygenassist $16, %%xmm3, %%xmm2 \n"
KeyExpansion256(160,176)
"aeskeygenassist $32, %%xmm3, %%xmm2 \n"
KeyExpansion256(192,208)
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
// key expansion final
"pshufd $0xff, %%xmm2, %%xmm2 \n"
"movaps %%xmm1, %%xmm4 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pxor %%xmm2, %%xmm1 \n"
"movups %%xmm1, 224(%[sched]) \n"
: // output
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
);
}
#endif
#if SUPPORTS_AES
#define EncryptAES256(sched) \
"pxor (%["#sched"]), %%xmm0 \n" \
"aesenc 16(%["#sched"]), %%xmm0 \n" \
"aesenc 32(%["#sched"]), %%xmm0 \n" \
"aesenc 48(%["#sched"]), %%xmm0 \n" \
"aesenc 64(%["#sched"]), %%xmm0 \n" \
"aesenc 80(%["#sched"]), %%xmm0 \n" \
"aesenc 96(%["#sched"]), %%xmm0 \n" \
"aesenc 112(%["#sched"]), %%xmm0 \n" \
"aesenc 128(%["#sched"]), %%xmm0 \n" \
"aesenc 144(%["#sched"]), %%xmm0 \n" \
"aesenc 160(%["#sched"]), %%xmm0 \n" \
"aesenc 176(%["#sched"]), %%xmm0 \n" \
"aesenc 192(%["#sched"]), %%xmm0 \n" \
"aesenc 208(%["#sched"]), %%xmm0 \n" \
"aesenclast 224(%["#sched"]), %%xmm0 \n"
#endif
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
(
"movups (%[in]), %%xmm0 \n"
EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
:
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
: "%xmm0", "memory"
);
}
else
#endif
{
AES_encrypt (in->buf, out->buf, &m_Key);
}
} }
#if SUPPORTS_AES ECBEncryption::~ECBEncryption ()
#define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \
"aesdec 208(%["#sched"]), %%xmm0 \n" \
"aesdec 192(%["#sched"]), %%xmm0 \n" \
"aesdec 176(%["#sched"]), %%xmm0 \n" \
"aesdec 160(%["#sched"]), %%xmm0 \n" \
"aesdec 144(%["#sched"]), %%xmm0 \n" \
"aesdec 128(%["#sched"]), %%xmm0 \n" \
"aesdec 112(%["#sched"]), %%xmm0 \n" \
"aesdec 96(%["#sched"]), %%xmm0 \n" \
"aesdec 80(%["#sched"]), %%xmm0 \n" \
"aesdec 64(%["#sched"]), %%xmm0 \n" \
"aesdec 48(%["#sched"]), %%xmm0 \n" \
"aesdec 32(%["#sched"]), %%xmm0 \n" \
"aesdec 16(%["#sched"]), %%xmm0 \n" \
"aesdeclast (%["#sched"]), %%xmm0 \n"
#endif
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
#if SUPPORTS_AES if (m_Ctx)
if(i2p::cpu::aesni) EVP_CIPHER_CTX_free (m_Ctx);
{
__asm__
(
"movups (%[in]), %%xmm0 \n"
DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
:
: [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out)
: "%xmm0", "memory"
);
}
else
#endif
{
AES_decrypt (in->buf, out->buf, &m_Key);
}
} }
#if SUPPORTS_AES void ECBEncryption::Encrypt (const uint8_t * in, uint8_t * out)
#define CallAESIMC(offset) \
"movaps "#offset"(%[shed]), %%xmm0 \n" \
"aesimc %%xmm0, %%xmm0 \n" \
"movaps %%xmm0, "#offset"(%[shed]) \n"
#endif
void ECBEncryption::SetKey (const AESKey& key)
{ {
#if SUPPORTS_AES EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_ecb(), NULL, m_Key, NULL);
if(i2p::cpu::aesni) EVP_CIPHER_CTX_set_padding (m_Ctx, 0);
{ int len;
ExpandKey (key); EVP_EncryptUpdate (m_Ctx, out, &len, in, 16);
} EVP_EncryptFinal_ex (m_Ctx, out + len, &len);
else
#endif
{
AES_set_encrypt_key (key, 256, &m_Key);
}
} }
void ECBDecryption::SetKey (const AESKey& key) ECBDecryption::ECBDecryption ()
{ {
#if SUPPORTS_AES m_Ctx = EVP_CIPHER_CTX_new ();
if(i2p::cpu::aesni)
{
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
__asm__
(
CallAESIMC(16)
CallAESIMC(32)
CallAESIMC(48)
CallAESIMC(64)
CallAESIMC(80)
CallAESIMC(96)
CallAESIMC(112)
CallAESIMC(128)
CallAESIMC(144)
CallAESIMC(160)
CallAESIMC(176)
CallAESIMC(192)
CallAESIMC(208)
:
: [shed]"r"(GetKeySchedule ())
: "%xmm0", "memory"
);
}
else
#endif
{
AES_set_decrypt_key (key, 256, &m_Key);
}
} }
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) ECBDecryption::~ECBDecryption ()
{ {
#if SUPPORTS_AES if (m_Ctx)
if(i2p::cpu::aesni) EVP_CIPHER_CTX_free (m_Ctx);
{
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"1: \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory"
);
}
else
#endif
{
for (int i = 0; i < numBlocks; i++)
{
*m_LastBlock.GetChipherBlock () ^= in[i];
m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ());
out[i] = *m_LastBlock.GetChipherBlock ();
}
}
} }
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) void ECBDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{
EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_ecb(), NULL, m_Key, NULL);
EVP_CIPHER_CTX_set_padding (m_Ctx, 0);
int len;
EVP_DecryptUpdate (m_Ctx, out, &len, in, 16);
EVP_DecryptFinal_ex (m_Ctx, out + len, &len);
}
CBCEncryption::CBCEncryption ()
{
m_Ctx = EVP_CIPHER_CTX_new ();
}
CBCEncryption::~CBCEncryption ()
{
if (m_Ctx)
EVP_CIPHER_CTX_free (m_Ctx);
}
void CBCEncryption::Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out)
{ {
// len/16 // len/16
int numBlocks = len >> 4; EVP_EncryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, iv);
if (numBlocks > 0) EVP_CIPHER_CTX_set_padding (m_Ctx, 0);
Encrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); int l;
EVP_EncryptUpdate (m_Ctx, out, &l, in, len);
EVP_EncryptFinal_ex (m_Ctx, out + l, &l);
} }
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) CBCDecryption::CBCDecryption ()
{ {
#if SUPPORTS_AES m_Ctx = EVP_CIPHER_CTX_new ();
if(i2p::cpu::aesni)
{
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
"movups %%xmm0, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory"
);
}
else
#endif
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) CBCDecryption::~CBCDecryption ()
{ {
#if SUPPORTS_AES if (m_Ctx)
if(i2p::cpu::aesni) EVP_CIPHER_CTX_free (m_Ctx);
{
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"1: \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz 1b \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
}
else
#endif
{
for (int i = 0; i < numBlocks; i++)
{
ChipherBlock tmp = in[i];
m_ECBDecryption.Decrypt (in + i, out + i);
out[i] ^= *m_IV.GetChipherBlock ();
*m_IV.GetChipherBlock () = tmp;
}
}
} }
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) void CBCDecryption::Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out)
{ {
int numBlocks = len >> 4; // len/16
if (numBlocks > 0) EVP_DecryptInit_ex (m_Ctx, EVP_aes_256_cbc(), NULL, m_Key, iv);
Decrypt (numBlocks, (const ChipherBlock *)in, (ChipherBlock *)out); EVP_CIPHER_CTX_set_padding (m_Ctx, 0);
} int l;
EVP_DecryptUpdate (m_Ctx, out, &l, in, len);
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) EVP_DecryptFinal_ex (m_Ctx, out + l, &l);
{
#if SUPPORTS_AES
if(i2p::cpu::aesni)
{
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n"
"movups %%xmm0, (%[iv]) \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
:
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory"
);
}
else
#endif
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
} }
void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out) void TunnelEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES uint8_t iv[16];
if(i2p::cpu::aesni) m_IVEncryption.Encrypt (in, iv); // iv
{ m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, iv, out + 16); // data
__asm__ m_IVEncryption.Encrypt (iv, out); // double iv
(
// encrypt IV
"movups (%[in]), %%xmm0 \n"
EncryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n"
// double IV encryption
EncryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n"
// encrypt data, IV is xmm1
"1: \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched_l)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n"
"dec %[num] \n"
"jnz 1b \n"
:
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "cc", "memory"
);
}
else
#endif
{
m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerEncryption.SetIV (out);
m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
}
} }
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{ {
#if SUPPORTS_AES uint8_t iv[16];
if(i2p::cpu::aesni) m_IVDecryption.Decrypt (in, iv); // iv
{ m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, iv, out + 16); // data
__asm__ m_IVDecryption.Decrypt (iv, out); // double iv
(
// decrypt IV
"movups (%[in]), %%xmm0 \n"
DecryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n"
// double IV encryption
DecryptAES256(sched_iv)
"movups %%xmm0, (%[out]) \n"
// decrypt data, IV is xmm1
"1: \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched_l)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n"
"jnz 1b \n"
:
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.ECB().GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
}
else
#endif
{
m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv
m_LayerDecryption.SetIV (out);
m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv
}
} }
// AEAD/ChaCha20/Poly1305 // AEAD/ChaCha20/Poly1305
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt) static bool AEADChaCha20Poly1305 (EVP_CIPHER_CTX * ctx, const uint8_t * msg, size_t msgLen,
const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt)
{ {
if (len < msgLen) return false; if (!ctx || len < msgLen) return false;
if (encrypt && len < msgLen + 16) return false; if (encrypt && len < msgLen + 16) return false;
bool ret = true; bool ret = true;
int outlen = 0; int outlen = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
if (encrypt) if (encrypt)
{ {
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
@@ -978,24 +651,64 @@ namespace crypto
EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen); EVP_DecryptUpdate(ctx, buf, &outlen, msg, msgLen);
ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0; ret = EVP_DecryptFinal_ex(ctx, buf + outlen, &outlen) > 0;
} }
return ret;
}
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt)
{
EVP_CIPHER_CTX * ctx = EVP_CIPHER_CTX_new ();
auto ret = AEADChaCha20Poly1305 (ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, encrypt);
EVP_CIPHER_CTX_free (ctx); EVP_CIPHER_CTX_free (ctx);
return ret; return ret;
} }
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac) AEADChaCha20Poly1305Encryptor::AEADChaCha20Poly1305Encryptor ()
{
m_Ctx = EVP_CIPHER_CTX_new ();
}
AEADChaCha20Poly1305Encryptor::~AEADChaCha20Poly1305Encryptor ()
{
if (m_Ctx)
EVP_CIPHER_CTX_free (m_Ctx);
}
bool AEADChaCha20Poly1305Encryptor::Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, true);
}
void AEADChaCha20Poly1305Encryptor::Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs,
const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
{ {
if (bufs.empty ()) return; if (bufs.empty ()) return;
int outlen = 0; int outlen = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); EVP_EncryptInit_ex(m_Ctx, EVP_chacha20_poly1305(), 0, 0, 0);
EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0); EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0); EVP_EncryptInit_ex(m_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(m_Ctx, it.first, &outlen, it.first, it.second);
EVP_EncryptFinal_ex(ctx, NULL, &outlen); EVP_EncryptFinal_ex(m_Ctx, NULL, &outlen);
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac); EVP_CIPHER_CTX_ctrl(m_Ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
EVP_CIPHER_CTX_free (ctx); }
AEADChaCha20Poly1305Decryptor::AEADChaCha20Poly1305Decryptor ()
{
m_Ctx = EVP_CIPHER_CTX_new ();
}
AEADChaCha20Poly1305Decryptor::~AEADChaCha20Poly1305Decryptor ()
{
if (m_Ctx)
EVP_CIPHER_CTX_free (m_Ctx);
}
bool AEADChaCha20Poly1305Decryptor::Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, false);
} }
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)
@@ -1157,9 +870,8 @@ namespace crypto
} }
}*/ }*/
void InitCrypto (bool precomputation, bool aesni, bool force) void InitCrypto (bool precomputation)
{ {
i2p::cpu::Detect (aesni, force);
/* auto numLocks = CRYPTO_num_locks(); /* auto numLocks = CRYPTO_num_locks();
for (int i = 0; i < numLocks; i++) for (int i = 0; i < numLocks; i++)
m_OpenSSLMutexes.emplace_back (new std::mutex); m_OpenSSLMutexes.emplace_back (new std::mutex);

View File

@@ -25,7 +25,6 @@
#include "Base.h" #include "Base.h"
#include "Tag.h" #include "Tag.h"
#include "CPU.h"
// recognize openssl version and features // recognize openssl version and features
#if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 #if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
@@ -85,142 +84,70 @@ namespace crypto
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
// AES // AES
struct ChipherBlock
{
uint8_t buf[16];
void operator^=(const ChipherBlock& other) // XOR
{
if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
{
for (int i = 0; i < 4; i++)
reinterpret_cast<uint32_t *>(buf)[i] ^= reinterpret_cast<const uint32_t *>(other.buf)[i];
}
else
{
for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i];
}
}
};
typedef i2p::data::Tag<32> AESKey; typedef i2p::data::Tag<32> AESKey;
template<size_t sz>
class AESAlignedBuffer // 16 bytes alignment
{
public:
AESAlignedBuffer ()
{
m_Buf = m_UnalignedBuffer;
uint8_t rem = ((size_t)m_Buf) & 0x0f;
if (rem)
m_Buf += (16 - rem);
}
operator uint8_t * () { return m_Buf; };
operator const uint8_t * () const { return m_Buf; };
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
private:
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
uint8_t * m_Buf;
};
#if SUPPORTS_AES
class ECBCryptoAESNI
{
public:
uint8_t * GetKeySchedule () { return m_KeySchedule; };
protected:
void ExpandKey (const AESKey& key);
private:
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
};
#endif
#if SUPPORTS_AES
class ECBEncryption: public ECBCryptoAESNI
#else
class ECBEncryption class ECBEncryption
#endif
{ {
public: public:
void SetKey (const AESKey& key); ECBEncryption ();
~ECBEncryption ();
void Encrypt(const ChipherBlock * in, ChipherBlock * out); void SetKey (const uint8_t * key) { m_Key = key; };
void Encrypt(const uint8_t * in, uint8_t * out);
private: private:
AES_KEY m_Key;
AESKey m_Key;
EVP_CIPHER_CTX * m_Ctx;
}; };
#if SUPPORTS_AES
class ECBDecryption: public ECBCryptoAESNI
#else
class ECBDecryption class ECBDecryption
#endif
{ {
public: public:
void SetKey (const AESKey& key); ECBDecryption ();
void Decrypt (const ChipherBlock * in, ChipherBlock * out); ~ECBDecryption ();
void SetKey (const uint8_t * key) { m_Key = key; };
void Decrypt (const uint8_t * in, uint8_t * out);
private: private:
AES_KEY m_Key;
AESKey m_Key;
EVP_CIPHER_CTX * m_Ctx;
}; };
class CBCEncryption class CBCEncryption
{ {
public: public:
CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); }; CBCEncryption ();
~CBCEncryption ();
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes void Encrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);
void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_LastBlock, 16); };
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Encrypt (const uint8_t * in, uint8_t * out); // one block
ECBEncryption & ECB() { return m_ECBEncryption; }
private: private:
AESAlignedBuffer<16> m_LastBlock; AESKey m_Key;
EVP_CIPHER_CTX * m_Ctx;
ECBEncryption m_ECBEncryption;
}; };
class CBCDecryption class CBCDecryption
{ {
public: public:
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); }; CBCDecryption ();
~CBCDecryption ();
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetKey (const uint8_t * key) { m_Key = key; }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes void Decrypt (const uint8_t * in, size_t len, const uint8_t * iv, uint8_t * out);
void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_IV, 16); };
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Decrypt (const uint8_t * in, uint8_t * out); // one block
ECBDecryption & ECB() { return m_ECBDecryption; }
private: private:
AESAlignedBuffer<16> m_IV; AESKey m_Key;
ECBDecryption m_ECBDecryption; EVP_CIPHER_CTX * m_Ctx;
}; };
class TunnelEncryption // with double IV encryption class TunnelEncryption // with double IV encryption
@@ -260,9 +187,41 @@ namespace crypto
}; };
// AEAD/ChaCha20/Poly1305 // AEAD/ChaCha20/Poly1305
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad class AEADChaCha20Poly1305Encryptor
{
public:
AEADChaCha20Poly1305Encryptor ();
~AEADChaCha20Poly1305Encryptor ();
bool Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag
void Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
private:
EVP_CIPHER_CTX * m_Ctx;
};
class AEADChaCha20Poly1305Decryptor
{
public:
AEADChaCha20Poly1305Decryptor ();
~AEADChaCha20Poly1305Decryptor ();
bool Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); // msgLen is len without tag
private:
EVP_CIPHER_CTX * m_Ctx;
};
bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
// ChaCha20 // ChaCha20
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);
@@ -288,7 +247,7 @@ namespace crypto
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate // init and terminate
void InitCrypto (bool precomputation, bool aesni, bool force); void InitCrypto (bool precomputation);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }

View File

@@ -160,7 +160,7 @@ namespace garlic
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
m_Destination->Encrypt ((uint8_t *)&elGamal, buf); m_Destination->Encrypt ((uint8_t *)&elGamal, buf);
m_Encryption.SetIV (iv); m_IV = iv;
buf += 514; buf += 514;
len += 514; len += 514;
} }
@@ -170,7 +170,7 @@ namespace garlic
memcpy (buf, tag, 32); memcpy (buf, tag, 32);
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(tag, 32, iv); SHA256(tag, 32, iv);
m_Encryption.SetIV (iv); m_IV = iv;
buf += 32; buf += 32;
len += 32; len += 32;
} }
@@ -210,7 +210,7 @@ namespace garlic
size_t rem = blockSize % 16; size_t rem = blockSize % 16;
if (rem) if (rem)
blockSize += (16-rem); //padding blockSize += (16-rem); //padding
m_Encryption.Encrypt(buf, blockSize, buf); m_Encryption.Encrypt(buf, blockSize, m_IV, buf);
return blockSize; return blockSize;
} }
@@ -514,8 +514,7 @@ namespace garlic
{ {
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(buf, 32, iv); SHA256(buf, 32, iv);
decryption->SetIV (iv); decryption->Decrypt (buf + 32, length - 32, iv, buf + 32);
decryption->Decrypt (buf + 32, length - 32, buf + 32);
HandleAESBlock (buf + 32, length - 32, decryption, msg->from); HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
found = true; found = true;
} }
@@ -533,8 +532,7 @@ namespace garlic
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey); auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
decryption->SetIV (iv); decryption->Decrypt(buf + 514, length - 514, iv, buf + 514);
decryption->Decrypt(buf + 514, length - 514, buf + 514);
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)) else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
@@ -550,7 +548,7 @@ namespace garlic
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 (eLogWarning, "Garlic: Incoming sessions come too ofter"); LogPrint (eLogWarning, "Garlic: Incoming sessions come too often");
} }
else else
LogPrint (eLogError, "Garlic: Failed to decrypt message"); LogPrint (eLogError, "Garlic: Failed to decrypt message");

View File

@@ -205,6 +205,7 @@ namespace garlic
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;
i2p::data::Tag<16> m_IV;
public: public:
@@ -286,7 +287,7 @@ namespace garlic
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
uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet
uint64_t m_LastIncomingSessionTimestamp; // in millseconds uint64_t m_LastIncomingSessionTimestamp; // in milliseconds
// incoming // incoming
int m_NumRatchetInboundTags; int m_NumRatchetInboundTags;
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;

View File

@@ -120,9 +120,8 @@ namespace transport
// encrypt X // encrypt X
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
encryption.SetKey (m_RemoteIdentHash); encryption.SetKey (m_RemoteIdentHash);
encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_IV, m_SessionRequestBuffer); // X
encryption.Encrypt (GetPub (), 32, m_SessionRequestBuffer); // X memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated
encryption.GetIV (m_IV); // save IV for SessionCreated
// encryption key for next block // encryption key for next block
if (!KDF1Alice ()) return false; if (!KDF1Alice ()) return false;
// fill options // fill options
@@ -161,8 +160,7 @@ namespace transport
// encrypt Y // encrypt Y
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
encryption.SetKey (i2p::context.GetIdentHash ()); encryption.SetKey (i2p::context.GetIdentHash ());
encryption.SetIV (m_IV); encryption.Encrypt (GetPub (), 32, m_IV, m_SessionCreatedBuffer); // Y
encryption.Encrypt (GetPub (), 32, m_SessionCreatedBuffer); // Y
// encryption key for next block (m_K) // encryption key for next block (m_K)
if (!KDF2Bob ()) return false; if (!KDF2Bob ()) return false;
uint8_t options[16]; uint8_t options[16];
@@ -208,9 +206,8 @@ namespace transport
// decrypt X // decrypt X
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetKey (i2p::context.GetIdentHash ());
decryption.SetIV (i2p::context.GetNTCP2IV ()); decryption.Decrypt (m_SessionRequestBuffer, 32, i2p::context.GetNTCP2IV (), GetRemotePub ());
decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ()); memcpy (m_IV, m_SessionRequestBuffer + 16, 16); // save last block as IV for SessionCreated
decryption.GetIV (m_IV); // save IV for SessionCreated
// decryption key for next block // decryption key for next block
if (!KDF1Bob ()) if (!KDF1Bob ())
{ {
@@ -268,8 +265,7 @@ namespace transport
// decrypt Y // decrypt Y
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (m_RemoteIdentHash); decryption.SetKey (m_RemoteIdentHash);
decryption.SetIV (m_IV); decryption.Decrypt (m_SessionCreatedBuffer, 32, m_IV, GetRemotePub ());
decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
// decryption key for next block (m_K) // decryption key for next block (m_K)
if (!KDF2Alice ()) if (!KDF2Alice ())
{ {
@@ -995,7 +991,7 @@ namespace transport
i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2); i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2);
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) if (m_Server.AEADChaCha20Poly1305Decrypt (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen))
{ {
LogPrint (eLogDebug, "NTCP2: Received message decrypted"); LogPrint (eLogDebug, "NTCP2: Received message decrypted");
ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16);
@@ -1184,7 +1180,7 @@ namespace transport
} }
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
i2p::crypto::AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers m_Server.AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers
SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block
// send buffers // send buffers
@@ -1215,7 +1211,7 @@ namespace transport
// encrypt // encrypt
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++; CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
i2p::crypto::AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2); m_Server.AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2);
SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer); SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer);
// send // send
m_IsSending = true; m_IsSending = true;
@@ -1984,5 +1980,17 @@ namespace transport
else else
m_Address4 = addr; m_Address4 = addr;
} }
void NTCP2Server::AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs,
const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
{
return m_Encryptor.Encrypt (bufs, key, nonce, mac);
}
bool NTCP2Server::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen,
const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
} }
} }

View File

@@ -272,6 +272,11 @@ namespace transport
auto& GetService () { return GetIOService (); }; auto& GetService () { return GetIOService (); };
auto& GetEstablisherService () { return m_EstablisherService.GetService (); }; auto& GetEstablisherService () { return m_EstablisherService.GetService (); };
std::mt19937& GetRng () { return m_Rng; }; std::mt19937& GetRng () { return m_Rng; };
void AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs,
const uint8_t * key, const uint8_t * nonce, uint8_t * mac);
bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false); bool AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming = false);
void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session); void RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session);
@@ -309,9 +314,12 @@ namespace transport
uint16_t m_ProxyPort; uint16_t m_ProxyPort;
boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::resolver m_Resolver;
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint; std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress; std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
std::mt19937 m_Rng; std::mt19937 m_Rng;
EstablisherService m_EstablisherService; EstablisherService m_EstablisherService;
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
public: public:

View File

@@ -637,7 +637,7 @@ namespace data
if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 1 hour if (checkForExpiration && uptime > i2p::transport::SSU2_TO_INTRODUCER_SESSION_DURATION) // 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;
bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no tranports bool isOffline = checkForExpiration && i2p::transport::transports.GetNumPeers () < NETDB_MIN_TRANSPORTS; // enough routers and uptime, but no transports
std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > > saveToDisk; std::list<std::pair<std::string, std::shared_ptr<RouterInfo::Buffer> > > saveToDisk;
std::list<std::string> removeFromDisk; std::list<std::string> removeFromDisk;

View File

@@ -1389,7 +1389,7 @@ namespace transport
excluded.insert (ident); excluded.insert (ident);
} }
// sesssion about to expire are not counted // session about to expire are not counted
for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++) for (auto i = introducers.size (); i < SSU2_MAX_NUM_INTRODUCERS + numOldSessions; i++)
{ {
auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded); auto introducer = i2p::data::netdb.GetRandomSSU2Introducer (v4, excluded);
@@ -1516,6 +1516,18 @@ namespace transport
} }
} }
bool SSU2Server::AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen,
const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return m_Encryptor.Encrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
bool SSU2Server::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen,
const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
{
return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to)
{ {

View File

@@ -82,6 +82,10 @@ namespace transport
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true); bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep, bool max = true);
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts); void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
std::mt19937& GetRng () { return m_Rng; } std::mt19937& GetRng () { return m_Rng; }
bool AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; } bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; }; bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from); void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
@@ -200,6 +204,8 @@ namespace transport
std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp) std::unordered_map<uint32_t, std::pair <std::weak_ptr<SSU2PeerTestSession>, uint64_t > > m_RequestedPeerTests; // nonce->(Alice, timestamp)
std::list<Packet *> m_ReceivedPacketsQueue; std::list<Packet *> m_ReceivedPacketsQueue;
mutable std::mutex m_ReceivedPacketsQueueMutex; mutable std::mutex m_ReceivedPacketsQueueMutex;
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
// proxy // proxy
bool m_IsThroughProxy; bool m_IsThroughProxy;

View File

@@ -68,7 +68,7 @@ namespace transport
void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len) void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len)
{ {
if (!ExtractEndpoint (buf, len, m_OurEndpoint)) if (!ExtractEndpoint (buf, len, m_OurEndpoint))
LogPrint (eLogWarning, "SSU2: Can't hanlde address block from peer test message"); LogPrint (eLogWarning, "SSU2: Can't handle address block from peer test message");
} }
void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len)
@@ -89,7 +89,7 @@ namespace transport
{ {
if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ())
{ {
m_PeerTestResendTimer.cancel (); // calcel delayed msg 6 if any m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any
m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ());
if (GetAddress ()) if (GetAddress ())
{ {

View File

@@ -349,7 +349,7 @@ namespace transport
void SSU2Session::Done () void SSU2Session::Done ()
{ {
m_Server.GetService ().post (std::bind (&SSU2Session::Terminate, shared_from_this ())); boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::Terminate, shared_from_this ()));
} }
void SSU2Session::SendLocalRouterInfo (bool update) void SSU2Session::SendLocalRouterInfo (bool update)
@@ -357,7 +357,7 @@ namespace transport
if (update || !IsOutgoing ()) if (update || !IsOutgoing ())
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
m_Server.GetService ().post ([s]() boost::asio::post (m_Server.GetService (), [s]()
{ {
if (!s->IsEstablished ()) return; if (!s->IsEstablished ()) return;
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
@@ -389,7 +389,7 @@ namespace transport
m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs); m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
} }
if (empty) if (empty)
m_Server.GetService ().post (std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ())); boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ()));
} }
void SSU2Session::PostI2NPMessages () void SSU2Session::PostI2NPMessages ()
@@ -1455,7 +1455,7 @@ namespace transport
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (m_SendPacketNum, nonce); CreateNonce (m_SendPacketNum, nonce);
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE, true); m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE);
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8)); header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8));
header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4)); header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
@@ -1495,8 +1495,8 @@ namespace transport
uint32_t packetNum = be32toh (header.h.packetNum); uint32_t packetNum = be32toh (header.h.packetNum);
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (packetNum, nonce); CreateNonce (packetNum, nonce);
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, payloadSize, header.buf, 16, if (!m_Server.AEADChaCha20Poly1305Decrypt (buf + 16, payloadSize, header.buf, 16,
m_KeyDataReceive, nonce, payload, payloadSize, false)) m_KeyDataReceive, nonce, payload, payloadSize))
{ {
LogPrint (eLogWarning, "SSU2: Data AEAD verification failed "); LogPrint (eLogWarning, "SSU2: Data AEAD verification failed ");
return; return;
@@ -2052,7 +2052,7 @@ namespace transport
auto vec = std::make_shared<std::vector<uint8_t> >(len); auto vec = std::make_shared<std::vector<uint8_t> >(len);
memcpy (vec->data (), buf, len); memcpy (vec->data (), buf, len);
auto s = shared_from_this (); auto s = shared_from_this ();
m_Server.GetService ().post ([s, vec, attempts]() boost::asio::post (m_Server.GetService (), [s, vec, attempts]()
{ {
LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1); LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1);
s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1); s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1);

View File

@@ -78,9 +78,9 @@ namespace stream
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_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0),
m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_RTO (INITIAL_RTO),
m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0),
m_Jitter (0), m_MinPacingTime (0), m_Jitter (0), m_MinPacingTime (0),
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0),
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
{ {
@@ -106,8 +106,8 @@ namespace stream
m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT), m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_RTT (INITIAL_RTT), m_SlowRTT (INITIAL_RTT), m_SlowRTT2 (INITIAL_RTT),
m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0), m_WindowSize (INITIAL_WINDOW_SIZE), m_LastWindowDropSize (0), m_WindowDropTargetSize (0), m_WindowIncCounter (0),
m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()), m_RTO (INITIAL_RTO), m_AckDelay (local.GetOwner ()->GetStreamingAckDelay ()),
m_PrevRTTSample (INITIAL_RTT), m_Jitter (0), m_MinPacingTime (0), m_PrevRTTSample (INITIAL_RTT), m_WindowSizeTail (0), m_Jitter (0), m_MinPacingTime (0),
m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_RemoteLeaseChangeTime (0), m_PacingTime (INITIAL_PACING_TIME), m_PacingTimeRem (0), m_LastSendTime (0), m_LastACKRecieveTime (0), m_ACKRecieveInterval (local.GetOwner ()->GetStreamingAckDelay ()), m_RemoteLeaseChangeTime (0),
m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed m_LastACKSendTime (0), m_PacketACKInterval (1), m_PacketACKIntervalRem (0), // for limit inbound speed
m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU) m_NumResendAttempts (0), m_NumPacketsToSend (0), m_MTU (STREAMING_MTU)
{ {
@@ -366,6 +366,7 @@ namespace stream
{ {
if (!m_IsWinDropped) if (!m_IsWinDropped)
{ {
LogPrint (eLogDebug, "Streaming: Client choked, set min. window size");
m_WindowDropTargetSize = MIN_WINDOW_SIZE; m_WindowDropTargetSize = MIN_WINDOW_SIZE;
m_LastWindowDropSize = 0; m_LastWindowDropSize = 0;
m_WindowIncCounter = 0; m_WindowIncCounter = 0;
@@ -537,12 +538,21 @@ namespace stream
m_SentPackets.erase (it++); m_SentPackets.erase (it++);
m_LocalDestination.DeletePacket (sentPacket); m_LocalDestination.DeletePacket (sentPacket);
acknowledged = true; acknowledged = true;
if (m_WindowSize < MAX_WINDOW_SIZE && !m_IsFirstACK) if (m_WindowIncCounter < MAX_WINDOW_SIZE && !m_IsFirstACK && !m_IsWinDropped)
incCounter++; incCounter++;
} }
else else
break; break;
} }
if (m_LastACKRecieveTime)
{
uint64_t interval = ts - m_LastACKRecieveTime;
if (m_ACKRecieveInterval)
m_ACKRecieveInterval = (m_ACKRecieveInterval + interval) / 2;
else
m_ACKRecieveInterval = interval;
}
m_LastACKRecieveTime = ts;
if (rttSample != INT_MAX) if (rttSample != INT_MAX)
{ {
if (m_IsFirstRttSample && !m_IsFirstACK) if (m_IsFirstRttSample && !m_IsFirstACK)
@@ -589,12 +599,15 @@ namespace stream
// //
// delay-based CC // delay-based CC
if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection if ((m_SlowRTT2 > m_SlowRTT + m_Jitter && rttSample > m_SlowRTT2 && rttSample > m_PrevRTTSample) && !m_IsWinDropped) // Drop window if RTT grows too fast, late detection
{
LogPrint (eLogDebug, "Streaming: Congestion detected, reduce window size");
ProcessWindowDrop (); ProcessWindowDrop ();
}
UpdatePacingTime (); UpdatePacingTime ();
m_PrevRTTSample = rttSample; m_PrevRTTSample = rttSample;
bool wasInitial = m_RTO == INITIAL_RTO; bool wasInitial = m_RTO == INITIAL_RTO;
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter + m_ACKRecieveInterval)); // TODO: implement it better
if (wasInitial) if (wasInitial)
ScheduleResend (); ScheduleResend ();
@@ -604,20 +617,10 @@ namespace stream
m_IsFirstRttSample = true; m_IsFirstRttSample = true;
m_IsWinDropped = false; m_IsWinDropped = false;
} }
if (m_WindowDropTargetSize && m_WindowSize <= m_WindowDropTargetSize) if (m_WindowDropTargetSize && int(m_SentPackets.size ()) <= m_WindowDropTargetSize)
{ {
m_WindowSize = m_WindowDropTargetSize;
m_WindowDropTargetSize = 0; m_WindowDropTargetSize = 0;
m_DropWindowDelaySequenceNumber = m_SequenceNumber;
}
if (acknowledged && m_WindowDropTargetSize && m_WindowSize > m_WindowDropTargetSize)
{
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // we assume that the next rtt sample may be much larger than the current
m_IsResendNeeded = true;
m_WindowSize = m_SentPackets.size () + 1; // if there are no packets to resend, just send one regular packet
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
if (m_WindowSize > MAX_WINDOW_SIZE) m_WindowSize = MAX_WINDOW_SIZE;
m_WindowIncCounter = 0;
UpdatePacingTime ();
} }
if (acknowledged || m_IsNAcked) if (acknowledged || m_IsNAcked)
{ {
@@ -626,12 +629,14 @@ namespace stream
if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss if (m_SendBuffer.IsEmpty () && m_SentPackets.size () > 0) // tail loss
{ {
m_IsResendNeeded = true; m_IsResendNeeded = true;
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter)); // to prevent spurious retransmit m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.5 + m_Jitter + m_ACKRecieveInterval)); // to prevent spurious retransmit
} }
if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ()) if (m_SentPackets.empty () && m_SendBuffer.IsEmpty ())
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_SendTimer.cancel (); m_SendTimer.cancel ();
m_LastACKRecieveTime = 0;
m_ACKRecieveInterval = m_AckDelay;
} }
if (acknowledged && m_IsFirstACK) if (acknowledged && m_IsFirstACK)
{ {
@@ -958,7 +963,7 @@ namespace stream
if (choking || requestImmediateAck) if (choking || requestImmediateAck)
{ {
htobe16buf (packet + size, 2); // 2 bytes delay interval htobe16buf (packet + size, 2); // 2 bytes delay interval
htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediated ack interval htobe16buf (packet + size + 2, choking ? DELAY_CHOKING : 0); // set choking or immediate ack interval
size += 2; size += 2;
if (requestImmediateAck) // ack request sent if (requestImmediateAck) // ack request sent
{ {
@@ -1147,7 +1152,6 @@ namespace stream
m_CurrentOutboundTunnel = routingPath->outboundTunnel; m_CurrentOutboundTunnel = routingPath->outboundTunnel;
m_CurrentRemoteLease = routingPath->remoteLease; m_CurrentRemoteLease = routingPath->remoteLease;
m_RTT = routingPath->rtt; m_RTT = routingPath->rtt;
m_RTO = std::max (MIN_RTO, (int)(m_RTT * 1.3 + m_Jitter)); // TODO: implement it better
} }
} }
@@ -1159,6 +1163,7 @@ namespace stream
} }
if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO) if (m_RemoteLeaseChangeTime && m_IsRemoteLeaseChangeInProgress && ts > m_RemoteLeaseChangeTime + INITIAL_RTO)
{ {
LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size");
CancelRemoteLeaseChange (); CancelRemoteLeaseChange ();
m_CurrentRemoteLease = m_NextRemoteLease; m_CurrentRemoteLease = m_NextRemoteLease;
HalveWindowSize (); HalveWindowSize ();
@@ -1306,6 +1311,11 @@ namespace stream
} }
UpdatePacingTime (); UpdatePacingTime ();
} }
else if (m_WindowIncCounter && m_WindowSize == MAX_WINDOW_SIZE && !m_SendBuffer.IsEmpty () && m_PacingTime > m_MinPacingTime)
{
m_WindowSizeTail = m_WindowSizeTail + m_WindowIncCounter;
if (m_WindowSizeTail > MAX_WINDOW_SIZE) m_WindowSizeTail = MAX_WINDOW_SIZE;
}
if (m_IsNAcked) if (m_IsNAcked)
ResendPacket (); ResendPacket ();
else if (m_IsResendNeeded) // resend packets else if (m_IsResendNeeded) // resend packets
@@ -1410,8 +1420,11 @@ namespace stream
{ {
// loss-based CC // loss-based CC
if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED) if (!m_IsWinDropped && LOSS_BASED_CONTROL_ENABLED)
{
LogPrint (eLogDebug, "Streaming: Packet loss, reduce window size");
ProcessWindowDrop (); ProcessWindowDrop ();
} }
}
else if (m_IsTimeOutResend) else if (m_IsTimeOutResend)
{ {
m_IsTimeOutResend = false; m_IsTimeOutResend = false;
@@ -1423,6 +1436,8 @@ namespace stream
m_IsFirstRttSample = true; m_IsFirstRttSample = true;
m_DropWindowDelaySequenceNumber = 0; m_DropWindowDelaySequenceNumber = 0;
m_IsFirstACK = true; m_IsFirstACK = true;
m_LastACKRecieveTime = 0;
m_ACKRecieveInterval = m_AckDelay;
UpdatePacingTime (); UpdatePacingTime ();
if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr); if (m_RoutingSession) m_RoutingSession->SetSharedRoutingPath (nullptr);
if (m_NumResendAttempts & 1) if (m_NumResendAttempts & 1)
@@ -1586,6 +1601,7 @@ namespace stream
} }
if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress) if (isLeaseChanged && !m_IsRemoteLeaseChangeInProgress)
{ {
LogPrint (eLogDebug, "Streaming: RemoteLease changed, set initial window size");
HalveWindowSize (); HalveWindowSize ();
} }
} }
@@ -1602,6 +1618,9 @@ namespace stream
void Stream::UpdatePacingTime () void Stream::UpdatePacingTime ()
{ {
if (m_WindowDropTargetSize)
m_PacingTime = std::round (m_RTT*1000/m_WindowDropTargetSize);
else
m_PacingTime = std::round (m_RTT*1000/m_WindowSize); m_PacingTime = std::round (m_RTT*1000/m_WindowSize);
if (m_MinPacingTime && m_PacingTime < m_MinPacingTime) if (m_MinPacingTime && m_PacingTime < m_MinPacingTime)
m_PacingTime = m_MinPacingTime; m_PacingTime = m_MinPacingTime;
@@ -1610,18 +1629,20 @@ namespace stream
void Stream::ProcessWindowDrop () void Stream::ProcessWindowDrop ()
{ {
if (m_WindowSize > m_LastWindowDropSize) if (m_WindowSize > m_LastWindowDropSize)
m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize) / 2; {
m_LastWindowDropSize = (m_LastWindowDropSize + m_WindowSize + m_WindowSizeTail) / 2;
if (m_LastWindowDropSize > MAX_WINDOW_SIZE) m_LastWindowDropSize = MAX_WINDOW_SIZE;
}
else else
m_LastWindowDropSize = m_WindowSize; m_LastWindowDropSize = m_WindowSize;
m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%; m_WindowDropTargetSize = m_LastWindowDropSize - (m_LastWindowDropSize / 4); // -25%;
if (m_WindowDropTargetSize < MIN_WINDOW_SIZE + 1) if (m_WindowDropTargetSize < MIN_WINDOW_SIZE)
m_WindowDropTargetSize = MIN_WINDOW_SIZE + 1; m_WindowDropTargetSize = MIN_WINDOW_SIZE;
m_WindowSize = m_SentPackets.size (); // stop sending now
if (m_WindowSize < MIN_WINDOW_SIZE) m_WindowSize = MIN_WINDOW_SIZE;
m_WindowIncCounter = 0; // disable window growth m_WindowIncCounter = 0; // disable window growth
m_DropWindowDelaySequenceNumber = m_SequenceNumber; m_DropWindowDelaySequenceNumber = m_SequenceNumber + int(m_WindowDropTargetSize);
m_IsFirstACK = true; // ignore first RTT sample m_IsFirstACK = true; // ignore first RTT sample
m_IsWinDropped = true; // don't drop window twice m_IsWinDropped = true; // don't drop window twice
m_WindowSizeTail = 0;
UpdatePacingTime (); UpdatePacingTime ();
} }
@@ -1639,6 +1660,7 @@ namespace stream
m_WindowIncCounter = 0; m_WindowIncCounter = 0;
m_IsFirstRttSample = true; m_IsFirstRttSample = true;
m_IsFirstACK = true; m_IsFirstACK = true;
m_WindowSizeTail = 0;
UpdatePacingTime (); UpdatePacingTime ();
} }

View File

@@ -295,10 +295,10 @@ namespace stream
SendBufferQueue m_SendBuffer; SendBufferQueue m_SendBuffer;
double m_RTT, m_SlowRTT, m_SlowRTT2; double m_RTT, m_SlowRTT, m_SlowRTT2;
float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize; float m_WindowSize, m_LastWindowDropSize, m_WindowDropTargetSize;
int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample; int m_WindowIncCounter, m_RTO, m_AckDelay, m_PrevRTTSample, m_WindowSizeTail;
double m_Jitter; double m_Jitter;
uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds uint64_t m_MinPacingTime, m_PacingTime, m_PacingTimeRem, // microseconds
m_LastSendTime, m_RemoteLeaseChangeTime; // miliseconds m_LastSendTime, m_LastACKRecieveTime, m_ACKRecieveInterval, m_RemoteLeaseChangeTime; // milliseconds
uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed uint64_t m_LastACKSendTime, m_PacketACKInterval, m_PacketACKIntervalRem; // for limit inbound speed
int m_NumResendAttempts, m_NumPacketsToSend; int m_NumResendAttempts, m_NumPacketsToSend;
size_t m_MTU; size_t m_MTU;

View File

@@ -434,8 +434,7 @@ namespace tunnel
else else
{ {
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET, reply);
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
} }
} }
return true; return true;

View File

@@ -79,8 +79,7 @@ namespace tunnel
uint8_t * record = records + index*TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = records + index*TUNNEL_BUILD_RECORD_SIZE;
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (replyKey); decryption.SetKey (replyKey);
decryption.SetIV (replyIV); decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, replyIV, record);
decryption.Decrypt(record, TUNNEL_BUILD_RECORD_SIZE, record);
} }
void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted) void ECIESTunnelHopConfig::EncryptECIES (const uint8_t * plainText, size_t len, uint8_t * encrypted)

View File

@@ -240,13 +240,13 @@ namespace tunnel
auto currentTransport = m_CurrentTransport.lock (); auto currentTransport = m_CurrentTransport.lock ();
if (!currentTransport) if (!currentTransport)
{ {
// try to obtain transport from peding reequest or send thought transport is not complete // try to obtain transport from pending request or send thought transport is not complete
if (m_PendingTransport.valid ()) // pending request? if (m_PendingTransport.valid ()) // pending request?
{ {
if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready) if (m_PendingTransport.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{ {
// pending request complete // pending request complete
currentTransport = m_PendingTransport.get (); // take tarnsports used in pending request currentTransport = m_PendingTransport.get (); // take transports used in pending request
if (currentTransport) if (currentTransport)
{ {
if (currentTransport->IsEstablished ()) if (currentTransport->IsEstablished ())
@@ -257,7 +257,7 @@ namespace tunnel
} }
else // still pending else // still pending
{ {
// send through transports, but don't update pedning transport // send through transports, but don't update pending transport
i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs)); i2p::transport::transports.SendMessages (m_Tunnel.GetNextIdentHash (), std::move (newTunnelMsgs));
return; return;
} }

View File

@@ -37,9 +37,7 @@ namespace api
i2p::fs::Init(); i2p::fs::Init();
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); i2p::crypto::InitCrypto (precomputation);
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
i2p::crypto::InitCrypto (precomputation, aesni, forceCpuExt);
int netID; i2p::config::GetOption("netid", netID); int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID); i2p::context.SetNetID (netID);

View File

@@ -879,7 +879,7 @@ namespace client
if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce)) if (!remoteSession || !m_Destination->SendMsg (buf + offset, payloadLen, remoteSession, nonce))
{ {
i2p::data::IdentHash identHash; i2p::data::IdentHash identHash;
SHA256(ident, identSize, identHash); // caclulate ident hash, because we don't need full identity SHA256(ident, identSize, identHash); // calculate ident hash, because we don't need full identity
m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce); m_Destination->SendMsgTo (buf + offset, payloadLen, identHash, nonce);
} }
} }

View File

@@ -86,7 +86,7 @@ namespace client
} }
else else
{ {
LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from differend address. Removed"); LogPrint(eLogWarning, "UDPServer: Session with from ", remotePort, " and to ", localPort, " ports already exists. But from different address. Removed");
m_Sessions.erase (it); m_Sessions.erase (it);
} }
} }

View File

@@ -65,6 +65,10 @@ set(test-eddsa_SRCS
test-eddsa.cpp test-eddsa.cpp
) )
set(test-aes_SRCS
test-aes.cpp
)
add_executable(test-http-merge_chunked ${test-http-merge_chunked_SRCS}) add_executable(test-http-merge_chunked ${test-http-merge_chunked_SRCS})
add_executable(test-http-req ${test-http-req_SRCS}) add_executable(test-http-req ${test-http-req_SRCS})
add_executable(test-http-res ${test-http-res_SRCS}) add_executable(test-http-res ${test-http-res_SRCS})
@@ -77,6 +81,7 @@ add_executable(test-aeadchacha20poly1305 ${test-aeadchacha20poly1305_SRCS})
add_executable(test-blinding ${test-blinding_SRCS}) add_executable(test-blinding ${test-blinding_SRCS})
add_executable(test-elligator ${test-elligator_SRCS}) add_executable(test-elligator ${test-elligator_SRCS})
add_executable(test-eddsa ${test-eddsa_SRCS}) add_executable(test-eddsa ${test-eddsa_SRCS})
add_executable(test-aes ${test-aes_SRCS})
set(LIBS set(LIBS
libi2pd libi2pd
@@ -101,6 +106,7 @@ target_link_libraries(test-aeadchacha20poly1305 ${LIBS})
target_link_libraries(test-blinding ${LIBS}) target_link_libraries(test-blinding ${LIBS})
target_link_libraries(test-elligator ${LIBS}) target_link_libraries(test-elligator ${LIBS})
target_link_libraries(test-eddsa ${LIBS}) target_link_libraries(test-eddsa ${LIBS})
target_link_libraries(test-aes ${LIBS})
add_test(test-http-merge_chunked ${TEST_PATH}/test-http-merge_chunked) add_test(test-http-merge_chunked ${TEST_PATH}/test-http-merge_chunked)
add_test(test-http-req ${TEST_PATH}/test-http-req) add_test(test-http-req ${TEST_PATH}/test-http-req)
@@ -114,3 +120,4 @@ add_test(test-aeadchacha20poly1305 ${TEST_PATH}/test-aeadchacha20poly1305)
add_test(test-blinding ${TEST_PATH}/test-blinding) add_test(test-blinding ${TEST_PATH}/test-blinding)
add_test(test-elligator ${TEST_PATH}/test-elligator) add_test(test-elligator ${TEST_PATH}/test-elligator)
add_test(test-eddsa ${TEST_PATH}/test-eddsa) add_test(test-eddsa ${TEST_PATH}/test-eddsa)
add_test(test-aes ${TEST_PATH}/test-aes)

View File

@@ -8,7 +8,7 @@ LIBI2PD = ../libi2pd.a
TESTS = \ TESTS = \
test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \ test-http-merge_chunked test-http-req test-http-res test-http-url test-http-url_decode \
test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \ test-gost test-gost-sig test-base-64 test-aeadchacha20poly1305 test-blinding \
test-elligator test-eddsa test-elligator test-eddsa test-aes
ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS))) ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
CXXFLAGS += -DWIN32_LEAN_AND_MEAN CXXFLAGS += -DWIN32_LEAN_AND_MEAN
@@ -56,6 +56,9 @@ test-elligator: test-elligator.cpp $(LIBI2PD)
test-eddsa: test-eddsa.cpp $(LIBI2PD) test-eddsa: test-eddsa.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
test-aes: test-aes.cpp $(LIBI2PD)
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)
run: $(TESTS) run: $(TESTS)
@for TEST in $(TESTS); do echo Running $$TEST; ./$$TEST ; done @for TEST in $(TESTS); do echo Running $$TEST; ./$$TEST ; done

69
tests/test-aes.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include <cassert>
#include <inttypes.h>
#include <string.h>
#include "Crypto.h"
uint8_t ecb_key1[32] =
{
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
};
uint8_t ecb_plain1[16] =
{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a
};
uint8_t ecb_cipher1[16] =
{
0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8
};
uint8_t cbc_key1[32] =
{
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
};
uint8_t cbc_iv1[16] =
{
0xF5, 0x8C, 0x4C, 0x04, 0xD6, 0xE5, 0xF1, 0xBA, 0x77, 0x9E, 0xAB, 0xFB, 0x5F, 0x7B, 0xFB, 0xD6
};
uint8_t cbc_plain1[16] =
{
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51
};
uint8_t cbc_cipher1[16] =
{
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d
};
int main ()
{
// ECB encrypt test1
i2p::crypto::ECBEncryption ecbencryption;
ecbencryption.SetKey (ecb_key1);
uint8_t out[16];
ecbencryption.Encrypt (ecb_plain1, out);
assert (memcmp (ecb_cipher1, out, 16) == 0);
// ECB decrypt test1
i2p::crypto::ECBDecryption ecbdecryption;
ecbdecryption.SetKey (ecb_key1);
ecbdecryption.Decrypt (ecb_cipher1, out);
assert (memcmp (ecb_plain1, out, 16) == 0);
// CBC encrypt test
i2p::crypto::CBCEncryption cbcencryption;
cbcencryption.SetKey (cbc_key1);
cbcencryption.Encrypt (cbc_plain1, 16, cbc_iv1, out);
assert (memcmp (cbc_cipher1, out, 16) == 0);
// CBC decrypt test
i2p::crypto::CBCDecryption cbcdecryption;
cbcdecryption.SetKey (cbc_key1);
cbcdecryption.Decrypt (cbc_cipher1, 16, cbc_iv1, out);
assert (memcmp (cbc_plain1, out, 16) == 0);
}