Reformat code

This commit is contained in:
Anatolii Cherednichenko 2022-08-30 02:11:28 +03:00
parent 3ddb370718
commit 55534ea002
140 changed files with 46068 additions and 48277 deletions

View file

@ -14,10 +14,8 @@
// Afrikaans localization file // Afrikaans localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace afrikaans // language namespace namespace afrikaans // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -71,9 +69,9 @@ namespace afrikaans // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// Armenian localization file // Armenian localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace armenian // language namespace namespace armenian // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -205,9 +203,9 @@ namespace armenian // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -15,10 +15,8 @@
// Simplified Chinese localization file // Simplified Chinese localization file
// This is an example translation file without strings in it. // This is an example translation file without strings in it.
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace chinese // language namespace namespace chinese // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -207,9 +205,9 @@ namespace chinese // language namespace
{"", {""}}, {"", {""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -15,10 +15,8 @@
// English localization file // English localization file
// This is an example translation file without strings in it. // This is an example translation file without strings in it.
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace english // language namespace namespace english // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -40,9 +38,9 @@ namespace english // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// French localization file // French localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace french // language namespace namespace french // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -201,9 +199,9 @@ namespace french // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// German localization file // German localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace german // language namespace namespace german // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -206,9 +204,9 @@ namespace german // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -11,12 +11,9 @@
#include "ClientContext.h" #include "ClientContext.h"
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n inline void SetLanguage(const std::string &lang) {
{
inline void SetLanguage(const std::string &lang)
{
const auto it = i2p::i18n::languages.find(lang); const auto it = i2p::i18n::languages.find(lang);
if (it == i2p::i18n::languages.end()) // fallback if (it == i2p::i18n::languages.end()) // fallback
i2p::client::context.SetLanguage(i2p::i18n::english::GetLocale()); i2p::client::context.SetLanguage(i2p::i18n::english::GetLocale());
@ -24,21 +21,18 @@ namespace i18n
i2p::client::context.SetLanguage(it->second.LocaleFunc()); i2p::client::context.SetLanguage(it->second.LocaleFunc());
} }
inline std::string translate (const std::string& arg) inline std::string translate(const std::string &arg) {
{
return i2p::client::context.GetLanguage()->GetString(arg); return i2p::client::context.GetLanguage()->GetString(arg);
} }
inline std::string translate (const std::string& arg, const std::string& arg2, const int& n) inline std::string translate(const std::string &arg, const std::string &arg2, const int &n) {
{
return i2p::client::context.GetLanguage()->GetPlural(arg, arg2, n); return i2p::client::context.GetLanguage()->GetPlural(arg, arg2, n);
} }
} // i18n } // i18n
} // i2p } // i2p
template<typename... TArgs> template<typename... TArgs>
std::string tr (TArgs&&... args) std::string tr(TArgs &&... args) {
{
return i2p::i18n::translate(std::forward<TArgs>(args)...); return i2p::i18n::translate(std::forward<TArgs>(args)...);
} }

View file

@ -9,12 +9,9 @@
#ifndef __I18N_LANGS_H__ #ifndef __I18N_LANGS_H__
#define __I18N_LANGS_H__ #define __I18N_LANGS_H__
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n class Locale {
{
class Locale
{
public: public:
Locale( Locale(
const std::string &language, const std::string &language,
@ -24,33 +21,25 @@ namespace i18n
) : m_Language(language), m_Strings(strings), m_Plurals(plurals), m_Formula(formula) {}; ) : m_Language(language), m_Strings(strings), m_Plurals(plurals), m_Formula(formula) {};
// Get activated language name for webconsole // Get activated language name for webconsole
std::string GetLanguage() const std::string GetLanguage() const {
{
return m_Language; return m_Language;
} }
std::string GetString (const std::string& arg) const std::string GetString(const std::string &arg) const {
{
const auto it = m_Strings.find(arg); const auto it = m_Strings.find(arg);
if (it == m_Strings.end()) if (it == m_Strings.end()) {
{
return arg; return arg;
} } else {
else
{
return it->second; return it->second;
} }
} }
std::string GetPlural (const std::string& arg, const std::string& arg2, const int& n) const std::string GetPlural(const std::string &arg, const std::string &arg2, const int &n) const {
{
const auto it = m_Plurals.find(arg2); const auto it = m_Plurals.find(arg2);
if (it == m_Plurals.end()) // not found, fallback to english if (it == m_Plurals.end()) // not found, fallback to english
{ {
return n == 1 ? arg : arg2; return n == 1 ? arg : arg2;
} } else {
else
{
int form = m_Formula(n); int form = m_Formula(n);
return it->second[form]; return it->second[form];
} }
@ -63,8 +52,7 @@ namespace i18n
std::function<int(int)> m_Formula; std::function<int(int)> m_Formula;
}; };
struct langData struct langData {
{
std::string LocaleName; // localized name std::string LocaleName; // localized name
std::string ShortCode; // short language code, like "en" std::string ShortCode; // short language code, like "en"
std::function<std::shared_ptr<const i2p::i18n::Locale>(void)> LocaleFunc; std::function<std::shared_ptr<const i2p::i18n::Locale>(void)> LocaleFunc;

View file

@ -14,10 +14,8 @@
// Russian localization file // Russian localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace russian // language namespace namespace russian // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -26,7 +24,8 @@ namespace russian // language namespace
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural(int n) { static int plural(int n) {
return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)
? 1 : 2;
} }
static std::map <std::string, std::string> strings static std::map <std::string, std::string> strings
@ -205,9 +204,9 @@ namespace russian // language namespace
{"", {"", "", ""}}, {"", {"", "", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// Turkmen localization file // Turkmen localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace turkmen // language namespace namespace turkmen // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -205,9 +203,9 @@ namespace turkmen // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// Ukrainian localization file // Ukrainian localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace ukrainian // language namespace namespace ukrainian // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -26,7 +24,8 @@ namespace ukrainian // language namespace
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural(int n) { static int plural(int n) {
return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20)
? 1 : 2;
} }
static std::map <std::string, std::string> strings static std::map <std::string, std::string> strings
@ -205,9 +204,9 @@ namespace ukrainian // language namespace
{"", {"", "", ""}}, {"", {"", "", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -14,10 +14,8 @@
// Ukrainian localization file // Ukrainian localization file
namespace i2p namespace i2p {
{ namespace i18n {
namespace i18n
{
namespace uzbek // language namespace namespace uzbek // language namespace
{ {
// language name in lowercase // language name in lowercase
@ -205,9 +203,9 @@ namespace uzbek // language namespace
{"", {"", ""}}, {"", {"", ""}},
}; };
std::shared_ptr<const i2p::i18n::Locale> GetLocale() std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
{ return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); }); [](int n) -> int { return plural(n); });
} }
} // language } // language

View file

@ -11,10 +11,8 @@
#include "Base.h" #include "Base.h"
namespace i2p 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',
@ -23,8 +21,7 @@ namespace data
'y', 'z', '2', '3', '4', '5', '6', '7', 'y', 'z', '2', '3', '4', '5', '6', '7',
}; };
const char * GetBase32SubstitutionTable () const char *GetBase32SubstitutionTable() {
{
return T32; return T32;
} }
@ -50,8 +47,7 @@ namespace data
'4', '5', '6', '7', '8', '9', '-', '~' '4', '5', '6', '7', '8', '9', '-', '~'
}; };
const char * GetBase64SubstitutionTable () const char *GetBase64SubstitutionTable() {
{
return T64; return T64;
} }
@ -82,8 +78,7 @@ namespace 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;
unsigned char acc_1; unsigned char acc_1;
@ -104,8 +99,7 @@ namespace data
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_1 = *ps++;
acc_2 = (acc_1 << 4) & 0x30; acc_2 = (acc_1 << 4) & 0x30;
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
@ -121,8 +115,7 @@ namespace data
acc_2 &= 0x3f; /* base64 digit #4 */ acc_2 &= 0x3f; /* base64 digit #4 */
*pd++ = T64[acc_2]; *pd++ = T64[acc_2];
} }
if ( m == 1 ) if (m == 1) {
{
acc_1 = *ps++; acc_1 = *ps++;
acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */ acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
@ -131,9 +124,7 @@ namespace data
*pd++ = P64; *pd++ = P64;
*pd++ = P64; *pd++ = P64;
} } else if (m == 2) {
else if ( m == 2 )
{
acc_1 = *ps++; acc_1 = *ps++;
acc_2 = (acc_1 << 4) & 0x3f; acc_2 = (acc_1 << 4) & 0x3f;
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
@ -165,8 +156,7 @@ namespace data
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;
unsigned char *pd; unsigned char *pd;
unsigned char acc_1; unsigned char acc_1;
@ -197,8 +187,7 @@ namespace data
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_1 = iT64[*ps++];
acc_2 = iT64[*ps++]; acc_2 = iT64[*ps++];
acc_1 <<= 2; acc_1 <<= 2;
@ -222,8 +211,7 @@ namespace data
return outCount; return outCount;
} }
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) if (d.rem)
d.quot++; d.quot++;
@ -231,8 +219,7 @@ namespace data
return 4 * 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);
@ -258,8 +245,7 @@ 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;
@ -267,12 +253,10 @@ namespace data
iT64[(int) P64] = 0; iT64[(int) P64] = 0;
} }
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) {
{
int tmp = 0, bits = 0; int tmp = 0, bits = 0;
size_t ret = 0; size_t ret = 0;
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++) {
{
char ch = inBuf[i]; char ch = inBuf[i];
if (ch >= '2' && ch <= '7') // digit if (ch >= '2' && ch <= '7') // digit
ch = (ch - '2') + 26; // 26 means a-z ch = (ch - '2') + 26; // 26 means a-z
@ -283,8 +267,7 @@ namespace data
tmp |= ch; tmp |= ch;
bits += 5; bits += 5;
if (bits >= 8) if (bits >= 8) {
{
if (ret >= outLen) return ret; if (ret >= outLen) return ret;
outBuf[ret] = tmp >> (bits - 8); outBuf[ret] = tmp >> (bits - 8);
bits -= 8; bits -= 8;
@ -295,22 +278,17 @@ namespace data
return ret; return ret;
} }
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) {
{
size_t ret = 0, pos = 1; size_t ret = 0, pos = 1;
int bits = 8, tmp = inBuf[0]; int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len)) while (ret < outLen && (bits > 0 || pos < len)) {
{ if (bits < 5) {
if (bits < 5) if (pos < len) {
{
if (pos < len)
{
tmp <<= 8; tmp <<= 8;
tmp |= inBuf[pos] & 0xFF; tmp |= inBuf[pos] & 0xFF;
pos++; pos++;
bits += 8; bits += 8;
} } else // last byte
else // last byte
{ {
tmp <<= (5 - bits); tmp <<= (5 - bits);
bits = 5; bits = 5;

View file

@ -16,11 +16,15 @@
namespace i2p { namespace i2p {
namespace data { namespace data {
size_t ByteStreamToBase64(const uint8_t *InBuffer, size_t InCount, char *OutBuffer, size_t len); size_t ByteStreamToBase64(const uint8_t *InBuffer, size_t InCount, char *OutBuffer, size_t len);
size_t Base64ToByteStream(const char *InBuffer, size_t InCount, uint8_t *OutBuffer, size_t len); size_t Base64ToByteStream(const char *InBuffer, size_t InCount, uint8_t *OutBuffer, size_t len);
const char *GetBase32SubstitutionTable(); const char *GetBase32SubstitutionTable();
const char *GetBase64SubstitutionTable(); const char *GetBase64SubstitutionTable();
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);
/** /**

View file

@ -20,12 +20,9 @@
#include "Signature.h" #include "Signature.h"
#include "Blinding.h" #include "Blinding.h"
namespace i2p 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);
@ -43,8 +40,8 @@ namespace data
return p; return p;
} }
static void BlindPrivateKeyECDSA (const EC_GROUP * group, const BIGNUM * priv, const uint8_t * seed, BIGNUM * blindedPriv) static void
{ BlindPrivateKeyECDSA(const EC_GROUP *group, const BIGNUM *priv, const uint8_t *seed, BIGNUM *blindedPriv) {
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);
@ -60,8 +57,9 @@ namespace data
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) {
BIGNUM *x = BN_bin2bn(pub, publicKeyLen / 2, NULL); BIGNUM *x = BN_bin2bn(pub, publicKeyLen / 2, NULL);
BIGNUM *y = BN_bin2bn(pub + publicKeyLen / 2, publicKeyLen / 2, NULL); BIGNUM *y = BN_bin2bn(pub + publicKeyLen / 2, publicKeyLen / 2, NULL);
EC_POINT *p = EC_POINT_new(group); EC_POINT *p = EC_POINT_new(group);
@ -72,11 +70,12 @@ namespace data
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);
} }
static void BlindEncodedPrivateKeyECDSA (size_t publicKeyLen, const EC_GROUP * group, const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub) static void BlindEncodedPrivateKeyECDSA(size_t publicKeyLen, const EC_GROUP *group, const uint8_t *priv,
{ const uint8_t *seed, uint8_t *blindedPriv, uint8_t *blindedPub) {
BIGNUM *a = BN_bin2bn(priv, publicKeyLen / 2, NULL); BIGNUM *a = BN_bin2bn(priv, publicKeyLen / 2, NULL);
BIGNUM *a1 = BN_new(); BIGNUM *a1 = BN_new();
BlindPrivateKeyECDSA(group, a, seed, a1); BlindPrivateKeyECDSA(group, a, seed, a1);
@ -92,31 +91,29 @@ namespace data
EC_POINT_free(p); EC_POINT_free(p);
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)
// blind is BlindEncodedPublicKeyECDSA or BlindEncodedPrivateKeyECDSA // blind is BlindEncodedPublicKeyECDSA or BlindEncodedPrivateKeyECDSA
{ {
size_t publicKeyLength = 0; size_t publicKeyLength = 0;
EC_GROUP *group = nullptr; EC_GROUP *group = nullptr;
switch (sigType) switch (sigType) {
{ 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;
} }
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: {
{
publicKeyLength = i2p::crypto::ECDSAP384_KEY_LENGTH; publicKeyLength = i2p::crypto::ECDSAP384_KEY_LENGTH;
group = EC_GROUP_new_by_curve_name(NID_secp384r1); group = EC_GROUP_new_by_curve_name(NID_secp384r1);
break; break;
} }
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: {
{
publicKeyLength = i2p::crypto::ECDSAP521_KEY_LENGTH; publicKeyLength = i2p::crypto::ECDSAP521_KEY_LENGTH;
group = EC_GROUP_new_by_curve_name(NID_secp521r1); group = EC_GROUP_new_by_curve_name(NID_secp521r1);
break; break;
@ -124,8 +121,7 @@ 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);
} }
@ -139,8 +135,7 @@ namespace data
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) :
m_IsClientAuth (clientAuth) m_IsClientAuth(clientAuth) {
{
if (!identity) return; if (!identity) return;
auto len = identity->GetSigningPublicKeyLen(); auto len = identity->GetSigningPublicKeyLen();
m_PublicKey.resize(len); m_PublicKey.resize(len);
@ -157,48 +152,49 @@ namespace data
{ {
uint8_t addr[40]; // TODO: define length from b33 uint8_t addr[40]; // TODO: define length from b33
size_t l = i2p::data::Base32ToByteStream(b33.c_str(), b33.length(), addr, 40); size_t l = i2p::data::Base32ToByteStream(b33.c_str(), b33.length(), addr, 40);
if (l < 32) if (l < 32) {
{
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);
m_BlindedSigType = bufbe16toh (addr + offset); offset += 2; offset += 2;
} m_BlindedSigType = bufbe16toh(addr + offset);
else // one byte sig offset += 2;
} else // one byte sig
{ {
m_SigType = addr[offset]; offset++; m_SigType = addr[offset];
m_BlindedSigType = addr[offset]; offset++; offset++;
m_BlindedSigType = addr[offset];
offset++;
} }
m_IsClientAuth = flags & B33_PER_CLIENT_AUTH_FLAG; m_IsClientAuth = flags & B33_PER_CLIENT_AUTH_FLAG;
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier(i2p::data::IdentityEx::CreateVerifier(m_SigType)); std::unique_ptr<i2p::crypto::Verifier> blindedVerifier(i2p::data::IdentityEx::CreateVerifier(m_SigType));
if (blindedVerifier) if (blindedVerifier) {
{
auto len = blindedVerifier->GetPublicKeyLen(); auto len = blindedVerifier->GetPublicKeyLen();
if (offset + len <= l) if (offset + len <= l) {
{
m_PublicKey.resize(len); m_PublicKey.resize(len);
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 ",
LogPrint (eLogError, "Blinding: Public key in b33 address is too short for signature type ", (int)m_SigType); (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");
} }
std::string BlindedPublicKey::ToB33 () const std::string BlindedPublicKey::ToB33() const {
{
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
@ -207,51 +203,54 @@ namespace data
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);
} }
void BlindedPublicKey::GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const void BlindedPublicKey::GetSubcredential(const uint8_t *blinded, size_t len, uint8_t *subcredential) const {
{
uint8_t credential[32]; uint8_t credential[32];
GetCredential(credential); GetCredential(credential);
// subcredential = H("subcredential", credential || blindedPublicKey) // subcredential = H("subcredential", credential || blindedPublicKey)
H ("subcredential", { {credential, 32}, {blinded, len} }, subcredential); H("subcredential", {{credential, 32},
{blinded, len}}, subcredential);
} }
void BlindedPublicKey::GenerateAlpha (const char * date, uint8_t * seed) const void BlindedPublicKey::GenerateAlpha(const char *date, uint8_t *seed) const {
{
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) {
{
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
publicKeyLength = BlindECDSA (m_SigType, GetPublicKey (), seed, BlindEncodedPublicKeyECDSA, blindedKey); publicKeyLength = BlindECDSA(m_SigType, GetPublicKey(), seed, BlindEncodedPublicKeyECDSA,
blindedKey);
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:
@ -264,24 +263,23 @@ namespace data
return publicKeyLength; return publicKeyLength;
} }
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) {
{
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub); publicKeyLength = BlindECDSA(m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv,
blindedPub);
break; break;
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
i2p::crypto::GetEd25519()->BlindPrivateKey(priv, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519()->BlindPrivateKey(priv, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: {
{
uint8_t exp[64]; uint8_t exp[64];
i2p::crypto::Ed25519::ExpandPrivateKey(priv, exp); i2p::crypto::Ed25519::ExpandPrivateKey(priv, exp);
i2p::crypto::GetEd25519()->BlindPrivateKey(exp, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519()->BlindPrivateKey(exp, seed, blindedPriv, blindedPub);
@ -294,8 +292,8 @@ namespace data
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());
@ -304,29 +302,25 @@ namespace data
SHA256_Final(hash, &ctx); SHA256_Final(hash, &ctx);
} }
i2p::data::IdentHash BlindedPublicKey::GetStoreHash (const char * date) const i2p::data::IdentHash BlindedPublicKey::GetStoreHash(const char *date) const {
{
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);
SHA256_CTX ctx; SHA256_CTX ctx;
SHA256_Init(&ctx); SHA256_Init(&ctx);
SHA256_Update(&ctx, (const uint8_t *) &stA1, 2); SHA256_Update(&ctx, (const uint8_t *) &stA1, 2);
SHA256_Update(&ctx, blinded, publicKeyLength); SHA256_Update(&ctx, blinded, publicKeyLength);
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;
} }

View file

@ -14,34 +14,41 @@
#include <vector> #include <vector>
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
class BlindedPublicKey // for encrypted LS2 class BlindedPublicKey // for encrypted LS2
{ {
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(); };
size_t GetPublicKeyLen() const { return m_PublicKey.size(); }; size_t GetPublicKeyLen() const { return m_PublicKey.size(); };
SigningKeyType GetSigType() const { return m_SigType; }; SigningKeyType GetSigType() const { return m_SigType; };
SigningKeyType GetBlindedSigType() const { return m_BlindedSigType; }; SigningKeyType GetBlindedSigType() const { return m_BlindedSigType; };
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,
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 uint8_t *blindedKey) 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 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
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:

View file

@ -11,31 +11,25 @@
#include <array> #include <array>
#include <openssl/sha.h> #include <openssl/sha.h>
namespace i2p namespace i2p {
{ namespace util {
namespace util
{
/** @brief decaying bloom filter implementation */ /** @brief decaying bloom filter implementation */
class DecayingBloomFilter : public IBloomFilter class DecayingBloomFilter : public IBloomFilter {
{
public: public:
DecayingBloomFilter(const std::size_t size) DecayingBloomFilter(const std::size_t size) {
{
m_Size = size; m_Size = size;
m_Data = new uint8_t[size]; m_Data = new uint8_t[size];
} }
/** @brief implements IBloomFilter::~IBloomFilter */ /** @brief implements IBloomFilter::~IBloomFilter */
~DecayingBloomFilter() ~DecayingBloomFilter() {
{
delete[] m_Data; delete[] m_Data;
} }
/** @brief implements IBloomFilter::Add */ /** @brief implements IBloomFilter::Add */
bool Add(const uint8_t * data, std::size_t len) bool Add(const uint8_t *data, std::size_t len) {
{
std::size_t idx; std::size_t idx;
uint8_t mask; uint8_t mask;
Get(data, len, idx, mask); Get(data, len, idx, mask);
@ -45,16 +39,14 @@ namespace util
} }
/** @brief implements IBloomFilter::Decay */ /** @brief implements IBloomFilter::Decay */
void Decay() void Decay() {
{
// reset bloom filter buffer // reset bloom filter buffer
memset(m_Data, 0, m_Size); memset(m_Data, 0, m_Size);
} }
private: private:
/** @brief get bit index for for data */ /** @brief get bit index for for data */
void Get(const uint8_t * data, std::size_t len, std::size_t & idx, uint8_t & bm) void Get(const uint8_t *data, std::size_t len, std::size_t &idx, uint8_t &bm) {
{
bm = 1; bm = 1;
uint8_t digest[32]; uint8_t digest[32];
// TODO: use blake2 because it's faster // TODO: use blake2 because it's faster
@ -69,8 +61,7 @@ namespace util
}; };
BloomFilterPtr BloomFilter(std::size_t capacity) BloomFilterPtr BloomFilter(std::size_t capacity) {
{
return std::make_shared<DecayingBloomFilter>(capacity); return std::make_shared<DecayingBloomFilter>(capacity);
} }
} }

View file

@ -8,22 +8,22 @@
#ifndef BLOOM_FILTER_H_ #ifndef BLOOM_FILTER_H_
#define BLOOM_FILTER_H_ #define BLOOM_FILTER_H_
#include <memory> #include <memory>
#include <cstdint> #include <cstdint>
namespace i2p namespace i2p {
{ namespace util {
namespace util
{
/** @brief interface for bloom filter */ /** @brief interface for bloom filter */
struct IBloomFilter struct IBloomFilter {
{
/** @brief destructor */ /** @brief destructor */
virtual ~IBloomFilter() {}; virtual ~IBloomFilter() {};
/** @brief add entry to bloom filter, return false if filter hit otherwise return true */ /** @brief add entry to bloom filter, return false if filter hit otherwise return true */
virtual bool Add(const uint8_t *data, std::size_t len) = 0; virtual bool Add(const uint8_t *data, std::size_t len) = 0;
/** @brief optionally decay old entries */ /** @brief optionally decay old entries */
virtual void Decay() = 0; virtual void Decay() = 0;
}; };

View file

@ -7,9 +7,11 @@
*/ */
#include "CPU.h" #include "CPU.h"
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h> #include <cpuid.h>
#endif #endif
#include "Log.h" #include "Log.h"
#ifndef bit_AES #ifndef bit_AES
@ -20,15 +22,12 @@
#endif #endif
namespace i2p namespace i2p {
{ namespace cpu {
namespace cpu
{
bool aesni = false; bool aesni = false;
bool avx = false; bool avx = false;
void Detect(bool AesSwitch, bool AvxSwitch, bool force) void Detect(bool AesSwitch, bool AvxSwitch, bool force) {
{
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
int info[4]; int info[4];
__cpuid(0, info[0], info[1], info[2], info[3]); __cpuid(0, info[0], info[1], info[2], info[3]);

View file

@ -9,10 +9,8 @@
#ifndef LIBI2PD_CPU_H #ifndef LIBI2PD_CPU_H
#define LIBI2PD_CPU_H #define LIBI2PD_CPU_H
namespace i2p namespace i2p {
{ namespace cpu {
namespace cpu
{
extern bool aesni; extern bool aesni;
extern bool avx; extern bool avx;

View file

@ -13,22 +13,17 @@
#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 {
{ void u32t8le(uint32_t v, uint8_t *p) {
namespace chacha
{
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];
@ -38,35 +33,34 @@ uint32_t u8t32le(const uint8_t * p)
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[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); 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[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); x[b] = rotl32(x[b] ^ x[c], 12);
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); x[a] += x[b];
x[d] = rotl32(x[d] ^ x[a], 8);
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) for (i = rounds; i > 0; i -= 2) {
{
quarterround(x.data, 0, 4, 8, 12); quarterround(x.data, 0, 4, 8, 12);
quarterround(x.data, 1, 5, 9, 13); quarterround(x.data, 1, 5, 9, 13);
quarterround(x.data, 2, 6, 10, 14); quarterround(x.data, 2, 6, 10, 14);
@ -80,8 +74,7 @@ void block (Chacha20State &input, int rounds)
input.block << x; 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) {
{
state.data[0] = 0x61707865; state.data[0] = 0x61707865;
state.data[1] = 0x3320646e; state.data[1] = 0x3320646e;
state.data[2] = 0x79622d32; state.data[2] = 0x79622d32;
@ -94,16 +87,13 @@ void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t *
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;
@ -114,14 +104,11 @@ void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
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;
} }

View file

@ -10,6 +10,7 @@
*/ */
#ifndef LIBI2PD_CHACHA20_H #ifndef LIBI2PD_CHACHA20_H
#define LIBI2PD_CHACHA20_H #define LIBI2PD_CHACHA20_H
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <inttypes.h> #include <inttypes.h>
@ -17,22 +18,21 @@
#include "Crypto.h" #include "Crypto.h"
#if !OPENSSL_AEAD_CHACHA20_POLY1305 #if !OPENSSL_AEAD_CHACHA20_POLY1305
namespace i2p 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
constexpr std::size_t blocksize = 64; 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];
@ -40,29 +40,30 @@ namespace chacha
void operator<<(const Chacha20State &st); void operator<<(const Chacha20State &st);
}; };
struct Chacha20State struct Chacha20State {
{
Chacha20State() : offset(0) {}; Chacha20State() : offset(0) {};
Chacha20State(Chacha20State &&) = delete; Chacha20State(Chacha20State &&) = delete;
Chacha20State & operator += (const Chacha20State & other) Chacha20State &operator+=(const Chacha20State &other) {
{
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
data[i] += other.data[i]; data[i] += other.data[i];
return *this; return *this;
} }
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 chacha
} // namespace crypto } // namespace crypto

View file

@ -28,41 +28,61 @@ namespace config {
options_description m_OptionsDesc; options_description m_OptionsDesc;
variables_map m_Options; variables_map m_Options;
void Init() void Init() {
{
options_description general("General options"); options_description general("General options");
general.add_options() general.add_options()
("help", "Show this message") ("help", "Show this message")
("version", "Show i2pd version") ("version", "Show i2pd version")
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)") ("conf", value<std::string>()->default_value(""),
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)") "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)")
("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d") ("tunconf", value<std::string>()->default_value(""),
("certsdir", value<std::string>()->default_value(""), "Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates") "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)")
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("tunnelsdir", value<std::string>()->default_value(""),
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("certsdir", value<std::string>()->default_value(""),
("loglevel", value<std::string>()->default_value("warn"), "Set the minimal level of log messages (debug, info, warn, error, none)") "Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates")
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") ("pidfile", value<std::string>()->default_value(""),
"Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
("log", value<std::string>()->default_value(""),
"Logs destination: stdout, file, syslog (stdout if not set)")
("logfile", value<std::string>()->default_value(""),
"Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("warn"),
"Set the minimal level of log messages (debug, info, warn, error, none)")
("logclftime", bool_switch()->default_value(false),
"Write full CLF-formatted date and time to log (default: disabled, write only time)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") ("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("datadir", value<std::string>()->default_value(""),
"Path to storage of i2pd data (RI, keys, peer profiles, ...)")
("host", value<std::string>()->default_value("0.0.0.0"), "External IP") ("host", value<std::string>()->default_value("0.0.0.0"), "External IP")
("ifname", value<std::string>()->default_value(""), "Network interface to bind to") ("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4") ("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6") ("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("nat", bool_switch()->default_value(true),
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)") "Should we assume we are behind NAT? (default: enabled)")
("port", value<uint16_t>()->default_value(0),
"Port to listen for incoming connections (default: auto)")
("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)")
("address4", value<std::string>()->default_value(""), "Local address to bind ipv4 transport sockets to") ("address4", value<std::string>()->default_value(""),
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") "Local address to bind ipv4 transport sockets to")
("address6", value<std::string>()->default_value(""), "Local address to bind ipv6 transport sockets to") ("ipv6", bool_switch()->default_value(false),
("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") "Enable communication through ipv6 (default: disabled)")
("address6", value<std::string>()->default_value(""),
"Local address to bind ipv6 transport sockets to")
("reservedrange", bool_switch()->default_value(true),
"Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") ("daemon", bool_switch()->default_value(false),
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") "Router will go to background after start (default: disabled)")
("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)") ("service", bool_switch()->default_value(false),
"Router will use system folders like '/var/lib/i2pd' (default: disabled)")
("notransit", bool_switch()->default_value(false),
"Router will not accept transit tunnels at startup (default: disabled)")
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)")
("bandwidth", value<std::string>()->default_value(""), "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("bandwidth", value<std::string>()->default_value(""),
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
("share", value<int>()->default_value(100),
"Limit of transit traffic from max bandwidth in percents. (default: 100)")
("ntcp", bool_switch()->default_value(false), "Ignored. Always false") ("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
("ntcpproxy", value<std::string>()->default_value(""), "Ignored") ("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
@ -75,13 +95,15 @@ namespace config {
options_description limits("Limits options"); options_description limits("Limits options");
limits.add_options() limits.add_options()
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.coresize", value<uint32_t>()->default_value(0),
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)") "Maximum size of corefile in Kb (0 - use system limit)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)") ("limits.openfiles", value<uint16_t>()->default_value(0),
"Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500),
"Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored") ("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored") ("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored") ("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored");
;
options_description httpserver("HTTP Server options"); options_description httpserver("HTTP Server options");
httpserver.add_options() httpserver.add_options()
@ -90,92 +112,119 @@ namespace config {
("http.port", value<uint16_t>()->default_value(7070), "Webconsole listen port") ("http.port", value<uint16_t>()->default_value(7070), "Webconsole listen port")
("http.auth", value<bool>()->default_value(false), "Enable Basic HTTP auth for webconsole") ("http.auth", value<bool>()->default_value(false), "Enable Basic HTTP auth for webconsole")
("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth") ("http.user", value<std::string>()->default_value("i2pd"), "Username for basic auth")
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)") ("http.pass", value<std::string>()->default_value(""),
"Password for basic auth (default: random, see logs)")
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI") ("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI")
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI") ("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )") ("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )")
("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )") ("http.lang", value<std::string>()->default_value("english"), "WebUI language (default: english )");
;
options_description httpproxy("HTTP Proxy options"); options_description httpproxy("HTTP Proxy options");
httpproxy.add_options() httpproxy.add_options()
("httpproxy.enabled", value<bool>()->default_value(true), "Enable or disable HTTP Proxy") ("httpproxy.enabled", value<bool>()->default_value(true), "Enable or disable HTTP Proxy")
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
("httpproxy.keys", value<std::string>()->default_value("transient-proxy"), "File to persist HTTP Proxy keys. Transient by default") ("httpproxy.keys", value<std::string>()->default_value("transient-proxy"),
"File to persist HTTP Proxy keys. Transient by default")
("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()-> ("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519),
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length") "Signature type for new keys. 7 (EdDSA) by default")
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length") ("httpproxy.inbound.length", value<std::string>()->default_value("3"),
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity") "HTTP proxy inbound tunnel length")
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity") ("httpproxy.outbound.length", value<std::string>()->default_value("3"),
("httpproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy inbound tunnels length variance") "HTTP proxy outbound tunnel length")
("httpproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy outbound tunnels length variance") ("httpproxy.inbound.quantity", value<std::string>()->default_value("5"),
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels") "HTTP proxy inbound tunnels quantity")
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.outbound.quantity", value<std::string>()->default_value("5"),
"HTTP proxy outbound tunnels quantity")
("httpproxy.inbound.lengthVariance", value<std::string>()->default_value("0"),
"HTTP proxy inbound tunnels length variance")
("httpproxy.outbound.lengthVariance", value<std::string>()->default_value("0"),
"HTTP proxy outbound tunnels length variance")
("httpproxy.latency.min", value<std::string>()->default_value("0"),
"HTTP proxy min 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.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type") ("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"),
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type") "Local destination's LeaseSet type")
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key") ("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");
options_description socksproxy("SOCKS Proxy options"); options_description socksproxy("SOCKS Proxy options");
socksproxy.add_options() socksproxy.add_options()
("socksproxy.enabled", value<bool>()->default_value(true), "Enable or disable SOCKS Proxy") ("socksproxy.enabled", value<bool>()->default_value(true), "Enable or disable SOCKS Proxy")
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.address", value<std::string>()->default_value("127.0.0.1"),
"SOCKS Proxy listen address")
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
("socksproxy.keys", value<std::string>()->default_value("transient-proxy"), "File to persist SOCKS Proxy keys. Transient by default") ("socksproxy.keys", value<std::string>()->default_value("transient-proxy"),
"File to persist SOCKS Proxy keys. Transient by default")
("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()-> ("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519),
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length") "Signature type for new keys. 7 (EdDSA) by default")
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length") ("socksproxy.inbound.length", value<std::string>()->default_value("3"),
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity") "SOCKS proxy inbound tunnel length")
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity") ("socksproxy.outbound.length", value<std::string>()->default_value("3"),
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy inbound tunnels length variance") "SOCKS proxy outbound tunnel length")
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy outbound tunnels length variance") ("socksproxy.inbound.quantity", value<std::string>()->default_value("5"),
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels") "SOCKS proxy inbound tunnels quantity")
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels") ("socksproxy.outbound.quantity", value<std::string>()->default_value("5"),
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy") "SOCKS proxy outbound tunnels quantity")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") ("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"),
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") "SOCKS proxy inbound tunnels length variance")
("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"), "Local destination's LeaseSet type") ("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"),
("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type") "SOCKS proxy outbound tunnels length variance")
("socksproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key") ("socksproxy.latency.min", value<std::string>()->default_value("0"),
; "SOCKS proxy min latency for tunnels")
("socksproxy.latency.max", value<std::string>()->default_value("0"),
"SOCKS proxy max latency for tunnels")
("socksproxy.outproxy.enabled", value<bool>()->default_value(false),
"Enable or disable SOCKS outproxy")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"),
"Upstream outproxy address for SOCKS Proxy")
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050),
"Upstream outproxy port for SOCKS Proxy")
("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"),
"Local destination's LeaseSet type")
("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"),
"Local destination's LeaseSet encryption type")
("socksproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""),
"LeaseSet private key");
options_description sam("SAM bridge options"); options_description sam("SAM bridge options");
sam.add_options() sam.add_options()
("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge") ("sam.enabled", value<bool>()->default_value(true), "Enable or disable SAM Application bridge")
("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address") ("sam.address", value<std::string>()->default_value("127.0.0.1"), "SAM listen address")
("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port") ("sam.port", value<uint16_t>()->default_value(7656), "SAM listen port")
("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread") ("sam.singlethread", value<bool>()->default_value(true), "Sessions run in the SAM bridge's thread");
;
options_description bob("BOB options"); options_description bob("BOB options");
bob.add_options() bob.add_options()
("bob.enabled", value<bool>()->default_value(false), "Enable or disable BOB command channel") ("bob.enabled", value<bool>()->default_value(false), "Enable or disable BOB command channel")
("bob.address", value<std::string>()->default_value("127.0.0.1"), "BOB listen address") ("bob.address", value<std::string>()->default_value("127.0.0.1"), "BOB listen address")
("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port") ("bob.port", value<uint16_t>()->default_value(2827), "BOB listen port");
;
options_description i2cp("I2CP options"); options_description i2cp("I2CP options");
i2cp.add_options() i2cp.add_options()
("i2cp.enabled", value<bool>()->default_value(false), "Enable or disable I2CP") ("i2cp.enabled", value<bool>()->default_value(false), "Enable or disable I2CP")
("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address") ("i2cp.address", value<std::string>()->default_value("127.0.0.1"), "I2CP listen address")
("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port") ("i2cp.port", value<uint16_t>()->default_value(7654), "I2CP listen port")
("i2cp.singlethread", value<bool>()->default_value(true), "Destinations run in the I2CP server's thread") ("i2cp.singlethread", value<bool>()->default_value(true),
; "Destinations run in the I2CP server's thread");
options_description i2pcontrol("I2PControl options"); options_description i2pcontrol("I2PControl options");
i2pcontrol.add_options() i2pcontrol.add_options()
("i2pcontrol.enabled", value<bool>()->default_value(false), "Enable or disable I2P Control Protocol") ("i2pcontrol.enabled", value<bool>()->default_value(false),
"Enable or disable I2P Control Protocol")
("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address") ("i2pcontrol.address", value<std::string>()->default_value("127.0.0.1"), "I2PCP listen address")
("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port") ("i2pcontrol.port", value<uint16_t>()->default_value(7650), "I2PCP listen port")
("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password") ("i2pcontrol.password", value<std::string>()->default_value("itoopie"), "I2PCP access password")
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"), "I2PCP connection certificate") ("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"),
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection certificate key") "I2PCP connection certificate")
; ("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"),
"I2PCP connection certificate key");
bool upnp_default = false; bool upnp_default = false;
#if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID))) #if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID)))
@ -183,9 +232,10 @@ namespace config {
#endif #endif
options_description upnp("UPnP options"); options_description upnp("UPnP options");
upnp.add_options() upnp.add_options()
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding") ("upnp.enabled", value<bool>()->default_value(upnp_default),
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwarding list") "Enable or disable UPnP: automatic port forwarding")
; ("upnp.name", value<std::string>()->default_value("I2Pd"),
"Name i2pd appears in UPnP forwarding list");
options_description precomputation("Precomputation options"); options_description precomputation("Precomputation options");
precomputation.add_options() precomputation.add_options()
@ -195,17 +245,21 @@ namespace config {
#else #else
value<bool>()->default_value(true), value<bool>()->default_value(true),
#endif #endif
"Enable or disable elgamal precomputation table") "Enable or disable elgamal precomputation table");
;
options_description reseed("Reseed options"); options_description reseed("Reseed options");
reseed.add_options() reseed.add_options()
("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature") ("reseed.verify", value<bool>()->default_value(false), "Verify .su3 signature")
("reseed.threshold", value<uint16_t>()->default_value(25), "Minimum number of known routers before requesting reseed") ("reseed.threshold", value<uint16_t>()->default_value(25),
("reseed.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from") "Minimum number of known routers before requesting reseed")
("reseed.file", value<std::string>()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from") ("reseed.floodfill", value<std::string>()->default_value(""),
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from") "Path to router info of floodfill to reseed from")
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks") ("reseed.file", value<std::string>()->default_value(""),
"Path to local .su3 file or HTTPS URL to reseed from")
("reseed.zipfile", value<std::string>()->default_value(""),
"Path to local .zip file to reseed from")
("reseed.proxy", value<std::string>()->default_value(""),
"url for reseed proxy, supports http/socks")
("reseed.urls", value<std::string>()->default_value( ("reseed.urls", value<std::string>()->default_value(
"https://reseed2.i2p.net/," "https://reseed2.i2p.net/,"
"https://reseed.diva.exchange/," "https://reseed.diva.exchange/,"
@ -225,59 +279,61 @@ namespace config {
"http://[320:8936:ec1a:31f1::216]/," "http://[320:8936:ec1a:31f1::216]/,"
"http://[306:3834:97b9:a00a::1]/," "http://[306:3834:97b9:a00a::1]/,"
"http://[316:f9e0:f22e:a74f::216]/" "http://[316:f9e0:f22e:a74f::216]/"
), "Reseed URLs through the Yggdrasil, separated by comma") ), "Reseed URLs through the Yggdrasil, separated by comma");
;
options_description addressbook("AddressBook options"); options_description addressbook("AddressBook options");
addressbook.add_options() addressbook.add_options()
("addressbook.enabled", value<bool>()->default_value(true), "Enable address book lookups and subscritions (default: enabled)") ("addressbook.enabled", value<bool>()->default_value(true),
"Enable address book lookups and subscritions (default: enabled)")
("addressbook.defaulturl", value<std::string>()->default_value( ("addressbook.defaulturl", value<std::string>()->default_value(
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt" "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
), "AddressBook subscription URL for initial setup") ), "AddressBook subscription URL for initial setup")
("addressbook.subscriptions", value<std::string>()->default_value( ("addressbook.subscriptions", value<std::string>()->default_value(
"http://reg.i2p/hosts.txt" "http://reg.i2p/hosts.txt"
), "AddressBook subscriptions URLs, separated by comma") ), "AddressBook subscriptions URLs, separated by comma")
("addressbook.hostsfile", value<std::string>()->default_value(""), "File to dump addresses in hosts.txt format"); ("addressbook.hostsfile", value<std::string>()->default_value(""),
"File to dump addresses in hosts.txt format");
options_description trust("Trust options"); options_description trust("Trust options");
trust.add_options() trust.add_options()
("trust.enabled", value<bool>()->default_value(false), "Enable explicit trust options") ("trust.enabled", value<bool>()->default_value(false), "Enable explicit trust options")
("trust.family", value<std::string>()->default_value(""), "Router Family to trust for first hops") ("trust.family", value<std::string>()->default_value(""), "Router Family to trust for first hops")
("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers") ("trust.routers", value<std::string>()->default_value(""), "Only Connect to these routers")
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?") ("trust.hidden", value<bool>()->default_value(false),
; "Should we hide our router from other routers?");
// Save deprecated websocket options for compatibility // Save deprecated websocket options for compatibility
options_description websocket("Websocket Options"); options_description websocket("Websocket Options");
websocket.add_options() websocket.add_options()
("websockets.enabled", value<bool>()->default_value(false), "Deprecated option") ("websockets.enabled", value<bool>()->default_value(false), "Deprecated option")
("websockets.address", value<std::string>()->default_value(""), "Deprecated option") ("websockets.address", value<std::string>()->default_value(""), "Deprecated option")
("websockets.port", value<uint16_t>()->default_value(0), "Deprecated option") ("websockets.port", value<uint16_t>()->default_value(0), "Deprecated option");
;
options_description exploratory("Exploratory Options"); options_description exploratory("Exploratory Options");
exploratory.add_options() exploratory.add_options()
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length") ("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
("exploratory.outbound.length", value<int>()->default_value(2), "Exploratory outbound tunnel length") ("exploratory.outbound.length", value<int>()->default_value(2),
("exploratory.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity") "Exploratory outbound tunnel length")
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity") ("exploratory.inbound.quantity", value<int>()->default_value(3),
; "Exploratory inbound tunnels quantity")
("exploratory.outbound.quantity", value<int>()->default_value(3),
"Exploratory outbound tunnels quantity");
options_description ntcp2("NTCP2 Options"); options_description ntcp2("NTCP2 Options");
ntcp2.add_options() ntcp2.add_options()
("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)") ("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)")
("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)") ("ntcp2.published", value<bool>()->default_value(true), "Publish NTCP2 (default: enabled)")
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ("ntcp2.port", value<uint16_t>()->default_value(0),
"Port to listen for incoming NTCP2 connections (default: auto)")
("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to publish NTCP2 with") ("ntcp2.addressv6", value<std::string>()->default_value("::"), "Address to publish NTCP2 with")
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport") ("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport");
;
options_description ssu2("SSU2 Options"); options_description ssu2("SSU2 Options");
ssu2.add_options() ssu2.add_options()
("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)") ("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)") ("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)") ("ssu2.port", value<uint16_t>()->default_value(0),
; "Port to listen for incoming SSU2 packets (default: auto)");
options_description nettime("Time sync options"); options_description nettime("Time sync options");
nettime.add_options() nettime.add_options()
@ -288,28 +344,31 @@ namespace config {
"2.pool.ntp.org," "2.pool.ntp.org,"
"3.pool.ntp.org" "3.pool.ntp.org"
), "Comma separated list of NTP servers") ), "Comma separated list of NTP servers")
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)") ("nettime.ntpsyncinterval", value<int>()->default_value(72),
("nettime.frompeers", value<bool>()->default_value(true), "Sync clock from transport peers (default: enabled)") "NTP sync interval in hours (default: 72)")
; ("nettime.frompeers", value<bool>()->default_value(true),
"Sync clock from transport peers (default: enabled)");
options_description persist("Network information persisting options"); options_description persist("Network information persisting options");
persist.add_options() persist.add_options()
("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)") ("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)")
("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");
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),
("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used") "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") ("cpuext.avx", bool_switch()->default_value(true),
; "Use auto detection for AVX CPU extensions. If false, AVX will be not used")
("cpuext.force", bool_switch()->default_value(false),
"Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines");
options_description meshnets("Meshnet transports options"); options_description meshnets("Meshnet transports options");
meshnets.add_options() meshnets.add_options()
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)") ("meshnets.yggdrasil", bool_switch()->default_value(false),
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish") "Support transports through the Yggdrasil (default: false)")
; ("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish");
#ifdef __linux__ #ifdef __linux__
options_description unix_specific("UNIX-specific options"); options_description unix_specific("UNIX-specific options");
@ -347,33 +406,28 @@ namespace config {
; ;
} }
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown) void ParseCmdline(int argc, char *argv[], bool ignoreUnknown) {
{ try {
try
{
auto style = boost::program_options::command_line_style::unix_style auto style = boost::program_options::command_line_style::unix_style
| boost::program_options::command_line_style::allow_long_disguise; | boost::program_options::command_line_style::allow_long_disguise;
style &= ~boost::program_options::command_line_style::allow_guessing; style &= ~boost::program_options::command_line_style::allow_guessing;
if (ignoreUnknown) if (ignoreUnknown)
store(command_line_parser(argc, argv).options(m_OptionsDesc).style (style).allow_unregistered().run(), m_Options); store(command_line_parser(argc, argv).options(m_OptionsDesc).style(
style).allow_unregistered().run(), m_Options);
else else
store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options); store(parse_command_line(argc, argv, m_OptionsDesc, style), m_Options);
} }
catch (boost::program_options::error& e) catch (boost::program_options::error &e) {
{
ThrowFatal("Error while parsing arguments: ", e.what()); ThrowFatal("Error while parsing arguments: ", e.what());
std::cerr << "args: " << e.what() << std::endl; std::cerr << "args: " << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h"))) if (!ignoreUnknown && (m_Options.count("help") || m_Options.count("h"))) {
{
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
std::cout << m_OptionsDesc; std::cout << m_OptionsDesc;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} } else if (m_Options.count("version")) {
else if (m_Options.count("version"))
{
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl; std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
std::cout << "Boost version " std::cout << "Boost version "
<< BOOST_VERSION / 100000 << "." // maj. version << BOOST_VERSION / 100000 << "." // maj. version
@ -391,38 +445,32 @@ namespace config {
} }
} }
void ParseConfig(const std::string& path) void ParseConfig(const std::string &path) {
{
if (path == "") return; if (path == "") return;
std::ifstream config(path, std::ios::in); std::ifstream config(path, std::ios::in);
if (!config.is_open()) if (!config.is_open()) {
{
ThrowFatal("Missing or unreadable config file: ", path); ThrowFatal("Missing or unreadable config file: ", path);
std::cerr << "missing/unreadable config file: " << path << std::endl; std::cerr << "missing/unreadable config file: " << path << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
try try {
{
store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options); store(boost::program_options::parse_config_file(config, m_OptionsDesc), m_Options);
} }
catch (boost::program_options::error& e) catch (boost::program_options::error &e) {
{
ThrowFatal("Error while parsing config file: ", e.what()); ThrowFatal("Error while parsing config file: ", e.what());
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}; };
} }
void Finalize() void Finalize() {
{
notify(m_Options); notify(m_Options);
} }
bool IsDefault(const char *name) bool IsDefault(const char *name) {
{
if (!m_Options.count(name)) if (!m_Options.count(name))
throw "try to check non-existent option"; throw "try to check non-existent option";
@ -431,16 +479,14 @@ namespace config {
return false; return false;
} }
bool GetOptionAsAny(const char *name, boost::any& value) bool GetOptionAsAny(const char *name, boost::any &value) {
{
if (!m_Options.count(name)) if (!m_Options.count(name))
return false; return false;
value = m_Options[name]; value = m_Options[name];
return true; return true;
} }
bool GetOptionAsAny(const std::string& name, boost::any& value) bool GetOptionAsAny(const std::string &name, boost::any &value) {
{
return GetOptionAsAny(name.c_str(), value); return GetOptionAsAny(name.c_str(), value);
} }

View file

@ -80,8 +80,7 @@ namespace config {
* Example: uint16_t port; GetOption("sam.port", port); * Example: uint16_t port; GetOption("sam.port", port);
*/ */
template<typename T> template<typename T>
bool GetOption(const char *name, T& value) bool GetOption(const char *name, T &value) {
{
if (!m_Options.count(name)) if (!m_Options.count(name))
return false; return false;
value = m_Options[name].as<T>(); value = m_Options[name].as<T>();
@ -89,12 +88,12 @@ namespace config {
} }
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);
/** /**
@ -106,8 +105,7 @@ namespace config {
* 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)) if (!m_Options.count(name))
return false; return false;
m_Options.at(name).value() = value; m_Options.at(name).value() = value;

View file

@ -16,22 +16,24 @@
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include "TunnelBase.h" #include "TunnelBase.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
#if OPENSSL_HKDF #if OPENSSL_HKDF
#include <openssl/kdf.h> #include <openssl/kdf.h>
#endif #endif
#if !OPENSSL_AEAD_CHACHA20_POLY1305 #if !OPENSSL_AEAD_CHACHA20_POLY1305
#include "ChaCha20.h" #include "ChaCha20.h"
#include "Poly1305.h" #include "Poly1305.h"
#endif #endif
#include "Crypto.h" #include "Crypto.h"
#include "Ed25519.h" #include "Ed25519.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Log.h" #include "Log.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
const uint8_t elgp_[256] = const uint8_t elgp_[256] =
{ {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
@ -86,8 +88,7 @@ namespace crypto
const int rsae_ = 65537; const int rsae_ = 65537;
struct CryptoConstants struct CryptoConstants {
{
// DH/ElGamal // DH/ElGamal
BIGNUM *elgp; BIGNUM *elgp;
BIGNUM *elgg; BIGNUM *elgg;
@ -101,8 +102,7 @@ namespace crypto
BIGNUM *rsae; BIGNUM *rsae;
CryptoConstants(const uint8_t *elgp_, int elgg_, const uint8_t *dsap_, CryptoConstants(const uint8_t *elgp_, int elgg_, const uint8_t *dsap_,
const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_) const uint8_t *dsaq_, const uint8_t *dsag_, int rsae_) {
{
elgp = BN_new(); elgp = BN_new();
BN_bin2bn(elgp_, 256, elgp); BN_bin2bn(elgp_, 256, elgp);
elgg = BN_new(); elgg = BN_new();
@ -117,20 +117,22 @@ namespace crypto
BN_set_word(rsae, rsae_); BN_set_word(rsae, rsae_);
} }
~CryptoConstants () ~CryptoConstants() {
{ BN_free(elgp);
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); BN_free(elgg);
BN_free(dsap);
BN_free(dsaq);
BN_free(dsag);
BN_free(rsae);
} }
}; };
static const CryptoConstants& GetCryptoConstants () static const CryptoConstants &GetCryptoConstants() {
{
static CryptoConstants cryptoConstants(elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_); static CryptoConstants cryptoConstants(elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_);
return cryptoConstants; return cryptoConstants;
} }
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len) bool bn2buf(const BIGNUM *bn, uint8_t *buf, size_t len) {
{
int offset = len - BN_num_bytes(bn); int offset = len - BN_num_bytes(bn);
if (offset < 0) return false; if (offset < 0) return false;
BN_bn2bin(bn, buf + offset); BN_bn2bin(bn, buf + offset);
@ -140,8 +142,8 @@ namespace crypto
// RSA // RSA
#define rsae GetCryptoConstants ().rsae #define rsae GetCryptoConstants ().rsae
const BIGNUM * GetRSAE ()
{ const BIGNUM *GetRSAE() {
return rsae; return rsae;
} }
@ -149,8 +151,8 @@ namespace crypto
#define dsap GetCryptoConstants ().dsap #define dsap GetCryptoConstants ().dsap
#define dsaq GetCryptoConstants ().dsaq #define dsaq GetCryptoConstants ().dsaq
#define dsag GetCryptoConstants ().dsag #define dsag GetCryptoConstants ().dsag
DSA * CreateDSA ()
{ DSA *CreateDSA() {
DSA *dsa = DSA_new(); DSA *dsa = DSA_new();
DSA_set0_pqg(dsa, BN_dup(dsap), BN_dup(dsaq), BN_dup(dsag)); DSA_set0_pqg(dsa, BN_dup(dsap), BN_dup(dsaq), BN_dup(dsag));
DSA_set0_key(dsa, NULL, NULL); DSA_set0_key(dsa, NULL, NULL);
@ -168,6 +170,7 @@ namespace crypto
#define elgg GetCryptoConstants ().elgg #define elgg GetCryptoConstants ().elgg
static BN_MONT_CTX *g_MontCtx = nullptr; static BN_MONT_CTX *g_MontCtx = nullptr;
static void PrecalculateElggTable(BIGNUM *table[][255], int len) // table is len's array of array of 255 bignums static void PrecalculateElggTable(BIGNUM *table[][255], int len) // table is len's array of array of 255 bignums
{ {
if (len <= 0) return; if (len <= 0) return;
@ -176,15 +179,13 @@ namespace crypto
BN_MONT_CTX_set(g_MontCtx, elgp, ctx); BN_MONT_CTX_set(g_MontCtx, elgp, ctx);
auto montCtx = BN_MONT_CTX_new(); auto montCtx = BN_MONT_CTX_new();
BN_MONT_CTX_copy(montCtx, g_MontCtx); BN_MONT_CTX_copy(montCtx, g_MontCtx);
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++) {
{
table[i][0] = BN_new(); table[i][0] = BN_new();
if (!i) if (!i)
BN_to_montgomery(table[0][0], elgg, montCtx, ctx); BN_to_montgomery(table[0][0], elgg, montCtx, ctx);
else else
BN_mod_mul_montgomery(table[i][0], table[i - 1][254], table[i - 1][0], montCtx, ctx); BN_mod_mul_montgomery(table[i][0], table[i - 1][254], table[i - 1][0], montCtx, ctx);
for (int j = 1; j < 255; j++) for (int j = 1; j < 255; j++) {
{
table[i][j] = BN_new(); table[i][j] = BN_new();
BN_mod_mul_montgomery(table[i][j], table[i][j - 1], table[i][0], montCtx, ctx); BN_mod_mul_montgomery(table[i][j], table[i][j - 1], table[i][0], montCtx, ctx);
} }
@ -193,11 +194,9 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
static void DestroyElggTable (BIGNUM * table[][255], int len) static void DestroyElggTable(BIGNUM *table[][255], int len) {
{
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
for (int j = 0; j < 255; j++) for (int j = 0; j < 255; j++) {
{
BN_free(table[i][j]); BN_free(table[i][j]);
table[i][j] = nullptr; table[i][j] = nullptr;
} }
@ -211,14 +210,11 @@ namespace crypto
auto montCtx = BN_MONT_CTX_new(); auto montCtx = BN_MONT_CTX_new();
BN_MONT_CTX_copy(montCtx, g_MontCtx); BN_MONT_CTX_copy(montCtx, g_MontCtx);
BIGNUM *res = nullptr; BIGNUM *res = nullptr;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++) {
{ if (res) {
if (res)
{
if (exp[i]) if (exp[i])
BN_mod_mul_montgomery(res, res, table[len - 1 - i][exp[i] - 1], montCtx, ctx); BN_mod_mul_montgomery(res, res, table[len - 1 - i][exp[i] - 1], montCtx, ctx);
} } else if (exp[i])
else if (exp[i])
res = BN_dup(table[len - i - 1][exp[i] - 1]); res = BN_dup(table[len - i - 1][exp[i] - 1]);
} }
if (res) if (res)
@ -227,8 +223,7 @@ namespace crypto
return res; return res;
} }
static BIGNUM * ElggPow (const BIGNUM * exp, BIGNUM * table[][255], BN_CTX * ctx) static BIGNUM *ElggPow(const BIGNUM *exp, BIGNUM *table[][255], BN_CTX *ctx) {
{
auto len = BN_num_bytes(exp); auto len = BN_num_bytes(exp);
uint8_t *buf = new uint8_t[len]; uint8_t *buf = new uint8_t[len];
BN_bn2bin(exp, buf); BN_bn2bin(exp, buf);
@ -241,27 +236,23 @@ namespace crypto
// DH // DH
DHKeys::DHKeys () DHKeys::DHKeys() {
{
m_DH = DH_new(); m_DH = DH_new();
DH_set0_pqg(m_DH, BN_dup(elgp), NULL, BN_dup(elgg)); DH_set0_pqg(m_DH, BN_dup(elgp), NULL, BN_dup(elgg));
DH_set0_key(m_DH, NULL, NULL); DH_set0_key(m_DH, NULL, NULL);
} }
DHKeys::~DHKeys () DHKeys::~DHKeys() {
{
DH_free(m_DH); DH_free(m_DH);
} }
void DHKeys::GenerateKeys () void DHKeys::GenerateKeys() {
{
BIGNUM *priv_key = NULL, *pub_key = NULL; BIGNUM *priv_key = NULL, *pub_key = NULL;
#if !defined(__x86_64__) // use short exponent for non x64 #if !defined(__x86_64__) // use short exponent for non x64
priv_key = BN_new(); priv_key = BN_new();
BN_rand(priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1); BN_rand(priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
#endif #endif
if (g_ElggTable) if (g_ElggTable) {
{
#if defined(__x86_64__) #if defined(__x86_64__)
priv_key = BN_new (); priv_key = BN_new ();
BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1); BN_rand (priv_key, ELGAMAL_FULL_EXPONENT_NUM_BITS, 0, 1);
@ -270,9 +261,7 @@ namespace crypto
pub_key = ElggPow(priv_key, g_ElggTable, ctx); pub_key = ElggPow(priv_key, g_ElggTable, ctx);
DH_set0_key(m_DH, pub_key, priv_key); DH_set0_key(m_DH, pub_key, priv_key);
BN_CTX_free(ctx); BN_CTX_free(ctx);
} } else {
else
{
DH_set0_key(m_DH, NULL, priv_key); DH_set0_key(m_DH, NULL, priv_key);
DH_generate_key(m_DH); DH_generate_key(m_DH);
DH_get0_key(m_DH, (const BIGNUM **) &pub_key, (const BIGNUM **) &priv_key); DH_get0_key(m_DH, (const BIGNUM **) &pub_key, (const BIGNUM **) &priv_key);
@ -281,16 +270,14 @@ namespace crypto
bn2buf(pub_key, m_PublicKey, 256); bn2buf(pub_key, m_PublicKey, 256);
} }
void DHKeys::Agree (const uint8_t * pub, uint8_t * shared) void DHKeys::Agree(const uint8_t *pub, uint8_t *shared) {
{
BIGNUM *pk = BN_bin2bn(pub, 256, NULL); BIGNUM *pk = BN_bin2bn(pub, 256, NULL);
DH_compute_key(shared, pk, m_DH); DH_compute_key(shared, pk, m_DH);
BN_free(pk); BN_free(pk);
} }
// x25519 // x25519
X25519Keys::X25519Keys () X25519Keys::X25519Keys() {
{
#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;
@ -299,8 +286,7 @@ namespace crypto
#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);
@ -321,8 +307,7 @@ namespace crypto
#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);
@ -331,8 +316,7 @@ namespace crypto
#endif #endif
} }
void X25519Keys::GenerateKeys () void X25519Keys::GenerateKeys() {
{
#if OPENSSL_X25519 #if OPENSSL_X25519
if (m_Pkey) if (m_Pkey)
{ {
@ -351,8 +335,7 @@ namespace crypto
#endif #endif
} }
bool X25519Keys::Agree (const uint8_t * pub, uint8_t * shared) bool X25519Keys::Agree(const uint8_t *pub, uint8_t *shared) {
{
if (!pub || (pub[31] & 0x80)) return false; // not x25519 key if (!pub || (pub[31] & 0x80)) return false; // not x25519 key
#if OPENSSL_X25519 #if OPENSSL_X25519
EVP_PKEY_derive_init (m_Ctx); EVP_PKEY_derive_init (m_Ctx);
@ -368,8 +351,7 @@ namespace crypto
return true; return true;
} }
void X25519Keys::GetPrivateKey (uint8_t * priv) const void X25519Keys::GetPrivateKey(uint8_t *priv) const {
{
#if OPENSSL_X25519 #if OPENSSL_X25519
size_t len = 32; size_t len = 32;
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len); EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
@ -378,8 +360,7 @@ namespace crypto
#endif #endif
} }
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic) void X25519Keys::SetPrivateKey(const uint8_t *priv, bool calculatePublic) {
{
#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);
@ -398,8 +379,7 @@ namespace crypto
} }
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted) void ElGamalEncrypt(const uint8_t *key, const uint8_t *data, uint8_t *encrypted) {
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BN_CTX_start(ctx); BN_CTX_start(ctx);
// everything, but a, because a might come from table // everything, but a, because a might come from table
@ -417,8 +397,7 @@ namespace crypto
BIGNUM *a; BIGNUM *a;
if (g_ElggTable) if (g_ElggTable)
a = ElggPow(k, g_ElggTable, ctx); a = ElggPow(k, g_ElggTable, ctx);
else else {
{
a = BN_new(); a = BN_new();
BN_mod_exp(a, elgg, k, elgp, ctx); BN_mod_exp(a, elgg, k, elgp, ctx);
} }
@ -446,13 +425,13 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data) bool ElGamalDecrypt(const uint8_t *key, const uint8_t *encrypted, uint8_t *data) {
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BN_CTX_start(ctx); BN_CTX_start(ctx);
BIGNUM *x = BN_CTX_get(ctx), *a = BN_CTX_get(ctx), *b = BN_CTX_get(ctx); BIGNUM *x = BN_CTX_get(ctx), *a = BN_CTX_get(ctx), *b = BN_CTX_get(ctx);
BN_bin2bn(key, 256, x); BN_bin2bn(key, 256, x);
BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1 BN_sub(x, elgp, x);
BN_sub_word(x, 1); // x = elgp - x- 1
BN_bin2bn(encrypted + 1, 256, a); BN_bin2bn(encrypted + 1, 256, a);
BN_bin2bn(encrypted + 258, 256, b); BN_bin2bn(encrypted + 258, 256, b);
// m = b*(a^x mod p) mod p // m = b*(a^x mod p) mod p
@ -464,8 +443,7 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
uint8_t hash[32]; uint8_t hash[32];
SHA256(m + 33, 222, hash); SHA256(m + 33, 222, hash);
if (memcmp (m + 1, hash, 32)) if (memcmp(m + 1, hash, 32)) {
{
LogPrint(eLogError, "ElGamal decrypt hash doesn't match"); LogPrint(eLogError, "ElGamal decrypt hash doesn't match");
return false; return false;
} }
@ -473,8 +451,7 @@ namespace crypto
return true; return true;
} }
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub) void GenerateElGamalKeyPair(uint8_t *priv, uint8_t *pub) {
{
#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) #if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER)
RAND_bytes (priv, 256); RAND_bytes (priv, 256);
#else #else
@ -495,8 +472,7 @@ namespace crypto
} }
// ECIES // ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted) void ECIESEncrypt(const EC_GROUP *curve, const EC_POINT *key, const uint8_t *data, uint8_t *encrypted) {
{
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);
@ -522,7 +498,8 @@ namespace crypto
SHA256(keyBuf, len, shared); SHA256(keyBuf, len, shared);
// create buffer // create buffer
uint8_t m[256]; uint8_t m[256];
m[0] = 0xFF; m[255] = 0xFF; m[0] = 0xFF;
m[255] = 0xFF;
memcpy(m + 33, data, 222); memcpy(m + 33, data, 222);
SHA256(m + 33, 222, m + 1); SHA256(m + 33, 222, m + 1);
// encrypt // encrypt
@ -536,8 +513,7 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data) bool ECIESDecrypt(const EC_GROUP *curve, const BIGNUM *key, const uint8_t *encrypted, uint8_t *data) {
{
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);
@ -549,8 +525,7 @@ namespace crypto
BN_bin2bn(encrypted + 1, len, x); BN_bin2bn(encrypted + 1, len, x);
BN_bin2bn(encrypted + 1 + len, len, y); BN_bin2bn(encrypted + 1 + len, len, y);
auto p = EC_POINT_new(curve); auto p = EC_POINT_new(curve);
if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr)) if (EC_POINT_set_affine_coordinates_GFp(curve, p, x, y, nullptr)) {
{
auto s = EC_POINT_new(curve); auto s = EC_POINT_new(curve);
EC_POINT_mul(curve, s, nullptr, p, key, ctx); EC_POINT_mul(curve, s, nullptr, p, key, ctx);
EC_POINT_get_affine_coordinates_GFp(curve, s, x, y, nullptr); EC_POINT_get_affine_coordinates_GFp(curve, s, x, y, nullptr);
@ -570,14 +545,11 @@ namespace crypto
SHA256(m + 33, 222, hash); SHA256(m + 33, 222, hash);
if (!memcmp(m + 1, hash, 32)) if (!memcmp(m + 1, hash, 32))
memcpy(data, m + 33, 222); memcpy(data, m + 33, 222);
else else {
{
LogPrint(eLogError, "ECIES decrypt hash doesn't match"); LogPrint(eLogError, "ECIES decrypt hash doesn't match");
ret = false; ret = false;
} }
} } else {
else
{
LogPrint(eLogError, "ECIES decrypt point is invalid"); LogPrint(eLogError, "ECIES decrypt point is invalid");
ret = false; ret = false;
} }
@ -588,8 +560,7 @@ namespace crypto
return ret; return ret;
} }
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub) void GenerateECIESKeyPair(const EC_GROUP *curve, BIGNUM *&priv, EC_POINT *&pub) {
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BIGNUM *q = BN_new(); BIGNUM *q = BN_new();
EC_GROUP_get_order(curve, q, ctx); EC_GROUP_get_order(curve, q, ctx);
@ -758,8 +729,7 @@ namespace crypto
"aesenclast 224(%["#sched"]), %%xmm0 \n" "aesenclast 224(%["#sched"]), %%xmm0 \n"
#endif #endif
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out) void ECBEncryption::Encrypt(const ChipherBlock *in, ChipherBlock *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -797,8 +767,7 @@ namespace crypto
"aesdeclast (%["#sched"]), %%xmm0 \n" "aesdeclast (%["#sched"]), %%xmm0 \n"
#endif #endif
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out) void ECBDecryption::Decrypt(const ChipherBlock *in, ChipherBlock *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -824,8 +793,7 @@ namespace crypto
"movaps %%xmm0, "#offset"(%[shed]) \n" "movaps %%xmm0, "#offset"(%[shed]) \n"
#endif #endif
void ECBEncryption::SetKey (const AESKey& key) void ECBEncryption::SetKey(const AESKey &key) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -838,8 +806,7 @@ namespace crypto
} }
} }
void ECBDecryption::SetKey (const AESKey& key) void ECBDecryption::SetKey(const AESKey &key) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -870,8 +837,7 @@ 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__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -898,8 +864,7 @@ namespace crypto
else else
#endif #endif
{ {
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++) {
{
*m_LastBlock.GetChipherBlock() ^= in[i]; *m_LastBlock.GetChipherBlock() ^= in[i];
m_ECBEncryption.Encrypt(m_LastBlock.GetChipherBlock(), m_LastBlock.GetChipherBlock()); m_ECBEncryption.Encrypt(m_LastBlock.GetChipherBlock(), m_LastBlock.GetChipherBlock());
out[i] = *m_LastBlock.GetChipherBlock(); out[i] = *m_LastBlock.GetChipherBlock();
@ -907,16 +872,14 @@ namespace crypto
} }
} }
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out) void CBCEncryption::Encrypt(const uint8_t *in, std::size_t len, uint8_t *out) {
{
// len/16 // len/16
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Encrypt(numBlocks, (const ChipherBlock *) in, (ChipherBlock *) out); Encrypt(numBlocks, (const ChipherBlock *) in, (ChipherBlock *) out);
} }
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out) void CBCEncryption::Encrypt(const uint8_t *in, uint8_t *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -939,8 +902,7 @@ namespace crypto
Encrypt(1, (const ChipherBlock *) in, (ChipherBlock *) out); Encrypt(1, (const ChipherBlock *) in, (ChipherBlock *) out);
} }
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCDecryption::Decrypt(int numBlocks, const ChipherBlock *in, ChipherBlock *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -968,8 +930,7 @@ namespace crypto
else else
#endif #endif
{ {
for (int i = 0; i < numBlocks; i++) for (int i = 0; i < numBlocks; i++) {
{
ChipherBlock tmp = in[i]; ChipherBlock tmp = in[i];
m_ECBDecryption.Decrypt(in + i, out + i); m_ECBDecryption.Decrypt(in + i, out + i);
out[i] ^= *m_IV.GetChipherBlock(); out[i] ^= *m_IV.GetChipherBlock();
@ -978,15 +939,13 @@ namespace crypto
} }
} }
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out) void CBCDecryption::Decrypt(const uint8_t *in, std::size_t len, uint8_t *out) {
{
int numBlocks = len >> 4; int numBlocks = len >> 4;
if (numBlocks > 0) if (numBlocks > 0)
Decrypt(numBlocks, (const ChipherBlock *) in, (ChipherBlock *) out); Decrypt(numBlocks, (const ChipherBlock *) in, (ChipherBlock *) out);
} }
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out) void CBCDecryption::Decrypt(const uint8_t *in, uint8_t *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -1009,8 +968,7 @@ namespace crypto
Decrypt(1, (const ChipherBlock *) in, (ChipherBlock *) out); 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) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -1050,8 +1008,7 @@ namespace crypto
} }
} }
void TunnelDecryption::Decrypt (const uint8_t * in, uint8_t * out) void TunnelDecryption::Decrypt(const uint8_t *in, uint8_t *out) {
{
#ifdef __AES__ #ifdef __AES__
if(i2p::cpu::aesni) if(i2p::cpu::aesni)
{ {
@ -1094,8 +1051,9 @@ 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) 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) {
if (len < msgLen) return false; if (len < msgLen) return false;
if (encrypt && len < msgLen + 16) return false; if (encrypt && len < msgLen + 16) return false;
bool ret = true; bool ret = true;
@ -1134,13 +1092,12 @@ namespace crypto
// create Poly1305 hash // create Poly1305 hash
Poly1305 polyHash(polyKey); Poly1305 polyHash(polyKey);
if (!ad) adLen = 0; if (!ad) adLen = 0;
uint8_t padding[16]; memset (padding, 0, 16); uint8_t padding[16];
if (ad) memset(padding, 0, 16);
{ if (ad) {
polyHash.Update(ad, adLen);// additional authenticated data polyHash.Update(ad, adLen);// additional authenticated data
auto rem = adLen & 0x0F; // %16 auto rem = adLen & 0x0F; // %16
if (rem) if (rem) {
{
// padding1 // padding1
rem = 16 - rem; rem = 16 - rem;
polyHash.Update(padding, rem); polyHash.Update(padding, rem);
@ -1150,20 +1107,16 @@ namespace crypto
Chacha20SetCounter(state, 1); Chacha20SetCounter(state, 1);
if (buf != msg) if (buf != msg)
memcpy(buf, msg, msgLen); memcpy(buf, msg, msgLen);
if (encrypt) if (encrypt) {
{
chacha::Chacha20Encrypt(state, buf, msgLen); // encrypt chacha::Chacha20Encrypt(state, buf, msgLen); // encrypt
polyHash.Update(buf, msgLen); // after encryption polyHash.Update(buf, msgLen); // after encryption
} } else {
else
{
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);
@ -1176,8 +1129,7 @@ namespace crypto
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));
else else {
{
uint64_t tag[4]; uint64_t tag[4];
// calculate Poly1305 tag // calculate Poly1305 tag
polyHash.Finish(tag); polyHash.Finish(tag);
@ -1187,8 +1139,8 @@ namespace crypto
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) void AEADChaCha20Poly1305Encrypt(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;
#if OPENSSL_AEAD_CHACHA20_POLY1305 #if OPENSSL_AEAD_CHACHA20_POLY1305
int outlen = 0; int outlen = 0;
@ -1212,8 +1164,7 @@ namespace crypto
// 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) {
{
chacha::Chacha20Encrypt(state, it.first, it.second); chacha::Chacha20Encrypt(state, it.first, it.second);
polyHash.Update(it.first, it.second); // after encryption polyHash.Update(it.first, it.second); // after encryption
size += it.second; size += it.second;
@ -1222,8 +1173,7 @@ namespace crypto
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);
@ -1237,8 +1187,7 @@ namespace crypto
#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) {
{
#if OPENSSL_AEAD_CHACHA20_POLY1305 #if OPENSSL_AEAD_CHACHA20_POLY1305
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new (); EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
uint32_t iv[4]; uint32_t iv[4];
@ -1257,8 +1206,7 @@ namespace crypto
} }
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
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr); EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
EVP_PKEY_derive_init (pctx); EVP_PKEY_derive_init (pctx);
@ -1281,14 +1229,17 @@ namespace crypto
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
@ -1296,8 +1247,7 @@ namespace crypto
// Noise // Noise
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) void NoiseSymmetricState::MixHash(const uint8_t *buf, size_t len) {
{
SHA256_CTX ctx; SHA256_CTX ctx;
SHA256_Init(&ctx); SHA256_Init(&ctx);
SHA256_Update(&ctx, m_H, 32); SHA256_Update(&ctx, m_H, 32);
@ -1305,8 +1255,7 @@ namespace crypto
SHA256_Final(m_H, &ctx); SHA256_Final(m_H, &ctx);
} }
void NoiseSymmetricState::MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs) void NoiseSymmetricState::MixHash(const std::vector<std::pair<uint8_t *, size_t> > &bufs) {
{
SHA256_CTX ctx; SHA256_CTX ctx;
SHA256_Init(&ctx); SHA256_Init(&ctx);
SHA256_Update(&ctx, m_H, 32); SHA256_Update(&ctx, m_H, 32);
@ -1315,15 +1264,13 @@ namespace crypto
SHA256_Final(m_H, &ctx); SHA256_Final(m_H, &ctx);
} }
void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) void NoiseSymmetricState::MixKey(const uint8_t *sharedSecret) {
{
HKDF(m_CK, sharedSecret, 32, "", m_CK); HKDF(m_CK, sharedSecret, 32, "", m_CK);
// new ck is m_CK[0:31], key is m_CK[32:63] // new ck is m_CK[0:31], key is m_CK[32:63]
} }
static void InitNoiseState(NoiseSymmetricState &state, const uint8_t *ck, static void InitNoiseState(NoiseSymmetricState &state, const uint8_t *ck,
const uint8_t * hh, const uint8_t * pub) const uint8_t *hh, const uint8_t *pub) {
{
// pub is Bob's public static key, hh = SHA256(h) // pub is Bob's public static key, hh = SHA256(h)
memcpy(state.m_CK, ck, 32); memcpy(state.m_CK, ck, 32);
SHA256_CTX ctx; SHA256_CTX ctx;
@ -1333,58 +1280,68 @@ namespace crypto
SHA256_Final(state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) SHA256_Final(state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
} }
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseNState(NoiseSymmetricState &state, const uint8_t *pub) {
{
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d,
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 0xc1,
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15,
0x54
}; // hh = SHA256(protocol_name || 0) }; // hh = SHA256(protocol_name || 0)
InitNoiseState(state, (const uint8_t *) protocolName, hh, pub); // ck = protocol_name || 0 InitNoiseState(state, (const uint8_t *) protocolName, hh, pub); // ck = protocol_name || 0
} }
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseXKState(NoiseSymmetricState &state, const uint8_t *pub) {
{
static const uint8_t protocolNameHash[32] = static const uint8_t protocolNameHash[32] =
{ {
0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7,
0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 0xed,
0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f,
0x71
}; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256") }; // SHA256 ("Noise_XKaesobfse+hs2+hs3_25519_ChaChaPoly_SHA256")
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05,
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e 0xb5,
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d,
0x1e
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState(state, protocolNameHash, hh, pub); InitNoiseState(state, protocolNameHash, hh, pub);
} }
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseXKState1(NoiseSymmetricState &state, const uint8_t *pub) {
{
static const uint8_t protocolNameHash[32] = static const uint8_t protocolNameHash[32] =
{ {
0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed, 0xf4, 0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed,
0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81, 0x32 0xf4,
0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81,
0x32
}; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256") }; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256")
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53, 0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4,
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33 0x53,
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc,
0x33
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState(state, protocolNameHash, hh, pub); InitNoiseState(state, protocolNameHash, hh, pub);
} }
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseIKState(NoiseSymmetricState &state, const uint8_t *pub) {
{
static const uint8_t protocolNameHash[32] = static const uint8_t protocolNameHash[32] =
{ {
0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba, 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d,
0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c 0xba,
0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4,
0x0c
}; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes }; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c 0x32,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b,
0x5c
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState(state, protocolNameHash, hh, pub); InitNoiseState(state, protocolNameHash, hh, pub);
} }
@ -1403,8 +1360,7 @@ namespace crypto
} }
}*/ }*/
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force) void InitCrypto(bool precomputation, bool aesni, bool avx, bool force) {
{
i2p::cpu::Detect(aesni, avx, force); i2p::cpu::Detect(aesni, avx, force);
#if LEGACY_OPENSSL #if LEGACY_OPENSSL
SSL_library_init(); SSL_library_init();
@ -1413,8 +1369,7 @@ namespace crypto
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);
CRYPTO_set_locking_callback (OpensslLockingCallback);*/ CRYPTO_set_locking_callback (OpensslLockingCallback);*/
if (precomputation) if (precomputation) {
{
#if defined(__x86_64__) #if defined(__x86_64__)
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255]; g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES); PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
@ -1425,10 +1380,8 @@ namespace crypto
} }
} }
void TerminateCrypto () void TerminateCrypto() {
{ if (g_ElggTable) {
if (g_ElggTable)
{
DestroyElggTable(g_ElggTable, DestroyElggTable(g_ElggTable,
#if defined(__x86_64__) #if defined(__x86_64__)
ELGAMAL_FULL_EXPONENT_NUM_BYTES ELGAMAL_FULL_EXPONENT_NUM_BYTES
@ -1436,7 +1389,8 @@ namespace crypto
ELGAMAL_SHORT_EXPONENT_NUM_BYTES ELGAMAL_SHORT_EXPONENT_NUM_BYTES
#endif #endif
); );
delete[] g_ElggTable; g_ElggTable = nullptr; delete[] g_ElggTable;
g_ElggTable = nullptr;
} }
/* CRYPTO_set_locking_callback (nullptr); /* CRYPTO_set_locking_callback (nullptr);
m_OpenSSLMutexes.clear ();*/ m_OpenSSLMutexes.clear ();*/

View file

@ -50,10 +50,8 @@
# endif # endif
#endif #endif
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
bool bn2buf(const BIGNUM *bn, uint8_t *buf, size_t len); bool bn2buf(const BIGNUM *bn, uint8_t *buf, size_t len);
// DSA // DSA
@ -63,15 +61,17 @@ namespace crypto
const BIGNUM *GetRSAE(); const BIGNUM *GetRSAE();
// DH // DH
class DHKeys class DHKeys {
{
public: public:
DHKeys(); DHKeys();
~DHKeys(); ~DHKeys();
void GenerateKeys(); void GenerateKeys();
const uint8_t *GetPublicKey() const { return m_PublicKey; }; const uint8_t *GetPublicKey() const { return m_PublicKey; };
void Agree(const uint8_t *pub, uint8_t *shared); void Agree(const uint8_t *pub, uint8_t *shared);
private: private:
@ -81,21 +81,26 @@ namespace crypto
}; };
// x25519 // x25519
class X25519Keys class X25519Keys {
{
public: public:
X25519Keys(); X25519Keys();
X25519Keys(const uint8_t *priv, const uint8_t *pub); // if pub is null, derive from priv X25519Keys(const uint8_t *priv, const uint8_t *pub); // if pub is null, derive from priv
~X25519Keys(); ~X25519Keys();
void GenerateKeys(); void GenerateKeys();
const uint8_t *GetPublicKey() const { return m_PublicKey; }; const uint8_t *GetPublicKey() const { return m_PublicKey; };
void GetPrivateKey(uint8_t *priv) const; void GetPrivateKey(uint8_t *priv) const;
void SetPrivateKey(const uint8_t *priv, bool calculatePublic = false); void SetPrivateKey(const uint8_t *priv, bool calculatePublic = false);
bool Agree(const uint8_t *pub, uint8_t *shared); bool Agree(const uint8_t *pub, uint8_t *shared);
bool IsElligatorIneligible() const { return m_IsElligatorIneligible; } bool IsElligatorIneligible() const { return m_IsElligatorIneligible; }
void SetElligatorIneligible() { m_IsElligatorIneligible = true; } void SetElligatorIneligible() { m_IsElligatorIneligible = true; }
private: private:
@ -112,22 +117,26 @@ namespace crypto
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted void ElGamalEncrypt(const uint8_t *key, const uint8_t *data,
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data uint8_t *encrypted); // 222 bytes data, 514 bytes encrypted
bool
ElGamalDecrypt(const uint8_t *key, const uint8_t *encrypted, uint8_t *data); // 514 bytes encrypted, 222 data
void GenerateElGamalKeyPair(uint8_t *priv, uint8_t *pub); void GenerateElGamalKeyPair(uint8_t *priv, uint8_t *pub);
// ECIES // ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted void ECIESEncrypt(const EC_GROUP *curve, const EC_POINT *key, const uint8_t *data,
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data uint8_t *encrypted); // 222 bytes data, 514 bytes encrypted
bool ECIESDecrypt(const EC_GROUP *curve, const BIGNUM *key, const uint8_t *encrypted,
uint8_t *data); // 514 bytes encrypted, 222 data
void GenerateECIESKeyPair(const EC_GROUP *curve, BIGNUM *&priv, EC_POINT *&pub); void GenerateECIESKeyPair(const EC_GROUP *curve, BIGNUM *&priv, EC_POINT *&pub);
// HMAC // HMAC
typedef i2p::data::Tag<32> MACKey; typedef i2p::data::Tag<32> MACKey;
void HMACMD5Digest(uint8_t *msg, size_t len, const MACKey &key, uint8_t *digest); void HMACMD5Digest(uint8_t *msg, size_t len, const MACKey &key, uint8_t *digest);
// AES // AES
struct ChipherBlock struct ChipherBlock {
{
uint8_t buf[16]; uint8_t buf[16];
void operator^=(const ChipherBlock &other) // XOR void operator^=(const ChipherBlock &other) // XOR
@ -136,9 +145,7 @@ namespace crypto
{ {
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];
} }
@ -152,8 +159,7 @@ namespace crypto
{ {
public: public:
AESAlignedBuffer () AESAlignedBuffer() {
{
m_Buf = m_UnalignedBuffer; m_Buf = m_UnalignedBuffer;
uint8_t rem = ((size_t) m_Buf) & 0x0f; uint8_t rem = ((size_t) m_Buf) & 0x0f;
if (rem) if (rem)
@ -161,8 +167,11 @@ namespace crypto
} }
operator uint8_t *() { return m_Buf; }; operator uint8_t *() { return m_Buf; };
operator const uint8_t *() const { return m_Buf; }; operator const uint8_t *() const { return m_Buf; };
ChipherBlock *GetChipherBlock() { return (ChipherBlock *) m_Buf; }; ChipherBlock *GetChipherBlock() { return (ChipherBlock *) m_Buf; };
const ChipherBlock *GetChipherBlock() const { return (const ChipherBlock *) m_Buf; }; const ChipherBlock *GetChipherBlock() const { return (const ChipherBlock *) m_Buf; };
private: private:
@ -192,6 +201,7 @@ namespace crypto
#ifdef __AES__ #ifdef __AES__
class ECBEncryption: public ECBCryptoAESNI class ECBEncryption: public ECBCryptoAESNI
#else #else
class ECBEncryption class ECBEncryption
#endif #endif
{ {
@ -208,19 +218,21 @@ namespace crypto
#ifdef __AES__ #ifdef __AES__
class ECBDecryption: public ECBCryptoAESNI class ECBDecryption: public ECBCryptoAESNI
#else #else
class ECBDecryption class ECBDecryption
#endif #endif
{ {
public: public:
void SetKey(const AESKey &key); void SetKey(const AESKey &key);
void Decrypt(const ChipherBlock *in, ChipherBlock *out); void Decrypt(const ChipherBlock *in, ChipherBlock *out);
private: private:
AES_KEY m_Key; AES_KEY m_Key;
}; };
class CBCEncryption class CBCEncryption {
{
public: public:
CBCEncryption() { memset((uint8_t *) m_LastBlock, 0, 16); }; CBCEncryption() { memset((uint8_t *) m_LastBlock, 0, 16); };
@ -230,7 +242,9 @@ namespace crypto
void GetIV(uint8_t *iv) const { memcpy(iv, (const uint8_t *) m_LastBlock, 16); }; 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(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, std::size_t len, uint8_t *out);
void Encrypt(const uint8_t *in, uint8_t *out); // one block void Encrypt(const uint8_t *in, uint8_t *out); // one block
ECBEncryption &ECB() { return m_ECBEncryption; } ECBEncryption &ECB() { return m_ECBEncryption; }
@ -242,8 +256,7 @@ namespace crypto
ECBEncryption m_ECBEncryption; ECBEncryption m_ECBEncryption;
}; };
class CBCDecryption class CBCDecryption {
{
public: public:
CBCDecryption() { memset((uint8_t *) m_IV, 0, 16); }; CBCDecryption() { memset((uint8_t *) m_IV, 0, 16); };
@ -253,7 +266,9 @@ namespace crypto
void GetIV(uint8_t *iv) const { memcpy(iv, (const uint8_t *) m_IV, 16); }; 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(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, std::size_t len, uint8_t *out);
void Decrypt(const uint8_t *in, uint8_t *out); // one block void Decrypt(const uint8_t *in, uint8_t *out); // one block
ECBDecryption &ECB() { return m_ECBDecryption; } ECBDecryption &ECB() { return m_ECBDecryption; }
@ -268,8 +283,7 @@ namespace crypto
{ {
public: public:
void SetKeys (const AESKey& layerKey, const AESKey& ivKey) void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
{
m_LayerEncryption.SetKey(layerKey); m_LayerEncryption.SetKey(layerKey);
m_IVEncryption.SetKey(ivKey); m_IVEncryption.SetKey(ivKey);
} }
@ -286,8 +300,7 @@ namespace crypto
{ {
public: public:
void SetKeys (const AESKey& layerKey, const AESKey& ivKey) void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
{
m_LayerDecryption.SetKey(layerKey); m_LayerDecryption.SetKey(layerKey);
m_IVDecryption.SetKey(ivKey); m_IVDecryption.SetKey(ivKey);
} }
@ -301,25 +314,30 @@ 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 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 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
// 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);
// 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
// Noise // Noise
struct NoiseSymmetricState struct NoiseSymmetricState {
{
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
void MixHash(const uint8_t *buf, size_t len); void MixHash(const uint8_t *buf, size_t len);
void MixHash(const std::vector<std::pair<uint8_t *, size_t> > &bufs); void MixHash(const std::vector<std::pair<uint8_t *, size_t> > &bufs);
void MixKey(const uint8_t *sharedSecret); void MixKey(const uint8_t *sharedSecret);
}; };
@ -330,79 +348,108 @@ namespace crypto
// init and terminate // init and terminate
void InitCrypto(bool precomputation, bool aesni, bool avx, bool force); void InitCrypto(bool precomputation, bool aesni, bool avx, bool force);
void TerminateCrypto(); void TerminateCrypto();
} }
} }
// take care about openssl below 1.1.0 // take care about openssl below 1.1.0
#if LEGACY_OPENSSL #if LEGACY_OPENSSL
// define getters and setters introduced in 1.1.0 // define getters and setters introduced in 1.1.0
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) {
{
if (d->p) BN_free(d->p); if (d->p) BN_free(d->p);
if (d->q) BN_free(d->q); if (d->q) BN_free(d->q);
if (d->g) BN_free(d->g); if (d->g) BN_free(d->g);
d->p = p; d->q = q; d->g = g; return 1; d->p = p;
d->q = q;
d->g = g;
return 1;
} }
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{ inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) {
if (d->pub_key) BN_free(d->pub_key); if (d->pub_key) BN_free(d->pub_key);
if (d->priv_key) BN_free(d->priv_key); if (d->priv_key) BN_free(d->priv_key);
d->pub_key = pub_key; d->priv_key = priv_key; return 1; d->pub_key = pub_key;
d->priv_key = priv_key;
return 1;
} }
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = d->pub_key; *priv_key = d->priv_key; } inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) {
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) *pub_key = d->pub_key;
{ *priv_key = d->priv_key;
}
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
if (sig->r) BN_free(sig->r); if (sig->r) BN_free(sig->r);
if (sig->s) BN_free(sig->s); if (sig->s) BN_free(sig->s);
sig->r = r; sig->s = s; return 1; sig->r = r;
sig->s = s;
return 1;
} }
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; }
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {
{ *pr = sig->r;
*ps = sig->s;
}
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
if (sig->r) BN_free(sig->r); if (sig->r) BN_free(sig->r);
if (sig->s) BN_free(sig->s); if (sig->s) BN_free(sig->s);
sig->r = r; sig->s = s; return 1; sig->r = r;
sig->s = s;
return 1;
} }
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; }
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {
{ *pr = sig->r;
*ps = sig->s;
}
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) {
if (r->n) BN_free(r->n); if (r->n) BN_free(r->n);
if (r->e) BN_free(r->e); if (r->e) BN_free(r->e);
if (r->d) BN_free(r->d); if (r->d) BN_free(r->d);
r->n = n; r->e = e; r->d = d; return 1; r->n = n;
r->e = e;
r->d = d;
return 1;
} }
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{ *n = r->n; *e = r->e; *d = r->d; }
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) {
{ *n = r->n;
*e = r->e;
*d = r->d;
}
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) {
if (dh->p) BN_free(dh->p); if (dh->p) BN_free(dh->p);
if (dh->q) BN_free(dh->q); if (dh->q) BN_free(dh->q);
if (dh->g) BN_free(dh->g); if (dh->g) BN_free(dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1; dh->p = p;
dh->q = q;
dh->g = g;
return 1;
} }
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{ inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) {
if (dh->pub_key) BN_free(dh->pub_key); if (dh->pub_key) BN_free(dh->pub_key);
if (dh->priv_key) BN_free(dh->priv_key); if (dh->priv_key) BN_free(dh->priv_key);
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1; dh->pub_key = pub_key;
dh->priv_key = priv_key;
return 1;
} }
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) {
{ return pkey->pkey.rsa; } *pub_key = dh->pub_key;
*priv_key = dh->priv_key;
}
inline EVP_MD_CTX *EVP_MD_CTX_new () inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) { return pkey->pkey.rsa; }
{ return EVP_MD_CTX_create(); }
inline void EVP_MD_CTX_free (EVP_MD_CTX *ctx) inline EVP_MD_CTX *EVP_MD_CTX_new() { return EVP_MD_CTX_create(); }
{ EVP_MD_CTX_destroy (ctx); }
inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_destroy(ctx); }
// ssl // ssl
#define TLS_method TLSv1_method #define TLS_method TLSv1_method

View file

@ -11,74 +11,62 @@
#include "Gost.h" #include "Gost.h"
#include "CryptoKey.h" #include "CryptoKey.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto ElGamalEncryptor::ElGamalEncryptor(const uint8_t *pub) {
{
ElGamalEncryptor::ElGamalEncryptor (const uint8_t * pub)
{
memcpy(m_PublicKey, pub, 256); memcpy(m_PublicKey, pub, 256);
} }
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted) void ElGamalEncryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
{
ElGamalEncrypt(m_PublicKey, data, encrypted); ElGamalEncrypt(m_PublicKey, data, encrypted);
} }
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv) ElGamalDecryptor::ElGamalDecryptor(const uint8_t *priv) {
{
memcpy(m_PrivateKey, priv, 256); memcpy(m_PrivateKey, priv, 256);
} }
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data) bool ElGamalDecryptor::Decrypt(const uint8_t *encrypted, uint8_t *data) {
{
return ElGamalDecrypt(m_PrivateKey, encrypted, data); return ElGamalDecrypt(m_PrivateKey, encrypted, data);
} }
ECIESP256Encryptor::ECIESP256Encryptor (const uint8_t * pub) ECIESP256Encryptor::ECIESP256Encryptor(const uint8_t *pub) {
{
m_Curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); m_Curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
m_PublicKey = EC_POINT_new(m_Curve); m_PublicKey = EC_POINT_new(m_Curve);
BIGNUM *x = BN_bin2bn(pub, 32, nullptr); BIGNUM *x = BN_bin2bn(pub, 32, nullptr);
BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr); BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr);
if (!EC_POINT_set_affine_coordinates_GFp(m_Curve, m_PublicKey, x, y, nullptr)) if (!EC_POINT_set_affine_coordinates_GFp(m_Curve, m_PublicKey, x, y, nullptr))
LogPrint(eLogError, "ECICS P256 invalid public key"); LogPrint(eLogError, "ECICS P256 invalid public key");
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
} }
ECIESP256Encryptor::~ECIESP256Encryptor () ECIESP256Encryptor::~ECIESP256Encryptor() {
{
if (m_Curve) EC_GROUP_free(m_Curve); if (m_Curve) EC_GROUP_free(m_Curve);
if (m_PublicKey) EC_POINT_free(m_PublicKey); if (m_PublicKey) EC_POINT_free(m_PublicKey);
} }
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted) void ECIESP256Encryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
{
if (m_Curve && m_PublicKey) if (m_Curve && m_PublicKey)
ECIESEncrypt(m_Curve, m_PublicKey, data, encrypted); ECIESEncrypt(m_Curve, m_PublicKey, data, encrypted);
} }
ECIESP256Decryptor::ECIESP256Decryptor (const uint8_t * priv) ECIESP256Decryptor::ECIESP256Decryptor(const uint8_t *priv) {
{
m_Curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); m_Curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
m_PrivateKey = BN_bin2bn(priv, 32, nullptr); m_PrivateKey = BN_bin2bn(priv, 32, nullptr);
} }
ECIESP256Decryptor::~ECIESP256Decryptor () ECIESP256Decryptor::~ECIESP256Decryptor() {
{
if (m_Curve) EC_GROUP_free(m_Curve); if (m_Curve) EC_GROUP_free(m_Curve);
if (m_PrivateKey) BN_free(m_PrivateKey); if (m_PrivateKey) BN_free(m_PrivateKey);
} }
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data) bool ECIESP256Decryptor::Decrypt(const uint8_t *encrypted, uint8_t *data) {
{
if (m_Curve && m_PrivateKey) if (m_Curve && m_PrivateKey)
return ECIESDecrypt(m_Curve, m_PrivateKey, encrypted, data); return ECIESDecrypt(m_Curve, m_PrivateKey, encrypted, data);
return false; return false;
} }
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESP256RandomKeys(uint8_t *priv, uint8_t *pub) {
{
EC_GROUP *curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); EC_GROUP *curve = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
EC_POINT *p = nullptr; EC_POINT *p = nullptr;
BIGNUM *key = nullptr; BIGNUM *key = nullptr;
@ -92,52 +80,47 @@ namespace crypto
bn2buf(y, pub + 32, 32); bn2buf(y, pub + 32, 32);
RAND_bytes(pub + 64, 192); RAND_bytes(pub + 64, 192);
EC_POINT_free(p); EC_POINT_free(p);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
EC_GROUP_free(curve); EC_GROUP_free(curve);
} }
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub) ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor(const uint8_t *pub) {
{
auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA); auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA);
m_PublicKey = EC_POINT_new(curve->GetGroup()); m_PublicKey = EC_POINT_new(curve->GetGroup());
BIGNUM *x = BN_bin2bn(pub, 32, nullptr); BIGNUM *x = BN_bin2bn(pub, 32, nullptr);
BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr); BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr);
if (!EC_POINT_set_affine_coordinates_GFp(curve->GetGroup(), m_PublicKey, x, y, nullptr)) if (!EC_POINT_set_affine_coordinates_GFp(curve->GetGroup(), m_PublicKey, x, y, nullptr))
LogPrint(eLogError, "ECICS GOST R 34.10 invalid public key"); LogPrint(eLogError, "ECICS GOST R 34.10 invalid public key");
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
} }
ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor () ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor() {
{
if (m_PublicKey) EC_POINT_free(m_PublicKey); if (m_PublicKey) EC_POINT_free(m_PublicKey);
} }
void ECIESGOSTR3410Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted) void ECIESGOSTR3410Encryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
{
if (m_PublicKey) if (m_PublicKey)
ECIESEncrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PublicKey, data, encrypted); ECIESEncrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PublicKey, data, encrypted);
} }
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv) ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor(const uint8_t *priv) {
{
m_PrivateKey = BN_bin2bn(priv, 32, nullptr); m_PrivateKey = BN_bin2bn(priv, 32, nullptr);
} }
ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor () ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor() {
{
if (m_PrivateKey) BN_free(m_PrivateKey); if (m_PrivateKey) BN_free(m_PrivateKey);
} }
bool ECIESGOSTR3410Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data) bool ECIESGOSTR3410Decryptor::Decrypt(const uint8_t *encrypted, uint8_t *data) {
{
if (m_PrivateKey) if (m_PrivateKey)
return ECIESDecrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PrivateKey, encrypted, data); return ECIESDecrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PrivateKey, encrypted, data);
return false; return false;
} }
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESGOSTR3410RandomKeys(uint8_t *priv, uint8_t *pub) {
{
auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA); auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA);
EC_POINT *p = nullptr; EC_POINT *p = nullptr;
BIGNUM *key = nullptr; BIGNUM *key = nullptr;
@ -151,31 +134,27 @@ namespace crypto
bn2buf(y, pub + 32, 32); bn2buf(y, pub + 32, 32);
RAND_bytes(pub + 64, 192); RAND_bytes(pub + 64, 192);
EC_POINT_free(p); EC_POINT_free(p);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
} }
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) void ECIESX25519AEADRatchetEncryptor::Encrypt(const uint8_t *, uint8_t *pub) {
{
memcpy(pub, m_PublicKey, 32); memcpy(pub, m_PublicKey, 32);
} }
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv, bool calculatePublic) ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor(const uint8_t *priv, bool calculatePublic) {
{
m_StaticKeys.SetPrivateKey(priv, calculatePublic); m_StaticKeys.SetPrivateKey(priv, calculatePublic);
} }
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret) bool ECIESX25519AEADRatchetDecryptor::Decrypt(const uint8_t *epub, uint8_t *sharedSecret) {
{
return m_StaticKeys.Agree(epub, sharedSecret); return m_StaticKeys.Agree(epub, sharedSecret);
} }
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);

View file

@ -12,24 +12,23 @@
#include <inttypes.h> #include <inttypes.h>
#include "Crypto.h" #include "Crypto.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto class CryptoKeyEncryptor {
{
class CryptoKeyEncryptor
{
public: public:
virtual ~CryptoKeyEncryptor() {}; virtual ~CryptoKeyEncryptor() {};
virtual void Encrypt(const uint8_t *data, uint8_t *encrypted) = 0; virtual void Encrypt(const uint8_t *data, uint8_t *encrypted) = 0;
}; };
class CryptoKeyDecryptor class CryptoKeyDecryptor {
{
public: public:
virtual ~CryptoKeyDecryptor() {}; virtual ~CryptoKeyDecryptor() {};
virtual bool Decrypt(const uint8_t *encrypted, uint8_t *data) = 0; virtual bool Decrypt(const uint8_t *encrypted, uint8_t *data) = 0;
virtual size_t GetPublicKeyLen() const = 0; // we need it to set key in LS2 virtual size_t GetPublicKeyLen() const = 0; // we need it to set key in LS2
}; };
@ -39,6 +38,7 @@ namespace crypto
public: public:
ElGamalEncryptor(const uint8_t *pub); ElGamalEncryptor(const uint8_t *pub);
void Encrypt(const uint8_t *data, uint8_t *encrypted) override; // 222 bytes data, 514 bytes encrypted void Encrypt(const uint8_t *data, uint8_t *encrypted) override; // 222 bytes data, 514 bytes encrypted
private: private:
@ -51,6 +51,7 @@ namespace crypto
public: public:
ElGamalDecryptor(const uint8_t *priv); ElGamalDecryptor(const uint8_t *priv);
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override; // 514 bytes encrypted, 222 bytes data bool Decrypt(const uint8_t *encrypted, uint8_t *data) override; // 514 bytes encrypted, 222 bytes data
size_t GetPublicKeyLen() const override { return 256; }; size_t GetPublicKeyLen() const override { return 256; };
@ -61,12 +62,13 @@ namespace crypto
// ECIES P256 // ECIES P256
class ECIESP256Encryptor: public CryptoKeyEncryptor class ECIESP256Encryptor : public CryptoKeyEncryptor {
{
public: public:
ECIESP256Encryptor(const uint8_t *pub); ECIESP256Encryptor(const uint8_t *pub);
~ECIESP256Encryptor(); ~ECIESP256Encryptor();
void Encrypt(const uint8_t *data, uint8_t *encrypted) override; void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
private: private:
@ -76,13 +78,15 @@ namespace crypto
}; };
class ECIESP256Decryptor: public CryptoKeyDecryptor class ECIESP256Decryptor : public CryptoKeyDecryptor {
{
public: public:
ECIESP256Decryptor(const uint8_t *priv); ECIESP256Decryptor(const uint8_t *priv);
~ECIESP256Decryptor(); ~ECIESP256Decryptor();
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override; bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
size_t GetPublicKeyLen() const override { return 64; }; size_t GetPublicKeyLen() const override { return 64; };
private: private:
@ -95,12 +99,13 @@ namespace crypto
// ECIES GOST R 34.10 // ECIES GOST R 34.10
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor class ECIESGOSTR3410Encryptor : public CryptoKeyEncryptor {
{
public: public:
ECIESGOSTR3410Encryptor(const uint8_t *pub); ECIESGOSTR3410Encryptor(const uint8_t *pub);
~ECIESGOSTR3410Encryptor(); ~ECIESGOSTR3410Encryptor();
void Encrypt(const uint8_t *data, uint8_t *encrypted) override; void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
private: private:
@ -109,13 +114,15 @@ namespace crypto
}; };
class ECIESGOSTR3410Decryptor: public CryptoKeyDecryptor class ECIESGOSTR3410Decryptor : public CryptoKeyDecryptor {
{
public: public:
ECIESGOSTR3410Decryptor(const uint8_t *priv); ECIESGOSTR3410Decryptor(const uint8_t *priv);
~ECIESGOSTR3410Decryptor(); ~ECIESGOSTR3410Decryptor();
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override; bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
size_t GetPublicKeyLen() const override { return 64; }; size_t GetPublicKeyLen() const override { return 64; };
private: private:
@ -127,12 +134,13 @@ 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) override; void Encrypt(const uint8_t *, uint8_t *pub) override;
// copies m_PublicKey to pub // copies m_PublicKey to pub
@ -141,15 +149,18 @@ namespace crypto
uint8_t m_PublicKey[32]; uint8_t m_PublicKey[32];
}; };
class ECIESX25519AEADRatchetDecryptor: public CryptoKeyDecryptor class ECIESX25519AEADRatchetDecryptor : public CryptoKeyDecryptor {
{
public: public:
ECIESX25519AEADRatchetDecryptor(const uint8_t *priv, bool calculatePublic = false); ECIESX25519AEADRatchetDecryptor(const uint8_t *priv, bool calculatePublic = false);
~ECIESX25519AEADRatchetDecryptor() {}; ~ECIESX25519AEADRatchetDecryptor() {};
bool Decrypt(const uint8_t *epub, uint8_t *sharedSecret) override; bool Decrypt(const uint8_t *epub, uint8_t *sharedSecret) override;
// agree with static and return in sharedSecret (32 bytes) // agree with static and return in sharedSecret (32 bytes)
size_t GetPublicKeyLen() const override { return 32; }; size_t GetPublicKeyLen() const override { return 32; };
const uint8_t *GetPubicKey() const { return m_StaticKeys.GetPublicKey(); }; const uint8_t *GetPubicKey() const { return m_StaticKeys.GetPublicKey(); };
private: private:

View file

@ -14,13 +14,10 @@
#include "Destination.h" #include "Destination.h"
#include "Datagram.h" #include "Datagram.h"
namespace i2p namespace i2p {
{ namespace datagram {
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) {
{
if (m_Gzip) if (m_Gzip)
m_Deflator.reset(new i2p::data::GzipDeflator); m_Deflator.reset(new i2p::data::GzipDeflator);
@ -30,80 +27,76 @@ namespace datagram
m_Signature.resize(m_Owner->GetIdentity()->GetSignatureLen()); m_Signature.resize(m_Owner->GetIdentity()->GetSignatureLen());
} }
DatagramDestination::~DatagramDestination () DatagramDestination::~DatagramDestination() {
{
m_Sessions.clear(); m_Sessions.clear();
} }
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort) void
{ DatagramDestination::SendDatagramTo(const uint8_t *payload, size_t len, const i2p::data::IdentHash &identity,
uint16_t fromPort, uint16_t toPort) {
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
SendDatagram(session, payload, len, fromPort, toPort); SendDatagram(session, payload, len, fromPort, toPort);
FlushSendQueue(session); FlushSendQueue(session);
} }
void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort) void
{ DatagramDestination::SendRawDatagramTo(const uint8_t *payload, size_t len, const i2p::data::IdentHash &identity,
uint16_t fromPort, uint16_t toPort) {
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
SendRawDatagram(session, payload, len, fromPort, toPort); SendRawDatagram(session, payload, len, fromPort, toPort);
FlushSendQueue(session); FlushSendQueue(session);
} }
std::shared_ptr<DatagramSession> DatagramDestination::GetSession(const i2p::data::IdentHash & ident) std::shared_ptr<DatagramSession> DatagramDestination::GetSession(const i2p::data::IdentHash &ident) {
{
return ObtainSession(ident); return ObtainSession(ident);
} }
void DatagramDestination::SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) void
{ DatagramDestination::SendDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
if (session) uint16_t fromPort, uint16_t toPort) {
{ if (session) {
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) if (m_Owner->GetIdentity()->GetSigningKeyType() == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) {
{
uint8_t hash[32]; uint8_t hash[32];
SHA256(payload, len, hash); SHA256(payload, len, hash);
m_Owner->Sign(hash, 32, m_Signature.data()); m_Owner->Sign(hash, 32, m_Signature.data());
} } else
else
m_Owner->Sign(payload, len, m_Signature.data()); m_Owner->Sign(payload, len, m_Signature.data());
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);
} }
} }
void DatagramDestination::SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) void DatagramDestination::SendRawDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload,
{ size_t len, uint16_t fromPort, uint16_t toPort) {
if (session) if (session)
session->SendMsg(CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ())); // raw session->SendMsg(
CreateDataMessage({{payload, len}}, fromPort, toPort, true, !session->IsRatchets())); // raw
} }
void DatagramDestination::FlushSendQueue (std::shared_ptr<DatagramSession> session) void DatagramDestination::FlushSendQueue(std::shared_ptr<DatagramSession> session) {
{
if (session) if (session)
session->FlushSendQueue(); session->FlushSendQueue();
} }
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;
size_t identityLen = identity.FromBuffer(buf, len); size_t identityLen = identity.FromBuffer(buf, len);
const uint8_t *signature = buf + identityLen; const uint8_t *signature = buf + identityLen;
size_t headerLen = identityLen + identity.GetSignatureLen(); size_t headerLen = identityLen + identity.GetSignatureLen();
bool verified = false; bool verified = false;
if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) if (identity.GetSigningKeyType() == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) {
{
uint8_t hash[32]; uint8_t hash[32];
SHA256(buf + headerLen, len - headerLen, hash); SHA256(buf + headerLen, len - headerLen, hash);
verified = identity.Verify(hash, 32, signature); verified = identity.Verify(hash, 32, signature);
} } else
else
verified = identity.Verify(buf + headerLen, len - headerLen, signature); verified = identity.Verify(buf + headerLen, len - headerLen, signature);
if (verified) if (verified) {
{
auto h = identity.GetIdentHash(); auto h = identity.GetIdentHash();
auto session = ObtainSession(h); auto session = ObtainSession(h);
session->Ack(); session->Ack();
@ -112,21 +105,19 @@ namespace datagram
r(identity, fromPort, toPort, buf + headerLen, len - headerLen); r(identity, fromPort, toPort, buf + headerLen, len - headerLen);
else else
LogPrint(eLogWarning, "DatagramDestination: no receiver for port ", toPort); LogPrint(eLogWarning, "DatagramDestination: no receiver for port ", toPort);
} } else
else
LogPrint(eLogWarning, "Datagram signature verification failed"); LogPrint(eLogWarning, "Datagram signature verification failed");
} }
void DatagramDestination::HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) void
{ DatagramDestination::HandleRawDatagram(uint16_t fromPort, uint16_t toPort, const uint8_t *buf, size_t len) {
if (m_RawReceiver) if (m_RawReceiver)
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);
Receiver r = m_Receiver; Receiver r = m_Receiver;
auto itr = m_ReceiversByPorts.find(port); auto itr = m_ReceiversByPorts.find(port);
@ -135,26 +126,23 @@ namespace datagram
return r; return r;
} }
void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw) void DatagramDestination::HandleDataMessagePayload(uint16_t fromPort, uint16_t toPort, const uint8_t *buf,
{ size_t len, bool isRaw) {
// unzip it // unzip it
uint8_t uncompressed[MAX_DATAGRAM_SIZE]; uint8_t uncompressed[MAX_DATAGRAM_SIZE];
size_t uncompressedLen = m_Inflator.Inflate(buf, len, uncompressed, MAX_DATAGRAM_SIZE); size_t uncompressedLen = m_Inflator.Inflate(buf, len, uncompressed, MAX_DATAGRAM_SIZE);
if (uncompressedLen) if (uncompressedLen) {
{
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) {
{
size_t size; size_t size;
auto msg = m_I2NPMsgsPool.AcquireShared(); auto msg = m_I2NPMsgsPool.AcquireShared();
uint8_t *buf = msg->GetPayload(); uint8_t *buf = msg->GetPayload();
@ -165,43 +153,37 @@ namespace datagram
else else
size = i2p::data::GzipNoCompression(payloads, buf, msg->maxLen - msg->len); size = i2p::data::GzipNoCompression(payloads, buf, msg->maxLen - msg->len);
if (size) if (size) {
{
htobe32buf(msg->GetPayload(), size); // length htobe32buf(msg->GetPayload(), size); // length
htobe16buf(buf + 4, fromPort); // source port htobe16buf(buf + 4, fromPort); // source port
htobe16buf(buf + 6, toPort); // destination port htobe16buf(buf + 6, toPort); // destination port
buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW
: i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol
msg->len += size + 4; msg->len += size + 4;
msg->FillI2NPMessageHeader(eI2NPData, 0, checksum); msg->FillI2NPMessageHeader(eI2NPData, 0, checksum);
} } else
else
msg = nullptr; msg = nullptr;
return msg; return msg;
} }
void DatagramDestination::CleanUp () void DatagramDestination::CleanUp() {
{
if (m_Sessions.empty()) return; if (m_Sessions.empty()) return;
auto now = i2p::util::GetMillisecondsSinceEpoch(); auto now = i2p::util::GetMillisecondsSinceEpoch();
LogPrint(eLogDebug, "DatagramDestination: clean up sessions"); LogPrint(eLogDebug, "DatagramDestination: clean up sessions");
std::unique_lock<std::mutex> lock(m_SessionsMutex); std::unique_lock<std::mutex> lock(m_SessionsMutex);
// for each session ... // for each session ...
for (auto it = m_Sessions.begin (); it != m_Sessions.end (); ) for (auto it = m_Sessions.begin(); it != m_Sessions.end();) {
{
// check if expired // check if expired
if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE) if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE) {
{
LogPrint(eLogInfo, "DatagramDestination: expiring idle session with ", it->first.ToBase32()); LogPrint(eLogInfo, "DatagramDestination: expiring idle session with ", it->first.ToBase32());
it->second->Stop(); it->second->Stop();
it = m_Sessions.erase(it); // we are expired it = m_Sessions.erase(it); // we are expired
} } else
else
it++; it++;
} }
} }
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity) std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash &identity) {
{
std::shared_ptr<DatagramSession> session = nullptr; std::shared_ptr<DatagramSession> session = nullptr;
std::lock_guard<std::mutex> lock(m_SessionsMutex); std::lock_guard<std::mutex> lock(m_SessionsMutex);
auto itr = m_Sessions.find(identity); auto itr = m_Sessions.find(identity);
@ -216,11 +198,10 @@ namespace datagram
return session; return session;
} }
std::shared_ptr<DatagramSession::Info> DatagramDestination::GetInfoForRemote(const i2p::data::IdentHash & remote) std::shared_ptr<DatagramSession::Info>
{ DatagramDestination::GetInfoForRemote(const i2p::data::IdentHash &remote) {
std::lock_guard<std::mutex> lock(m_SessionsMutex); std::lock_guard<std::mutex> lock(m_SessionsMutex);
for ( auto & item : m_Sessions) for (auto &item: m_Sessions) {
{
if (item.first == remote) return std::make_shared<DatagramSession::Info>(item.second->GetSessionInfo()); if (item.first == remote) return std::make_shared<DatagramSession::Info>(item.second->GetSessionInfo());
} }
return nullptr; return nullptr;
@ -230,21 +211,17 @@ namespace datagram
const i2p::data::IdentHash &remoteIdent) : const i2p::data::IdentHash &remoteIdent) :
m_LocalDestination(localDestination), m_LocalDestination(localDestination),
m_RemoteIdent(remoteIdent), m_RemoteIdent(remoteIdent),
m_RequestingLS(false) m_RequestingLS(false) {
{
} }
void DatagramSession::Start () void DatagramSession::Start() {
{
m_LastUse = i2p::util::GetMillisecondsSinceEpoch(); m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
} }
void DatagramSession::Stop () void DatagramSession::Stop() {
{
} }
void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg) void DatagramSession::SendMsg(std::shared_ptr<I2NPMessage> msg) {
{
// we used this session // we used this session
m_LastUse = i2p::util::GetMillisecondsSinceEpoch(); m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
if (msg || m_SendQueue.empty()) if (msg || m_SendQueue.empty())
@ -254,8 +231,7 @@ namespace datagram
FlushSendQueue(); FlushSendQueue();
} }
DatagramSession::Info DatagramSession::GetSessionInfo() const DatagramSession::Info DatagramSession::GetSessionInfo() const {
{
if (!m_RoutingSession) if (!m_RoutingSession)
return DatagramSession::Info(nullptr, nullptr, m_LastUse); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
@ -264,21 +240,18 @@ namespace datagram
return DatagramSession::Info(nullptr, nullptr, m_LastUse); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
auto lease = routingPath->remoteLease; auto lease = routingPath->remoteLease;
auto tunnel = routingPath->outboundTunnel; auto tunnel = routingPath->outboundTunnel;
if(lease) if (lease) {
{
if (tunnel) if (tunnel)
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse); return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse);
else else
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse); return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse);
} } else if (tunnel)
else if(tunnel)
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse); return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse);
else else
return DatagramSession::Info(nullptr, nullptr, m_LastUse); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
} }
void DatagramSession::Ack() void DatagramSession::Ack() {
{
m_LastUse = i2p::util::GetMillisecondsSinceEpoch(); m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
auto path = GetSharedRoutingPath(); auto path = GetSharedRoutingPath();
if (path) if (path)
@ -287,24 +260,21 @@ namespace datagram
SendMsg(nullptr); // send empty message in case if we have some data to send SendMsg(nullptr); // send empty message in case if we have some data to send
} }
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath () std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath() {
{ if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired()) {
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
{
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent); m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
if (!m_RemoteLeaseSet) if (!m_RemoteLeaseSet) {
{ if (!m_RequestingLS) {
if(!m_RequestingLS)
{
m_RequestingLS = true; m_RequestingLS = true;
m_LocalDestination->RequestDestination(m_RemoteIdent, std::bind(&DatagramSession::HandleLeaseSetUpdated, this, std::placeholders::_1)); m_LocalDestination->RequestDestination(m_RemoteIdent,
std::bind(&DatagramSession::HandleLeaseSetUpdated, this,
std::placeholders::_1));
} }
return nullptr; return nullptr;
} }
} }
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) if (!m_RoutingSession || m_RoutingSession->IsTerminated() || !m_RoutingSession->IsReadyToSend()) {
{
bool found = false; bool found = false;
for (auto &it: m_PendingRoutingSessions) for (auto &it: m_PendingRoutingSessions)
if (it->GetOwner() && m_RoutingSession->IsReadyToSend()) // found established session if (it->GetOwner() && m_RoutingSession->IsReadyToSend()) // found established session
@ -314,8 +284,7 @@ namespace datagram
found = true; found = true;
break; break;
} }
if (!found) if (!found) {
{
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true); m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
if (!m_RoutingSession->GetOwner() || !m_RoutingSession->IsReadyToSend()) if (!m_RoutingSession->GetOwner() || !m_RoutingSession->IsReadyToSend())
m_PendingRoutingSessions.push_back(m_RoutingSession); m_PendingRoutingSessions.push_back(m_RoutingSession);
@ -324,74 +293,62 @@ namespace datagram
auto path = m_RoutingSession->GetSharedRoutingPath(); auto path = m_RoutingSession->GetSharedRoutingPath();
if (path && m_RoutingSession->IsRatchets() && if (path && m_RoutingSession->IsRatchets() &&
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT) m_LastUse > m_RoutingSession->GetLastActivityTimestamp() * 1000 + DATAGRAM_SESSION_PATH_TIMEOUT) {
{
m_RoutingSession->SetSharedRoutingPath(nullptr); m_RoutingSession->SetSharedRoutingPath(nullptr);
path = nullptr; path = nullptr;
} }
if (path) if (path) {
{ if (path->outboundTunnel && !path->outboundTunnel->IsEstablished()) {
if (path->outboundTunnel && !path->outboundTunnel->IsEstablished ())
{
// bad outbound tunnel, switch outbound tunnel // bad outbound tunnel, switch outbound tunnel
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(path->outboundTunnel); path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(
path->outboundTunnel);
if (!path->outboundTunnel) if (!path->outboundTunnel)
m_RoutingSession->SetSharedRoutingPath(nullptr); m_RoutingSession->SetSharedRoutingPath(nullptr);
} }
if (path->remoteLease && path->remoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) if (path->remoteLease && path->remoteLease->ExpiresWithin(DATAGRAM_SESSION_LEASE_HANDOVER_WINDOW)) {
{
// bad lease, switch to next one // bad lease, switch to next one
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet) {
{
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding( auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding(
[&](const i2p::data::Lease& l) -> bool [&](const i2p::data::Lease &l) -> bool {
{
return l.tunnelID == path->remoteLease->tunnelID; return l.tunnelID == path->remoteLease->tunnelID;
}); });
auto sz = ls.size(); auto sz = ls.size();
if (sz) if (sz) {
{
auto idx = rand() % sz; auto idx = rand() % sz;
path->remoteLease = ls[idx]; path->remoteLease = ls[idx];
} } else
else
m_RoutingSession->SetSharedRoutingPath(nullptr); m_RoutingSession->SetSharedRoutingPath(nullptr);
} } else {
else
{
// no remote lease set? // no remote lease set?
LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32()); LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ",
m_RemoteIdent.ToBase32());
m_RoutingSession->SetSharedRoutingPath(nullptr); m_RoutingSession->SetSharedRoutingPath(nullptr);
} }
} }
} } else {
else
{
// no current path, make one // no current path, make one
path = std::make_shared<i2p::garlic::GarlicRoutingPath>(); path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet) {
{
// pick random next good lease // pick random next good lease
auto ls = m_RemoteLeaseSet->GetNonExpiredLeases(); auto ls = m_RemoteLeaseSet->GetNonExpiredLeases();
auto sz = ls.size(); auto sz = ls.size();
if (sz) if (sz) {
{
auto idx = rand() % sz; auto idx = rand() % sz;
path->remoteLease = ls[idx]; path->remoteLease = ls[idx];
} } else
else
return nullptr; return nullptr;
auto leaseRouter = i2p::data::netdb.FindRouter(path->remoteLease->tunnelGateway); auto leaseRouter = i2p::data::netdb.FindRouter(path->remoteLease->tunnelGateway);
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr, path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr,
leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports); leaseRouter
? leaseRouter->GetCompatibleTransports(
false)
: (i2p::data::RouterInfo::CompatibleTransports) i2p::data::RouterInfo::eAllTransports);
if (!path->outboundTunnel) return nullptr; if (!path->outboundTunnel) return nullptr;
} } else {
else
{
// no remote lease set currently, bail // no remote lease set currently, bail
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32()); LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
return nullptr; return nullptr;
@ -401,8 +358,7 @@ namespace datagram
return path; return path;
} }
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls) void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls) {
{
m_RequestingLS = false; m_RequestingLS = false;
if (!ls) return; if (!ls) return;
// only update lease set if found and newer than previous lease set // only update lease set if found and newer than previous lease set
@ -411,19 +367,18 @@ namespace datagram
if (ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls; if (ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
} }
void DatagramSession::FlushSendQueue () void DatagramSession::FlushSendQueue() {
{
if (m_SendQueue.empty()) return; if (m_SendQueue.empty()) return;
std::vector<i2p::tunnel::TunnelMessageBlock> send; std::vector<i2p::tunnel::TunnelMessageBlock> send;
auto routingPath = GetSharedRoutingPath(); auto routingPath = GetSharedRoutingPath();
// if we don't have a routing path we will drop all queued messages // if we don't have a routing path we will drop all queued messages
if(routingPath && routingPath->outboundTunnel && routingPath->remoteLease) if (routingPath && routingPath->outboundTunnel && routingPath->remoteLease) {
{ for (const auto &msg: m_SendQueue) {
for (const auto & msg : m_SendQueue)
{
auto m = m_RoutingSession->WrapSingleMessage(msg); auto m = m_RoutingSession->WrapSingleMessage(msg);
if (m) if (m)
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m}); send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,
routingPath->remoteLease->tunnelGateway,
routingPath->remoteLease->tunnelID, m});
} }
routingPath->outboundTunnel->SendTunnelDataMsg(send); routingPath->outboundTunnel->SendTunnelDataMsg(send);
} }

View file

@ -20,14 +20,11 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Garlic.h" #include "Garlic.h"
namespace i2p namespace i2p {
{ namespace client {
namespace client
{
class ClientDestination; class ClientDestination;
} }
namespace datagram namespace datagram {
{
// milliseconds for max session idle time // milliseconds for max session idle time
const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000; const uint64_t DATAGRAM_SESSION_MAX_IDLE = 10 * 60 * 1000;
// milliseconds for how long we try sticking to a dead routing path before trying to switch // milliseconds for how long we try sticking to a dead routing path before trying to switch
@ -43,14 +40,15 @@ namespace datagram
// 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: public:
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent); DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
const i2p::data::IdentHash &remoteIdent);
void Start(); void Start();
void Stop(); void Stop();
@ -59,19 +57,21 @@ namespace datagram
/** 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);
void FlushSendQueue(); void FlushSendQueue();
/** 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);
@ -104,34 +104,61 @@ namespace datagram
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr; typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
const size_t MAX_DATAGRAM_SIZE = 32768; const size_t MAX_DATAGRAM_SIZE = 32768;
class DatagramDestination
{ class DatagramDestination {
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,
typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver; 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;
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
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); 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);
// TODO: implement calls from other thread from SAM // TODO: implement calls from other thread from SAM
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash &ident); std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash &ident);
void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
uint16_t fromPort, uint16_t toPort);
void SendRawDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
uint16_t fromPort, uint16_t toPort);
void FlushSendQueue(std::shared_ptr<DatagramSession> session); void FlushSendQueue(std::shared_ptr<DatagramSession> session);
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; };
void SetReceiver (const Receiver& receiver, uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts[port] = receiver; }; void SetReceiver(const Receiver &receiver, uint16_t port) {
void ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); }; std::lock_guard<std::mutex> lock(m_ReceiversMutex);
m_ReceiversByPorts[port] = receiver;
};
void ResetReceiver(uint16_t port) {
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
m_ReceiversByPorts.erase(port);
};
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);
@ -143,10 +170,12 @@ namespace datagram
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 */

File diff suppressed because it is too large Load diff

View file

@ -28,10 +28,8 @@
#include "Datagram.h" #include "Datagram.h"
#include "util.h" #include "util.h"
namespace i2p namespace i2p {
{ namespace client {
namespace client
{
const uint8_t PROTOCOL_TYPE_STREAMING = 6; const uint8_t PROTOCOL_TYPE_STREAMING = 6;
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17; const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
const uint8_t PROTOCOL_TYPE_RAW = 18; const uint8_t PROTOCOL_TYPE_RAW = 18;
@ -89,12 +87,11 @@ namespace client
typedef std::function<void(std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete; typedef std::function<void(std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
class LeaseSetDestination : public i2p::garlic::GarlicDestination, class LeaseSetDestination : public i2p::garlic::GarlicDestination,
public std::enable_shared_from_this<LeaseSetDestination> public std::enable_shared_from_this<LeaseSetDestination> {
{
typedef std::function<void(std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete; typedef std::function<void(std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete;
// leaseSet = nullptr means not found // leaseSet = nullptr means not found
struct LeaseSetRequest struct LeaseSetRequest {
{
LeaseSetRequest(boost::asio::io_service &service) : requestTime(0), requestTimeoutTimer(service) {}; LeaseSetRequest(boost::asio::io_service &service) : requestTime(0), requestTimeoutTimer(service) {};
std::set<i2p::data::IdentHash> excluded; std::set<i2p::data::IdentHash> excluded;
uint64_t requestTime; uint64_t requestTime;
@ -104,8 +101,7 @@ namespace client
std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel; std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel;
std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey; // for encrypted LeaseSet2 only std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey; // for encrypted LeaseSet2 only
void Complete (std::shared_ptr<i2p::data::LeaseSet> ls) void Complete(std::shared_ptr<i2p::data::LeaseSet> ls) {
{
for (auto &it: requestComplete) it(ls); for (auto &it: requestComplete) it(ls);
requestComplete.clear(); requestComplete.clear();
} }
@ -113,71 +109,115 @@ 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);
~LeaseSetDestination(); ~LeaseSetDestination();
const std::string &GetNickname() const { return m_Nickname; }; const std::string &GetNickname() const { return m_Nickname; };
boost::asio::io_service &GetService() { return m_Service; }; boost::asio::io_service &GetService() { return m_Service; };
virtual void Start(); virtual void Start();
virtual void Stop(); virtual void Stop();
/** 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);
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet(); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet();
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const { return m_Pool; } std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const { return m_Pool; }
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey(const uint8_t *key, const uint8_t *tag); bool SubmitSessionKey(const uint8_t *key, const uint8_t *tag);
void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag); void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag);
void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
void SetLeaseSetUpdated(); void SetLeaseSetUpdated();
bool IsPublic() const { return m_IsPublic; }; bool IsPublic() const { return m_IsPublic; };
void SetPublic(bool pub) { m_IsPublic = pub; }; void SetPublic(bool pub) { m_IsPublic = pub; };
protected: protected:
// 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, uint32_t msgID); bool HandleCloveI2NPMessage(I2NPMessageType typeID, const uint8_t *payload, size_t len, uint32_t msgID);
void SetLeaseSet(std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet); void SetLeaseSet(std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
int GetLeaseSetType() const { return m_LeaseSetType; }; int GetLeaseSetType() const { return m_LeaseSetType; };
void SetLeaseSetType(int leaseSetType) { m_LeaseSetType = leaseSetType; }; void SetLeaseSetType(int leaseSetType) { m_LeaseSetType = leaseSetType; };
int GetAuthType() const { return m_AuthType; }; int GetAuthType() const { return m_AuthType; };
virtual void CleanupDestination() {}; // additional clean up in derived classes virtual void CleanupDestination() {}; // additional clean up in derived classes
// I2CP // I2CP
virtual void HandleDataMessage(const uint8_t *buf, size_t len) = 0; virtual void HandleDataMessage(const uint8_t *buf, size_t len) = 0;
virtual void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels) = 0;
virtual void
CreateNewLeaseSet(const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels) = 0;
private: private:
void UpdateLeaseSet(); void UpdateLeaseSet();
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt(); std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt();
void Publish(); void Publish();
void HandlePublishConfirmationTimer(const boost::system::error_code &ecode); void HandlePublishConfirmationTimer(const boost::system::error_code &ecode);
void HandlePublishVerificationTimer(const boost::system::error_code &ecode); void HandlePublishVerificationTimer(const boost::system::error_code &ecode);
void HandlePublishDelayTimer(const boost::system::error_code &ecode); void HandlePublishDelayTimer(const boost::system::error_code &ecode);
void HandleDatabaseStoreMessage(const uint8_t *buf, size_t len); void HandleDatabaseStoreMessage(const uint8_t *buf, size_t len);
void HandleDatabaseSearchReplyMessage(const uint8_t *buf, size_t len); void HandleDatabaseSearchReplyMessage(const uint8_t *buf, size_t len);
void HandleDeliveryStatusMessage(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,
bool 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::BlindedPublicKey> requestedBlindedKey = nullptr);
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();
i2p::data::CryptoKeyType GetPreferredCryptoType() const; i2p::data::CryptoKeyType GetPreferredCryptoType() const;
private: private:
@ -205,21 +245,31 @@ namespace client
// for HTTP only // for HTTP only
int GetNumRemoteLeaseSets() const { return m_RemoteLeaseSets.size(); }; int GetNumRemoteLeaseSets() const { return m_RemoteLeaseSets.size(); };
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; }; const decltype(m_RemoteLeaseSets)
bool IsEncryptedLeaseSet () const { return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; }; &
GetLeaseSets() const { return m_RemoteLeaseSets; };
bool IsEncryptedLeaseSet() const {
return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
};
bool IsPerClientAuth() const { return m_AuthType > 0; }; bool IsPerClientAuth() const { return m_AuthType > 0; };
}; };
class ClientDestination: public LeaseSetDestination class ClientDestination : public LeaseSetDestination {
{ struct EncryptionKey {
struct EncryptionKey
{
uint8_t pub[256], priv[256]; uint8_t pub[256], priv[256];
i2p::data::CryptoKeyType keyType; i2p::data::CryptoKeyType keyType;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> decryptor; std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> decryptor;
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); };
}; };
@ -227,51 +277,78 @@ namespace client
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();
void Start(); void Start();
void Stop(); void Stop();
const i2p::data::PrivateKeys &GetPrivateKeys() const { return m_Keys; }; const i2p::data::PrivateKeys &GetPrivateKeys() const { return m_Keys; };
void Sign(const uint8_t *buf, int len, uint8_t *signature) const { m_Keys.Sign(buf, len, signature); }; void Sign(const uint8_t *buf, int len, uint8_t *signature) const { m_Keys.Sign(buf, len, signature); };
// ref counter // ref counter
int Acquire() { return ++m_RefCounter; }; int Acquire() { return ++m_RefCounter; };
int Release() { return --m_RefCounter; }; int Release() { return --m_RefCounter; };
int GetRefCounter() const { return m_RefCounter; }; int GetRefCounter() const { return m_RefCounter; };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination>
CreateStreamingDestination(int port, bool gzip = true); // additional
std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination(int port = 0) const; std::shared_ptr<i2p::stream::StreamingDestination> GetStreamingDestination(int port = 0) const;
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination(int port); std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination(int port);
// following methods operate with default streaming destination // following methods operate with default streaming destination
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, int port = 0); void
void CreateStream (StreamRequestComplete streamRequestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0); CreateStream(StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash &dest, int port = 0);
std::shared_ptr<i2p::stream::Stream> CreateStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void CreateStream(StreamRequestComplete streamRequestComplete,
std::shared_ptr<const i2p::data::BlindedPublicKey> dest, int port = 0);
std::shared_ptr<i2p::stream::Stream>
CreateStream(std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void SendPing(const i2p::data::IdentHash &to); void SendPing(const i2p::data::IdentHash &to);
void SendPing(std::shared_ptr<const i2p::data::BlindedPublicKey> to); void SendPing(std::shared_ptr<const i2p::data::BlindedPublicKey> to);
void AcceptStreams(const i2p::stream::StreamingDestination::Acceptor &acceptor); void AcceptStreams(const i2p::stream::StreamingDestination::Acceptor &acceptor);
void StopAcceptingStreams(); void StopAcceptingStreams();
bool IsAcceptingStreams() const; bool IsAcceptingStreams() const;
void AcceptOnce(const i2p::stream::StreamingDestination::Acceptor &acceptor); void AcceptOnce(const i2p::stream::StreamingDestination::Acceptor &acceptor);
int GetStreamingAckDelay() const { return m_StreamingAckDelay; } int GetStreamingAckDelay() const { return m_StreamingAckDelay; }
bool IsStreamingAnswerPings() const { return m_IsStreamingAnswerPings; } bool IsStreamingAnswerPings() const { return m_IsStreamingAnswerPings; }
// 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, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt(const uint8_t *encrypted, uint8_t *data, 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:
void CleanupDestination(); void CleanupDestination();
// I2CP // I2CP
void HandleDataMessage(const uint8_t *buf, size_t len); void HandleDataMessage(const uint8_t *buf, size_t len);
void CreateNewLeaseSet(const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels); void CreateNewLeaseSet(const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels);
private: private:
@ -279,7 +356,9 @@ namespace client
std::shared_ptr<ClientDestination> GetSharedFromThis() { std::shared_ptr<ClientDestination> GetSharedFromThis() {
return std::static_pointer_cast<ClientDestination>(shared_from_this()); return std::static_pointer_cast<ClientDestination>(shared_from_this());
} }
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:
@ -303,17 +382,20 @@ namespace client
// for HTTP only // for HTTP only
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams() const; std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams() const;
bool DeleteStream(uint32_t recvStreamID); bool DeleteStream(uint32_t recvStreamID);
}; };
class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination class RunnableClientDestination : private i2p::util::RunnableService, public ClientDestination {
{
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

View file

@ -21,10 +21,8 @@
#include "Garlic.h" #include "Garlic.h"
#include "Tag.h" #include "Tag.h"
namespace i2p namespace i2p {
{ namespace garlic {
namespace garlic
{
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
@ -39,22 +37,29 @@ namespace garlic
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 RatchetTagSet class RatchetTagSet {
{
public: public:
RatchetTagSet() {}; RatchetTagSet() {};
virtual ~RatchetTagSet() {}; virtual ~RatchetTagSet() {};
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);
void DeleteSymmKey(int index); void DeleteSymmKey(int index);
int GetTagSetID() const { return m_TagSetID; }; int GetTagSetID() const { return m_TagSetID; };
void SetTagSetID(int tagsetID) { m_TagSetID = tagsetID; }; void SetTagSetID(int tagsetID) { m_TagSetID = tagsetID; };
private: private:
@ -68,23 +73,28 @@ namespace garlic
}; };
class ECIESX25519AEADRatchetSession; class ECIESX25519AEADRatchetSession;
class ReceiveRatchetTagSet : public RatchetTagSet, class ReceiveRatchetTagSet : public RatchetTagSet,
public std::enable_shared_from_this<ReceiveRatchetTagSet> public std::enable_shared_from_this<ReceiveRatchetTagSet> {
{
public: public:
ReceiveRatchetTagSet(std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false) : ReceiveRatchetTagSet(std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false) :
m_Session(session), m_IsNS(isNS) {}; m_Session(session), m_IsNS(isNS) {};
bool IsNS() const { return m_IsNS; }; bool IsNS() const { return m_IsNS; };
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession() { return m_Session; }; std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession() { return m_Session; };
void SetTrimBehind(int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; }; void SetTrimBehind(int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
int GetTrimBehind() const { return m_TrimBehindIndex; }; int GetTrimBehind() const { return m_TrimBehindIndex; };
void Expire(); void Expire();
bool IsExpired(uint64_t ts) const; bool IsExpired(uint64_t ts) const;
virtual bool IsIndexExpired(int index) const; virtual bool IsIndexExpired(int index) const;
virtual bool HandleNextMessage(uint8_t *buf, size_t len, int index); virtual bool HandleNextMessage(uint8_t *buf, size_t len, int index);
private: private:
@ -95,13 +105,13 @@ namespace garlic
uint64_t m_ExpirationTimestamp = 0; uint64_t m_ExpirationTimestamp = 0;
}; };
class SymmetricKeyTagSet: public ReceiveRatchetTagSet class SymmetricKeyTagSet : public ReceiveRatchetTagSet {
{
public: public:
SymmetricKeyTagSet(GarlicDestination *destination, const uint8_t *key); SymmetricKeyTagSet(GarlicDestination *destination, const uint8_t *key);
bool IsIndexExpired(int index) const { return false; }; bool IsIndexExpired(int index) const { return false; };
bool HandleNextMessage(uint8_t *buf, size_t len, int index); bool HandleNextMessage(uint8_t *buf, size_t len, int index);
private: private:
@ -110,8 +120,7 @@ namespace garlic
uint8_t m_Key[32]; uint8_t m_Key[32];
}; };
enum ECIESx25519BlockType enum ECIESx25519BlockType {
{
eECIESx25519BlkDateTime = 0, eECIESx25519BlkDateTime = 0,
eECIESx25519BlkSessionID = 1, eECIESx25519BlkSessionID = 1,
eECIESx25519BlkTermination = 4, eECIESx25519BlkTermination = 4,
@ -129,10 +138,8 @@ namespace garlic
class ECIESX25519AEADRatchetSession : public GarlicRoutingSession, class ECIESX25519AEADRatchetSession : public GarlicRoutingSession,
private i2p::crypto::NoiseSymmetricState, private i2p::crypto::NoiseSymmetricState,
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> {
{ enum SessionState {
enum SessionState
{
eSessionStateNew = 0, eSessionStateNew = 0,
eSessionStateNewSessionReceived, eSessionStateNewSessionReceived,
eSessionStateNewSessionSent, eSessionStateNewSessionSent,
@ -141,8 +148,7 @@ namespace garlic
eSessionStateOneTime eSessionStateOneTime
}; };
struct DHRatchet struct DHRatchet {
{
int keyID = 0; int keyID = 0;
std::shared_ptr<i2p::crypto::X25519Keys> key; std::shared_ptr<i2p::crypto::X25519Keys> key;
uint8_t remote[32]; // last remote public key uint8_t remote[32]; // last remote public key
@ -152,36 +158,55 @@ namespace garlic
public: public:
ECIESX25519AEADRatchetSession(GarlicDestination *owner, bool attachLeaseSetNS); ECIESX25519AEADRatchetSession(GarlicDestination *owner, bool attachLeaseSetNS);
~ECIESX25519AEADRatchetSession(); ~ECIESX25519AEADRatchetSession();
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0); bool HandleNextMessage(uint8_t *buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> 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);
std::shared_ptr<I2NPMessage> WrapOneTimeMessage(std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapOneTimeMessage(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 Terminate() { m_IsTerminated = true; } void Terminate() { m_IsTerminated = true; }
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_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool CanBeRestarted(uint64_t ts) const {
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT;
}
bool IsInactive(uint64_t ts) const {
return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted(ts);
}
bool IsRatchets() const { return true; }; bool IsRatchets() const { return true; };
bool IsReadyToSend() const { return m_State != eSessionStateNewSessionSent; }; bool IsReadyToSend() const { return m_State != eSessionStateNewSessionSent; };
bool IsTerminated() const { return m_IsTerminated; } bool IsTerminated() const { return m_IsTerminated; }
uint64_t GetLastActivityTimestamp() const { return m_LastActivityTimestamp; }; uint64_t GetLastActivityTimestamp() const { return m_LastActivityTimestamp; };
protected: protected:
i2p::crypto::NoiseSymmetricState &GetNoiseState() { return *this; }; i2p::crypto::NoiseSymmetricState &GetNoiseState() { return *this; };
void SetNoiseState(const i2p::crypto::NoiseSymmetricState &state) { GetNoiseState() = state; }; void SetNoiseState(const i2p::crypto::NoiseSymmetricState &state) { GetNoiseState() = state; };
void CreateNonce(uint64_t seqn, uint8_t *nonce); void CreateNonce(uint64_t seqn, uint8_t *nonce);
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
void
HandlePayload(const uint8_t *buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet> &receiveTagset,
int index);
private: private:
@ -189,20 +214,34 @@ namespace garlic
void InitNewSessionTagset(std::shared_ptr<RatchetTagSet> tagsetNsr) const; void InitNewSessionTagset(std::shared_ptr<RatchetTagSet> tagsetNsr) const;
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 HandleExistingSessionMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index);
void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset);
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic = true); bool HandleNewOutgoingSessionReply(uint8_t *buf, size_t len);
bool
HandleExistingSessionMessage(uint8_t *buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset,
int index);
void
HandleNextKey(const uint8_t *buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet> &receiveTagset);
bool NewOutgoingSessionMessage(const uint8_t *payload, size_t len, uint8_t *out, size_t outLen,
bool isStatic = true);
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);
size_t CreatePayload(std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t *payload); size_t CreatePayload(std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t *payload);
size_t CreateGarlicClove(std::shared_ptr<const I2NPMessage> msg, uint8_t *buf, size_t len); size_t CreateGarlicClove(std::shared_ptr<const I2NPMessage> msg, 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);
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<ReceiveRatchetTagSet> receiveTagset, int numTags); void GenerateMoreReceiveTags(std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags);
void NewNextSendRatchet(); void NewNextSendRatchet();
private: private:
@ -225,19 +264,20 @@ namespace garlic
// for HTTP only // for HTTP only
int GetState() const { return (int) m_State; } int GetState() const { return (int) m_State; }
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();
} }
}; };
// single session for all incoming messages // single session for all incoming messages
class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession class RouterIncomingRatchetSession : public ECIESX25519AEADRatchetSession {
{
public: public:
RouterIncomingRatchetSession(const i2p::crypto::NoiseSymmetricState &initState); RouterIncomingRatchetSession(const i2p::crypto::NoiseSymmetricState &initState);
bool HandleNextMessage(const uint8_t *buf, size_t len); bool HandleNextMessage(const uint8_t *buf, size_t len);
i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; };
private: private:
@ -245,8 +285,11 @@ namespace garlic
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag); std::shared_ptr<I2NPMessage>
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey); WrapECIESX25519Message(std::shared_ptr<const I2NPMessage> msg, const uint8_t *key, uint64_t tag);
std::shared_ptr<I2NPMessage>
WrapECIESX25519MessageForRouter(std::shared_ptr<const I2NPMessage> msg, const uint8_t *routerPublicKey);
} }
} }

View file

@ -11,12 +11,9 @@
#include "Crypto.h" #include "Crypto.h"
#include "Ed25519.h" #include "Ed25519.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto Ed25519::Ed25519() {
{
Ed25519::Ed25519 ()
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BIGNUM *tmp = BN_new(); BIGNUM *tmp = BN_new();
@ -62,8 +59,7 @@ namespace crypto
// precalculate Bi256 table // precalculate Bi256 table
Bi256Carry = {Bx, By}; // B Bi256Carry = {Bx, By}; // B
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++) {
{
Bi256[i][0] = Bi256Carry; // first point Bi256[i][0] = Bi256Carry; // first point
for (int j = 1; j < 128; j++) for (int j = 1; j < 128; j++)
Bi256[i][j] = Sum(Bi256[i][j - 1], Bi256[i][0], ctx); // (256+j+1)^i*B Bi256[i][j] = Sum(Bi256[i][j - 1], Bi256[i][0], ctx); // (256+j+1)^i*B
@ -76,16 +72,15 @@ namespace crypto
} }
Ed25519::Ed25519(const Ed25519 &other) : q(BN_dup(other.q)), l(BN_dup(other.l)), Ed25519::Ed25519(const Ed25519 &other) : q(BN_dup(other.q)), l(BN_dup(other.l)),
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), d(BN_dup(other.d)), I(BN_dup(other.I)),
Bi256Carry (other.Bi256Carry) two_252_2(BN_dup(other.two_252_2)),
{ Bi256Carry(other.Bi256Carry) {
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
for (int j = 0; j < 128; j++) for (int j = 0; j < 128; j++)
Bi256[i][j] = other.Bi256[i][j]; Bi256[i][j] = other.Bi256[i][j];
} }
Ed25519::~Ed25519 () Ed25519::~Ed25519() {
{
BN_free(q); BN_free(q);
BN_free(l); BN_free(l);
BN_free(d); BN_free(d);
@ -94,23 +89,19 @@ namespace crypto
} }
EDDSAPoint Ed25519::GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const EDDSAPoint Ed25519::GeneratePublicKey(const uint8_t *expandedPrivateKey, BN_CTX *ctx) const {
{
return MulB(expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian return MulB(expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian
} }
EDDSAPoint Ed25519::DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const EDDSAPoint Ed25519::DecodePublicKey(const uint8_t *buf, BN_CTX *ctx) const {
{
return DecodePoint(buf, ctx); return DecodePoint(buf, ctx);
} }
void Ed25519::EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const void Ed25519::EncodePublicKey(const EDDSAPoint &publicKey, uint8_t *buf, BN_CTX *ctx) const {
{
EncodePoint(Normalize(publicKey, ctx), buf); EncodePoint(Normalize(publicKey, ctx), buf);
} }
bool Ed25519::Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const bool Ed25519::Verify(const EDDSAPoint &publicKey, const uint8_t *digest, const uint8_t *signature) const {
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BIGNUM *h = DecodeBN<64>(digest); BIGNUM *h = DecodeBN<64>(digest);
// signature 0..31 - R, 32..63 - S // signature 0..31 - R, 32..63 - S
@ -130,20 +121,22 @@ namespace crypto
} }
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();
// calculate r // calculate r
SHA512_CTX ctx; SHA512_CTX ctx;
SHA512_Init(&ctx); SHA512_Init(&ctx);
SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key SHA512_Update(&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH,
EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
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<32>(digest); // DecodeBN<64> (digest); // for test vectors BIGNUM *r = DecodeBN<32>(digest); // DecodeBN<64> (digest); // for test vectors
// 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 /
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors 2]; // we must use separate buffer because signature might be inside buf
EncodePoint(Normalize(MulB(digest, bnCtx), bnCtx),
R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors
// 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
@ -157,13 +150,14 @@ namespace crypto
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);
EncodeBN(h, signature + EDDSA25519_SIGNATURE_LENGTH / 2, EDDSA25519_SIGNATURE_LENGTH / 2); // S EncodeBN(h, signature + EDDSA25519_SIGNATURE_LENGTH / 2, EDDSA25519_SIGNATURE_LENGTH / 2); // S
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);
} }
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();
// T = 80 random bytes // T = 80 random bytes
uint8_t T[80]; uint8_t T[80];
@ -180,7 +174,8 @@ namespace crypto
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);
@ -195,12 +190,13 @@ namespace crypto
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);
EncodeBN(h, signature + EDDSA25519_SIGNATURE_LENGTH / 2, EDDSA25519_SIGNATURE_LENGTH / 2); // S EncodeBN(h, signature + EDDSA25519_SIGNATURE_LENGTH / 2, EDDSA25519_SIGNATURE_LENGTH / 2); // S
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)
// y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2) // y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2)
// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
@ -212,20 +208,23 @@ namespace crypto
BN_CTX_start(ctx); BN_CTX_start(ctx);
BIGNUM *t1 = p1.t, *t2 = p2.t; BIGNUM *t1 = p1.t, *t2 = p2.t;
if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } if (!t1) {
if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } t1 = BN_CTX_get(ctx);
BN_mul(t1, p1.x, p1.y, ctx);
}
if (!t2) {
t2 = BN_CTX_get(ctx);
BN_mul(t2, p2.x, p2.y, ctx);
}
BN_mul(t3, t1, t2, ctx); BN_mul(t3, t1, t2, ctx);
BN_mul(t3, t3, d, ctx); // C = d*t1*t2 BN_mul(t3, t3, d, ctx); // C = d*t1*t2
if (p1.z) if (p1.z) {
{
if (p2.z) if (p2.z)
BN_mul(z3, p1.z, p2.z, ctx); // D = z1*z2 BN_mul(z3, p1.z, p2.z, ctx); // D = z1*z2
else else
BN_copy(z3, p1.z); // D = z1 BN_copy(z3, p1.z); // D = z1
} } else {
else
{
if (p2.z) if (p2.z)
BN_copy(z3, p2.z); // D = z2 BN_copy(z3, p2.z); // D = z2
else else
@ -252,8 +251,7 @@ namespace crypto
return EDDSAPoint{x3, y3, z3, t3}; return EDDSAPoint{x3, y3, z3, t3};
} }
void Ed25519::Double (EDDSAPoint& p, BN_CTX * ctx) const void Ed25519::Double(EDDSAPoint &p, BN_CTX *ctx) const {
{
BN_CTX_start(ctx); BN_CTX_start(ctx);
BIGNUM *x2 = BN_CTX_get(ctx), *y2 = BN_CTX_get(ctx), *z2 = BN_CTX_get(ctx), *t2 = BN_CTX_get(ctx); BIGNUM *x2 = BN_CTX_get(ctx), *y2 = BN_CTX_get(ctx), *z2 = BN_CTX_get(ctx), *t2 = BN_CTX_get(ctx);
@ -261,8 +259,7 @@ namespace crypto
BN_sqr(y2, p.y, ctx); // y2 = B = y^2 BN_sqr(y2, p.y, ctx); // y2 = B = y^2
if (p.t) if (p.t)
BN_sqr(t2, p.t, ctx); // t2 = t^2 BN_sqr(t2, p.t, ctx); // t2 = t^2
else else {
{
BN_mul(t2, p.x, p.y, ctx); // t = x*y BN_mul(t2, p.x, p.y, ctx); // t = x*y
BN_sqr(t2, t2, ctx); // t2 = t^2 BN_sqr(t2, t2, ctx); // t2 = t^2
} }
@ -290,16 +287,14 @@ namespace crypto
BN_CTX_end(ctx); BN_CTX_end(ctx);
} }
EDDSAPoint Ed25519::Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const EDDSAPoint Ed25519::Mul(const EDDSAPoint &p, const BIGNUM *e, BN_CTX *ctx) const {
{
BIGNUM *zero = BN_new(), *one = BN_new(); BIGNUM *zero = BN_new(), *one = BN_new();
BN_zero (zero); BN_one (one); BN_zero(zero);
BN_one(one);
EDDSAPoint res{zero, one}; EDDSAPoint res{zero, one};
if (!BN_is_zero (e)) if (!BN_is_zero(e)) {
{
int bitCount = BN_num_bits(e); int bitCount = BN_num_bits(e);
for (int i = bitCount - 1; i >= 0; i--) for (int i = bitCount - 1; i >= 0; i--) {
{
Double(res, ctx); Double(res, ctx);
if (BN_is_bit_set(e, i)) res = Sum(res, p, ctx); if (BN_is_bit_set(e, i)) res = Sum(res, p, ctx);
} }
@ -310,28 +305,23 @@ namespace crypto
EDDSAPoint Ed25519::MulB(const uint8_t *e, BN_CTX *ctx) const // B*e, e is 32 bytes Little Endian EDDSAPoint Ed25519::MulB(const uint8_t *e, BN_CTX *ctx) const // B*e, e is 32 bytes Little Endian
{ {
BIGNUM *zero = BN_new(), *one = BN_new(); BIGNUM *zero = BN_new(), *one = BN_new();
BN_zero (zero); BN_one (one); BN_zero(zero);
BN_one(one);
EDDSAPoint res{zero, one}; EDDSAPoint res{zero, one};
bool carry = false; bool carry = false;
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++) {
{
uint8_t x = e[i]; uint8_t x = e[i];
if (carry) if (carry) {
{ if (x < 255) {
if (x < 255)
{
x++; x++;
carry = false; carry = false;
} } else
else
x = 0; x = 0;
} }
if (x > 0) if (x > 0) {
{
if (x <= 128) if (x <= 128)
res = Sum(res, Bi256[i][x - 1], ctx); res = Sum(res, Bi256[i][x - 1], ctx);
else else {
{
res = Sum(res, -Bi256[i][255 - x], ctx); // -Bi[256-x] res = Sum(res, -Bi256[i][255 - x], ctx); // -Bi[256-x]
carry = true; carry = true;
} }
@ -341,22 +331,18 @@ namespace crypto
return res; return res;
} }
EDDSAPoint Ed25519::Normalize (const EDDSAPoint& p, BN_CTX * ctx) const EDDSAPoint Ed25519::Normalize(const EDDSAPoint &p, BN_CTX *ctx) const {
{ if (p.z) {
if (p.z)
{
BIGNUM *x = BN_new(), *y = BN_new(); BIGNUM *x = BN_new(), *y = BN_new();
BN_mod_inverse(y, p.z, q, ctx); BN_mod_inverse(y, p.z, q, ctx);
BN_mod_mul(x, p.x, y, q, ctx); // x = x/z BN_mod_mul(x, p.x, y, q, ctx); // x = x/z
BN_mod_mul(y, p.y, y, q, ctx); // y = y/z BN_mod_mul(y, p.y, y, q, ctx); // y = y/z
return EDDSAPoint{x, y}; return EDDSAPoint{x, y};
} } else
else
return EDDSAPoint{BN_dup(p.x), BN_dup(p.y)}; return EDDSAPoint{BN_dup(p.x), BN_dup(p.y)};
} }
bool Ed25519::IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const bool Ed25519::IsOnCurve(const EDDSAPoint &p, BN_CTX *ctx) const {
{
BN_CTX_start(ctx); BN_CTX_start(ctx);
BIGNUM *x2 = BN_CTX_get(ctx), *y2 = BN_CTX_get(ctx), *tmp = BN_CTX_get(ctx); BIGNUM *x2 = BN_CTX_get(ctx), *y2 = BN_CTX_get(ctx), *tmp = BN_CTX_get(ctx);
BN_sqr(x2, p.x, ctx); // x^2 BN_sqr(x2, p.x, ctx); // x^2
@ -373,8 +359,7 @@ namespace crypto
return ret; return ret;
} }
BIGNUM * Ed25519::RecoverX (const BIGNUM * y, BN_CTX * ctx) const BIGNUM *Ed25519::RecoverX(const BIGNUM *y, BN_CTX *ctx) const {
{
BN_CTX_start(ctx); BN_CTX_start(ctx);
BIGNUM *y2 = BN_CTX_get(ctx), *xx = BN_CTX_get(ctx); BIGNUM *y2 = BN_CTX_get(ctx), *xx = BN_CTX_get(ctx);
BN_sqr(y2, y, ctx); // y^2 BN_sqr(y2, y, ctx); // y^2
@ -398,8 +383,7 @@ namespace crypto
return x; return x;
} }
EDDSAPoint Ed25519::DecodePoint (const uint8_t * buf, BN_CTX * ctx) const EDDSAPoint Ed25519::DecodePoint(const uint8_t *buf, BN_CTX *ctx) const {
{
// buf is 32 bytes Little Endian, convert it to Big Endian // buf is 32 bytes Little Endian, convert it to Big Endian
uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH];
for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH / 2; i++) // invert bytes for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH / 2; i++) // invert bytes
@ -416,23 +400,22 @@ namespace crypto
if (BN_is_bit_set(x, 0) != isHighestBitSet) if (BN_is_bit_set(x, 0) != isHighestBitSet)
BN_sub(x, q, x); // x = q - x BN_sub(x, q, x); // x = q - x
BIGNUM *z = BN_new(), *t = BN_new(); BIGNUM *z = BN_new(), *t = BN_new();
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t BN_one(z);
BN_mod_mul(t, x, y, q, ctx); // pre-calculate t
EDDSAPoint p{x, y, z, t}; EDDSAPoint p{x, y, z, t};
if (!IsOnCurve(p, ctx)) if (!IsOnCurve(p, ctx))
LogPrint(eLogError, "Decoded point is not on 25519"); LogPrint(eLogError, "Decoded point is not on 25519");
return p; return p;
} }
void Ed25519::EncodePoint (const EDDSAPoint& p, uint8_t * buf) const void Ed25519::EncodePoint(const EDDSAPoint &p, uint8_t *buf) const {
{
EncodeBN(p.y, buf, EDDSA25519_PUBLIC_KEY_LENGTH); EncodeBN(p.y, buf, EDDSA25519_PUBLIC_KEY_LENGTH);
if (BN_is_bit_set(p.x, 0)) // highest bit if (BN_is_bit_set(p.x, 0)) // highest bit
buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
} }
template<int len> template<int len>
BIGNUM * Ed25519::DecodeBN (const uint8_t * buf) const BIGNUM *Ed25519::DecodeBN(const uint8_t *buf) const {
{
// buf is Little Endian convert it to Big Endian // buf is Little Endian convert it to Big Endian
uint8_t buf1[len]; uint8_t buf1[len];
for (size_t i = 0; i < len / 2; i++) // invert bytes for (size_t i = 0; i < len / 2; i++) // invert bytes
@ -445,8 +428,7 @@ namespace crypto
return res; return res;
} }
void Ed25519::EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const void Ed25519::EncodeBN(const BIGNUM *bn, uint8_t *buf, size_t len) const {
{
bn2buf(bn, buf, len); bn2buf(bn, buf, len);
// To Little Endian // To Little Endian
for (size_t i = 0; i < len / 2; i++) // invert bytes for (size_t i = 0; i < len / 2; i++) // invert bytes
@ -458,25 +440,30 @@ namespace crypto
} }
#if !OPENSSL_X25519 #if !OPENSSL_X25519
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
{ BIGNUM *Ed25519::ScalarMul(const BIGNUM *u, const BIGNUM *k, BN_CTX *ctx) const {
BN_CTX_start(ctx); BN_CTX_start(ctx);
auto x1 = BN_CTX_get (ctx); BN_copy (x1, u); auto x1 = BN_CTX_get(ctx);
auto x2 = BN_CTX_get (ctx); BN_one (x2); BN_copy(x1, u);
auto z2 = BN_CTX_get (ctx); BN_zero (z2); auto x2 = BN_CTX_get(ctx);
auto x3 = BN_CTX_get (ctx); BN_copy (x3, u); BN_one(x2);
auto z3 = BN_CTX_get (ctx); BN_one (z3); auto z2 = BN_CTX_get(ctx);
auto c121666 = BN_CTX_get (ctx); BN_set_word (c121666, 121666); BN_zero(z2);
auto tmp0 = BN_CTX_get (ctx); auto tmp1 = BN_CTX_get (ctx); auto x3 = BN_CTX_get(ctx);
BN_copy(x3, u);
auto z3 = BN_CTX_get(ctx);
BN_one(z3);
auto c121666 = BN_CTX_get(ctx);
BN_set_word(c121666, 121666);
auto tmp0 = BN_CTX_get(ctx);
auto tmp1 = BN_CTX_get(ctx);
unsigned int swap = 0; unsigned int swap = 0;
auto bits = BN_num_bits(k); auto bits = BN_num_bits(k);
while(bits) while (bits) {
{
--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);
} }
@ -500,8 +487,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);
} }
@ -512,33 +498,40 @@ namespace crypto
return res; return res;
} }
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const void Ed25519::ScalarMul(const uint8_t *p, const uint8_t *e, uint8_t *buf, BN_CTX *ctx) const {
{
BIGNUM *p1 = DecodeBN<32>(p); BIGNUM *p1 = DecodeBN<32>(p);
uint8_t k[32]; uint8_t k[32];
memcpy(k, e, 32); memcpy(k, e, 32);
k[0] &= 248; k[31] &= 127; k[31] |= 64; k[0] &= 248;
k[31] &= 127;
k[31] |= 64;
BIGNUM *n = DecodeBN<32>(k); BIGNUM *n = DecodeBN<32>(k);
BIGNUM *q1 = ScalarMul(p1, n, ctx); BIGNUM *q1 = ScalarMul(p1, n, ctx);
EncodeBN(q1, buf, 32); EncodeBN(q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1); BN_free(p1);
BN_free(n);
BN_free(q1);
} }
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const void Ed25519::ScalarMulB(const uint8_t *e, uint8_t *buf, BN_CTX *ctx) const {
{ BIGNUM *p1 = BN_new();
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); BN_set_word(p1, 9);
uint8_t k[32]; uint8_t k[32];
memcpy(k, e, 32); memcpy(k, e, 32);
k[0] &= 248; k[31] &= 127; k[31] |= 64; k[0] &= 248;
k[31] &= 127;
k[31] |= 64;
BIGNUM *n = DecodeBN<32>(k); BIGNUM *n = DecodeBN<32>(k);
BIGNUM *q1 = ScalarMul(p1, n, ctx); BIGNUM *q1 = ScalarMul(p1, n, ctx);
EncodeBN(q1, buf, 32); EncodeBN(q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1); BN_free(p1);
BN_free(n);
BN_free(q1);
} }
#endif #endif
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded) void Ed25519::BlindPublicKey(const uint8_t *pub, const uint8_t *seed, uint8_t *blinded) {
{
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
@ -552,8 +545,8 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
void Ed25519::BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub) void
{ Ed25519::BlindPrivateKey(const uint8_t *priv, const uint8_t *seed, uint8_t *blindedPriv, uint8_t *blindedPub) {
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
@ -566,20 +559,19 @@ namespace crypto
// 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);
} }
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) void Ed25519::ExpandPrivateKey(const uint8_t *key, uint8_t *expandedKey) {
{
SHA512(key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey); SHA512(key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey);
expandedKey[0] &= 0xF8; // drop last 3 bits expandedKey[0] &= 0xF8; // drop last 3 bits
expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits
expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
} }
void Ed25519::CreateRedDSAPrivateKey (uint8_t * priv) void Ed25519::CreateRedDSAPrivateKey(uint8_t *priv) {
{
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);
@ -591,10 +583,9 @@ namespace crypto
} }
static std::unique_ptr<Ed25519> g_Ed25519; static std::unique_ptr<Ed25519> g_Ed25519;
std::unique_ptr<Ed25519>& GetEd25519 ()
{ std::unique_ptr<Ed25519> &GetEd25519() {
if (!g_Ed25519) if (!g_Ed25519) {
{
auto c = new Ed25519(); auto c = new Ed25519();
if (!g_Ed25519) // make sure it was not created already if (!g_Ed25519) // make sure it was not created already
g_Ed25519.reset(c); g_Ed25519.reset(c);

View file

@ -13,59 +13,74 @@
#include <openssl/bn.h> #include <openssl/bn.h>
#include "Crypto.h" #include "Crypto.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto struct EDDSAPoint {
{
struct EDDSAPoint
{
BIGNUM *x{nullptr}; BIGNUM *x{nullptr};
BIGNUM *y{nullptr}; BIGNUM *y{nullptr};
BIGNUM *z{nullptr}; BIGNUM *z{nullptr};
BIGNUM *t{nullptr}; // projective coordinates BIGNUM *t{nullptr}; // projective coordinates
EDDSAPoint() {} EDDSAPoint() {}
EDDSAPoint(const EDDSAPoint &other) { *this = other; } EDDSAPoint(const EDDSAPoint &other) { *this = other; }
EDDSAPoint(EDDSAPoint &&other) { *this = std::move(other); } EDDSAPoint(EDDSAPoint &&other) { *this = std::move(other); }
EDDSAPoint(BIGNUM *x1, BIGNUM *y1, BIGNUM *z1 = nullptr, BIGNUM *t1 = nullptr) EDDSAPoint(BIGNUM *x1, BIGNUM *y1, BIGNUM *z1 = nullptr, BIGNUM *t1 = nullptr)
: x(x1) : x(x1), y(y1), z(z1), t(t1) {}
, y(y1)
, z(z1)
, t(t1)
{}
~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); }
EDDSAPoint& operator=(EDDSAPoint&& other) ~EDDSAPoint() {
{ BN_free(x);
if (this != &other) BN_free(y);
{ BN_free(z);
BN_free (x); x = other.x; other.x = nullptr; BN_free(t);
BN_free (y); y = other.y; other.y = nullptr; }
BN_free (z); z = other.z; other.z = nullptr;
BN_free (t); t = other.t; other.t = nullptr; EDDSAPoint &operator=(EDDSAPoint &&other) {
if (this != &other) {
BN_free(x);
x = other.x;
other.x = nullptr;
BN_free(y);
y = other.y;
other.y = nullptr;
BN_free(z);
z = other.z;
other.z = nullptr;
BN_free(t);
t = other.t;
other.t = nullptr;
} }
return *this; return *this;
} }
EDDSAPoint& operator=(const EDDSAPoint& other) EDDSAPoint &operator=(const EDDSAPoint &other) {
{ if (this != &other) {
if (this != &other) BN_free(x);
{ x = other.x ? BN_dup(other.x) : nullptr;
BN_free (x); x = other.x ? BN_dup (other.x) : nullptr; BN_free(y);
BN_free (y); y = other.y ? BN_dup (other.y) : nullptr; y = other.y ? BN_dup(other.y) : nullptr;
BN_free (z); z = other.z ? BN_dup (other.z) : nullptr; BN_free(z);
BN_free (t); t = other.t ? BN_dup (other.t) : nullptr; z = other.z ? BN_dup(other.z) : nullptr;
BN_free(t);
t = other.t ? BN_dup(other.t) : nullptr;
} }
return *this; return *this;
} }
EDDSAPoint operator-() const EDDSAPoint operator-() const {
{
BIGNUM *x1 = NULL, *y1 = NULL, *z1 = NULL, *t1 = NULL; BIGNUM *x1 = NULL, *y1 = NULL, *z1 = NULL, *t1 = NULL;
if (x) { x1 = BN_dup (x); BN_set_negative (x1, !BN_is_negative (x)); }; if (x) {
x1 = BN_dup(x);
BN_set_negative(x1, !BN_is_negative(x));
};
if (y) y1 = BN_dup(y); if (y) y1 = BN_dup(y);
if (z) z1 = BN_dup(z); if (z) z1 = BN_dup(z);
if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; if (t) {
t1 = BN_dup(t);
BN_set_negative(t1, !BN_is_negative(t));
};
return EDDSAPoint{x1, y1, z1, t1}; return EDDSAPoint{x1, y1, z1, t1};
} }
}; };
@ -73,51 +88,77 @@ namespace crypto
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
const size_t EDDSA25519_SIGNATURE_LENGTH = 64; const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
class Ed25519
{ class Ed25519 {
public: public:
Ed25519(); Ed25519();
Ed25519(const Ed25519 &other); Ed25519(const Ed25519 &other);
~Ed25519(); ~Ed25519();
EDDSAPoint GeneratePublicKey(const uint8_t *expandedPrivateKey, BN_CTX *ctx) const; EDDSAPoint GeneratePublicKey(const uint8_t *expandedPrivateKey, BN_CTX *ctx) const;
EDDSAPoint DecodePublicKey(const uint8_t *buf, BN_CTX *ctx) const; EDDSAPoint DecodePublicKey(const uint8_t *buf, BN_CTX *ctx) const;
void EncodePublicKey(const EDDSAPoint &publicKey, uint8_t *buf, BN_CTX *ctx) const; void EncodePublicKey(const EDDSAPoint &publicKey, uint8_t *buf, BN_CTX *ctx) const;
#if !OPENSSL_X25519 #if !OPENSSL_X25519
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMul(const uint8_t *p, const uint8_t *e, uint8_t *buf,
BN_CTX *ctx) const; // p is point, e is number for x25519
void ScalarMulB(const uint8_t *e, uint8_t *buf, BN_CTX *ctx) const; void ScalarMulB(const uint8_t *e, uint8_t *buf, BN_CTX *ctx) const;
#endif #endif
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPublicKey(const uint8_t *pub, const uint8_t *seed,
uint8_t *blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
void BlindPrivateKey(const uint8_t *priv, const uint8_t *seed, uint8_t *blindedPriv,
uint8_t *blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
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 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 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;
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;
void Double(EDDSAPoint &p, BN_CTX *ctx) const; void Double(EDDSAPoint &p, BN_CTX *ctx) const;
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;
template<int len> template<int len>
BIGNUM *DecodeBN(const uint8_t *buf) const; BIGNUM *DecodeBN(const uint8_t *buf) const;
void EncodeBN(const BIGNUM *bn, uint8_t *buf, size_t len) const; void EncodeBN(const BIGNUM *bn, uint8_t *buf, size_t len) const;
#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:

View file

@ -10,24 +10,29 @@
#include "Crypto.h" #include "Crypto.h"
#include "Elligator.h" #include "Elligator.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
Elligator2::Elligator2 () Elligator2::Elligator2() {
{
// TODO: share with Ed22519 // TODO: share with Ed22519
p = BN_new(); p = BN_new();
// 2^255-19 // 2^255-19
BN_set_bit(p, 255); // 2^255 BN_set_bit(p, 255); // 2^255
BN_sub_word(p, 19); BN_sub_word(p, 19);
p38 = BN_dup (p); BN_add_word (p38, 3); BN_div_word (p38, 8); // (p+3)/8 p38 = BN_dup(p);
p12 = BN_dup (p); BN_sub_word (p12, 1); BN_div_word (p12, 2); // (p-1)/2 BN_add_word(p38, 3);
p14 = BN_dup (p); BN_sub_word (p14, 1); BN_div_word (p14, 4); // (p-1)/4 BN_div_word(p38, 8); // (p+3)/8
p12 = BN_dup(p);
BN_sub_word(p12, 1);
BN_div_word(p12, 2); // (p-1)/2
p14 = BN_dup(p);
BN_sub_word(p14, 1);
BN_div_word(p14, 4); // (p-1)/4
A = BN_new (); BN_set_word (A, 486662); A = BN_new();
nA = BN_new (); BN_sub (nA, p, A); BN_set_word(A, 486662);
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)
@ -35,21 +40,27 @@ namespace crypto
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();
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx); BN_set_word(u, 2);
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 (p); BN_free (p38); BN_free (p12); BN_free (p14); BN_free(p38);
BN_free (sqrtn1); BN_free (A); BN_free (nA); BN_free(p12);
BN_free (u); BN_free (iu); BN_free(p14);
BN_free(sqrtn1);
BN_free(A);
BN_free(nA);
BN_free(u);
BN_free(iu);
} }
bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, 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);
@ -61,31 +72,28 @@ namespace crypto
key1[31 - i] = key[i]; key1[31 - i] = key[i];
} }
BIGNUM * x = BN_CTX_get (ctx); BN_bin2bn (key1, 32, x); BIGNUM *x = BN_CTX_get(ctx);
BIGNUM * xA = BN_CTX_get (ctx); BN_add (xA, x, A); // x + A BN_bin2bn(key1, 32, x);
BIGNUM *xA = BN_CTX_get(ctx);
BN_add(xA, x, A); // x + A
BN_sub(xA, p, xA); // p - (x + A) BN_sub(xA, p, xA); // p - (x + A)
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);
} }
@ -102,8 +110,7 @@ namespace crypto
encoded[i] = encoded[31 - i]; encoded[i] = encoded[31 - i];
encoded[31 - i] = tmp; encoded[31 - i] = tmp;
} }
} } else
else
ret = false; ret = false;
BN_CTX_end(ctx); BN_CTX_end(ctx);
@ -111,8 +118,7 @@ namespace crypto
return ret; return ret;
} }
bool Elligator2::Decode (const uint8_t * encoded, uint8_t * key) const bool Elligator2::Decode(const uint8_t *encoded, uint8_t *key) 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);
@ -125,12 +131,14 @@ namespace crypto
} }
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);
@ -139,7 +147,8 @@ namespace crypto
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);
@ -147,8 +156,7 @@ namespace crypto
BIGNUM *x = BN_CTX_get(ctx); BIGNUM *x = BN_CTX_get(ctx);
if (legendre == 1) if (legendre == 1)
BN_copy(x, v); BN_copy(x, v);
else else {
{
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);
} }
@ -160,8 +168,7 @@ namespace crypto
key[i] = key[31 - i]; key[i] = key[31 - i];
key[31 - i] = tmp; key[31 - i] = tmp;
} }
} } else
else
ret = false; ret = false;
BN_CTX_end(ctx); BN_CTX_end(ctx);
@ -170,8 +177,7 @@ namespace crypto
return ret; return ret;
} }
void Elligator2::SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const void Elligator2::SquareRoot(const BIGNUM *x, BIGNUM *r, BN_CTX *ctx) const {
{
BIGNUM *t = BN_CTX_get(ctx); BIGNUM *t = BN_CTX_get(ctx);
BN_mod_exp(t, x, p14, p, ctx); // t = x^((p-1)/4) BN_mod_exp(t, x, p14, p, ctx); // t = x^((p-1)/4)
BN_mod_exp(r, x, p38, p, ctx); // r = x^((p+3)/8) BN_mod_exp(r, x, p38, p, ctx); // r = x^((p+3)/8)
@ -184,8 +190,7 @@ namespace crypto
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);
@ -198,10 +203,9 @@ namespace crypto
} }
static std::unique_ptr<Elligator2> g_Elligator; static std::unique_ptr<Elligator2> g_Elligator;
std::unique_ptr<Elligator2>& GetElligator ()
{ std::unique_ptr<Elligator2> &GetElligator() {
if (!g_Elligator) if (!g_Elligator) {
{
auto el = new Elligator2(); auto el = new Elligator2();
if (!g_Elligator) // make sure it was not created already if (!g_Elligator) // make sure it was not created already
g_Elligator.reset(el); g_Elligator.reset(el);

View file

@ -13,24 +13,24 @@
#include <memory> #include <memory>
#include <openssl/bn.h> #include <openssl/bn.h>
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
class Elligator2 class Elligator2 {
{
public: public:
Elligator2(); Elligator2();
~Elligator2(); ~Elligator2();
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:

View file

@ -158,15 +158,12 @@ namespace fs {
} }
void SetCertsDir(const std::string &cmdline_certsdir) { void SetCertsDir(const std::string &cmdline_certsdir) {
if (cmdline_certsdir != "") if (cmdline_certsdir != "") {
{
if (cmdline_certsdir[cmdline_certsdir.length() - 1] == '/') if (cmdline_certsdir[cmdline_certsdir.length() - 1] == '/')
certsDir = cmdline_certsdir.substr(0, cmdline_certsdir.size() - 1); // strip trailing slash certsDir = cmdline_certsdir.substr(0, cmdline_certsdir.size() - 1); // strip trailing slash
else else
certsDir = cmdline_certsdir; certsDir = cmdline_certsdir;
} } else {
else
{
certsDir = i2p::fs::DataDirPath("certificates"); certsDir = i2p::fs::DataDirPath("certificates");
} }
return; return;
@ -208,8 +205,7 @@ namespace fs {
return boost::filesystem::exists(path); return boost::filesystem::exists(path);
} }
uint32_t GetLastUpdateTime (const std::string & path) uint32_t GetLastUpdateTime(const std::string &path) {
{
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(path))
return 0; return 0;
boost::system::error_code ec; boost::system::error_code ec;
@ -223,8 +219,7 @@ namespace fs {
return boost::filesystem::remove(path); return boost::filesystem::remove(path);
} }
bool CreateDirectory (const std::string& path) bool CreateDirectory(const std::string &path) {
{
if (boost::filesystem::exists(path) && boost::filesystem::is_directory(boost::filesystem::status(path))) if (boost::filesystem::exists(path) && boost::filesystem::is_directory(boost::filesystem::status(path)))
return true; return true;
return boost::filesystem::create_directory(path); return boost::filesystem::create_directory(path);
@ -276,8 +271,7 @@ namespace fs {
}); });
} }
void HashedStorage::Iterate(FilenameVisitor v) void HashedStorage::Iterate(FilenameVisitor v) {
{
boost::filesystem::path p(root); boost::filesystem::path p(root);
boost::filesystem::recursive_directory_iterator it(p); boost::filesystem::recursive_directory_iterator it(p);
boost::filesystem::recursive_directory_iterator end; boost::filesystem::recursive_directory_iterator end;

View file

@ -35,8 +35,7 @@ namespace fs {
* 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: protected:
std::string root; /**< path to storage with it's name included */ std::string root; /**< path to storage with it's name included */
@ -48,27 +47,36 @@ namespace fs {
public: public:
typedef std::function<void(const std::string &)> FilenameVisitor; typedef std::function<void(const std::string &)> FilenameVisitor;
HashedStorage(const char *n, const char *p1, const char *p2, const char *s) : HashedStorage(const char *n, const char *p1, const char *p2, const char *s) :
name(n), prefix1(p1), prefix2(p2), suffix(s) {}; name(n), prefix1(p1), prefix2(p2), suffix(s) {};
/** create subdirs in storage */ /** create subdirs in storage */
bool Init(const char *chars, size_t cnt); bool Init(const char *chars, size_t cnt);
const std::string &GetRoot() const { return root; } const std::string &GetRoot() const { return root; }
const std::string &GetName() const { return name; } const std::string &GetName() const { return name; }
/** set directory where to place storage directory */ /** set directory where to place storage directory */
void SetPlace(const std::string &path); void SetPlace(const std::string &path);
/** path to file with given ident */ /** path to file with given ident */
std::string Path(const std::string &ident) const; std::string Path(const std::string &ident) const;
/** remove file by ident */ /** remove file by ident */
void Remove(const std::string &ident); void Remove(const std::string &ident);
/** find all files in storage and store list in provided vector */ /** find all files in storage and store list in provided vector */
void Traverse(std::vector <std::string> &files); void Traverse(std::vector <std::string> &files);
/** visit every file in this storage with a visitor */ /** visit every file in this storage with a visitor */
void Iterate(FilenameVisitor v); void Iterate(FilenameVisitor v);
}; };
/** @brief Returns current application name, default 'i2pd' */ /** @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);
@ -168,8 +176,7 @@ namespace fs {
} }
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) {
{
std::stringstream s(""); std::stringstream s("");
s << storage.GetRoot(); s << storage.GetRoot();
_ExpandPath(s, filenames...); _ExpandPath(s, filenames...);

View file

@ -15,68 +15,55 @@
#include "Family.h" #include "Family.h"
#include "Config.h" #include "Config.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data Families::Families() {
{
Families::Families ()
{
} }
Families::~Families () Families::~Families() {
{
} }
void Families::LoadCertificate (const std::string& filename) void Families::LoadCertificate(const std::string &filename) {
{
SSL_CTX *ctx = SSL_CTX_new(TLS_method()); SSL_CTX *ctx = SSL_CTX_new(TLS_method());
int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
if (ret) if (ret) {
{
SSL *ssl = SSL_new(ctx); SSL *ssl = SSL_new(ctx);
X509 *cert = SSL_get_certificate(ssl); X509 *cert = SSL_get_certificate(ssl);
if (cert) if (cert) {
{
std::shared_ptr<i2p::crypto::Verifier> verifier; std::shared_ptr<i2p::crypto::Verifier> verifier;
// extract issuer name // extract issuer name
char name[100]; char name[100];
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100); X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
char *cn = strstr(name, "CN="); char *cn = strstr(name, "CN=");
if (cn) if (cn) {
{
cn += 3; cn += 3;
char *family = strstr(cn, ".family"); char *family = strstr(cn, ".family");
if (family) family[0] = 0; if (family) family[0] = 0;
} }
auto pkey = X509_get_pubkey(cert); auto pkey = X509_get_pubkey(cert);
int keyType = EVP_PKEY_base_id(pkey); int keyType = EVP_PKEY_base_id(pkey);
switch (keyType) switch (keyType) {
{
case EVP_PKEY_DSA: case EVP_PKEY_DSA:
// TODO: // TODO:
break; break;
case EVP_PKEY_EC: case EVP_PKEY_EC: {
{
EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey); EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey);
if (ecKey) if (ecKey) {
{
auto group = EC_KEY_get0_group(ecKey); auto group = EC_KEY_get0_group(ecKey);
if (group) if (group) {
{
int curve = EC_GROUP_get_curve_name(group); int curve = EC_GROUP_get_curve_name(group);
if (curve == NID_X9_62_prime256v1) if (curve == NID_X9_62_prime256v1) {
{
uint8_t signingKey[64]; uint8_t signingKey[64];
BIGNUM *x = BN_new(), *y = BN_new(); BIGNUM *x = BN_new(), *y = BN_new();
EC_POINT_get_affine_coordinates_GFp(group, EC_POINT_get_affine_coordinates_GFp(group,
EC_KEY_get0_public_key(ecKey), x, y, NULL); EC_KEY_get0_public_key(ecKey), x, y, NULL);
i2p::crypto::bn2buf(x, signingKey, 32); i2p::crypto::bn2buf(x, signingKey, 32);
i2p::crypto::bn2buf(y, signingKey + 32, 32); i2p::crypto::bn2buf(y, signingKey + 32, 32);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(); verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>();
verifier->SetPublicKey(signingKey); verifier->SetPublicKey(signingKey);
} } else
else
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported"); LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
} }
EC_KEY_free(ecKey); EC_KEY_free(ecKey);
@ -91,14 +78,12 @@ namespace data
m_SigningKeys.emplace(cn, std::make_pair(verifier, m_SigningKeys.size() + 1)); m_SigningKeys.emplace(cn, std::make_pair(verifier, m_SigningKeys.size() + 1));
} }
SSL_free(ssl); SSL_free(ssl);
} } else
else
LogPrint(eLogError, "Family: Can't open certificate file ", filename); LogPrint(eLogError, "Family: Can't open certificate file ", filename);
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
} }
void Families::LoadCertificates () void Families::LoadCertificates() {
{
std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "family"; std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "family";
std::vector<std::string> files; std::vector<std::string> files;
@ -121,12 +106,10 @@ namespace data
} }
bool Families::VerifyFamily(const std::string &family, const IdentHash &ident, bool Families::VerifyFamily(const std::string &family, const IdentHash &ident,
const char * signature, const char * key) const const char *signature, const char *key) const {
{
uint8_t buf[100], signatureBuf[64]; uint8_t buf[100], signatureBuf[64];
size_t len = family.length(), signatureLen = strlen(signature); size_t len = family.length(), signatureLen = strlen(signature);
if (len + 32 > 100) if (len + 32 > 100) {
{
LogPrint(eLogError, "Family: ", family, " is too long"); LogPrint(eLogError, "Family: ", family, " is too long");
return false; return false;
} }
@ -142,33 +125,27 @@ namespace data
return true; return true;
} }
FamilyID Families::GetFamilyID (const std::string& family) const FamilyID Families::GetFamilyID(const std::string &family) const {
{
auto it = m_SigningKeys.find(family); auto it = m_SigningKeys.find(family);
if (it != m_SigningKeys.end()) if (it != m_SigningKeys.end())
return it->second.second; return it->second.second;
return 0; return 0;
} }
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident) std::string CreateFamilySignature(const std::string &family, const IdentHash &ident) {
{
auto filename = i2p::fs::DataDirPath("family", (family + ".key")); auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
std::string sig; std::string sig;
SSL_CTX *ctx = SSL_CTX_new(TLS_method()); SSL_CTX *ctx = SSL_CTX_new(TLS_method());
int ret = SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
if (ret) if (ret) {
{
SSL *ssl = SSL_new(ctx); SSL *ssl = SSL_new(ctx);
EVP_PKEY *pkey = SSL_get_privatekey(ssl); EVP_PKEY *pkey = SSL_get_privatekey(ssl);
EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey); EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey);
if (ecKey) if (ecKey) {
{
auto group = EC_KEY_get0_group(ecKey); auto group = EC_KEY_get0_group(ecKey);
if (group) if (group) {
{
int curve = EC_GROUP_get_curve_name(group); int curve = EC_GROUP_get_curve_name(group);
if (curve == NID_X9_62_prime256v1) if (curve == NID_X9_62_prime256v1) {
{
uint8_t signingPrivateKey[32], buf[50], signature[64]; uint8_t signingPrivateKey[32], buf[50], signature[64];
i2p::crypto::bn2buf(EC_KEY_get0_private_key(ecKey), signingPrivateKey, 32); i2p::crypto::bn2buf(EC_KEY_get0_private_key(ecKey), signingPrivateKey, 32);
i2p::crypto::ECDSAP256Signer signer(signingPrivateKey); i2p::crypto::ECDSAP256Signer signer(signingPrivateKey);
@ -183,14 +160,12 @@ namespace data
b64[len] = 0; b64[len] = 0;
sig = b64; sig = b64;
delete[] b64; delete[] b64;
} } else
else
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported"); LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
} }
} }
SSL_free(ssl); SSL_free(ssl);
} } else
else
LogPrint(eLogError, "Family: Can't open keys file: ", filename); LogPrint(eLogError, "Family: Can't open keys file: ", filename);
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
return sig; return sig;

View file

@ -15,20 +15,22 @@
#include "Signature.h" #include "Signature.h"
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
typedef int FamilyID; typedef int FamilyID;
class Families
{ class Families {
public: public:
Families(); Families();
~Families(); ~Families();
void LoadCertificates(); void LoadCertificates();
bool VerifyFamily(const std::string &family, const IdentHash &ident, bool VerifyFamily(const std::string &family, const IdentHash &ident,
const char *signature, const char *key = nullptr) const; const char *signature, const char *key = nullptr) const;
FamilyID GetFamilyID(const std::string &family) const; FamilyID GetFamilyID(const std::string &family) const;
private: private:

File diff suppressed because it is too large Load diff

View file

@ -22,26 +22,21 @@
#include "Queue.h" #include "Queue.h"
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p {
{ namespace tunnel {
namespace tunnel
{
class OutboundTunnel; class OutboundTunnel;
} }
namespace garlic namespace garlic {
{
enum GarlicDeliveryType enum GarlicDeliveryType {
{
eGarlicDeliveryTypeLocal = 0, eGarlicDeliveryTypeLocal = 0,
eGarlicDeliveryTypeDestination = 1, eGarlicDeliveryTypeDestination = 1,
eGarlicDeliveryTypeRouter = 2, eGarlicDeliveryTypeRouter = 2,
eGarlicDeliveryTypeTunnel = 3 eGarlicDeliveryTypeTunnel = 3
}; };
struct ElGamalBlock struct ElGamalBlock {
{
uint8_t sessionKey[32]; uint8_t sessionKey[32];
uint8_t preIV[32]; uint8_t preIV[32];
uint8_t padding[158]; uint8_t padding[158];
@ -54,28 +49,33 @@ namespace garlic
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
struct SessionTag: public i2p::data::Tag<32> struct SessionTag : public i2p::data::Tag<32> {
{
SessionTag(const uint8_t *buf, uint32_t ts = 0) : Tag<32>(buf), creationTime(ts) {}; SessionTag(const uint8_t *buf, uint32_t ts = 0) : Tag<32>(buf), creationTime(ts) {};
SessionTag() = default; SessionTag() = default;
SessionTag(const SessionTag &) = default; SessionTag(const SessionTag &) = default;
SessionTag &operator=(const SessionTag &) = default; SessionTag &operator=(const SessionTag &) = default;
#ifndef _WIN32 #ifndef _WIN32
SessionTag(SessionTag &&) = default; SessionTag(SessionTag &&) = default;
SessionTag &operator=(SessionTag &&) = default; SessionTag &operator=(SessionTag &&) = default;
#endif #endif
uint32_t creationTime; // seconds since epoch uint32_t creationTime; // seconds since epoch
}; };
// AESDecryption is associated with session tags and store key // AESDecryption is associated with session tags and store key
class AESDecryption: public i2p::crypto::CBCDecryption class AESDecryption : public i2p::crypto::CBCDecryption {
{
public: public:
AESDecryption (const uint8_t * key): m_Key (key) AESDecryption(const uint8_t *key) : m_Key(key) {
{
SetKey(key); SetKey(key);
} }
const i2p::crypto::AESKey &GetKey() const { return m_Key; }; const i2p::crypto::AESKey &GetKey() const { return m_Key; };
private: private:
@ -83,8 +83,7 @@ namespace garlic
i2p::crypto::AESKey m_Key; i2p::crypto::AESKey m_Key;
}; };
struct GarlicRoutingPath struct GarlicRoutingPath {
{
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel; std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
std::shared_ptr<const i2p::data::Lease> remoteLease; std::shared_ptr<const i2p::data::Lease> remoteLease;
int rtt; // RTT int rtt; // RTT
@ -93,12 +92,11 @@ namespace garlic
}; };
class GarlicDestination; class GarlicDestination;
class GarlicRoutingSession
{ class GarlicRoutingSession {
protected: protected:
enum LeaseSetUpdateStatus enum LeaseSetUpdateStatus {
{
eLeaseSetUpToDate = 0, eLeaseSetUpToDate = 0,
eLeaseSetUpdated, eLeaseSetUpdated,
eLeaseSetSubmitted, eLeaseSetSubmitted,
@ -108,37 +106,54 @@ namespace garlic
public: public:
GarlicRoutingSession(GarlicDestination *owner, bool attachLeaseSet); GarlicRoutingSession(GarlicDestination *owner, bool attachLeaseSet);
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; };
virtual bool IsReadyToSend() const { return true; }; virtual bool IsReadyToSend() const { return true; };
virtual bool IsTerminated() const { return !GetOwner(); }; virtual bool IsTerminated() const { return !GetOwner(); };
virtual uint64_t GetLastActivityTimestamp() const { return 0; }; // non-zero for rathets only virtual uint64_t GetLastActivityTimestamp() const { return 0; }; // non-zero for rathets only
void SetLeaseSetUpdated () void SetLeaseSetUpdated() {
{
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
}; };
bool IsLeaseSetNonConfirmed() const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; }; bool IsLeaseSetNonConfirmed() const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
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);
@ -158,14 +173,14 @@ namespace garlic
// 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;
@ -175,25 +190,33 @@ namespace garlic
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);
size_t CreateGarlicClove(uint8_t *buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination); size_t CreateGarlicClove(uint8_t *buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination);
size_t CreateDeliveryStatusClove(uint8_t *buf, uint32_t msgID); size_t CreateDeliveryStatusClove(uint8_t *buf, uint32_t msgID);
void TagsConfirmed(uint32_t msgID); void TagsConfirmed(uint32_t msgID);
UnconfirmedTags *GenerateSessionTags(); UnconfirmedTags *GenerateSessionTags();
private: private:
@ -212,33 +235,45 @@ namespace garlic
// 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 ReceiveRatchetTagSet; class ReceiveRatchetTagSet;
typedef std::shared_ptr<ReceiveRatchetTagSet> ReceiveRatchetTagSetPtr; typedef std::shared_ptr<ReceiveRatchetTagSet> ReceiveRatchetTagSetPtr;
struct ECIESX25519AEADRatchetIndexTagset struct ECIESX25519AEADRatchetIndexTagset {
{
int index; int index;
ReceiveRatchetTagSetPtr tagset; ReceiveRatchetTagSetPtr tagset;
}; };
class GarlicDestination: public i2p::data::LocalDestination class GarlicDestination : public i2p::data::LocalDestination {
{
public: public:
GarlicDestination(); GarlicDestination();
~GarlicDestination(); ~GarlicDestination();
void CleanUp(); void CleanUp();
void SetNumTags(int numTags) { m_NumTags = numTags; }; void SetNumTags(int numTags) { m_NumTags = numTags; };
int GetNumTags() const { return m_NumTags; }; int GetNumTags() const { return m_NumTags; };
void SetNumRatchetInboundTags(int numTags) { m_NumRatchetInboundTags = numTags; }; void SetNumRatchetInboundTags(int numTags) { m_NumRatchetInboundTags = numTags; };
int GetNumRatchetInboundTags() const { return m_NumRatchetInboundTags; }; int GetNumRatchetInboundTags() const { return m_NumRatchetInboundTags; };
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
std::shared_ptr<GarlicRoutingSession>
GetRoutingSession(std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void CleanupExpiredTags(); void CleanupExpiredTags();
void RemoveDeliveryStatusSession(uint32_t msgID); void RemoveDeliveryStatusSession(uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessageForRouter(std::shared_ptr<const i2p::data::RouterInfo> router, std::shared_ptr<I2NPMessage> WrapMessageForRouter(std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> msg);
@ -247,14 +282,21 @@ namespace garlic
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
virtual void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag); // from different thread virtual void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag); // from different thread
void DeliveryStatusSent(GarlicRoutingSessionPtr session, uint32_t msgID); void DeliveryStatusSent(GarlicRoutingSessionPtr session, uint32_t msgID);
uint64_t AddECIESx25519SessionNextTag(ReceiveRatchetTagSetPtr tagset); uint64_t AddECIESx25519SessionNextTag(ReceiveRatchetTagSetPtr 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);
uint8_t *GetPayloadBuffer(); uint8_t *GetPayloadBuffer();
virtual void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg); virtual void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg); virtual void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated(); virtual void SetLeaseSetUpdated();
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet() = 0; // TODO virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet() = 0; // TODO
@ -265,17 +307,22 @@ namespace garlic
void AddECIESx25519Key(const uint8_t *key, const uint8_t *tag); // one tag void AddECIESx25519Key(const uint8_t *key, const uint8_t *tag); // one tag
bool HandleECIESx25519TagMessage(uint8_t *buf, size_t len); // return true if found bool HandleECIESx25519TagMessage(uint8_t *buf, size_t len); // return true if found
virtual void HandleI2NPMessage(const uint8_t *buf, size_t len) = 0; // called from clove only virtual void HandleI2NPMessage(const uint8_t *buf, size_t len) = 0; // called from clove only
virtual bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len, uint32_t msgID) = 0; virtual bool
HandleCloveI2NPMessage(I2NPMessageType typeID, const uint8_t *payload, size_t len, uint32_t msgID) = 0;
void HandleGarlicMessage(std::shared_ptr<I2NPMessage> msg); void HandleGarlicMessage(std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage(uint32_t msgID); void HandleDeliveryStatusMessage(uint32_t msgID);
void SaveTags(); void SaveTags();
void LoadTags(); void LoadTags();
private: private:
void HandleAESBlock(uint8_t *buf, size_t len, std::shared_ptr<AESDecryption> decryption, void HandleAESBlock(uint8_t *buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from); std::shared_ptr<i2p::tunnel::InboundTunnel> from);
void HandleGarlicPayload(uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleGarlicPayload(uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
private: private:
@ -299,9 +346,17 @@ namespace garlic
// for HTTP only // for HTTP only
size_t GetNumIncomingTags() const { return m_Tags.size(); } size_t GetNumIncomingTags() const { return m_Tags.size(); }
size_t GetNumIncomingECIESx25519Tags() const { return m_ECIESx25519Tags.size(); } size_t GetNumIncomingECIESx25519Tags() const { return m_ECIESx25519Tags.size(); }
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
const decltype(m_ECIESx25519Sessions)& GetECIESx25519Sessions () const { return m_ECIESx25519Sessions; } const decltype(m_Sessions)
&
GetSessions() const { return m_Sessions; };
const decltype(m_ECIESx25519Sessions)
&
GetECIESx25519Sessions() const { return m_ECIESx25519Sessions; }
}; };
void CleanUpTagsFiles(); void CleanUpTagsFiles();

View file

@ -14,15 +14,12 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Gost.h" #include "Gost.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
// GOST R 34.10 // GOST R 34.10
GOSTR3410Curve::GOSTR3410Curve (BIGNUM * a, BIGNUM * b, BIGNUM * p, BIGNUM * q, BIGNUM * x, BIGNUM * y) GOSTR3410Curve::GOSTR3410Curve(BIGNUM *a, BIGNUM *b, BIGNUM *p, BIGNUM *q, BIGNUM *x, BIGNUM *y) {
{
m_KeyLen = BN_num_bytes(p); m_KeyLen = BN_num_bytes(p);
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
m_Group = EC_GROUP_new_curve_GFp(p, a, b, ctx); m_Group = EC_GROUP_new_curve_GFp(p, a, b, ctx);
@ -34,13 +31,11 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
GOSTR3410Curve::~GOSTR3410Curve () GOSTR3410Curve::~GOSTR3410Curve() {
{
EC_GROUP_free(m_Group); EC_GROUP_free(m_Group);
} }
EC_POINT * GOSTR3410Curve::MulP (const BIGNUM * n) const EC_POINT *GOSTR3410Curve::MulP(const BIGNUM *n) const {
{
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
auto p = EC_POINT_new(m_Group); auto p = EC_POINT_new(m_Group);
EC_POINT_mul(m_Group, p, n, nullptr, nullptr, ctx); EC_POINT_mul(m_Group, p, n, nullptr, nullptr, ctx);
@ -48,20 +43,17 @@ namespace crypto
return p; return p;
} }
bool GOSTR3410Curve::GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const bool GOSTR3410Curve::GetXY(const EC_POINT *p, BIGNUM *x, BIGNUM *y) const {
{
return EC_POINT_get_affine_coordinates_GFp(m_Group, p, x, y, nullptr); return EC_POINT_get_affine_coordinates_GFp(m_Group, p, x, y, nullptr);
} }
EC_POINT * GOSTR3410Curve::CreatePoint (const BIGNUM * x, const BIGNUM * y) const EC_POINT *GOSTR3410Curve::CreatePoint(const BIGNUM *x, const BIGNUM *y) const {
{
EC_POINT *p = EC_POINT_new(m_Group); EC_POINT *p = EC_POINT_new(m_Group);
EC_POINT_set_affine_coordinates_GFp(m_Group, p, x, y, nullptr); EC_POINT_set_affine_coordinates_GFp(m_Group, p, x, y, nullptr);
return p; return p;
} }
void GOSTR3410Curve::Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s) void GOSTR3410Curve::Sign(const BIGNUM *priv, const BIGNUM *digest, BIGNUM *r, BIGNUM *s) {
{
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);
@ -79,8 +71,7 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
bool GOSTR3410Curve::Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s) bool GOSTR3410Curve::Verify(const EC_POINT *pub, const BIGNUM *digest, const BIGNUM *r, const BIGNUM *s) {
{
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);
@ -105,15 +96,14 @@ namespace crypto
return ret; return ret;
} }
EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const EC_POINT *GOSTR3410Curve::RecoverPublicKey(const BIGNUM *digest, const BIGNUM *r, const BIGNUM *s,
{ bool isNegativeY) const {
// s*P = r*Q + h*C // s*P = r*Q + h*C
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
BN_CTX_start(ctx); BN_CTX_start(ctx);
EC_POINT *C = EC_POINT_new(m_Group); // C = k*P = (rx, ry) EC_POINT *C = EC_POINT_new(m_Group); // C = k*P = (rx, ry)
EC_POINT *Q = nullptr; EC_POINT *Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx)) if (EC_POINT_set_compressed_coordinates_GFp(m_Group, C, r, isNegativeY ? 1 : 0, ctx)) {
{
EC_POINT *S = EC_POINT_new(m_Group); // S = s*P EC_POINT *S = EC_POINT_new(m_Group); // S = s*P
EC_POINT_mul(m_Group, S, s, nullptr, nullptr, ctx); EC_POINT_mul(m_Group, S, s, nullptr, nullptr, ctx);
BIGNUM *q = BN_CTX_get(ctx); BIGNUM *q = BN_CTX_get(ctx);
@ -137,8 +127,7 @@ namespace crypto
return Q; return Q;
} }
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet) static GOSTR3410Curve *CreateGOSTR3410Curve(GOSTR3410ParamSet paramSet) {
{
// a, b, p, q, x, y // a, b, p, q, x, y
static const char *params[eGOSTR3410NumParamSets][6] = static const char *params[eGOSTR3410NumParamSets][6] =
{ {
@ -168,15 +157,19 @@ namespace crypto
BN_hex2bn(&x, params[paramSet][4]); BN_hex2bn(&x, params[paramSet][4]);
BN_hex2bn(&y, params[paramSet][5]); BN_hex2bn(&y, params[paramSet][5]);
auto curve = new GOSTR3410Curve(a, b, p, q, x, y); auto curve = new GOSTR3410Curve(a, b, p, q, x, y);
BN_free (a); BN_free (b); BN_free (p); BN_free (q); BN_free (x); BN_free (y); BN_free(a);
BN_free(b);
BN_free(p);
BN_free(q);
BN_free(x);
BN_free(y);
return curve; return curve;
} }
static std::array <std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves; static std::array <std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{ std::unique_ptr <GOSTR3410Curve> &GetGOSTR3410Curve(GOSTR3410ParamSet paramSet) {
if (!g_GOSTR3410Curves[paramSet]) if (!g_GOSTR3410Curves[paramSet]) {
{
auto c = CreateGOSTR3410Curve(paramSet); auto c = CreateGOSTR3410Curve(paramSet);
if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already
g_GOSTR3410Curves[paramSet].reset(c); g_GOSTR3410Curves[paramSet].reset(c);
@ -783,28 +776,24 @@ namespace crypto
uint8_t buf[64]; uint8_t buf[64];
uint64_t ll[8]; uint64_t ll[8];
GOST3411Block operator^(const GOST3411Block& other) const GOST3411Block operator^(const GOST3411Block &other) const {
{
GOST3411Block ret; GOST3411Block ret;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i] ^ other.ll[i]; ret.ll[i] = ll[i] ^ other.ll[i];
return ret; return ret;
} }
GOST3411Block operator^(const uint64_t * other) const GOST3411Block operator^(const uint64_t *other) const {
{
GOST3411Block ret; GOST3411Block ret;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i] ^ other[i]; ret.ll[i] = ll[i] ^ other[i];
return ret; return ret;
} }
GOST3411Block operator+(const GOST3411Block& other) const GOST3411Block operator+(const GOST3411Block &other) const {
{
GOST3411Block ret; GOST3411Block ret;
uint8_t carry = 0; uint8_t carry = 0;
for (int i = 63; i >= 0; i--) for (int i = 63; i >= 0; i--) {
{
uint16_t sum = buf[i] + other.buf[i] + carry; uint16_t sum = buf[i] + other.buf[i] + carry;
ret.buf[i] = sum; ret.buf[i] = sum;
carry = sum >> 8; carry = sum >> 8;
@ -812,10 +801,8 @@ namespace crypto
return ret; return ret;
} }
void Add (uint32_t c) void Add(uint32_t c) {
{ for (int i = 63; i >= 0; i--) {
for (int i = 63; i >= 0; i--)
{
if (!c) return; if (!c) return;
c += buf[i]; c += buf[i];
buf[i] = c; buf[i] = c;
@ -823,11 +810,9 @@ namespace crypto
} }
} }
void F () void F() {
{
uint64_t res[8]; uint64_t res[8];
for (int b=0; b<8; b++) for (int b = 0; b < 8; b++) {
{
uint64_t r; uint64_t r;
r = T0[buf[b + 56]]; r = T0[buf[b + 56]];
r ^= T1[buf[b + 48]]; r ^= T1[buf[b + 48]];
@ -842,12 +827,10 @@ namespace crypto
memcpy(buf, res, 64); memcpy(buf, res, 64);
} }
GOST3411Block E (const GOST3411Block& m) GOST3411Block E(const GOST3411Block &m) {
{
GOST3411Block k = *this; GOST3411Block k = *this;
GOST3411Block res = k ^ m; GOST3411Block res = k ^ m;
for (int i = 0; i < 12; i++) for (int i = 0; i < 12; i++) {
{
res.F(); res.F();
k = k ^ C_[i]; k = k ^ C_[i];
k.F(); k.F();
@ -857,8 +840,7 @@ namespace crypto
} }
}; };
static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m) static GOST3411Block gN(const GOST3411Block &N, const GOST3411Block &h, const GOST3411Block &m) {
{
GOST3411Block res = N ^ h; GOST3411Block res = N ^ h;
res.F(); res.F();
res = res.E(m); res = res.E(m);
@ -867,8 +849,7 @@ namespace crypto
return res; return res;
} }
static void H (const uint8_t * iv, const uint8_t * buf, size_t len, uint8_t * digest) static void H(const uint8_t *iv, const uint8_t *buf, size_t len, uint8_t *digest) {
{
// stage 1 // stage 1
GOST3411Block h, N, s, m; GOST3411Block h, N, s, m;
memcpy(h.buf, iv, 64); memcpy(h.buf, iv, 64);
@ -876,8 +857,7 @@ namespace crypto
memset(s.buf, 0, 64); memset(s.buf, 0, 64);
size_t l = len; size_t l = len;
// stage 2 // stage 2
while (l >= 64) while (l >= 64) {
{
memcpy(m.buf, buf + l - 64, 64); // TODO memcpy(m.buf, buf + l - 64, 64); // TODO
h = gN(N, h, m); h = gN(N, h, m);
N.Add(512); N.Add(512);
@ -886,8 +866,7 @@ namespace crypto
} }
// stage 3 // stage 3
size_t padding = 64 - l; size_t padding = 64 - l;
if (padding) if (padding) {
{
memset(m.buf, 0, padding - 1); memset(m.buf, 0, padding - 1);
m.buf[padding - 1] = 1; m.buf[padding - 1] = 1;
} }
@ -905,8 +884,7 @@ namespace crypto
memcpy(digest, h.buf, 64); memcpy(digest, h.buf, 64);
} }
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest) void GOSTR3411_2012_256(const uint8_t *buf, size_t len, uint8_t *digest) {
{
uint8_t iv[64]; uint8_t iv[64];
memset(iv, 1, 64); memset(iv, 1, 64);
uint8_t h[64]; uint8_t h[64];
@ -914,33 +892,28 @@ namespace crypto
memcpy(digest, h, 32); // first half memcpy(digest, h, 32); // first half
} }
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest) void GOSTR3411_2012_512(const uint8_t *buf, size_t len, uint8_t *digest) {
{
uint8_t iv[64]; uint8_t iv[64];
memset(iv, 0, 64); memset(iv, 0, 64);
H(iv, buf, len, digest); H(iv, buf, len, digest);
} }
// reverse order // reverse order
struct GOSTR3411_2012_CTX struct GOSTR3411_2012_CTX {
{
GOST3411Block h, N, s, m; GOST3411Block h, N, s, m;
size_t len; size_t len;
bool is512; bool is512;
}; };
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new () GOSTR3411_2012_CTX *GOSTR3411_2012_CTX_new() {
{
return new GOSTR3411_2012_CTX; return new GOSTR3411_2012_CTX;
} }
void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx) void GOSTR3411_2012_CTX_free(GOSTR3411_2012_CTX *ctx) {
{
delete ctx; delete ctx;
} }
void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512) void GOSTR3411_2012_CTX_Init(GOSTR3411_2012_CTX *ctx, bool is512) {
{
uint8_t iv[64]; uint8_t iv[64];
memset(iv, is512 ? 0 : 1, 64); memset(iv, is512 ? 0 : 1, 64);
memcpy(ctx->h.buf, iv, 64); memcpy(ctx->h.buf, iv, 64);
@ -950,8 +923,7 @@ namespace crypto
ctx->is512 = is512; ctx->is512 = is512;
} }
void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx) void GOSTR3411_2012_CTX_Update(const uint8_t *buf, size_t len, GOSTR3411_2012_CTX *ctx) {
{
if (!len) return; if (!len) return;
if (ctx->len > 0) // something left from buffer if (ctx->len > 0) // something left from buffer
{ {
@ -959,17 +931,19 @@ namespace crypto
if (len < l) l = len; if (len < l) l = len;
for (size_t i = 0; i < l; i++) for (size_t i = 0; i < l; i++)
ctx->m.buf[ctx->len + i] = buf[l - i - 1]; // invert ctx->m.buf[ctx->len + i] = buf[l - i - 1]; // invert
ctx->len += l; len -= l; buf += l; ctx->len += l;
len -= l;
buf += l;
ctx->h = gN(ctx->N, ctx->h, ctx->m); ctx->h = gN(ctx->N, ctx->h, ctx->m);
ctx->N.Add(512); ctx->N.Add(512);
ctx->s = ctx->m + ctx->s; ctx->s = ctx->m + ctx->s;
} }
while (len >= 64) while (len >= 64) {
{
for (size_t i = 0; i < 64; i++) for (size_t i = 0; i < 64; i++)
ctx->m.buf[i] = buf[63 - i]; // invert ctx->m.buf[i] = buf[63 - i]; // invert
len -= 64; buf += 64; len -= 64;
buf += 64;
ctx->h = gN(ctx->N, ctx->h, ctx->m); ctx->h = gN(ctx->N, ctx->h, ctx->m);
ctx->N.Add(512); ctx->N.Add(512);
ctx->s = ctx->m + ctx->s; ctx->s = ctx->m + ctx->s;
@ -982,12 +956,10 @@ namespace crypto
ctx->len = len; ctx->len = len;
} }
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx) void GOSTR3411_2012_CTX_Finish(uint8_t *digest, GOSTR3411_2012_CTX *ctx) {
{
GOST3411Block m; GOST3411Block m;
size_t padding = 64 - ctx->len; size_t padding = 64 - ctx->len;
if (padding) if (padding) {
{
memset(m.buf, 0, padding - 1); memset(m.buf, 0, padding - 1);
m.buf[padding - 1] = 1; m.buf[padding - 1] = 1;
} }

View file

@ -12,15 +12,12 @@
#include <memory> #include <memory>
#include <openssl/ec.h> #include <openssl/ec.h>
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
// ГОСТ Р 34.10 // ГОСТ Р 34.10
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
@ -29,21 +26,29 @@ namespace crypto
eGOSTR3410NumParamSets eGOSTR3410NumParamSets
}; };
class GOSTR3410Curve class GOSTR3410Curve {
{
public: public:
GOSTR3410Curve(BIGNUM *a, BIGNUM *b, BIGNUM *p, BIGNUM *q, BIGNUM *x, BIGNUM *y); GOSTR3410Curve(BIGNUM *a, BIGNUM *b, BIGNUM *p, BIGNUM *q, BIGNUM *x, BIGNUM *y);
~GOSTR3410Curve(); ~GOSTR3410Curve();
size_t GetKeyLen() const { return m_KeyLen; }; size_t GetKeyLen() const { return m_KeyLen; };
const EC_GROUP *GetGroup() const { return m_Group; }; const EC_GROUP *GetGroup() const { return m_Group; };
EC_POINT *MulP(const BIGNUM *n) const; EC_POINT *MulP(const BIGNUM *n) const;
bool GetXY(const EC_POINT *p, BIGNUM *x, BIGNUM *y) const; bool GetXY(const EC_POINT *p, BIGNUM *x, BIGNUM *y) const;
EC_POINT *CreatePoint(const BIGNUM *x, const BIGNUM *y) const; EC_POINT *CreatePoint(const BIGNUM *x, const BIGNUM *y) const;
void Sign(const BIGNUM *priv, const BIGNUM *digest, BIGNUM *r, BIGNUM *s); void Sign(const BIGNUM *priv, const BIGNUM *digest, BIGNUM *r, BIGNUM *s);
bool Verify(const EC_POINT *pub, const BIGNUM *digest, const BIGNUM *r, const BIGNUM *s); bool Verify(const EC_POINT *pub, const BIGNUM *digest, const BIGNUM *r, const BIGNUM *s);
EC_POINT * RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY = false) const;
EC_POINT *
RecoverPublicKey(const BIGNUM *digest, const BIGNUM *r, const BIGNUM *s, bool isNegativeY = false) const;
private: private:
@ -55,14 +60,20 @@ namespace crypto
// Big Endian // Big Endian
void GOSTR3411_2012_256(const uint8_t *buf, size_t len, uint8_t *digest); void GOSTR3411_2012_256(const uint8_t *buf, size_t len, uint8_t *digest);
void GOSTR3411_2012_512(const uint8_t *buf, size_t len, uint8_t *digest); void GOSTR3411_2012_512(const uint8_t *buf, size_t len, uint8_t *digest);
// Little Endian // Little Endian
struct GOSTR3411_2012_CTX; struct GOSTR3411_2012_CTX;
GOSTR3411_2012_CTX *GOSTR3411_2012_CTX_new(); GOSTR3411_2012_CTX *GOSTR3411_2012_CTX_new();
void GOSTR3411_2012_CTX_Init(GOSTR3411_2012_CTX *ctx, bool is512 = true); void GOSTR3411_2012_CTX_Init(GOSTR3411_2012_CTX *ctx, bool is512 = true);
void GOSTR3411_2012_CTX_Update(const uint8_t *buf, size_t len, GOSTR3411_2012_CTX *ctx); void GOSTR3411_2012_CTX_Update(const uint8_t *buf, size_t len, GOSTR3411_2012_CTX *ctx);
void GOSTR3411_2012_CTX_Finish(uint8_t *digest, GOSTR3411_2012_CTX *ctx); void GOSTR3411_2012_CTX_Finish(uint8_t *digest, GOSTR3411_2012_CTX *ctx);
void GOSTR3411_2012_CTX_free(GOSTR3411_2012_CTX *ctx); void GOSTR3411_2012_CTX_free(GOSTR3411_2012_CTX *ctx);
} }
} }

View file

@ -13,40 +13,32 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Gzip.h" #include "Gzip.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
const size_t GZIP_CHUNK_SIZE = 16384; const size_t GZIP_CHUNK_SIZE = 16384;
GzipInflator::GzipInflator (): m_IsDirty (false) GzipInflator::GzipInflator() : m_IsDirty(false) {
{
memset(&m_Inflator, 0, sizeof(m_Inflator)); memset(&m_Inflator, 0, sizeof(m_Inflator));
inflateInit2(&m_Inflator, MAX_WBITS + 16); // gzip inflateInit2(&m_Inflator, MAX_WBITS + 16); // gzip
} }
GzipInflator::~GzipInflator () GzipInflator::~GzipInflator() {
{
inflateEnd(&m_Inflator); inflateEnd(&m_Inflator);
} }
size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) size_t GzipInflator::Inflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen) {
{
if (inLen < 23) return 0; if (inLen < 23) return 0;
if (in[10] == 0x01) // non compressed if (in[10] == 0x01) // non compressed
{ {
size_t len = bufle16toh(in + 11); size_t len = bufle16toh(in + 11);
if (len + 23 < inLen) if (len + 23 < inLen) {
{
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);
@ -62,59 +54,50 @@ namespace data
} }
} }
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) {
{
m_IsDirty = true; m_IsDirty = true;
uint8_t *out = new uint8_t[GZIP_CHUNK_SIZE]; uint8_t *out = new uint8_t[GZIP_CHUNK_SIZE];
m_Inflator.next_in = const_cast<uint8_t *>(in); m_Inflator.next_in = const_cast<uint8_t *>(in);
m_Inflator.avail_in = inLen; m_Inflator.avail_in = inLen;
int ret; int ret;
do do {
{
m_Inflator.next_out = out; m_Inflator.next_out = out;
m_Inflator.avail_out = GZIP_CHUNK_SIZE; m_Inflator.avail_out = GZIP_CHUNK_SIZE;
ret = inflate(&m_Inflator, Z_NO_FLUSH); ret = inflate(&m_Inflator, Z_NO_FLUSH);
if (ret < 0) if (ret < 0) {
{
inflateEnd(&m_Inflator); inflateEnd(&m_Inflator);
os.setstate(std::ios_base::failbit); os.setstate(std::ios_base::failbit);
break; break;
} }
os.write((char *) out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); os.write((char *) out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
} } while (!m_Inflator.avail_out); // more data to read
while (!m_Inflator.avail_out); // more data to read
delete[] out; delete[] out;
} }
void GzipInflator::Inflate (std::istream& in, std::ostream& out) void GzipInflator::Inflate(std::istream &in, std::ostream &out) {
{
uint8_t *buf = new uint8_t[GZIP_CHUNK_SIZE]; uint8_t *buf = new uint8_t[GZIP_CHUNK_SIZE];
while (!in.eof ()) while (!in.eof()) {
{
in.read((char *) buf, GZIP_CHUNK_SIZE); in.read((char *) buf, GZIP_CHUNK_SIZE);
Inflate(buf, in.gcount(), out); Inflate(buf, in.gcount(), out);
} }
delete[] buf; delete[] buf;
} }
GzipDeflator::GzipDeflator (): m_IsDirty (false) GzipDeflator::GzipDeflator() : m_IsDirty(false) {
{
memset(&m_Deflator, 0, sizeof(m_Deflator)); memset(&m_Deflator, 0, sizeof(m_Deflator));
deflateInit2 (&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip deflateInit2(&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8,
Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip
} }
GzipDeflator::~GzipDeflator () GzipDeflator::~GzipDeflator() {
{
deflateEnd(&m_Deflator); deflateEnd(&m_Deflator);
} }
void GzipDeflator::SetCompressionLevel (int level) void GzipDeflator::SetCompressionLevel(int level) {
{
deflateParams(&m_Deflator, level, Z_DEFAULT_STRATEGY); deflateParams(&m_Deflator, level, Z_DEFAULT_STRATEGY);
} }
size_t GzipDeflator::Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) size_t GzipDeflator::Deflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen) {
{
if (m_IsDirty) deflateReset(&m_Deflator); if (m_IsDirty) deflateReset(&m_Deflator);
m_IsDirty = true; m_IsDirty = true;
m_Deflator.next_in = const_cast<uint8_t *>(in); m_Deflator.next_in = const_cast<uint8_t *>(in);
@ -122,8 +105,7 @@ namespace data
m_Deflator.next_out = out; m_Deflator.next_out = out;
m_Deflator.avail_out = outLen; m_Deflator.avail_out = outLen;
int err; int err;
if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) if ((err = deflate(&m_Deflator, Z_FINISH)) == 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;
} }
@ -132,24 +114,21 @@ namespace data
return 0; return 0;
} }
size_t GzipDeflator::Deflate (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen) size_t GzipDeflator::Deflate(const std::vector <std::pair<const uint8_t *, size_t>> &bufs, uint8_t *out,
{ size_t outLen) {
if (m_IsDirty) deflateReset(&m_Deflator); if (m_IsDirty) deflateReset(&m_Deflator);
m_IsDirty = true; m_IsDirty = true;
size_t offset = 0; size_t offset = 0;
int err; int err;
for (const auto& it: bufs) for (const auto &it: bufs) {
{
m_Deflator.next_in = const_cast<uint8_t *>(it.first); m_Deflator.next_in = const_cast<uint8_t *>(it.first);
m_Deflator.avail_in = it.second; m_Deflator.avail_in = it.second;
m_Deflator.next_out = out + offset; m_Deflator.next_out = out + offset;
m_Deflator.avail_out = outLen - offset; m_Deflator.avail_out = outLen - offset;
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;
} }
@ -162,8 +141,7 @@ namespace data
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};
if (outLen < (size_t) inLen + 23) return 0; if (outLen < (size_t) inLen + 23) return 0;
memcpy(out, gzipHeader, 11); memcpy(out, gzipHeader, 11);
@ -175,14 +153,13 @@ namespace data
return inLen + 23; return inLen + 23;
} }
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;
size_t len = 0, len1; size_t len = 0, len1;
for (const auto& it: bufs) for (const auto &it: bufs) {
{
len1 = len; len1 = len;
len += it.second; len += it.second;
if (outLen < len + 23) return 0; if (outLen < len + 23) return 0;

View file

@ -12,20 +12,20 @@
#include <zlib.h> #include <zlib.h>
#include <vector> #include <vector>
namespace i2p namespace i2p {
{ namespace data {
namespace data class GzipInflator {
{
class GzipInflator
{
public: public:
GzipInflator(); GzipInflator();
~GzipInflator(); ~GzipInflator();
size_t Inflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen); size_t Inflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen);
/** @note @a os failbit will be set in case of error */ /** @note @a os failbit will be set in case of error */
void Inflate(const uint8_t *in, size_t inLen, std::ostream &os); void Inflate(const uint8_t *in, size_t inLen, std::ostream &os);
void Inflate(std::istream &in, std::ostream &out); void Inflate(std::istream &in, std::ostream &out);
private: private:
@ -34,15 +34,17 @@ namespace data
bool m_IsDirty; bool m_IsDirty;
}; };
class GzipDeflator class GzipDeflator {
{
public: public:
GzipDeflator(); GzipDeflator();
~GzipDeflator(); ~GzipDeflator();
void SetCompressionLevel(int level); void SetCompressionLevel(int level);
size_t Deflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen); size_t Deflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen);
size_t Deflate(const std::vector <std::pair<const uint8_t *, size_t>> &bufs, uint8_t *out, size_t outLen); size_t Deflate(const std::vector <std::pair<const uint8_t *, size_t>> &bufs, uint8_t *out, size_t outLen);
private: private:
@ -52,7 +54,8 @@ 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

View file

@ -14,13 +14,12 @@
#include "Base.h" #include "Base.h"
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p {
{ namespace http {
namespace http
{
const std::vector <std::string> HTTP_METHODS = { const std::vector <std::string> HTTP_METHODS = {
"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods
"COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK", "SEARCH" // WebDAV methods, for SEARCH see rfc5323 "COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK",
"SEARCH" // WebDAV methods, for SEARCH see rfc5323
}; };
const std::vector <std::string> HTTP_VERSIONS = { const std::vector <std::string> HTTP_VERSIONS = {
"HTTP/1.0", "HTTP/1.1" "HTTP/1.0", "HTTP/1.1"
@ -55,8 +54,7 @@ namespace http
} }
} }
static std::pair<std::string, std::string> parse_header_line(const std::string& line) static std::pair <std::string, std::string> parse_header_line(const std::string &line) {
{
std::size_t pos = 0; std::size_t pos = 0;
std::size_t len = 1; /*: */ std::size_t len = 1; /*: */
std::size_t max = line.length(); std::size_t max = line.length();
@ -119,8 +117,7 @@ namespace http
auto pos_b = url.find(']', pos_p); auto pos_b = url.find(']', pos_p);
if (pos_b == std::string::npos) return false; if (pos_b == std::string::npos) return false;
pos_c = url.find_first_of(":/", pos_b); pos_c = url.find_first_of(":/", pos_b);
} } else
else
pos_c = url.find_first_of(":/", pos_p); pos_c = url.find_first_of(":/", pos_p);
if (pos_c == std::string::npos) { if (pos_c == std::string::npos) {
/* only hostname, without post and path */ /* only hostname, without post and path */
@ -224,8 +221,7 @@ namespace http
return out; return out;
} }
bool URL::is_i2p() const bool URL::is_i2p() const {
{
return host.rfind(".i2p") == (host.size() - 4); return host.rfind(".i2p") == (host.size() - 4);
} }
@ -254,7 +250,9 @@ namespace http
} }
int HTTPReq::parse(const std::string &str) { int HTTPReq::parse(const std::string &str) {
enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE; enum {
REQ_LINE, HEADER_LINE
} expect = REQ_LINE;
std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eoh = str.find(HTTP_EOH); /* request head size */
std::size_t eol = 0, pos = 0; std::size_t eol = 0, pos = 0;
URL url; URL url;
@ -280,9 +278,7 @@ namespace http
uri = tokens[1]; uri = tokens[1];
version = tokens[2]; version = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} } else {
else
{
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length() > 0) if (p.first.length() > 0)
@ -297,40 +293,33 @@ namespace http
return eoh + strlen(HTTP_EOH); return eoh + strlen(HTTP_EOH);
} }
void HTTPReq::write(std::ostream & o) void HTTPReq::write(std::ostream &o) {
{
o << method << " " << uri << " " << version << CRLF; o << method << " " << uri << " " << version << CRLF;
for (auto &h: headers) for (auto &h: headers)
o << h.first << ": " << h.second << CRLF; o << h.first << ": " << h.second << CRLF;
o << CRLF; o << CRLF;
} }
std::string HTTPReq::to_string() std::string HTTPReq::to_string() {
{
std::stringstream ss; std::stringstream ss;
write(ss); write(ss);
return ss.str(); return ss.str();
} }
void HTTPReq::AddHeader (const std::string& name, const std::string& value) void HTTPReq::AddHeader(const std::string &name, const std::string &value) {
{
headers.push_back(std::make_pair(name, value)); headers.push_back(std::make_pair(name, value));
} }
void HTTPReq::UpdateHeader (const std::string& name, const std::string& value) void HTTPReq::UpdateHeader(const std::string &name, const std::string &value) {
{
for (auto &it: headers) for (auto &it: headers)
if (it.first == name) if (it.first == name) {
{
it.second = value; it.second = value;
break; break;
} }
} }
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt) void HTTPReq::RemoveHeader(const std::string &name, const std::string &exempt) {
{ for (auto it = headers.begin(); it != headers.end();) {
for (auto it = headers.begin (); it != headers.end ();)
{
if (!it->first.compare(0, name.length(), name) && it->first != exempt) if (!it->first.compare(0, name.length(), name) && it->first != exempt)
it = headers.erase(it); it = headers.erase(it);
else else
@ -338,16 +327,14 @@ namespace http
} }
} }
std::string HTTPReq::GetHeader (const std::string& name) const std::string HTTPReq::GetHeader(const std::string &name) const {
{
for (auto &it: headers) for (auto &it: headers)
if (it.first == name) if (it.first == name)
return it.second; return it.second;
return ""; return "";
} }
bool HTTPRes::is_chunked() const bool HTTPRes::is_chunked() const {
{
auto it = headers.find("Transfer-Encoding"); auto it = headers.find("Transfer-Encoding");
if (it == headers.end()) if (it == headers.end())
return false; return false;
@ -356,8 +343,7 @@ namespace http
return false; return false;
} }
bool HTTPRes::is_gzipped(bool includingI2PGzip) const bool HTTPRes::is_gzipped(bool includingI2PGzip) const {
{
auto it = headers.find("Content-Encoding"); auto it = headers.find("Content-Encoding");
if (it == headers.end()) if (it == headers.end())
return false; /* no header */ return false; /* no header */
@ -368,8 +354,7 @@ namespace http
return false; return false;
} }
long int HTTPMsg::content_length() const long int HTTPMsg::content_length() const {
{
unsigned long int length = 0; unsigned long int length = 0;
auto it = headers.find("Content-Length"); auto it = headers.find("Content-Length");
if (it == headers.end()) if (it == headers.end())
@ -387,7 +372,9 @@ namespace http
} }
int HTTPRes::parse(const std::string &str) { int HTTPRes::parse(const std::string &str) {
enum { RES_LINE, HEADER_LINE } expect = RES_LINE; enum {
RES_LINE, HEADER_LINE
} expect = RES_LINE;
std::size_t eoh = str.find(HTTP_EOH); /* request head size */ std::size_t eoh = str.find(HTTP_EOH); /* request head size */
std::size_t eol = 0, pos = 0; std::size_t eol = 0, pos = 0;
@ -450,41 +437,74 @@ namespace http
const char *HTTPCodeToStatus(int code) { const char *HTTPCodeToStatus(int code) {
const char *ptr; const char *ptr;
switch (code) { switch (code) {
case 105: ptr = "Name Not Resolved"; break; case 105:
ptr = "Name Not Resolved";
break;
/* success */ /* success */
case 200: ptr = "OK"; break; case 200:
case 206: ptr = "Partial Content"; break; ptr = "OK";
break;
case 206:
ptr = "Partial Content";
break;
/* redirect */ /* redirect */
case 301: ptr = "Moved Permanently"; break; case 301:
case 302: ptr = "Found"; break; ptr = "Moved Permanently";
case 304: ptr = "Not Modified"; break; break;
case 307: ptr = "Temporary Redirect"; break; case 302:
ptr = "Found";
break;
case 304:
ptr = "Not Modified";
break;
case 307:
ptr = "Temporary Redirect";
break;
/* client error */ /* client error */
case 400: ptr = "Bad Request"; break; case 400:
case 401: ptr = "Unauthorized"; break; ptr = "Bad Request";
case 403: ptr = "Forbidden"; break; break;
case 404: ptr = "Not Found"; break; case 401:
case 407: ptr = "Proxy Authentication Required"; break; ptr = "Unauthorized";
case 408: ptr = "Request Timeout"; break; break;
case 403:
ptr = "Forbidden";
break;
case 404:
ptr = "Not Found";
break;
case 407:
ptr = "Proxy Authentication Required";
break;
case 408:
ptr = "Request Timeout";
break;
/* server error */ /* server error */
case 500: ptr = "Internal Server Error"; break; case 500:
case 502: ptr = "Bad Gateway"; break; ptr = "Internal Server Error";
case 503: ptr = "Not Implemented"; break; break;
case 504: ptr = "Gateway Timeout"; break; case 502:
default: ptr = "Unknown Status"; break; ptr = "Bad Gateway";
break;
case 503:
ptr = "Not Implemented";
break;
case 504:
ptr = "Gateway Timeout";
break;
default:
ptr = "Unknown Status";
break;
} }
return ptr; return ptr;
} }
std::string UrlDecode(const std::string& data, bool allow_null) std::string UrlDecode(const std::string &data, bool allow_null) {
{
std::string decoded(data); std::string decoded(data);
size_t pos = 0; size_t pos = 0;
while ((pos = decoded.find('%', pos)) != std::string::npos) while ((pos = decoded.find('%', pos)) != std::string::npos) {
{
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16); char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16);
if (c == '\0' && !allow_null) if (c == '\0' && !allow_null) {
{
pos += 3; pos += 3;
continue; continue;
} }
@ -494,11 +514,9 @@ namespace http
return decoded; return decoded;
} }
bool MergeChunkedResponse (std::istream& in, std::ostream& out) bool MergeChunkedResponse(std::istream &in, std::ostream &out) {
{
std::string hexLen; std::string hexLen;
while (!in.eof ()) while (!in.eof()) {
{
std::getline(in, hexLen); std::getline(in, hexLen);
errno = 0; errno = 0;
long int len = strtoul(hexLen.c_str(), (char **) NULL, 16); long int len = strtoul(hexLen.c_str(), (char **) NULL, 16);
@ -517,8 +535,7 @@ namespace http
return true; return true;
} }
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass) std::string CreateBasicAuthorizationString(const std::string &user, const std::string &pass) {
{
if (user.empty() && pass.empty()) return ""; if (user.empty() && pass.empty()) return "";
return "Basic " + i2p::data::ToBase64Standard(user + ":" + pass); return "Basic " + i2p::data::ToBase64Standard(user + ":" + pass);
} }

View file

@ -16,17 +16,14 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace i2p namespace i2p {
{ namespace http {
namespace http
{
const char CRLF[] = "\r\n"; /**< HTTP line terminator */ const char CRLF[] = "\r\n"; /**< HTTP line terminator */
const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */ const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */
extern const std::vector <std::string> HTTP_METHODS; /**< list of valid HTTP methods */ extern const std::vector <std::string> HTTP_METHODS; /**< list of valid HTTP methods */
extern const std::vector <std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */ extern const std::vector <std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */
struct URL struct URL {
{
std::string schema; std::string schema;
std::string user; std::string user;
std::string pass; std::string pass;
@ -43,6 +40,7 @@ namespace http
* @return true on success, false on invalid url * @return true on success, false on invalid url
*/ */
bool parse(const char *str, std::size_t len = 0); bool parse(const char *str, std::size_t len = 0);
bool parse(const std::string &url); bool parse(const std::string &url);
/** /**
@ -63,20 +61,20 @@ namespace http
bool is_i2p() const; bool is_i2p() const;
}; };
struct HTTPMsg struct HTTPMsg {
{
std::map <std::string, std::string> headers; std::map <std::string, std::string> headers;
void add_header(const char *name, std::string &value, bool replace = false); void add_header(const char *name, std::string &value, bool replace = false);
void add_header(const char *name, const char *value, bool replace = false); void add_header(const char *name, const char *value, bool replace = false);
void del_header(const char *name); void del_header(const char *name);
/** @brief Returns declared message length or -1 if unknown */ /** @brief Returns declared message length or -1 if unknown */
long int content_length() const; long int content_length() const;
}; };
struct HTTPReq struct HTTPReq {
{
std::list <std::pair<std::string, std::string>> headers; std::list <std::pair<std::string, std::string>> headers;
std::string version; std::string version;
std::string method; std::string method;
@ -90,16 +88,22 @@ namespace http
* @note Positive return value is a size of header * @note Positive return value is a size of header
*/ */
int parse(const char *buf, size_t len); int parse(const char *buf, size_t len);
int parse(const std::string &buf); int parse(const std::string &buf);
/** @brief Serialize HTTP request to string */ /** @brief Serialize HTTP request to string */
std::string to_string(); std::string to_string();
void write(std::ostream &o); void write(std::ostream &o);
void AddHeader(const std::string &name, const std::string &value); void AddHeader(const std::string &name, const std::string &value);
void UpdateHeader(const std::string &name, const std::string &value); void UpdateHeader(const std::string &name, const std::string &value);
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader(const std::string &name,
const std::string &exempt); // remove all headers starting with name, but exempt
void RemoveHeader(const std::string &name) { RemoveHeader(name, ""); }; void RemoveHeader(const std::string &name) { RemoveHeader(name, ""); };
std::string GetHeader(const std::string &name) const; std::string GetHeader(const std::string &name) const;
}; };
@ -124,6 +128,7 @@ namespace http
* @note Positive return value is a size of header * @note Positive return value is a size of header
*/ */
int parse(const char *buf, size_t len); int parse(const char *buf, size_t len);
int parse(const std::string &buf); int parse(const std::string &buf);
/** /**

View file

@ -24,30 +24,24 @@
using namespace i2p::transport; using namespace i2p::transport;
namespace i2p namespace i2p {
{ std::shared_ptr<I2NPMessage> NewI2NPMessage() {
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
{
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
} }
std::shared_ptr<I2NPMessage> NewI2NPShortMessage () std::shared_ptr<I2NPMessage> NewI2NPShortMessage() {
{
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
} }
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint) std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage(bool endpoint) {
{
return i2p::tunnel::tunnels.NewI2NPTunnelMessage(endpoint); return i2p::tunnel::tunnels.NewI2NPTunnelMessage(endpoint);
} }
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len) std::shared_ptr<I2NPMessage> NewI2NPMessage(size_t len) {
{
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage() : NewI2NPMessage(); return (len < I2NP_MAX_SHORT_MESSAGE_SIZE - I2NP_HEADER_SIZE - 2) ? NewI2NPShortMessage() : NewI2NPMessage();
} }
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum) void I2NPMessage::FillI2NPMessageHeader(I2NPMessageType msgType, uint32_t replyMsgID, bool checksum) {
{
SetTypeID(msgType); SetTypeID(msgType);
if (!replyMsgID) RAND_bytes((uint8_t * ) & replyMsgID, 4); if (!replyMsgID) RAND_bytes((uint8_t * ) & replyMsgID, 4);
SetMsgID(replyMsgID); SetMsgID(replyMsgID);
@ -56,23 +50,22 @@ namespace i2p
if (checksum) UpdateChks(); if (checksum) UpdateChks();
} }
void I2NPMessage::RenewI2NPMessageHeader () void I2NPMessage::RenewI2NPMessageHeader() {
{
uint32_t msgID; uint32_t msgID;
RAND_bytes((uint8_t * ) & msgID, 4); RAND_bytes((uint8_t * ) & msgID, 4);
SetMsgID(msgID); SetMsgID(msgID);
SetExpiration(i2p::util::GetMillisecondsSinceEpoch() + I2NP_MESSAGE_EXPIRATION_TIMEOUT); SetExpiration(i2p::util::GetMillisecondsSinceEpoch() + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
} }
bool I2NPMessage::IsExpired () const bool I2NPMessage::IsExpired() const {
{
auto ts = i2p::util::GetMillisecondsSinceEpoch(); auto ts = i2p::util::GetMillisecondsSinceEpoch();
auto exp = GetExpiration(); auto exp = GetExpiration();
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) ||
(ts < exp - 3 * I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
} }
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID) std::shared_ptr<I2NPMessage>
{ CreateI2NPMessage(I2NPMessageType msgType, const uint8_t *buf, size_t len, uint32_t replyMsgID) {
auto msg = NewI2NPMessage(len); auto msg = NewI2NPMessage(len);
if (msg->Concat(buf, len) < len) if (msg->Concat(buf, len) < len)
LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length ", msg->maxLen); LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length ", msg->maxLen);
@ -80,22 +73,19 @@ namespace i2p
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<I2NPMessage>
{ CreateI2NPMessage(const uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) {
auto msg = NewI2NPMessage(); auto msg = NewI2NPMessage();
if (msg->offset + len < msg->maxLen) if (msg->offset + len < msg->maxLen) {
{
memcpy(msg->GetBuffer(), buf, len); memcpy(msg->GetBuffer(), buf, len);
msg->len = msg->offset + len; msg->len = msg->offset + len;
msg->from = from; msg->from = from;
} } else
else
LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length"); LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length");
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg) std::shared_ptr<I2NPMessage> CopyI2NPMessage(std::shared_ptr<I2NPMessage> msg) {
{
if (!msg) return nullptr; if (!msg) return nullptr;
auto newMsg = NewI2NPMessage(msg->len); auto newMsg = NewI2NPMessage(msg->len);
newMsg->offset = msg->offset; newMsg->offset = msg->offset;
@ -103,16 +93,13 @@ namespace i2p
return newMsg; return newMsg;
} }
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID) std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg(uint32_t msgID) {
{
auto m = NewI2NPShortMessage(); auto m = NewI2NPShortMessage();
uint8_t *buf = m->GetPayload(); uint8_t *buf = m->GetPayload();
if (msgID) if (msgID) {
{
htobe32buf(buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe32buf(buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
htobe64buf(buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::GetMillisecondsSinceEpoch()); htobe64buf(buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::GetMillisecondsSinceEpoch());
} } else // for SSU establishment
else // for SSU establishment
{ {
RAND_bytes((uint8_t * ) & msgID, 4); RAND_bytes((uint8_t * ) & msgID, 4);
htobe32buf(buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe32buf(buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
@ -124,8 +111,8 @@ namespace i2p
} }
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg(const uint8_t *key, const uint8_t *from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg(const uint8_t *key, const uint8_t *from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers) uint32_t replyTunnelID, bool exploratory,
{ std::set<i2p::data::IdentHash> *excludedPeers) {
auto m = excludedPeers ? NewI2NPMessage() : NewI2NPShortMessage(); auto m = excludedPeers ? NewI2NPMessage() : NewI2NPShortMessage();
uint8_t *buf = m->GetPayload(); uint8_t *buf = m->GetPayload();
memcpy(buf, key, 32); // key memcpy(buf, key, 32); // key
@ -133,31 +120,24 @@ namespace i2p
memcpy(buf, from, 32); // from memcpy(buf, from, 32); // from
buf += 32; buf += 32;
uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP; uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP;
if (replyTunnelID) if (replyTunnelID) {
{
*buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag *buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag
htobe32buf(buf + 1, replyTunnelID); htobe32buf(buf + 1, replyTunnelID);
buf += 5; buf += 5;
} } else {
else
{
*buf = flag; // flag *buf = flag; // flag
buf++; buf++;
} }
if (excludedPeers) if (excludedPeers) {
{
int cnt = excludedPeers->size(); int cnt = excludedPeers->size();
htobe16buf(buf, cnt); htobe16buf(buf, cnt);
buf += 2; buf += 2;
for (auto& it: *excludedPeers) for (auto &it: *excludedPeers) {
{
memcpy(buf, it, 32); memcpy(buf, it, 32);
buf += 32; buf += 32;
} }
} } else {
else
{
// nothing to exclude // nothing to exclude
htobuf16(buf, 0); htobuf16(buf, 0);
buf += 2; buf += 2;
@ -170,9 +150,9 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg(const i2p::data::IdentHash &dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg(const i2p::data::IdentHash &dest,
const std::set<i2p::data::IdentHash> &excludedFloodfills, const std::set<i2p::data::IdentHash> &excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyTag, bool replyECIES) const uint8_t *replyKey,
{ const uint8_t *replyTag, bool replyECIES) {
int cnt = excludedFloodfills.size(); int cnt = excludedFloodfills.size();
auto m = cnt > 7 ? NewI2NPMessage() : NewI2NPShortMessage(); auto m = cnt > 7 ? NewI2NPMessage() : NewI2NPShortMessage();
uint8_t *buf = m->GetPayload(); uint8_t *buf = m->GetPayload();
@ -187,17 +167,14 @@ namespace i2p
buf += 4; buf += 4;
// 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) {
{ for (auto &it: excludedFloodfills) {
for (auto& it: excludedFloodfills)
{
memcpy(buf, it, 32); memcpy(buf, it, 32);
buf += 32; buf += 32;
} }
@ -205,13 +182,10 @@ namespace i2p
// encryption // encryption
memcpy(buf, replyKey, 32); memcpy(buf, replyKey, 32);
buf[32] = 1; // 1 tag buf[32] = 1; // 1 tag
if (replyECIES) if (replyECIES) {
{
memcpy(buf + 33, replyTag, 8); // 8 bytes tag memcpy(buf + 33, replyTag, 8); // 8 bytes tag
buf += 41; buf += 41;
} } else {
else
{
memcpy(buf + 33, replyTag, 32); // 32 bytes tag memcpy(buf + 33, replyTag, 32); // 32 bytes tag
buf += 65; buf += 65;
} }
@ -222,8 +196,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();
size_t len = 0; size_t len = 0;
@ -231,8 +204,7 @@ namespace i2p
len += 32; len += 32;
buf[len] = routers.size(); buf[len] = routers.size();
len++; len++;
for (const auto& it: routers) for (const auto &it: routers) {
{
memcpy(buf + len, it, 32); memcpy(buf + len, it, 32);
len += 32; len += 32;
} }
@ -244,13 +216,12 @@ namespace i2p
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg(std::shared_ptr<const i2p::data::RouterInfo> router, std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg(std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) uint32_t replyToken,
{ std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) {
if (!router) // we send own RouterInfo if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo(); router = context.GetSharedRouterInfo();
if (!router->GetBuffer ()) if (!router->GetBuffer()) {
{
LogPrint(eLogError, "I2NP: Invalid RouterInfo buffer for DatabaseStore"); LogPrint(eLogError, "I2NP: Invalid RouterInfo buffer for DatabaseStore");
return nullptr; return nullptr;
} }
@ -262,17 +233,13 @@ namespace i2p
payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken); htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
uint8_t *buf = payload + DATABASE_STORE_HEADER_SIZE; uint8_t *buf = payload + DATABASE_STORE_HEADER_SIZE;
if (replyToken) if (replyToken) {
{ if (replyTunnel) {
if (replyTunnel)
{
htobe32buf(buf, replyTunnel->GetNextTunnelID()); htobe32buf(buf, replyTunnel->GetNextTunnelID());
buf += 4; // reply tunnelID buf += 4; // reply tunnelID
memcpy(buf, replyTunnel->GetNextIdentHash(), 32); memcpy(buf, replyTunnel->GetNextIdentHash(), 32);
buf += 32; // reply tunnel gateway buf += 32; // reply tunnel gateway
} } else {
else
{
memset(buf, 0, 4); // zero tunnelID means direct reply memset(buf, 0, 4); // zero tunnelID means direct reply
buf += 4; buf += 4;
memcpy(buf, context.GetIdentHash(), 32); memcpy(buf, context.GetIdentHash(), 32);
@ -286,25 +253,22 @@ namespace i2p
size_t size = 0; size_t size = 0;
if (router->GetBufferLen() + (buf - payload) <= 940) // fits one tunnel message if (router->GetBufferLen() + (buf - payload) <= 940) // fits one tunnel message
size = i2p::data::GzipNoCompression(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len); size = i2p::data::GzipNoCompression(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len);
else else {
{
i2p::data::GzipDeflator deflator; i2p::data::GzipDeflator deflator;
size = deflator.Deflate(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len); size = deflator.Deflate(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len);
} }
if (size) if (size) {
{
htobe16buf(sizePtr, size); // size htobe16buf(sizePtr, size); // size
m->len += size; m->len += size;
} } else
else
m = nullptr; m = nullptr;
if (m) if (m)
m->FillI2NPMessageHeader(eI2NPDatabaseStore); m->FillI2NPMessageHeader(eI2NPDatabaseStore);
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet) std::shared_ptr<I2NPMessage>
{ CreateDatabaseStoreMsg(const i2p::data::IdentHash &storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet) {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage(); auto m = NewI2NPShortMessage();
uint8_t *payload = m->GetPayload(); uint8_t *payload = m->GetPayload();
@ -319,8 +283,9 @@ 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();
uint8_t *payload = m->GetPayload(); uint8_t *payload = m->GetPayload();
@ -328,16 +293,13 @@ namespace i2p
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType(); // LeaseSet or LeaseSet2 payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType(); // LeaseSet or LeaseSet2
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken); htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
size_t size = DATABASE_STORE_HEADER_SIZE; size_t size = DATABASE_STORE_HEADER_SIZE;
if (replyToken && replyTunnel) if (replyToken && replyTunnel) {
{ if (replyTunnel) {
if (replyTunnel)
{
htobe32buf(payload + size, replyTunnel->GetNextTunnelID()); htobe32buf(payload + size, replyTunnel->GetNextTunnelID());
size += 4; // reply tunnelID size += 4; // reply tunnelID
memcpy(payload + size, replyTunnel->GetNextIdentHash(), 32); memcpy(payload + size, replyTunnel->GetNextIdentHash(), 32);
size += 32; // reply tunnel gateway size += 32; // reply tunnel gateway
} } else
else
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
} }
memcpy(payload + size, leaseSet->GetBuffer(), leaseSet->GetBufferLen()); memcpy(payload + size, leaseSet->GetBuffer(), leaseSet->GetBufferLen());
@ -347,43 +309,38 @@ namespace i2p
return m; return m;
} }
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg) bool IsRouterInfoMsg(std::shared_ptr<I2NPMessage> msg) {
{
if (!msg || msg->GetTypeID() != eI2NPDatabaseStore) return false; if (!msg || msg->GetTypeID() != eI2NPDatabaseStore) return false;
return !msg->GetPayload()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo return !msg->GetPayload()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
} }
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO: static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels) void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels) {
{ if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels) {
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
{
LogPrint(eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels); LogPrint(eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
g_MaxNumTransitTunnels = maxNumTransitTunnels; g_MaxNumTransitTunnels = maxNumTransitTunnels;
} }
} }
uint16_t GetMaxNumTransitTunnels () uint16_t GetMaxNumTransitTunnels() {
{
return g_MaxNumTransitTunnels; return g_MaxNumTransitTunnels;
} }
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) static bool HandleBuildRequestRecords(int num, uint8_t *records, uint8_t *clearText) {
{ for (int i = 0; i < num; i++) {
for (int i = 0; i < num; i++)
{
uint8_t *record = records + i * TUNNEL_BUILD_RECORD_SIZE; uint8_t *record = records + i * TUNNEL_BUILD_RECORD_SIZE;
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) if (!memcmp(record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET,
{ (const uint8_t *) i2p::context.GetRouterInfo().GetIdentHash(), 16)) {
LogPrint(eLogDebug, "I2NP: Build request record ", i, " is ours"); LogPrint(eLogDebug, "I2NP: Build request record ", i, " is ours");
if (!i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) return false; if (!i2p::context.DecryptTunnelBuildRecord(record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET,
clearText))
return false;
uint8_t retCode = 0; uint8_t retCode = 0;
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels() && if (i2p::context.AcceptsTunnels() &&
i2p::tunnel::tunnels.GetTransitTunnels().size() <= g_MaxNumTransitTunnels && i2p::tunnel::tunnels.GetTransitTunnels().size() <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded() && !i2p::transport::transports.IsBandwidthExceeded() &&
!i2p::transport::transports.IsTransitBandwidthExceeded ()) !i2p::transport::transports.IsTransitBandwidthExceeded()) {
{
auto transitTunnel = i2p::tunnel::CreateTransitTunnel( auto transitTunnel = i2p::tunnel::CreateTransitTunnel(
bufbe32toh(clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh(clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
@ -393,31 +350,27 @@ namespace i2p
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG, clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_GATEWAY_FLAG,
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG); clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG);
i2p::tunnel::tunnels.AddTransitTunnel(transitTunnel); i2p::tunnel::tunnels.AddTransitTunnel(transitTunnel);
} } else
else
retCode = 30; // always reject with bandwidth reason (30) retCode = 30; // always reject with bandwidth reason (30)
memset(record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset(record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
// encrypt reply // encrypt reply
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++) {
{
uint8_t *reply = records + j * TUNNEL_BUILD_RECORD_SIZE; uint8_t *reply = records + j * TUNNEL_BUILD_RECORD_SIZE;
if (j == i) if (j == i) {
{
uint8_t nonce[12]; uint8_t nonce[12];
memset(nonce, 0, 12); memset(nonce, 0, 12);
auto &noiseState = i2p::context.GetCurrentNoiseState(); auto &noiseState = i2p::context.GetCurrentNoiseState();
if (!i2p::crypto::AEADChaCha20Poly1305(reply, TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305(reply, TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, noiseState.m_CK, nonce, reply,
TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint(eLogWarning, "I2NP: Reply AEAD encryption failed"); LogPrint(eLogWarning, "I2NP: Reply AEAD encryption failed");
return false; return false;
} }
} } 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.SetIV(clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
@ -429,132 +382,111 @@ namespace i2p
return false; return false;
} }
static void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) static void HandleVariableTunnelBuildMsg(uint32_t replyMsgID, uint8_t *buf, size_t len) {
{
int num = buf[0]; int num = buf[0];
LogPrint(eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); LogPrint(eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) if (len < num * TUNNEL_BUILD_RECORD_SIZE + 1) {
{
LogPrint(eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len); LogPrint(eLogError, "I2NP: VaribleTunnelBuild message of ", num, " records is too short ", len);
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
LogPrint(eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID()); LogPrint(eLogDebug, "I2NP: VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID());
if (tunnel->HandleTunnelBuildResponse (buf, len)) if (tunnel->HandleTunnelBuildResponse(buf, len)) {
{
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been created"); LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been created");
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished); tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddInboundTunnel(tunnel); i2p::tunnel::tunnels.AddInboundTunnel(tunnel);
} } else {
else
{
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined"); LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined");
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed); tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
} }
} } else {
else
{
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (HandleBuildRequestRecords (num, buf + 1, clearText)) if (HandleBuildRequestRecords(num, buf + 1, clearText)) {
{ if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] &
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
transports.SendMessage(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg(bufbe32toh(
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len, eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh(clearText +
} ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
else } else
transports.SendMessage(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage(eI2NPVariableTunnelBuild, buf, len, CreateI2NPMessage(eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh(clearText +
ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
} }
} }
static void HandleTunnelBuildMsg (uint8_t * buf, size_t len) static void HandleTunnelBuildMsg(uint8_t *buf, size_t len) {
{
LogPrint(eLogWarning, "I2NP: TunnelBuild is too old for ECIES router"); LogPrint(eLogWarning, "I2NP: TunnelBuild is too old for ECIES router");
} }
static void HandleTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len, bool isShort) static void HandleTunnelBuildReplyMsg(uint32_t replyMsgID, uint8_t *buf, size_t len, bool isShort) {
{
int num = buf[0]; int num = buf[0];
LogPrint(eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID); LogPrint(eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE; size_t recordSize = isShort ? SHORT_TUNNEL_BUILD_RECORD_SIZE : TUNNEL_BUILD_RECORD_SIZE;
if (len < num*recordSize + 1) if (len < num * recordSize + 1) {
{
LogPrint(eLogError, "I2NP: TunnelBuildReply message of ", num, " records is too short ", len); LogPrint(eLogError, "I2NP: TunnelBuildReply message of ", num, " records is too short ", len);
return; return;
} }
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel(replyMsgID); auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel(replyMsgID);
if (tunnel) if (tunnel) {
{
// reply for outbound tunnel // reply for outbound tunnel
if (tunnel->HandleTunnelBuildResponse (buf, len)) if (tunnel->HandleTunnelBuildResponse(buf, len)) {
{
LogPrint(eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID(), " has been created"); LogPrint(eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID(), " has been created");
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished); tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddOutboundTunnel(tunnel); i2p::tunnel::tunnels.AddOutboundTunnel(tunnel);
} } else {
else
{
LogPrint(eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID(), " has been declined"); LogPrint(eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID(), " has been declined");
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed); tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
} }
} } else
else
LogPrint(eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found"); LogPrint(eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
} }
static void HandleShortTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) static void HandleShortTunnelBuildMsg(uint32_t replyMsgID, uint8_t *buf, size_t len) {
{
int num = buf[0]; int num = buf[0];
LogPrint(eLogDebug, "I2NP: ShortTunnelBuild ", num, " records"); LogPrint(eLogDebug, "I2NP: ShortTunnelBuild ", num, " records");
if (len < num*SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) if (len < num * SHORT_TUNNEL_BUILD_RECORD_SIZE + 1) {
{
LogPrint(eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len); LogPrint(eLogError, "I2NP: ShortTunnelBuild message of ", num, " records is too short ", len);
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
LogPrint(eLogDebug, "I2NP: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID()); LogPrint(eLogDebug, "I2NP: ShortTunnelBuild reply for tunnel ", tunnel->GetTunnelID());
if (tunnel->HandleTunnelBuildResponse (buf, len)) if (tunnel->HandleTunnelBuildResponse(buf, len)) {
{
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been created"); LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been created");
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished); tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddInboundTunnel(tunnel); i2p::tunnel::tunnels.AddInboundTunnel(tunnel);
} } else {
else
{
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined"); LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined");
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed); tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
} }
return; return;
} }
const uint8_t *record = buf + 1; const uint8_t *record = buf + 1;
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++) {
{ if (!memcmp(record, (const uint8_t *) i2p::context.GetRouterInfo().GetIdentHash(), 16)) {
if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{
LogPrint(eLogDebug, "I2NP: Short request record ", i, " is ours"); LogPrint(eLogDebug, "I2NP: Short request record ", i, " is ours");
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) if (!i2p::context.DecryptTunnelShortRequestRecord(record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET,
{ clearText)) {
LogPrint(eLogWarning, "I2NP: Can't decrypt short request record ", i); LogPrint(eLogWarning, "I2NP: Can't decrypt short request record ", i);
return; return;
} }
if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES if (clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE]) // not AES
{ {
LogPrint (eLogWarning, "I2NP: Unknown layer encryption type ", clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record"); LogPrint(eLogWarning, "I2NP: Unknown layer encryption type ",
clearText[SHORT_REQUEST_RECORD_LAYER_ENCRYPTION_TYPE], " in short request record");
return; return;
} }
auto &noiseState = i2p::context.GetCurrentNoiseState(); auto &noiseState = i2p::context.GetCurrentNoiseState();
@ -564,12 +496,10 @@ namespace i2p
i2p::crypto::HKDF(noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK); i2p::crypto::HKDF(noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
memcpy(layerKey, noiseState.m_CK + 32, 32); memcpy(layerKey, noiseState.m_CK + 32, 32);
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
if (isEndpoint) if (isEndpoint) {
{
i2p::crypto::HKDF(noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK); i2p::crypto::HKDF(noiseState.m_CK, nullptr, 0, "TunnelLayerIVKey", noiseState.m_CK);
memcpy(ivKey, noiseState.m_CK + 32, 32); memcpy(ivKey, noiseState.m_CK + 32, 32);
} } else
else
memcpy(ivKey, noiseState.m_CK, 32); memcpy(ivKey, noiseState.m_CK, 32);
// check if we accept this tunnel // check if we accept this tunnel
@ -579,8 +509,7 @@ namespace i2p
i2p::transport::transports.IsBandwidthExceeded() || i2p::transport::transports.IsBandwidthExceeded() ||
i2p::transport::transports.IsTransitBandwidthExceeded()) i2p::transport::transports.IsTransitBandwidthExceeded())
retCode = 30; retCode = 30;
if (!retCode) if (!retCode) {
{
// create new transit tunnel // create new transit tunnel
auto transitTunnel = i2p::tunnel::CreateTransitTunnel( auto transitTunnel = i2p::tunnel::CreateTransitTunnel(
bufbe32toh(clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh(clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
@ -596,30 +525,28 @@ namespace i2p
uint8_t nonce[12]; uint8_t nonce[12];
memset(nonce, 0, 12); memset(nonce, 0, 12);
uint8_t *reply = buf + 1; uint8_t *reply = buf + 1;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++) {
{
nonce[4] = j; // nonce is record # nonce[4] = j; // nonce is record #
if (j == i) if (j == i) {
{
memset(reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset(reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode; reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
if (!i2p::crypto::AEADChaCha20Poly1305(reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305(reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, replyKey, nonce, reply,
SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint(eLogWarning, "I2NP: Short reply AEAD encryption failed"); LogPrint(eLogWarning, "I2NP: Short reply AEAD encryption failed");
return; return;
} }
} } else
else
i2p::crypto::ChaCha20(reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply); i2p::crypto::ChaCha20(reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
} }
// send reply // send reply
if (isEndpoint) if (isEndpoint) {
{
auto replyMsg = NewI2NPShortMessage(); auto replyMsg = NewI2NPShortMessage();
replyMsg->Concat(buf, len); replyMsg->Concat(buf, len);
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); replyMsg->FillI2NPMessageHeader(eI2NPShortTunnelBuildReply,
bufbe32toh(clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
if (memcmp((const uint8_t *) i2p::context.GetIdentHash(), if (memcmp((const uint8_t *) i2p::context.GetIdentHash(),
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
{ {
@ -628,11 +555,11 @@ namespace i2p
memcpy(&tag, noiseState.m_CK, 8); memcpy(&tag, noiseState.m_CK, 8);
// we send it to reply tunnel // we send it to reply tunnel
transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg(
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag))); bufbe32toh(clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
} i2p::garlic::WrapECIESX25519Message(replyMsg,
else noiseState.m_CK + 32, tag)));
{ } else {
// IBGW is local // IBGW is local
uint32_t tunnelID = bufbe32toh(clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET); uint32_t tunnelID = bufbe32toh(clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
auto tunnel = i2p::tunnel::tunnels.GetTunnel(tunnelID); auto tunnel = i2p::tunnel::tunnels.GetTunnel(tunnelID);
@ -641,27 +568,25 @@ namespace i2p
else else
LogPrint(eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply"); LogPrint(eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
} }
} } else
else
transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage(eI2NPShortTunnelBuild, buf, len, CreateI2NPMessage(eI2NPShortTunnelBuild, buf, len,
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh(clearText +
SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
return; return;
} }
record += SHORT_TUNNEL_BUILD_RECORD_SIZE; record += SHORT_TUNNEL_BUILD_RECORD_SIZE;
} }
} }
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(const uint8_t *buf) {
{
auto msg = NewI2NPTunnelMessage(false); auto msg = NewI2NPTunnelMessage(false);
msg->Concat(buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE); msg->Concat(buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->FillI2NPMessageHeader(eI2NPTunnelData); msg->FillI2NPMessageHeader(eI2NPTunnelData);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(uint32_t tunnelID, const uint8_t *payload) {
{
auto msg = NewI2NPTunnelMessage(false); auto msg = NewI2NPTunnelMessage(false);
htobe32buf(msg->GetPayload(), tunnelID); htobe32buf(msg->GetPayload(), tunnelID);
msg->len += 4; // tunnelID msg->len += 4; // tunnelID
@ -670,15 +595,13 @@ namespace i2p
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (bool endpoint) std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg(bool endpoint) {
{
auto msg = NewI2NPTunnelMessage(endpoint); auto msg = NewI2NPTunnelMessage(endpoint);
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len) std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, const uint8_t *buf, size_t len) {
{
auto msg = NewI2NPMessage(len); auto msg = NewI2NPMessage(len);
uint8_t *payload = msg->GetPayload(); uint8_t *payload = msg->GetPayload();
htobe32buf(payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID); htobe32buf(payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
@ -690,10 +613,8 @@ namespace i2p
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg) std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg) {
{ if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE) {
if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE)
{
// message is capable to be used without copying // message is capable to be used without copying
uint8_t *payload = msg->GetBuffer() - TUNNEL_GATEWAY_HEADER_SIZE; uint8_t *payload = msg->GetBuffer() - TUNNEL_GATEWAY_HEADER_SIZE;
htobe32buf(payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID); htobe32buf(payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
@ -703,14 +624,12 @@ namespace i2p
msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + len; msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + len;
msg->FillI2NPMessageHeader(eI2NPTunnelGateway); msg->FillI2NPMessageHeader(eI2NPTunnelGateway);
return msg; return msg;
} } else
else
return CreateTunnelGatewayMsg(tunnelID, msg->GetBuffer(), msg->GetLength()); return CreateTunnelGatewayMsg(tunnelID, msg->GetBuffer(), msg->GetLength());
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID) const uint8_t *buf, size_t len, uint32_t replyMsgID) {
{
auto msg = NewI2NPMessage(len); auto msg = NewI2NPMessage(len);
size_t gatewayMsgOffset = I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE; size_t gatewayMsgOffset = I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE;
msg->offset += gatewayMsgOffset; msg->offset += gatewayMsgOffset;
@ -727,26 +646,21 @@ namespace i2p
return msg; return msg;
} }
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len) size_t GetI2NPMessageLength(const uint8_t *msg, size_t len) {
{ if (len < I2NP_HEADER_SIZE_OFFSET + 2) {
if (len < I2NP_HEADER_SIZE_OFFSET + 2)
{
LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header"); LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header");
return len; return len;
} }
auto l = bufbe16toh(msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE; auto l = bufbe16toh(msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
if (l > len) if (l > len) {
{
LogPrint(eLogError, "I2NP: Message length ", l, " exceeds buffer length ", len); LogPrint(eLogError, "I2NP: Message length ", l, " exceeds buffer length ", len);
l = len; l = len;
} }
return l; return l;
} }
void HandleI2NPMessage (uint8_t * msg, size_t len) void HandleI2NPMessage(uint8_t *msg, size_t len) {
{ if (len < I2NP_HEADER_SIZE) {
if (len < I2NP_HEADER_SIZE)
{
LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header"); LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header");
return; return;
} }
@ -756,13 +670,11 @@ namespace i2p
uint8_t *buf = msg + I2NP_HEADER_SIZE; uint8_t *buf = msg + I2NP_HEADER_SIZE;
auto size = bufbe16toh(msg + I2NP_HEADER_SIZE_OFFSET); auto size = bufbe16toh(msg + I2NP_HEADER_SIZE_OFFSET);
len -= I2NP_HEADER_SIZE; len -= I2NP_HEADER_SIZE;
if (size > len) if (size > len) {
{
LogPrint(eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len); LogPrint(eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
size = len; size = len;
} }
switch (typeID) switch (typeID) {
{
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
HandleVariableTunnelBuildMsg(msgID, buf, size); HandleVariableTunnelBuildMsg(msgID, buf, size);
break; break;
@ -786,22 +698,18 @@ namespace i2p
} }
} }
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg) void HandleI2NPMessage(std::shared_ptr<I2NPMessage> msg) {
{ if (msg) {
if (msg)
{
uint8_t typeID = msg->GetTypeID(); uint8_t typeID = msg->GetTypeID();
LogPrint(eLogDebug, "I2NP: Handling message with type ", (int) typeID); LogPrint(eLogDebug, "I2NP: Handling message with type ", (int) typeID);
switch (typeID) switch (typeID) {
{
case eI2NPTunnelData: case eI2NPTunnelData:
i2p::tunnel::tunnels.PostTunnelData(msg); i2p::tunnel::tunnels.PostTunnelData(msg);
break; break;
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
i2p::tunnel::tunnels.PostTunnelData(msg); i2p::tunnel::tunnels.PostTunnelData(msg);
break; break;
case eI2NPGarlic: case eI2NPGarlic: {
{
if (msg->from && msg->from->GetTunnelPool()) if (msg->from && msg->from->GetTunnelPool())
msg->from->GetTunnelPool()->ProcessGarlicMessage(msg); msg->from->GetTunnelPool()->ProcessGarlicMessage(msg);
else else
@ -814,8 +722,7 @@ namespace i2p
// forward to netDb // forward to netDb
i2p::data::netdb.PostI2NPMsg(msg); i2p::data::netdb.PostI2NPMsg(msg);
break; break;
case eI2NPDeliveryStatus: case eI2NPDeliveryStatus: {
{
if (msg->from && msg->from->GetTunnelPool()) if (msg->from && msg->from->GetTunnelPool())
msg->from->GetTunnelPool()->ProcessDeliveryStatus(msg); msg->from->GetTunnelPool()->ProcessDeliveryStatus(msg);
else else
@ -837,17 +744,13 @@ namespace i2p
} }
} }
I2NPMessagesHandler::~I2NPMessagesHandler () I2NPMessagesHandler::~I2NPMessagesHandler() {
{
Flush(); Flush();
} }
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage>&& msg) void I2NPMessagesHandler::PutNextMessage(std::shared_ptr<I2NPMessage> &&msg) {
{ if (msg) {
if (msg) switch (msg->GetTypeID()) {
{
switch (msg->GetTypeID ())
{
case eI2NPTunnelData: case eI2NPTunnelData:
m_TunnelMsgs.push_back(msg); m_TunnelMsgs.push_back(msg);
break; break;
@ -860,15 +763,12 @@ namespace i2p
} }
} }
void I2NPMessagesHandler::Flush () void I2NPMessagesHandler::Flush() {
{ if (!m_TunnelMsgs.empty()) {
if (!m_TunnelMsgs.empty ())
{
i2p::tunnel::tunnels.PostTunnelData(m_TunnelMsgs); i2p::tunnel::tunnels.PostTunnelData(m_TunnelMsgs);
m_TunnelMsgs.clear(); m_TunnelMsgs.clear();
} }
if (!m_TunnelGatewayMsgs.empty ()) if (!m_TunnelGatewayMsgs.empty()) {
{
i2p::tunnel::tunnels.PostTunnelData(m_TunnelGatewayMsgs); i2p::tunnel::tunnels.PostTunnelData(m_TunnelGatewayMsgs);
m_TunnelGatewayMsgs.clear(); m_TunnelGatewayMsgs.clear();
} }

View file

@ -19,8 +19,7 @@
#include "RouterInfo.h" #include "RouterInfo.h"
#include "LeaseSet.h" #include "LeaseSet.h"
namespace i2p namespace i2p {
{
// I2NP header // I2NP header
const size_t I2NP_HEADER_TYPEID_OFFSET = 0; const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1; const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1;
@ -72,8 +71,10 @@ namespace i2p
const size_t ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET = ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16; const size_t ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET = ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET + 16;
const size_t ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET = ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET + 1; const size_t ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET = ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET + 1;
const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET + 3; const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET = ECIES_BUILD_REQUEST_RECORD_MORE_FLAGS_OFFSET + 3;
const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET = ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4; const size_t ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET =
const size_t ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4; ECIES_BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET =
ECIES_BUILD_REQUEST_RECORD_REQUEST_EXPIRATION_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_PADDING_OFFSET = ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4; const size_t ECIES_BUILD_REQUEST_RECORD_PADDING_OFFSET = ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464; const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464;
@ -99,8 +100,7 @@ namespace i2p
const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0; const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201; const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201;
enum I2NPMessageType enum I2NPMessageType {
{
eI2NPDummyMsg = 0, eI2NPDummyMsg = 0,
eI2NPDatabaseStore = 1, eI2NPDatabaseStore = 1,
eI2NPDatabaseLookup = 2, eI2NPDatabaseLookup = 2,
@ -132,9 +132,9 @@ namespace i2p
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000 const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100 const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
namespace tunnel namespace tunnel {
{
class InboundTunnel; class InboundTunnel;
class TunnelPool; class TunnelPool;
} }
@ -143,8 +143,7 @@ namespace tunnel
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60 * 1000; // 1 minute in milliseconds const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60 * 1000; // 1 minute in milliseconds
struct I2NPMessage struct I2NPMessage {
{
uint8_t *buf; uint8_t *buf;
size_t len, offset, maxLen; size_t len, offset, maxLen;
std::shared_ptr<i2p::tunnel::InboundTunnel> from; std::shared_ptr<i2p::tunnel::InboundTunnel> from;
@ -154,19 +153,32 @@ namespace tunnel
// header accessors // header accessors
uint8_t *GetHeader() { return GetBuffer(); }; uint8_t *GetHeader() { return GetBuffer(); };
const uint8_t *GetHeader() const { return GetBuffer(); }; const uint8_t *GetHeader() const { return GetBuffer(); };
void SetTypeID(uint8_t typeID) { GetHeader()[I2NP_HEADER_TYPEID_OFFSET] = typeID; }; void SetTypeID(uint8_t typeID) { GetHeader()[I2NP_HEADER_TYPEID_OFFSET] = typeID; };
uint8_t GetTypeID() const { return GetHeader()[I2NP_HEADER_TYPEID_OFFSET]; }; uint8_t GetTypeID() const { return GetHeader()[I2NP_HEADER_TYPEID_OFFSET]; };
void SetMsgID(uint32_t msgID) { htobe32buf(GetHeader() + I2NP_HEADER_MSGID_OFFSET, msgID); }; void SetMsgID(uint32_t msgID) { htobe32buf(GetHeader() + I2NP_HEADER_MSGID_OFFSET, msgID); };
uint32_t GetMsgID() const { return bufbe32toh(GetHeader() + I2NP_HEADER_MSGID_OFFSET); }; uint32_t GetMsgID() const { return bufbe32toh(GetHeader() + I2NP_HEADER_MSGID_OFFSET); };
void SetExpiration (uint64_t expiration) { htobe64buf (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET, expiration); };
void SetExpiration(uint64_t expiration) {
htobe64buf(GetHeader() + I2NP_HEADER_EXPIRATION_OFFSET, expiration);
};
uint64_t GetExpiration() const { return bufbe64toh(GetHeader() + I2NP_HEADER_EXPIRATION_OFFSET); }; uint64_t GetExpiration() const { return bufbe64toh(GetHeader() + I2NP_HEADER_EXPIRATION_OFFSET); };
void SetSize(uint16_t size) { htobe16buf(GetHeader() + I2NP_HEADER_SIZE_OFFSET, size); }; void SetSize(uint16_t size) { htobe16buf(GetHeader() + I2NP_HEADER_SIZE_OFFSET, size); };
uint16_t GetSize() const { return bufbe16toh(GetHeader() + I2NP_HEADER_SIZE_OFFSET); }; uint16_t GetSize() const { return bufbe16toh(GetHeader() + I2NP_HEADER_SIZE_OFFSET); };
void UpdateSize() { SetSize(GetPayloadLength()); }; void UpdateSize() { SetSize(GetPayloadLength()); };
void SetChks(uint8_t chks) { GetHeader()[I2NP_HEADER_CHKS_OFFSET] = chks; }; void SetChks(uint8_t chks) { GetHeader()[I2NP_HEADER_CHKS_OFFSET] = chks; };
void UpdateChks ()
{ void UpdateChks() {
uint8_t hash[32]; uint8_t hash[32];
SHA256(GetPayload(), GetPayloadLength(), hash); SHA256(GetPayload(), GetPayloadLength(), hash);
GetHeader()[I2NP_HEADER_CHKS_OFFSET] = hash[0]; GetHeader()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
@ -174,25 +186,27 @@ namespace tunnel
// payload // payload
uint8_t *GetPayload() { return GetBuffer() + I2NP_HEADER_SIZE; }; uint8_t *GetPayload() { return GetBuffer() + I2NP_HEADER_SIZE; };
const uint8_t *GetPayload() const { return GetBuffer() + I2NP_HEADER_SIZE; }; const uint8_t *GetPayload() const { return GetBuffer() + I2NP_HEADER_SIZE; };
uint8_t *GetBuffer() { return buf + offset; }; uint8_t *GetBuffer() { return buf + offset; };
const uint8_t *GetBuffer() const { return buf + offset; }; const uint8_t *GetBuffer() const { return buf + offset; };
size_t GetLength() const { return len - offset; }; size_t GetLength() const { return len - offset; };
size_t GetPayloadLength() const { return GetLength() - I2NP_HEADER_SIZE; }; size_t GetPayloadLength() const { return GetLength() - I2NP_HEADER_SIZE; };
void Align (size_t alignment) void Align(size_t alignment) {
{
if (len + alignment > maxLen) return; if (len + alignment > maxLen) return;
size_t rem = ((size_t) GetBuffer()) % alignment; size_t rem = ((size_t) GetBuffer()) % alignment;
if (rem) if (rem) {
{
offset += (alignment - rem); offset += (alignment - rem);
len += (alignment - rem); len += (alignment - rem);
} }
} }
size_t Concat (const uint8_t * buf1, size_t len1) size_t Concat(const uint8_t *buf1, size_t len1) {
{
// make sure with don't write beyond maxLen // make sure with don't write beyond maxLen
if (len + len1 > maxLen) len1 = maxLen - len; if (len + len1 > maxLen) len1 = maxLen - len;
memcpy(buf + len, buf1, len1); memcpy(buf + len, buf1, len1);
@ -200,8 +214,7 @@ namespace tunnel
return len1; return len1;
} }
I2NPMessage& operator=(const I2NPMessage& other) I2NPMessage &operator=(const I2NPMessage &other) {
{
memcpy(buf + offset, other.buf + other.offset, other.GetLength()); memcpy(buf + offset, other.buf + other.offset, other.GetLength());
len = offset + other.GetLength(); len = offset + other.GetLength();
from = other.from; from = other.from;
@ -210,6 +223,7 @@ namespace tunnel
// for SSU only // for SSU only
uint8_t *GetSSUHeader() { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; }; uint8_t *GetSSUHeader() { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
void FromSSU(uint32_t msgID) // we have received SSU message and convert it to regular void FromSSU(uint32_t msgID) // we have received SSU message and convert it to regular
{ {
const uint8_t *ssu = GetSSUHeader(); const uint8_t *ssu = GetSSUHeader();
@ -219,21 +233,25 @@ namespace tunnel
SetSize(len - offset - I2NP_HEADER_SIZE); SetSize(len - offset - I2NP_HEADER_SIZE);
SetChks(0); SetChks(0);
} }
uint32_t ToSSU() // return msgID uint32_t ToSSU() // return msgID
{ {
uint8_t header[I2NP_HEADER_SIZE]; uint8_t header[I2NP_HEADER_SIZE];
memcpy(header, GetHeader(), I2NP_HEADER_SIZE); memcpy(header, GetHeader(), I2NP_HEADER_SIZE);
uint8_t *ssu = GetSSUHeader(); uint8_t *ssu = GetSSUHeader();
ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET] = header[I2NP_HEADER_TYPEID_OFFSET]; // typeid ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET] = header[I2NP_HEADER_TYPEID_OFFSET]; // typeid
htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL); htobe32buf(ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET,
bufbe64toh(header + I2NP_HEADER_EXPIRATION_OFFSET) / 1000LL);
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh(header + I2NP_HEADER_SIZE_OFFSET); len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh(header + I2NP_HEADER_SIZE_OFFSET);
return bufbe32toh(header + I2NP_HEADER_MSGID_OFFSET); return bufbe32toh(header + I2NP_HEADER_MSGID_OFFSET);
} }
// for NTCP2 only // for NTCP2 only
uint8_t *GetNTCP2Header() { return GetPayload() - I2NP_NTCP2_HEADER_SIZE; }; uint8_t *GetNTCP2Header() { return GetPayload() - I2NP_NTCP2_HEADER_SIZE; };
size_t GetNTCP2Length() const { return GetPayloadLength() + I2NP_NTCP2_HEADER_SIZE; }; size_t GetNTCP2Length() const { return GetPayloadLength() + I2NP_NTCP2_HEADER_SIZE; };
void FromNTCP2 ()
{ void FromNTCP2() {
const uint8_t *ntcp2 = GetNTCP2Header(); const uint8_t *ntcp2 = GetNTCP2Header();
memcpy(GetHeader() + I2NP_HEADER_TYPEID_OFFSET, ntcp2 + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid memcpy(GetHeader() + I2NP_HEADER_TYPEID_OFFSET, ntcp2 + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid
SetExpiration(bufbe32toh(ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET) * 1000LL); SetExpiration(bufbe32toh(ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET) * 1000LL);
@ -241,67 +259,98 @@ namespace tunnel
SetChks(0); SetChks(0);
} }
void ToNTCP2 () void ToNTCP2() {
{
uint8_t *ntcp2 = GetNTCP2Header(); uint8_t *ntcp2 = GetNTCP2Header();
htobe32buf (ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET, bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL); htobe32buf(ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET,
bufbe64toh(GetHeader() + I2NP_HEADER_EXPIRATION_OFFSET) / 1000LL);
memcpy(ntcp2 + I2NP_HEADER_TYPEID_OFFSET, GetHeader() + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid memcpy(ntcp2 + I2NP_HEADER_TYPEID_OFFSET, GetHeader() + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid
} }
void FillI2NPMessageHeader(I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true); void FillI2NPMessageHeader(I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true);
void RenewI2NPMessageHeader(); void RenewI2NPMessageHeader();
bool IsExpired() const; bool IsExpired() const;
}; };
template<int sz> template<int sz>
struct I2NPMessageBuffer: public I2NPMessage struct I2NPMessageBuffer : public I2NPMessage {
{ I2NPMessageBuffer() {
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; }; buf = m_Buffer;
maxLen = sz;
};
uint8_t m_Buffer[sz + 32]; // 16 alignment + 16 padding uint8_t m_Buffer[sz + 32]; // 16 alignment + 16 padding
}; };
std::shared_ptr<I2NPMessage> NewI2NPMessage(); std::shared_ptr<I2NPMessage> NewI2NPMessage();
std::shared_ptr<I2NPMessage> NewI2NPShortMessage(); std::shared_ptr<I2NPMessage> NewI2NPShortMessage();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage(bool endpoint); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage(bool endpoint);
std::shared_ptr<I2NPMessage> NewI2NPMessage(size_t len); std::shared_ptr<I2NPMessage> NewI2NPMessage(size_t len);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); std::shared_ptr<I2NPMessage>
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr); CreateI2NPMessage(I2NPMessageType msgType, const uint8_t *buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage>
CreateI2NPMessage(const uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CopyI2NPMessage(std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CopyI2NPMessage(std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg(uint32_t msgID); std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg(uint32_t msgID);
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg(const uint8_t *key, const uint8_t *from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg(const uint8_t *key, const uint8_t *from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false,
std::set<i2p::data::IdentHash> *excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg(const i2p::data::IdentHash &dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg(const i2p::data::IdentHash &dest,
const std::set<i2p::data::IdentHash> &excludedFloodfills, const std::set<i2p::data::IdentHash> &excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false); const uint8_t *replyKey, const uint8_t *replyTag,
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); bool replyECIES = false);
std::shared_ptr<I2NPMessage>
CreateDatabaseSearchReply(const i2p::data::IdentHash &ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage>
CreateDatabaseStoreMsg(std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg(const i2p::data::IdentHash &storeHash,
std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
std::shared_ptr<I2NPMessage>
CreateDatabaseStoreMsg(std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (const i2p::data::IdentHash& storeHash, std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
bool IsRouterInfoMsg(std::shared_ptr<I2NPMessage> msg); bool IsRouterInfoMsg(std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(const uint8_t *buf); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(const uint8_t *buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(uint32_t tunnelID, const uint8_t *payload); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg(uint32_t tunnelID, const uint8_t *payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg(bool endpoint); std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg(bool endpoint);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, const uint8_t *buf, size_t len); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, const uint8_t *buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t *buf, size_t len, uint32_t replyMsgID = 0); const uint8_t *buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
size_t GetI2NPMessageLength(const uint8_t *msg, size_t len); size_t GetI2NPMessageLength(const uint8_t *msg, size_t len);
void HandleI2NPMessage(uint8_t *msg, size_t len); void HandleI2NPMessage(uint8_t *msg, size_t len);
void HandleI2NPMessage(std::shared_ptr<I2NPMessage> msg); void HandleI2NPMessage(std::shared_ptr<I2NPMessage> msg);
class I2NPMessagesHandler class I2NPMessagesHandler {
{
public: public:
~I2NPMessagesHandler(); ~I2NPMessagesHandler();
void PutNextMessage(std::shared_ptr<I2NPMessage> &&msg); void PutNextMessage(std::shared_ptr<I2NPMessage> &&msg);
void Flush(); void Flush();
private: private:
@ -310,7 +359,9 @@ namespace tunnel
}; };
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500; const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels); void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels);
uint16_t GetMaxNumTransitTunnels(); uint16_t GetMaxNumTransitTunnels();
} }

View file

@ -14,39 +14,35 @@
#include "LittleBigEndian.h" #include "LittleBigEndian.h"
#ifdef NEEDS_LOCAL_ENDIAN #ifdef NEEDS_LOCAL_ENDIAN
uint16_t htobe16(uint16_t int16)
{ uint16_t htobe16(uint16_t int16) {
BigEndian<uint16_t> u16(int16); BigEndian<uint16_t> u16(int16);
return u16.raw_value; return u16.raw_value;
} }
uint32_t htobe32(uint32_t int32) uint32_t htobe32(uint32_t int32) {
{
BigEndian<uint32_t> u32(int32); BigEndian<uint32_t> u32(int32);
return u32.raw_value; return u32.raw_value;
} }
uint64_t htobe64(uint64_t int64) uint64_t htobe64(uint64_t int64) {
{
BigEndian<uint64_t> u64(int64); BigEndian<uint64_t> u64(int64);
return u64.raw_value; return u64.raw_value;
} }
uint16_t be16toh(uint16_t big16) uint16_t be16toh(uint16_t big16) {
{
LittleEndian<uint16_t> u16(big16); LittleEndian<uint16_t> u16(big16);
return u16.raw_value; return u16.raw_value;
} }
uint32_t be32toh(uint32_t big32) uint32_t be32toh(uint32_t big32) {
{
LittleEndian<uint32_t> u32(big32); LittleEndian<uint32_t> u32(big32);
return u32.raw_value; return u32.raw_value;
} }
uint64_t be64toh(uint64_t big64) uint64_t be64toh(uint64_t big64) {
{
LittleEndian<uint64_t> u64(big64); LittleEndian<uint64_t> u64(big64);
return u64.raw_value; return u64.raw_value;
} }
#endif #endif

View file

@ -8,6 +8,7 @@
#ifndef I2PENDIAN_H__ #ifndef I2PENDIAN_H__
#define I2PENDIAN_H__ #define I2PENDIAN_H__
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
@ -53,13 +54,19 @@
#else #else
#define NEEDS_LOCAL_ENDIAN #define NEEDS_LOCAL_ENDIAN
#include <cstdint> #include <cstdint>
uint16_t htobe16(uint16_t int16); uint16_t htobe16(uint16_t int16);
uint32_t htobe32(uint32_t int32); uint32_t htobe32(uint32_t int32);
uint64_t htobe64(uint64_t int64); uint64_t htobe64(uint64_t int64);
uint16_t be16toh(uint16_t big16); uint16_t be16toh(uint16_t big16);
uint32_t be32toh(uint32_t big32); uint32_t be32toh(uint32_t big32);
uint64_t be64toh(uint64_t big64); uint64_t be64toh(uint64_t big64);
// assume LittleEndine // assume LittleEndine
@ -72,99 +79,81 @@ uint64_t be64toh(uint64_t big64);
#endif #endif
inline uint16_t buf16toh(const void *buf) inline uint16_t buf16toh(const void *buf) {
{
uint16_t b16; uint16_t b16;
memcpy(&b16, buf, sizeof(uint16_t)); memcpy(&b16, buf, sizeof(uint16_t));
return b16; return b16;
} }
inline uint32_t buf32toh(const void *buf) inline uint32_t buf32toh(const void *buf) {
{
uint32_t b32; uint32_t b32;
memcpy(&b32, buf, sizeof(uint32_t)); memcpy(&b32, buf, sizeof(uint32_t));
return b32; return b32;
} }
inline uint64_t buf64toh(const void *buf) inline uint64_t buf64toh(const void *buf) {
{
uint64_t b64; uint64_t b64;
memcpy(&b64, buf, sizeof(uint64_t)); memcpy(&b64, buf, sizeof(uint64_t));
return b64; return b64;
} }
inline uint16_t bufbe16toh(const void *buf) inline uint16_t bufbe16toh(const void *buf) {
{
return be16toh(buf16toh(buf)); return be16toh(buf16toh(buf));
} }
inline uint32_t bufbe32toh(const void *buf) inline uint32_t bufbe32toh(const void *buf) {
{
return be32toh(buf32toh(buf)); return be32toh(buf32toh(buf));
} }
inline uint64_t bufbe64toh(const void *buf) inline uint64_t bufbe64toh(const void *buf) {
{
return be64toh(buf64toh(buf)); return be64toh(buf64toh(buf));
} }
inline void htobuf16(void *buf, uint16_t b16) inline void htobuf16(void *buf, uint16_t b16) {
{
memcpy(buf, &b16, sizeof(uint16_t)); memcpy(buf, &b16, sizeof(uint16_t));
} }
inline void htobuf32(void *buf, uint32_t b32) inline void htobuf32(void *buf, uint32_t b32) {
{
memcpy(buf, &b32, sizeof(uint32_t)); memcpy(buf, &b32, sizeof(uint32_t));
} }
inline void htobuf64(void *buf, uint64_t b64) inline void htobuf64(void *buf, uint64_t b64) {
{
memcpy(buf, &b64, sizeof(uint64_t)); memcpy(buf, &b64, sizeof(uint64_t));
} }
inline void htobe16buf(void *buf, uint16_t big16) inline void htobe16buf(void *buf, uint16_t big16) {
{
htobuf16(buf, htobe16(big16)); htobuf16(buf, htobe16(big16));
} }
inline void htobe32buf(void *buf, uint32_t big32) inline void htobe32buf(void *buf, uint32_t big32) {
{
htobuf32(buf, htobe32(big32)); htobuf32(buf, htobe32(big32));
} }
inline void htobe64buf(void *buf, uint64_t big64) inline void htobe64buf(void *buf, uint64_t big64) {
{
htobuf64(buf, htobe64(big64)); htobuf64(buf, htobe64(big64));
} }
inline void htole16buf(void *buf, uint16_t big16) inline void htole16buf(void *buf, uint16_t big16) {
{
htobuf16(buf, htole16(big16)); htobuf16(buf, htole16(big16));
} }
inline void htole32buf(void *buf, uint32_t big32) inline void htole32buf(void *buf, uint32_t big32) {
{
htobuf32(buf, htole32(big32)); htobuf32(buf, htole32(big32));
} }
inline void htole64buf(void *buf, uint64_t big64) inline void htole64buf(void *buf, uint64_t big64) {
{
htobuf64(buf, htole64(big64)); htobuf64(buf, htole64(big64));
} }
inline uint16_t bufle16toh(const void *buf) inline uint16_t bufle16toh(const void *buf) {
{
return le16toh(buf16toh(buf)); return le16toh(buf16toh(buf));
} }
inline uint32_t bufle32toh(const void *buf) inline uint32_t bufle32toh(const void *buf) {
{
return le32toh(buf32toh(buf)); return le32toh(buf32toh(buf));
} }
inline uint64_t bufle64toh(const void *buf) inline uint64_t bufle64toh(const void *buf) {
{
return le64toh(buf64toh(buf)); return le64toh(buf64toh(buf));
} }

View file

@ -12,12 +12,9 @@
#include "Timestamp.h" #include "Timestamp.h"
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data Identity &Identity::operator=(const Keys &keys) {
{
Identity& Identity::operator=(const Keys& keys)
{
// copy public and signing keys together // copy public and signing keys together
memcpy(publicKey, keys.publicKey, sizeof(publicKey)); memcpy(publicKey, keys.publicKey, sizeof(publicKey));
memcpy(signingKey, keys.signingKey, sizeof(signingKey)); memcpy(signingKey, keys.signingKey, sizeof(signingKey));
@ -25,8 +22,7 @@ namespace data
return *this; return *this;
} }
size_t Identity::FromBuffer (const uint8_t * buf, size_t len) size_t Identity::FromBuffer(const uint8_t *buf, size_t len) {
{
if (len < DEFAULT_IDENTITY_SIZE) { if (len < DEFAULT_IDENTITY_SIZE) {
// buffer too small, don't overflow // buffer too small, don't overflow
return 0; return 0;
@ -35,49 +31,40 @@ namespace data
return DEFAULT_IDENTITY_SIZE; return DEFAULT_IDENTITY_SIZE;
} }
IdentHash Identity::Hash () const IdentHash Identity::Hash() const {
{
IdentHash hash; IdentHash hash;
SHA256(publicKey, DEFAULT_IDENTITY_SIZE, hash); SHA256(publicKey, DEFAULT_IDENTITY_SIZE, hash);
return hash; return hash;
} }
IdentityEx::IdentityEx() : IdentityEx::IdentityEx() :
m_ExtendedLen (0) m_ExtendedLen(0) {
{
} }
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType) IdentityEx::IdentityEx(const uint8_t *publicKey, const uint8_t *signingKey, SigningKeyType type,
{ CryptoKeyType cryptoType) {
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) {
{
memcpy(m_StandardIdentity.publicKey, publicKey, 32); memcpy(m_StandardIdentity.publicKey, publicKey, 32);
RAND_bytes(m_StandardIdentity.publicKey + 32, 224); RAND_bytes(m_StandardIdentity.publicKey + 32, 224);
} } else
else
memcpy(m_StandardIdentity.publicKey, publicKey, 256); memcpy(m_StandardIdentity.publicKey, publicKey, 256);
if (type != SIGNING_KEY_TYPE_DSA_SHA1) if (type != SIGNING_KEY_TYPE_DSA_SHA1) {
{
size_t excessLen = 0; size_t excessLen = 0;
uint8_t *excessBuf = nullptr; uint8_t *excessBuf = nullptr;
switch (type) switch (type) {
{ case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: {
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
RAND_bytes(m_StandardIdentity.signingKey, padding); RAND_bytes(m_StandardIdentity.signingKey, padding);
memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH); memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: {
{
size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96
RAND_bytes(m_StandardIdentity.signingKey, padding); RAND_bytes(m_StandardIdentity.signingKey, padding);
memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH); memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: {
{
memcpy(m_StandardIdentity.signingKey, signingKey, 128); memcpy(m_StandardIdentity.signingKey, signingKey, 128);
excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128 excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128
excessBuf = new uint8_t[excessLen]; excessBuf = new uint8_t[excessLen];
@ -90,23 +77,22 @@ namespace data
LogPrint(eLogError, "Identity: RSA signing key type ", (int) type, " is not supported"); LogPrint(eLogError, "Identity: RSA signing key type ", (int) type, " is not supported");
break; break;
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: {
{
size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32
RAND_bytes(m_StandardIdentity.signingKey, padding); RAND_bytes(m_StandardIdentity.signingKey, padding);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); memcpy(m_StandardIdentity.signingKey + padding, signingKey,
i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: {
{
// 256 // 256
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
RAND_bytes(m_StandardIdentity.signingKey, padding); RAND_bytes(m_StandardIdentity.signingKey, padding);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH); memcpy(m_StandardIdentity.signingKey + padding, signingKey,
i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH);
break; break;
} }
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: {
{
// 512 // 512
// no padding, key length is 128 // no padding, key length is 128
memcpy(m_StandardIdentity.signingKey, signingKey, i2p::crypto::GOSTR3410_512_PUBLIC_KEY_LENGTH); memcpy(m_StandardIdentity.signingKey, signingKey, i2p::crypto::GOSTR3410_512_PUBLIC_KEY_LENGTH);
@ -122,10 +108,8 @@ namespace data
// fill extended buffer // fill extended buffer
htobe16buf(m_ExtendedBuffer, type); htobe16buf(m_ExtendedBuffer, type);
htobe16buf(m_ExtendedBuffer + 2, cryptoType); htobe16buf(m_ExtendedBuffer + 2, cryptoType);
if (excessLen && excessBuf) if (excessLen && excessBuf) {
{ if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4) {
if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4)
{
LogPrint(eLogError, "Identity: Unexpected excessive signing key len ", excessLen); LogPrint(eLogError, "Identity: Unexpected excessive signing key len ", excessLen);
excessLen = MAX_EXTENDED_BUFFER_SIZE - 4; excessLen = MAX_EXTENDED_BUFFER_SIZE - 4;
} }
@ -134,8 +118,7 @@ namespace data
} }
// calculate ident hash // calculate ident hash
RecalculateIdentHash(); RecalculateIdentHash();
} } else // DSA-SHA1
else // DSA-SHA1
{ {
memcpy(m_StandardIdentity.signingKey, signingKey, sizeof(m_StandardIdentity.signingKey)); memcpy(m_StandardIdentity.signingKey, signingKey, sizeof(m_StandardIdentity.signingKey));
memset(m_StandardIdentity.certificate, 0, sizeof(m_StandardIdentity.certificate)); memset(m_StandardIdentity.certificate, 0, sizeof(m_StandardIdentity.certificate));
@ -145,8 +128,7 @@ namespace data
CreateVerifier(); CreateVerifier();
} }
void IdentityEx::RecalculateIdentHash(uint8_t * buf) void IdentityEx::RecalculateIdentHash(uint8_t *buf) {
{
bool dofree = buf == nullptr; bool dofree = buf == nullptr;
size_t sz = GetFullLen(); size_t sz = GetFullLen();
if (!buf) if (!buf)
@ -158,36 +140,30 @@ namespace data
} }
IdentityEx::IdentityEx(const uint8_t *buf, size_t len) : IdentityEx::IdentityEx(const uint8_t *buf, size_t len) :
m_ExtendedLen (0) m_ExtendedLen(0) {
{
FromBuffer(buf, len); FromBuffer(buf, len);
} }
IdentityEx::IdentityEx(const IdentityEx &other) : IdentityEx::IdentityEx(const IdentityEx &other) :
m_ExtendedLen (0) m_ExtendedLen(0) {
{
*this = other; *this = other;
} }
IdentityEx::IdentityEx(const Identity &standard) : IdentityEx::IdentityEx(const Identity &standard) :
m_ExtendedLen (0) m_ExtendedLen(0) {
{
*this = standard; *this = standard;
} }
IdentityEx::~IdentityEx () IdentityEx::~IdentityEx() {
{
delete m_Verifier; delete m_Verifier;
} }
IdentityEx& IdentityEx::operator=(const IdentityEx& other) IdentityEx &IdentityEx::operator=(const IdentityEx &other) {
{
memcpy(&m_StandardIdentity, &other.m_StandardIdentity, DEFAULT_IDENTITY_SIZE); memcpy(&m_StandardIdentity, &other.m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
m_IdentHash = other.m_IdentHash; m_IdentHash = other.m_IdentHash;
m_ExtendedLen = other.m_ExtendedLen; m_ExtendedLen = other.m_ExtendedLen;
if (m_ExtendedLen > 0) if (m_ExtendedLen > 0) {
{
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE; if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
memcpy(m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen); memcpy(m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
} }
@ -198,8 +174,7 @@ namespace data
return *this; return *this;
} }
IdentityEx& IdentityEx::operator=(const Identity& standard) IdentityEx &IdentityEx::operator=(const Identity &standard) {
{
m_StandardIdentity = standard; m_StandardIdentity = standard;
m_IdentHash = m_StandardIdentity.Hash(); m_IdentHash = m_StandardIdentity.Hash();
@ -211,31 +186,25 @@ namespace data
return *this; return *this;
} }
size_t IdentityEx::FromBuffer (const uint8_t * buf, size_t len) size_t IdentityEx::FromBuffer(const uint8_t *buf, size_t len) {
{ if (len < DEFAULT_IDENTITY_SIZE) {
if (len < DEFAULT_IDENTITY_SIZE)
{
LogPrint(eLogError, "Identity: Buffer length ", len, " is too small"); LogPrint(eLogError, "Identity: Buffer length ", len, " is too small");
return 0; return 0;
} }
memcpy(&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE); memcpy(&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
m_ExtendedLen = bufbe16toh(m_StandardIdentity.certificate + 1); m_ExtendedLen = bufbe16toh(m_StandardIdentity.certificate + 1);
if (m_ExtendedLen) if (m_ExtendedLen) {
{ if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len) {
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
{
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE; if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
memcpy(m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen); memcpy(m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen);
} } else {
else LogPrint(eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ",
{ len - DEFAULT_IDENTITY_SIZE);
LogPrint (eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
m_ExtendedLen = 0; m_ExtendedLen = 0;
return 0; return 0;
} }
} } else
else
m_ExtendedLen = 0; m_ExtendedLen = 0;
SHA256(buf, GetFullLen(), m_IdentHash); SHA256(buf, GetFullLen(), m_IdentHash);
@ -245,8 +214,7 @@ namespace data
return GetFullLen(); return GetFullLen();
} }
size_t IdentityEx::ToBuffer (uint8_t * buf, size_t len) const size_t IdentityEx::ToBuffer(uint8_t *buf, size_t len) const {
{
const size_t fullLen = GetFullLen(); const size_t fullLen = GetFullLen();
if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else
memcpy(buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE); memcpy(buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
@ -255,16 +223,14 @@ namespace data
return fullLen; return fullLen;
} }
size_t IdentityEx::FromBase64(const std::string& s) size_t IdentityEx::FromBase64(const std::string &s) {
{
const size_t slen = s.length(); const size_t slen = s.length();
std::vector<uint8_t> buf(slen); // binary data can't exceed base64 std::vector<uint8_t> buf(slen); // binary data can't exceed base64
const size_t len = Base64ToByteStream(s.c_str(), slen, buf.data(), slen); const size_t len = Base64ToByteStream(s.c_str(), slen, buf.data(), slen);
return FromBuffer(buf.data(), len); return FromBuffer(buf.data(), len);
} }
std::string IdentityEx::ToBase64 () const std::string IdentityEx::ToBase64() const {
{
const size_t bufLen = GetFullLen(); const size_t bufLen = GetFullLen();
const size_t strLen = Base64EncodingBufferSize(bufLen); const size_t strLen = Base64EncodingBufferSize(bufLen);
std::vector<uint8_t> buf(bufLen); std::vector<uint8_t> buf(bufLen);
@ -274,68 +240,59 @@ namespace data
return std::string(str.data(), l1); return std::string(str.data(), l1);
} }
size_t IdentityEx::GetSigningPublicKeyLen () const size_t IdentityEx::GetSigningPublicKeyLen() const {
{
if (!m_Verifier) CreateVerifier(); if (!m_Verifier) CreateVerifier();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetPublicKeyLen(); return m_Verifier->GetPublicKeyLen();
return 128; return 128;
} }
const uint8_t * IdentityEx::GetSigningPublicKeyBuffer () const const uint8_t *IdentityEx::GetSigningPublicKeyBuffer() const {
{
auto keyLen = GetSigningPublicKeyLen(); auto keyLen = GetSigningPublicKeyLen();
if (keyLen > 128) return nullptr; // P521 if (keyLen > 128) return nullptr; // P521
return m_StandardIdentity.signingKey + 128 - keyLen; return m_StandardIdentity.signingKey + 128 - keyLen;
} }
size_t IdentityEx::GetSigningPrivateKeyLen () const size_t IdentityEx::GetSigningPrivateKeyLen() const {
{
if (!m_Verifier) CreateVerifier(); if (!m_Verifier) CreateVerifier();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetPrivateKeyLen(); return m_Verifier->GetPrivateKeyLen();
return GetSignatureLen() / 2; return GetSignatureLen() / 2;
} }
size_t IdentityEx::GetSignatureLen () const size_t IdentityEx::GetSignatureLen() const {
{
if (!m_Verifier) CreateVerifier(); if (!m_Verifier) CreateVerifier();
if (m_Verifier) if (m_Verifier)
return m_Verifier->GetSignatureLen(); return m_Verifier->GetSignatureLen();
return i2p::crypto::DSA_SIGNATURE_LENGTH; return i2p::crypto::DSA_SIGNATURE_LENGTH;
} }
bool IdentityEx::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ bool IdentityEx::Verify(const uint8_t *buf, size_t len, const uint8_t *signature) const {
if (!m_Verifier) CreateVerifier(); if (!m_Verifier) CreateVerifier();
if (m_Verifier) if (m_Verifier)
return m_Verifier->Verify(buf, len, signature); return m_Verifier->Verify(buf, len, signature);
return false; return false;
} }
SigningKeyType IdentityEx::GetSigningKeyType () const SigningKeyType IdentityEx::GetSigningKeyType() const {
{
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 2) if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 2)
return bufbe16toh(m_ExtendedBuffer); // signing key return bufbe16toh(m_ExtendedBuffer); // signing key
return SIGNING_KEY_TYPE_DSA_SHA1; return SIGNING_KEY_TYPE_DSA_SHA1;
} }
bool IdentityEx::IsRSA () const bool IdentityEx::IsRSA() const {
{
auto sigType = GetSigningKeyType(); auto sigType = GetSigningKeyType();
return sigType <= SIGNING_KEY_TYPE_RSA_SHA512_4096 && sigType >= SIGNING_KEY_TYPE_RSA_SHA256_2048; return sigType <= SIGNING_KEY_TYPE_RSA_SHA512_4096 && sigType >= SIGNING_KEY_TYPE_RSA_SHA256_2048;
} }
CryptoKeyType IdentityEx::GetCryptoKeyType () const CryptoKeyType IdentityEx::GetCryptoKeyType() const {
{
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 4) if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 4)
return bufbe16toh(m_ExtendedBuffer + 2); // crypto key return bufbe16toh(m_ExtendedBuffer + 2); // crypto key
return CRYPTO_KEY_TYPE_ELGAMAL; return CRYPTO_KEY_TYPE_ELGAMAL;
} }
i2p::crypto::Verifier * IdentityEx::CreateVerifier (SigningKeyType keyType) i2p::crypto::Verifier *IdentityEx::CreateVerifier(SigningKeyType keyType) {
{ switch (keyType) {
switch (keyType)
{
case SIGNING_KEY_TYPE_DSA_SHA1: case SIGNING_KEY_TYPE_DSA_SHA1:
return new i2p::crypto::DSAVerifier(); return new i2p::crypto::DSAVerifier();
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
@ -363,22 +320,20 @@ 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
auto verifier = CreateVerifier(GetSigningKeyType()); auto verifier = CreateVerifier(GetSigningKeyType());
if (verifier) if (verifier) {
{
auto keyLen = verifier->GetPublicKeyLen(); auto keyLen = verifier->GetPublicKeyLen();
if (keyLen <= 128) if (keyLen <= 128)
verifier->SetPublicKey(m_StandardIdentity.signingKey + 128 - keyLen); verifier->SetPublicKey(m_StandardIdentity.signingKey + 128 - keyLen);
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;
} }
@ -386,8 +341,7 @@ namespace data
UpdateVerifier(verifier); UpdateVerifier(verifier);
} }
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const void IdentityEx::UpdateVerifier(i2p::crypto::Verifier *verifier) const {
{
bool del = false; bool del = false;
{ {
std::lock_guard<std::mutex> l(m_VerifierMutex); std::lock_guard<std::mutex> l(m_VerifierMutex);
@ -400,8 +354,7 @@ namespace data
delete verifier; delete verifier;
} }
void IdentityEx::DropVerifier () const void IdentityEx::DropVerifier() const {
{
i2p::crypto::Verifier *verifier; i2p::crypto::Verifier *verifier;
{ {
std::lock_guard<std::mutex> l(m_VerifierMutex); std::lock_guard<std::mutex> l(m_VerifierMutex);
@ -411,10 +364,9 @@ namespace data
delete verifier; delete verifier;
} }
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key) std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>
{ IdentityEx::CreateEncryptor(CryptoKeyType keyType, const uint8_t *key) {
switch (keyType) switch (keyType) {
{
case CRYPTO_KEY_TYPE_ELGAMAL: case CRYPTO_KEY_TYPE_ELGAMAL:
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key); return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
break; break;
@ -434,14 +386,12 @@ namespace data
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 {
{
if (!key) key = GetEncryptionPublicKey(); // use publicKey if (!key) key = GetEncryptionPublicKey(); // use publicKey
return CreateEncryptor(GetCryptoKeyType(), key); return CreateEncryptor(GetCryptoKeyType(), key);
} }
PrivateKeys& PrivateKeys::operator=(const Keys& keys) PrivateKeys &PrivateKeys::operator=(const Keys &keys) {
{
m_Public = std::make_shared<IdentityEx>(Identity(keys)); m_Public = std::make_shared<IdentityEx>(Identity(keys));
memcpy(m_PrivateKey, keys.privateKey, 256); // 256 memcpy(m_PrivateKey, keys.privateKey, 256); // 256
memcpy(m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen()); memcpy(m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen());
@ -453,29 +403,28 @@ namespace data
return *this; return *this;
} }
PrivateKeys& PrivateKeys::operator=(const PrivateKeys& other) PrivateKeys &PrivateKeys::operator=(const PrivateKeys &other) {
{
m_Public = std::make_shared<IdentityEx>(*other.m_Public); m_Public = std::make_shared<IdentityEx>(*other.m_Public);
memcpy(m_PrivateKey, other.m_PrivateKey, 256); // 256 memcpy(m_PrivateKey, other.m_PrivateKey, 256); // 256
m_OfflineSignature = other.m_OfflineSignature; m_OfflineSignature = other.m_OfflineSignature;
m_TransientSignatureLen = other.m_TransientSignatureLen; m_TransientSignatureLen = other.m_TransientSignatureLen;
m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen; m_TransientSigningPrivateKeyLen = other.m_TransientSigningPrivateKeyLen;
memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_TransientSigningPrivateKeyLen > 0 ? m_TransientSigningPrivateKeyLen : m_Public->GetSigningPrivateKeyLen ()); memcpy(m_SigningPrivateKey, other.m_SigningPrivateKey,
m_TransientSigningPrivateKeyLen > 0 ? m_TransientSigningPrivateKeyLen
: m_Public->GetSigningPrivateKeyLen());
m_Signer = nullptr; m_Signer = nullptr;
CreateSigner(); CreateSigner();
return *this; return *this;
} }
size_t PrivateKeys::GetFullLen () const size_t PrivateKeys::GetFullLen() const {
{
size_t ret = m_Public->GetFullLen() + GetPrivateKeyLen() + m_Public->GetSigningPrivateKeyLen(); size_t ret = m_Public->GetFullLen() + GetPrivateKeyLen() + m_Public->GetSigningPrivateKeyLen();
if (IsOfflineSignature()) if (IsOfflineSignature())
ret += m_OfflineSignature.size() + m_TransientSigningPrivateKeyLen; ret += m_OfflineSignature.size() + m_TransientSigningPrivateKeyLen;
return ret; return ret;
} }
size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len) size_t PrivateKeys::FromBuffer(const uint8_t *buf, size_t len) {
{
m_Public = std::make_shared<IdentityEx>(); m_Public = std::make_shared<IdentityEx>();
size_t ret = m_Public->FromBuffer(buf, len); size_t ret = m_Public->FromBuffer(buf, len);
auto cryptoKeyLen = GetPrivateKeyLen(); auto cryptoKeyLen = GetPrivateKeyLen();
@ -490,25 +439,24 @@ 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;
} }
if (allzeros) if (allzeros) {
{
// offline information // offline information
const uint8_t *offlineInfo = buf + ret; const uint8_t *offlineInfo = buf + ret;
ret += 4; // expires timestamp ret += 4; // expires timestamp
SigningKeyType keyType = bufbe16toh (buf + ret); ret += 2; // key type SigningKeyType keyType = bufbe16toh(buf + ret);
ret += 2; // key type
std::unique_ptr<i2p::crypto::Verifier> transientVerifier(IdentityEx::CreateVerifier(keyType)); std::unique_ptr<i2p::crypto::Verifier> transientVerifier(IdentityEx::CreateVerifier(keyType));
if (!transientVerifier) return 0; if (!transientVerifier) return 0;
auto keyLen = transientVerifier->GetPublicKeyLen(); auto keyLen = transientVerifier->GetPublicKeyLen();
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;
} }
@ -524,14 +472,12 @@ namespace data
memcpy(m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen); memcpy(m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen);
ret += m_TransientSigningPrivateKeyLen; ret += m_TransientSigningPrivateKeyLen;
CreateSigner(keyType); CreateSigner(keyType);
} } else
else
CreateSigner(m_Public->GetSigningKeyType()); CreateSigner(m_Public->GetSigningKeyType());
return ret; return ret;
} }
size_t PrivateKeys::ToBuffer (uint8_t * buf, size_t len) const size_t PrivateKeys::ToBuffer(uint8_t *buf, size_t len) const {
{
size_t ret = m_Public->ToBuffer(buf, len); size_t ret = m_Public->ToBuffer(buf, len);
auto cryptoKeyLen = GetPrivateKeyLen(); auto cryptoKeyLen = GetPrivateKeyLen();
memcpy(buf + ret, m_PrivateKey, cryptoKeyLen); memcpy(buf + ret, m_PrivateKey, cryptoKeyLen);
@ -543,8 +489,7 @@ namespace data
else else
memcpy(buf + ret, m_SigningPrivateKey, signingPrivateKeySize); memcpy(buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
ret += signingPrivateKeySize; ret += signingPrivateKeySize;
if (IsOfflineSignature ()) if (IsOfflineSignature()) {
{
// offline signature // offline signature
auto offlineSignatureLen = m_OfflineSignature.size(); auto offlineSignatureLen = m_OfflineSignature.size();
if (ret + offlineSignatureLen > len) return 0; if (ret + offlineSignatureLen > len) return 0;
@ -558,8 +503,7 @@ namespace data
return ret; return ret;
} }
size_t PrivateKeys::FromBase64(const std::string& s) size_t PrivateKeys::FromBase64(const std::string &s) {
{
uint8_t *buf = new uint8_t[s.length()]; uint8_t *buf = new uint8_t[s.length()];
size_t l = i2p::data::Base64ToByteStream(s.c_str(), s.length(), buf, s.length()); size_t l = i2p::data::Base64ToByteStream(s.c_str(), s.length(), buf, s.length());
size_t ret = FromBuffer(buf, l); size_t ret = FromBuffer(buf, l);
@ -567,8 +511,7 @@ namespace data
return ret; return ret;
} }
std::string PrivateKeys::ToBase64 () const std::string PrivateKeys::ToBase64() const {
{
uint8_t *buf = new uint8_t[GetFullLen()]; uint8_t *buf = new uint8_t[GetFullLen()];
char *str = new char[GetFullLen() * 2]; char *str = new char[GetFullLen() * 2];
size_t l = ToBuffer(buf, GetFullLen()); size_t l = ToBuffer(buf, GetFullLen());
@ -580,40 +523,37 @@ namespace data
return ret; return ret;
} }
void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const void PrivateKeys::Sign(const uint8_t *buf, int len, uint8_t *signature) const {
{
if (!m_Signer) if (!m_Signer)
CreateSigner(); CreateSigner();
m_Signer->Sign(buf, len, signature); m_Signer->Sign(buf, len, signature);
} }
void PrivateKeys::CreateSigner () const void PrivateKeys::CreateSigner() const {
{
if (IsOfflineSignature()) if (IsOfflineSignature())
CreateSigner(bufbe16toh(m_OfflineSignature.data() + 4)); // key type CreateSigner(bufbe16toh(m_OfflineSignature.data() + 4)); // key type
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())
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check m_Signer.reset(new i2p::crypto::EDDSA25519Signer(m_SigningPrivateKey,
else m_Public->GetStandardIdentity().certificate -
{ i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
else {
// 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) {
{ switch (keyType) {
switch (keyType)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
return new i2p::crypto::ECDSAP256Signer(priv); return new i2p::crypto::ECDSAP256Signer(priv);
break; break;
@ -646,36 +586,31 @@ namespace data
return nullptr; return nullptr;
} }
size_t PrivateKeys::GetSignatureLen () const size_t PrivateKeys::GetSignatureLen() const {
{
return IsOfflineSignature() ? m_TransientSignatureLen : m_Public->GetSignatureLen(); return IsOfflineSignature() ? m_TransientSignatureLen : m_Public->GetSignatureLen();
} }
size_t PrivateKeys::GetPrivateKeyLen () const size_t PrivateKeys::GetPrivateKeyLen() const {
{
// private key length always 256, but type 4 // private key length always 256, but type 4
return (m_Public->GetCryptoKeyType() == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256; return (m_Public->GetCryptoKeyType() == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
} }
uint8_t * PrivateKeys::GetPadding() uint8_t *PrivateKeys::GetPadding() {
{
if (m_Public->GetSigningKeyType() == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) if (m_Public->GetSigningKeyType() == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
return m_Public->GetEncryptionPublicKeyBuffer() + 256; return m_Public->GetEncryptionPublicKeyBuffer() + 256;
else else
return nullptr; // TODO: implement me return nullptr; // TODO: implement me
} }
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (const uint8_t * key) const std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor(const uint8_t *key) const {
{
if (!key) key = m_PrivateKey; // use privateKey if (!key) key = m_PrivateKey; // use privateKey
return CreateDecryptor(m_Public->GetCryptoKeyType(), key); return CreateDecryptor(m_Public->GetCryptoKeyType(), key);
} }
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key) std::shared_ptr<i2p::crypto::CryptoKeyDecryptor>
{ PrivateKeys::CreateDecryptor(CryptoKeyType cryptoType, const uint8_t *key) {
if (!key) return nullptr; if (!key) return nullptr;
switch (cryptoType) switch (cryptoType) {
{
case CRYPTO_KEY_TYPE_ELGAMAL: case CRYPTO_KEY_TYPE_ELGAMAL:
return std::make_shared<i2p::crypto::ElGamalDecryptor>(key); return std::make_shared<i2p::crypto::ElGamalDecryptor>(key);
break; break;
@ -695,10 +630,8 @@ namespace data
return nullptr; return nullptr;
} }
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType) PrivateKeys PrivateKeys::CreateRandomKeys(SigningKeyType type, CryptoKeyType cryptoType) {
{ if (type != SIGNING_KEY_TYPE_DSA_SHA1) {
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{
PrivateKeys keys; PrivateKeys keys;
// signature // signature
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
@ -715,10 +648,8 @@ namespace data
return PrivateKeys(i2p::data::CreateRandomKeys()); // DSA-SHA1 return PrivateKeys(i2p::data::CreateRandomKeys()); // DSA-SHA1
} }
void PrivateKeys::GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub) void PrivateKeys::GenerateSigningKeyPair(SigningKeyType type, uint8_t *priv, uint8_t *pub) {
{ switch (type) {
switch (type)
{
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
i2p::crypto::CreateECDSAP256RandomKeys(priv, pub); i2p::crypto::CreateECDSAP256RandomKeys(priv, pub);
break; break;
@ -749,15 +680,14 @@ namespace data
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
} }
} }
void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub) void PrivateKeys::GenerateCryptoKeyPair(CryptoKeyType type, uint8_t *priv, uint8_t *pub) {
{ switch (type) {
switch (type)
{
case CRYPTO_KEY_TYPE_ELGAMAL: case CRYPTO_KEY_TYPE_ELGAMAL:
i2p::crypto::GenerateElGamalKeyPair(priv, pub); i2p::crypto::GenerateElGamalKeyPair(priv, pub);
break; break;
@ -776,20 +706,20 @@ 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();
keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen(); keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen();
keys.m_TransientSignatureLen = verifier->GetSignatureLen(); keys.m_TransientSignatureLen = verifier->GetSignatureLen();
keys.m_OfflineSignature.resize(pubKeyLen + m_Public->GetSignatureLen() + 6); keys.m_OfflineSignature.resize(pubKeyLen + m_Public->GetSignatureLen() + 6);
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,
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature keys.m_OfflineSignature.data() + 6); // public key
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);
@ -797,8 +727,7 @@ namespace data
return keys; return keys;
} }
Keys CreateRandomKeys () Keys CreateRandomKeys() {
{
Keys keys; Keys keys;
// encryption // encryption
i2p::crypto::GenerateElGamalKeyPair(keys.privateKey, keys.publicKey); i2p::crypto::GenerateElGamalKeyPair(keys.privateKey, keys.publicKey);
@ -807,8 +736,7 @@ namespace data
return keys; return keys;
} }
IdentHash CreateRoutingKey (const IdentHash& ident) IdentHash CreateRoutingKey(const IdentHash &ident) {
{
uint8_t buf[41]; // ident + yyyymmdd uint8_t buf[41]; // ident + yyyymmdd
memcpy(buf, (const uint8_t *) ident, 32); memcpy(buf, (const uint8_t *) ident, 32);
i2p::util::GetCurrentDate((char *) (buf + 32)); i2p::util::GetCurrentDate((char *) (buf + 32));
@ -817,8 +745,7 @@ namespace data
return key; return key;
} }
XORMetric operator^(const IdentHash& key1, const IdentHash& key2) XORMetric operator^(const IdentHash &key1, const IdentHash &key2) {
{
XORMetric m; XORMetric m;
#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600) #if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
if(i2p::cpu::avx) if(i2p::cpu::avx)

View file

@ -20,18 +20,15 @@
#include "Signature.h" #include "Signature.h"
#include "CryptoKey.h" #include "CryptoKey.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
typedef Tag<32> IdentHash; typedef Tag<32> IdentHash;
inline std::string GetIdentHashAbbreviation (const IdentHash& ident)
{ inline std::string GetIdentHashAbbreviation(const IdentHash &ident) {
return ident.ToBase64().substr(0, 4); return ident.ToBase64().substr(0, 4);
} }
struct Keys struct Keys {
{
uint8_t privateKey[256]; uint8_t privateKey[256];
uint8_t signingPrivateKey[20]; uint8_t signingPrivateKey[20];
uint8_t publicKey[256]; uint8_t publicKey[256];
@ -45,16 +42,19 @@ namespace data
const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4; const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4;
const uint8_t CERTIFICATE_TYPE_KEY = 5; const uint8_t CERTIFICATE_TYPE_KEY = 5;
struct Identity struct Identity {
{
uint8_t publicKey[256]; uint8_t publicKey[256];
uint8_t signingKey[128]; uint8_t signingKey[128];
uint8_t certificate[3]; // byte 1 - type, bytes 2-3 - length uint8_t certificate[3]; // byte 1 - type, bytes 2-3 - length
Identity() = default; Identity() = default;
Identity(const Keys &keys) { *this = keys; }; Identity(const Keys &keys) { *this = keys; };
Identity &operator=(const Keys &keys); Identity &operator=(const Keys &keys);
size_t FromBuffer(const uint8_t *buf, size_t len); size_t FromBuffer(const uint8_t *buf, size_t len);
IdentHash Hash() const; IdentHash Hash() const;
}; };
@ -85,50 +85,76 @@ namespace data
typedef uint16_t CryptoKeyType; typedef uint16_t CryptoKeyType;
const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521 const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521
class IdentityEx class IdentityEx {
{
public: public:
IdentityEx(); IdentityEx();
IdentityEx(const uint8_t *publicKey, const uint8_t *signingKey, IdentityEx(const uint8_t *publicKey, const uint8_t *signingKey,
SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1,
CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
IdentityEx(const uint8_t *buf, size_t len); IdentityEx(const uint8_t *buf, size_t len);
IdentityEx(const IdentityEx &other); IdentityEx(const IdentityEx &other);
IdentityEx(const Identity &standard); IdentityEx(const Identity &standard);
~IdentityEx(); ~IdentityEx();
IdentityEx &operator=(const IdentityEx &other); IdentityEx &operator=(const IdentityEx &other);
IdentityEx &operator=(const Identity &standard); IdentityEx &operator=(const Identity &standard);
size_t FromBuffer(const uint8_t *buf, size_t len); size_t FromBuffer(const uint8_t *buf, size_t len);
size_t ToBuffer(uint8_t *buf, size_t len) const; size_t ToBuffer(uint8_t *buf, size_t len) const;
size_t FromBase64(const std::string &s); size_t FromBase64(const std::string &s);
std::string ToBase64() const; std::string ToBase64() const;
const Identity &GetStandardIdentity() const { return m_StandardIdentity; }; const Identity &GetStandardIdentity() const { return m_StandardIdentity; };
const IdentHash &GetIdentHash() const { return m_IdentHash; }; const IdentHash &GetIdentHash() const { return m_IdentHash; };
const uint8_t *GetEncryptionPublicKey() const { return m_StandardIdentity.publicKey; }; const uint8_t *GetEncryptionPublicKey() const { return m_StandardIdentity.publicKey; };
uint8_t *GetEncryptionPublicKeyBuffer() { return m_StandardIdentity.publicKey; }; uint8_t *GetEncryptionPublicKeyBuffer() { return m_StandardIdentity.publicKey; };
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor(const uint8_t *key) const; std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor(const uint8_t *key) const;
size_t GetFullLen() const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetFullLen() const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
size_t GetSigningPublicKeyLen() const; size_t GetSigningPublicKeyLen() const;
const uint8_t *GetSigningPublicKeyBuffer() const; // returns NULL for P521 const uint8_t *GetSigningPublicKeyBuffer() const; // returns NULL for P521
size_t GetSigningPrivateKeyLen() const; size_t GetSigningPrivateKeyLen() const;
size_t GetSignatureLen() const; size_t GetSignatureLen() const;
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;
SigningKeyType GetSigningKeyType() const; SigningKeyType GetSigningKeyType() const;
bool IsRSA() const; // signing key type bool IsRSA() const; // signing key type
CryptoKeyType GetCryptoKeyType() const; CryptoKeyType GetCryptoKeyType() const;
void DropVerifier() const; // to save memory void DropVerifier() const; // to save memory
bool operator==(const IdentityEx &other) const { return GetIdentHash() == other.GetIdentHash(); } bool operator==(const IdentityEx &other) const { return GetIdentHash() == other.GetIdentHash(); }
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:
void CreateVerifier() const; void CreateVerifier() const;
void UpdateVerifier(i2p::crypto::Verifier *verifier) const; void UpdateVerifier(i2p::crypto::Verifier *verifier) const;
private: private:
@ -146,44 +172,67 @@ namespace data
public: public:
PrivateKeys() = default; PrivateKeys() = default;
PrivateKeys(const PrivateKeys &other) { *this = other; }; PrivateKeys(const PrivateKeys &other) { *this = other; };
PrivateKeys(const Keys &keys) { *this = keys; }; PrivateKeys(const Keys &keys) { *this = keys; };
PrivateKeys &operator=(const Keys &keys); PrivateKeys &operator=(const Keys &keys);
PrivateKeys &operator=(const PrivateKeys &other); PrivateKeys &operator=(const PrivateKeys &other);
~PrivateKeys() = default; ~PrivateKeys() = default;
std::shared_ptr<const IdentityEx> GetPublic() const { return m_Public; }; std::shared_ptr<const IdentityEx> GetPublic() const { return m_Public; };
const uint8_t *GetPrivateKey() const { return m_PrivateKey; }; const uint8_t *GetPrivateKey() const { return m_PrivateKey; };
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;
size_t GetFullLen() const; size_t GetFullLen() const;
size_t FromBuffer(const uint8_t *buf, size_t len); size_t FromBuffer(const uint8_t *buf, size_t len);
size_t ToBuffer(uint8_t *buf, size_t len) const; size_t ToBuffer(uint8_t *buf, size_t len) const;
size_t FromBase64(const std::string &s); size_t FromBase64(const std::string &s);
std::string ToBase64() const; std::string ToBase64() const;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor(const uint8_t *key) const; std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor(const uint8_t *key) const;
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key); static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor>
static PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL); CreateDecryptor(CryptoKeyType cryptoType, const uint8_t *key);
static PrivateKeys CreateRandomKeys(SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1,
CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
static void 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:
void CreateSigner() const; void CreateSigner() const;
void CreateSigner(SigningKeyType keyType) const; void CreateSigner(SigningKeyType keyType) const;
size_t GetPrivateKeyLen() const; size_t GetPrivateKeyLen() const;
private: private:
@ -198,49 +247,59 @@ namespace data
}; };
// kademlia // kademlia
struct XORMetric struct XORMetric {
{ union {
union
{
uint8_t metric[32]; uint8_t metric[32];
uint64_t metric_ll[4]; uint64_t metric_ll[4];
}; };
void SetMin() { memset(metric, 0, 32); }; void SetMin() { memset(metric, 0, 32); };
void SetMax() { memset(metric, 0xFF, 32); }; void SetMax() { memset(metric, 0xFF, 32); };
bool operator<(const XORMetric &other) const { return memcmp(metric, other.metric, 32) < 0; }; bool operator<(const XORMetric &other) const { return memcmp(metric, other.metric, 32) < 0; };
}; };
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 instructions // destination for delivery instructions
class RoutingDestination class RoutingDestination {
{
public: public:
RoutingDestination() {}; RoutingDestination() {};
virtual ~RoutingDestination() {}; virtual ~RoutingDestination() {};
virtual std::shared_ptr<const IdentityEx> GetIdentity() const = 0; virtual std::shared_ptr<const IdentityEx> GetIdentity() const = 0;
virtual void Encrypt(const uint8_t *data, uint8_t *encrypted) const = 0; // encrypt data for virtual void Encrypt(const uint8_t *data, uint8_t *encrypted) const = 0; // encrypt data for
virtual bool IsDestination() const = 0; // for garlic virtual bool IsDestination() const = 0; // for garlic
const IdentHash &GetIdentHash() const { return GetIdentity()->GetIdentHash(); }; const IdentHash &GetIdentHash() const { return GetIdentity()->GetIdentHash(); };
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override in LeaseSet2
virtual CryptoKeyType
GetEncryptionType() const { return GetIdentity()->GetCryptoKeyType(); }; // override in LeaseSet2
}; };
class LocalDestination class LocalDestination {
{
public: public:
virtual ~LocalDestination() {}; virtual ~LocalDestination() {};
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
virtual bool Decrypt(const uint8_t *encrypted, uint8_t *data,
CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL) const = 0;
virtual std::shared_ptr<const IdentityEx> GetIdentity() const = 0; virtual std::shared_ptr<const IdentityEx> GetIdentity() const = 0;
const IdentHash &GetIdentHash() const { return GetIdentity()->GetIdentHash(); }; const IdentHash &GetIdentHash() const { return GetIdentity()->GetIdentHash(); };
virtual bool SupportsEncryptionType (CryptoKeyType keyType) const { return GetIdentity ()->GetCryptoKeyType () == keyType; }; // override for LeaseSet
virtual const uint8_t * GetEncryptionPublicKey (CryptoKeyType keyType) const { return GetIdentity ()->GetEncryptionPublicKey (); }; // override for LeaseSet virtual bool SupportsEncryptionType(CryptoKeyType keyType) const {
return GetIdentity()->GetCryptoKeyType() == keyType;
}; // override for LeaseSet
virtual const uint8_t *GetEncryptionPublicKey(
CryptoKeyType keyType) const { return GetIdentity()->GetEncryptionPublicKey(); }; // override for LeaseSet
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -19,19 +19,15 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Blinding.h" #include "Blinding.h"
namespace i2p namespace i2p {
{
namespace tunnel namespace tunnel {
{
class InboundTunnel; class InboundTunnel;
} }
namespace data namespace data {
{
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
struct Lease struct Lease {
{
IdentHash tunnelGateway; IdentHash tunnelGateway;
uint32_t tunnelID; uint32_t tunnelID;
uint64_t endDate; // 0 means invalid uint64_t endDate; // 0 means invalid
@ -45,10 +41,8 @@ namespace data
} }
}; };
struct LeaseCmp struct LeaseCmp {
{ bool operator()(std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const {
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
{
if (l1->tunnelID != l2->tunnelID) if (l1->tunnelID != l2->tunnelID)
return l1->tunnelID < l2->tunnelID; return l1->tunnelID < l2->tunnelID;
else else
@ -64,57 +58,91 @@ namespace data
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;
class LeaseSet: public RoutingDestination
{ class LeaseSet : public RoutingDestination {
public: public:
LeaseSet(const uint8_t *buf, size_t len, bool storeLeases = true); LeaseSet(const uint8_t *buf, size_t len, bool storeLeases = true);
virtual ~LeaseSet () { delete[] m_EncryptionKey; delete[] m_Buffer; };
virtual ~LeaseSet() {
delete[] m_EncryptionKey;
delete[] m_Buffer;
};
virtual void Update(const uint8_t *buf, size_t len, bool verifySignature = true); virtual void Update(const uint8_t *buf, size_t len, bool verifySignature = true);
virtual bool IsNewer(const uint8_t *buf, size_t len) const; virtual bool IsNewer(const uint8_t *buf, size_t len) const;
void PopulateLeases(); // from buffer void PopulateLeases(); // from buffer
const uint8_t *GetBuffer() const { return m_Buffer; }; const uint8_t *GetBuffer() const { return m_Buffer; };
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(); };
uint64_t GetExpirationTime() const { return m_ExpirationTime; }; uint64_t GetExpirationTime() const { return m_ExpirationTime; };
bool ExpiresSoon(const uint64_t dlt = 1000 * 5, const uint64_t fudge = 0) const; bool ExpiresSoon(const uint64_t dlt = 1000 * 5, const uint64_t fudge = 0) const;
bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; bool operator==(const LeaseSet &other) const {
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
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; }; std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; };
void Encrypt(const uint8_t *data, uint8_t *encrypted) const; void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
bool IsDestination() const { return true; }; bool IsDestination() const { return true; };
protected: protected:
void UpdateLeasesBegin(); void UpdateLeasesBegin();
void UpdateLeasesEnd(); void UpdateLeasesEnd();
void UpdateLease(const Lease &lease, uint64_t ts); void UpdateLease(const Lease &lease, uint64_t ts);
// 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; };
bool IsStoreLeases() const { return m_StoreLeases; }; bool IsStoreLeases() const { return m_StoreLeases; };
private: private:
void ReadFromBuffer(bool readIdentity = true, bool verifySignature = true); void ReadFromBuffer(bool readIdentity = true, bool verifySignature = true);
virtual uint64_t ExtractExpirationTimestamp (const uint8_t * buf, size_t len) const; // returns max expiration time
virtual uint64_t
ExtractExpirationTimestamp(const uint8_t *buf, size_t len) const; // returns max expiration time
private: private:
@ -141,37 +169,55 @@ namespace data
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 {
{
public: public:
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); LeaseSet2(uint8_t storeType, const uint8_t *buf, size_t len, bool storeLeases = true,
LeaseSet2 (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret = nullptr, CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL);
LeaseSet2(const uint8_t *buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
const uint8_t *secret = nullptr,
CryptoKeyType preferredCrypto = CRYPTO_KEY_TYPE_ELGAMAL); // store type 5, called from local netdb only
uint8_t GetStoreType() const { return m_StoreType; }; uint8_t GetStoreType() const { return m_StoreType; };
uint32_t GetPublishedTimestamp() const { return m_PublishedTimestamp; }; uint32_t GetPublishedTimestamp() const { return m_PublishedTimestamp; };
bool IsPublic() const { return m_IsPublic; }; bool IsPublic() const { return m_IsPublic; };
bool IsPublishedEncrypted() const { return m_IsPublishedEncrypted; }; bool IsPublishedEncrypted() const { return m_IsPublishedEncrypted; };
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier() const { return m_TransientVerifier; }; std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier() const { return m_TransientVerifier; };
void Update(const uint8_t *buf, size_t len, bool verifySignature); void Update(const uint8_t *buf, size_t len, bool verifySignature);
bool IsNewer(const uint8_t *buf, size_t len) const; bool IsNewer(const uint8_t *buf, size_t len) const;
// implements RoutingDestination // implements RoutingDestination
void Encrypt(const uint8_t *data, uint8_t *encrypted) const; void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
CryptoKeyType GetEncryptionType() const { return m_EncryptionType; }; CryptoKeyType GetEncryptionType() const { return m_EncryptionType; };
private: private:
void ReadFromBuffer(const uint8_t *buf, size_t len, bool readIdentity = true, bool verifySignature = true); void ReadFromBuffer(const uint8_t *buf, size_t len, bool readIdentity = true, bool verifySignature = true);
void ReadFromBufferEncrypted (const uint8_t * buf, size_t len, std::shared_ptr<const BlindedPublicKey> key, const uint8_t * secret);
void ReadFromBufferEncrypted(const uint8_t *buf, size_t len, std::shared_ptr<const BlindedPublicKey> key,
const uint8_t *secret);
size_t ReadStandardLS2TypeSpecificPart(const uint8_t *buf, size_t len); size_t ReadStandardLS2TypeSpecificPart(const uint8_t *buf, size_t len);
size_t ReadMetaLS2TypeSpecificPart(const uint8_t *buf, size_t len); size_t ReadMetaLS2TypeSpecificPart(const uint8_t *buf, size_t len);
template<typename Verifier> template<typename Verifier>
bool VerifySignature(Verifier &verifier, const uint8_t *buf, size_t len, size_t signatureOffset); bool VerifySignature(Verifier &verifier, const uint8_t *buf, size_t len, size_t signatureOffset);
uint64_t ExtractExpirationTimestamp(const uint8_t *buf, size_t len) const; uint64_t ExtractExpirationTimestamp(const uint8_t *buf, size_t len) const;
uint64_t ExtractPublishedTimestamp(const uint8_t *buf, size_t len, uint64_t &expiration) const; uint64_t ExtractPublishedTimestamp(const uint8_t *buf, size_t len, uint64_t &expiration) const;
size_t ExtractClientAuthData (const uint8_t * buf, size_t len, const uint8_t * secret, const uint8_t * subcredential, uint8_t * authCookie) const; // subcredential is subcredential + timestamp, return length of autData without flag
size_t
ExtractClientAuthData(const uint8_t *buf, size_t len, const uint8_t *secret, const uint8_t *subcredential,
uint8_t *authCookie) const; // subcredential is subcredential + timestamp, return length of autData without flag
private: private:
@ -185,18 +231,21 @@ namespace data
// 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) {
if (offset + 6 >= len) return nullptr; if (offset + 6 >= len) return nullptr;
const uint8_t *signedData = buf + offset; const uint8_t *signedData = buf + offset;
uint32_t expiresTimestamp = bufbe32toh (buf + offset); offset += 4; // expires timestamp uint32_t expiresTimestamp = bufbe32toh(buf + offset);
offset += 4; // expires timestamp
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch()) return nullptr; if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch()) return nullptr;
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; uint16_t keyType = bufbe16toh(buf + offset);
offset += 2;
std::shared_ptr<i2p::crypto::Verifier> transientVerifier(i2p::data::IdentityEx::CreateVerifier(keyType)); std::shared_ptr<i2p::crypto::Verifier> transientVerifier(i2p::data::IdentityEx::CreateVerifier(keyType));
if (!transientVerifier) return nullptr; if (!transientVerifier) return nullptr;
auto keyLen = transientVerifier->GetPublicKeyLen(); auto keyLen = transientVerifier->GetPublicKeyLen();
if (offset + keyLen >= len) return nullptr; if (offset + keyLen >= len) return nullptr;
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();
@ -204,31 +253,47 @@ namespace data
} }
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
class LocalLeaseSet class LocalLeaseSet {
{
public: public:
LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * encryptionPublicKey, std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels); LocalLeaseSet(std::shared_ptr<const IdentityEx> identity, const uint8_t *encryptionPublicKey,
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
LocalLeaseSet(std::shared_ptr<const IdentityEx> identity, const uint8_t *buf, size_t len); LocalLeaseSet(std::shared_ptr<const IdentityEx> identity, const uint8_t *buf, size_t len);
virtual ~LocalLeaseSet() { delete[] m_Buffer; }; virtual ~LocalLeaseSet() { delete[] m_Buffer; };
virtual uint8_t *GetBuffer() const { return m_Buffer; }; virtual uint8_t *GetBuffer() const { return m_Buffer; };
uint8_t *GetSignature() { return GetBuffer() + GetBufferLen() - GetSignatureLen(); }; uint8_t *GetSignature() { return GetBuffer() + GetBufferLen() - GetSignatureLen(); };
virtual size_t GetBufferLen() const { return m_BufferLen; }; virtual size_t GetBufferLen() const { return m_BufferLen; };
size_t GetSignatureLen() const { return m_Identity->GetSignatureLen(); }; size_t GetSignatureLen() const { return m_Identity->GetSignatureLen(); };
uint8_t *GetLeases() { return m_Leases; }; uint8_t *GetLeases() { return m_Leases; };
const IdentHash &GetIdentHash() const { return m_Identity->GetIdentHash(); }; const IdentHash &GetIdentHash() const { return m_Identity->GetIdentHash(); };
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; }; std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; };
bool IsExpired() const; bool IsExpired() const;
uint64_t GetExpirationTime() const { return m_ExpirationTime; }; uint64_t GetExpirationTime() const { return m_ExpirationTime; };
void SetExpirationTime(uint64_t expirationTime) { m_ExpirationTime = expirationTime; }; void SetExpirationTime(uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
bool operator== (const LeaseSet& other) const
{ return GetBufferLen () == other.GetBufferLen () && !memcmp (GetBuffer (), other.GetBuffer (), GetBufferLen ()); }; bool operator==(const LeaseSet &other) const {
return GetBufferLen() == other.GetBufferLen() && !memcmp(GetBuffer(), other.GetBuffer(),
GetBufferLen());
};
virtual uint8_t GetStoreType() const { return NETDB_STORE_TYPE_LEASESET; }; virtual uint8_t GetStoreType() const { return NETDB_STORE_TYPE_LEASESET; };
virtual const IdentHash& GetStoreHash () const { return GetIdentHash (); }; // differ from ident hash for encrypted LeaseSet2
virtual std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet () const { return nullptr; }; // non-null for encrypted LeaseSet2 virtual const IdentHash &
GetStoreHash() const { return GetIdentHash(); }; // differ from ident hash for encrypted LeaseSet2
virtual std::shared_ptr<const LocalLeaseSet>
GetInnerLeaseSet() const { return nullptr; }; // non-null for encrypted LeaseSet2
private: private:
@ -238,12 +303,10 @@ namespace data
size_t m_BufferLen; size_t m_BufferLen;
}; };
class LocalLeaseSet2: public LocalLeaseSet class LocalLeaseSet2 : public LocalLeaseSet {
{
public: public:
struct KeySection struct KeySection {
{
uint16_t keyType, keyLen; uint16_t keyType, keyLen;
const uint8_t *encryptionPublicKey; const uint8_t *encryptionPublicKey;
}; };
@ -254,18 +317,22 @@ namespace data
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels, const 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; };
uint8_t GetStoreType() const { return m_Buffer[0]; }; uint8_t GetStoreType() const { return m_Buffer[0]; };
protected: protected:
LocalLeaseSet2 (std::shared_ptr<const IdentityEx> identity): LocalLeaseSet (identity, nullptr, 0), m_Buffer (nullptr), m_BufferLen(0) {}; // called from LocalEncryptedLeaseSet2 LocalLeaseSet2(std::shared_ptr<const IdentityEx> identity) : LocalLeaseSet(identity, nullptr, 0),
m_Buffer(nullptr), m_BufferLen(
0) {}; // called from LocalEncryptedLeaseSet2
protected: protected:
@ -280,20 +347,25 @@ namespace data
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
const IdentHash &GetStoreHash() const { return m_StoreHash; }; const IdentHash &GetStoreHash() const { return m_StoreHash; };
std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet() const { return m_InnerLeaseSet; }; std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet() const { return m_InnerLeaseSet; };
private: private:
void CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const; void CreateClientAuthData(const uint8_t *subcredential, int authType,
std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t *authCookie,
uint8_t *authData) const;
private: private:

View file

@ -34,41 +34,35 @@ struct BigEndian;
// Little-Endian template // Little-Endian template
#pragma pack(push, 1) #pragma pack(push, 1)
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) {
{
for (unsigned i = 0; i < sizeof(T); i++) for (unsigned i = 0; i < sizeof(T); i++)
bytes[sizeof(T) - 1 - i] = static_cast<unsigned char>(t >> (i << 3)); bytes[sizeof(T) - 1 - i] = static_cast<unsigned char>(t >> (i << 3));
return t; return t;
@ -76,42 +70,34 @@ struct LittleEndian
// 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;
@ -119,17 +105,14 @@ struct LittleEndian
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;
@ -137,46 +120,41 @@ struct LittleEndian
return (*this); return (*this);
} }
}; };
#pragma pack(pop) #pragma pack(pop)
// Big-Endian template // Big-Endian template
#pragma pack(push, 1) #pragma pack(push, 1)
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;
@ -184,42 +162,34 @@ struct BigEndian
// 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;
@ -227,17 +197,14 @@ struct BigEndian
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;
@ -245,6 +212,7 @@ struct BigEndian
return (*this); return (*this);
} }
}; };
#pragma pack(pop) #pragma pack(pop)
#endif // LITTLEBIGENDIAN_H #endif // LITTLEBIGENDIAN_H

View file

@ -45,6 +45,7 @@ namespace log {
#endif #endif
#ifndef _WIN32 #ifndef _WIN32
/** /**
* @brief Maps our log levels to syslog one * @brief Maps our log levels to syslog one
* @return syslog priority LOG_*, as defined in syslog.h * @return syslog priority LOG_*, as defined in syslog.h
@ -52,42 +53,49 @@ namespace log {
static inline int GetSyslogPrio(enum LogLevel l) { static inline int GetSyslogPrio(enum LogLevel l) {
int priority = LOG_DEBUG; int priority = LOG_DEBUG;
switch (l) { switch (l) {
case eLogNone : priority = LOG_CRIT; break; case eLogNone :
case eLogError : priority = LOG_ERR; break; priority = LOG_CRIT;
case eLogWarning : priority = LOG_WARNING; break; break;
case eLogInfo : priority = LOG_INFO; break; case eLogError :
case eLogDebug : priority = LOG_DEBUG; break; priority = LOG_ERR;
default : priority = LOG_DEBUG; break; break;
case eLogWarning :
priority = LOG_WARNING;
break;
case eLogInfo :
priority = LOG_INFO;
break;
case eLogDebug :
priority = LOG_DEBUG;
break;
default :
priority = LOG_DEBUG;
break;
} }
return priority; return priority;
} }
#endif #endif
Log::Log() : Log::Log() :
m_Destination(eLogStdout), m_MinLevel(eLogInfo), m_Destination(eLogStdout), m_MinLevel(eLogInfo),
m_LogStream(nullptr), m_Logfile(""), m_HasColors(true), m_TimeFormat("%H:%M:%S"), m_LogStream(nullptr), m_Logfile(""), m_HasColors(true), m_TimeFormat("%H:%M:%S"),
m_IsRunning (false), m_Thread (nullptr) m_IsRunning(false), m_Thread(nullptr) {
{
} }
Log::~Log () Log::~Log() {
{
delete m_Thread; delete m_Thread;
} }
void Log::Start () void Log::Start() {
{ if (!m_IsRunning) {
if (!m_IsRunning)
{
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread(std::bind(&Log::Run, this)); m_Thread = new std::thread(std::bind(&Log::Run, this));
} }
} }
void Log::Stop () void Log::Stop() {
{ switch (m_Destination) {
switch (m_Destination)
{
#ifndef _WIN32 #ifndef _WIN32
case eLogSyslog : case eLogSyslog :
closelog(); closelog();
@ -103,8 +111,7 @@ namespace log {
} }
m_IsRunning = false; m_IsRunning = false;
m_Queue.WakeUp(); m_Queue.WakeUp();
if (m_Thread) if (m_Thread) {
{
m_Thread->join(); m_Thread->join();
delete m_Thread; delete m_Thread;
m_Thread = nullptr; m_Thread = nullptr;
@ -148,8 +155,7 @@ namespace log {
* Unfortunately, with current startup process with late fork() this * Unfortunately, with current startup process with late fork() this
* will give us nothing but pain. Maybe later. See in NetDb as example. * will give us nothing but pain. Maybe later. See in NetDb as example.
*/ */
void Log::Process(std::shared_ptr<LogMsg> msg) void Log::Process(std::shared_ptr <LogMsg> msg) {
{
if (!msg) return; if (!msg) return;
std::hash <std::thread::id> hasher; std::hash <std::thread::id> hasher;
unsigned short short_tid; unsigned short short_tid;
@ -172,19 +178,18 @@ namespace log {
default: default:
std::cout << TimeAsString(msg->timestamp) std::cout << TimeAsString(msg->timestamp)
<< "@" << short_tid << "@" << short_tid
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels] << "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level]
<< LogMsgColors[eNumLogLevels]
<< " - " << msg->text << std::endl; << " - " << msg->text << std::endl;
break; break;
} // switch } // switch
} }
void Log::Run () void Log::Run() {
{
i2p::util::SetThreadName("Logging"); i2p::util::SetThreadName("Logging");
Reopen(); Reopen();
while (m_IsRunning) while (m_IsRunning) {
{
std::shared_ptr <LogMsg> msg; std::shared_ptr <LogMsg> msg;
while ((msg = m_Queue.Get())) while ((msg = m_Queue.Get()))
Process(msg); Process(msg);
@ -194,18 +199,15 @@ namespace log {
} }
} }
void Log::Append(std::shared_ptr<i2p::log::LogMsg> & msg) void Log::Append(std::shared_ptr <i2p::log::LogMsg> &msg) {
{
m_Queue.Put(msg); m_Queue.Put(msg);
} }
void Log::SendTo (const std::string& path) void Log::SendTo(const std::string &path) {
{
if (m_LogStream) m_LogStream = nullptr; // close previous if (m_LogStream) m_LogStream = nullptr; // close previous
auto flags = std::ofstream::out | std::ofstream::app; auto flags = std::ofstream::out | std::ofstream::app;
auto os = std::make_shared<std::ofstream>(path, flags); auto os = std::make_shared<std::ofstream>(path, flags);
if (os->is_open ()) if (os->is_open()) {
{
m_HasColors = false; m_HasColors = false;
m_Logfile = path; m_Logfile = path;
m_Destination = eLogFile; m_Destination = eLogFile;
@ -222,6 +224,7 @@ namespace log {
} }
#ifndef _WIN32 #ifndef _WIN32
void Log::SendTo(const char *name, int facility) { void Log::SendTo(const char *name, int facility) {
if (m_MinLevel == eLogNone) return; if (m_MinLevel == eLogNone) return;
m_HasColors = false; m_HasColors = false;
@ -229,6 +232,7 @@ namespace log {
m_LogStream = nullptr; m_LogStream = nullptr;
openlog(name, LOG_CONS | LOG_PID, facility); openlog(name, LOG_CONS | LOG_PID, facility);
} }
#endif #endif
void Log::Reopen() { void Log::Reopen() {
@ -241,7 +245,9 @@ 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

View file

@ -21,11 +21,12 @@
#include "Queue.h" #include "Queue.h"
#ifndef _WIN32 #ifndef _WIN32
#include <syslog.h> #include <syslog.h>
#endif #endif
enum LogLevel enum LogLevel {
{
eLogNone = 0, eLogNone = 0,
eLogError, eLogError,
eLogWarning, eLogWarning,
@ -48,8 +49,7 @@ namespace log {
struct LogMsg; /* forward declaration */ struct LogMsg; /* forward declaration */
class Log class Log {
{
private: private:
enum LogType m_Destination; enum LogType m_Destination;
@ -58,7 +58,8 @@ namespace log {
std::string m_Logfile; std::string m_Logfile;
std::time_t m_LastTimestamp; std::time_t m_LastTimestamp;
char m_LastDateTime[64]; char m_LastDateTime[64];
i2p::util::Queue<std::shared_ptr<LogMsg> > m_Queue; i2p::util::Queue<std::shared_ptr < LogMsg> >
m_Queue;
bool m_HasColors; bool m_HasColors;
std::string m_TimeFormat; std::string m_TimeFormat;
volatile bool m_IsRunning; volatile bool m_IsRunning;
@ -68,9 +69,11 @@ namespace log {
/** prevent making copies */ /** prevent making copies */
Log(const Log &); Log(const Log &);
const Log &operator=(const Log &); const Log &operator=(const Log &);
void Run(); void Run();
void Process(std::shared_ptr <LogMsg> msg); void Process(std::shared_ptr <LogMsg> msg);
/** /**
@ -84,12 +87,15 @@ namespace log {
public: public:
Log(); Log();
~Log(); ~Log();
LogType GetLogType() { return m_Destination; }; LogType GetLogType() { return m_Destination; };
LogLevel GetLogLevel() { return m_MinLevel; }; LogLevel GetLogLevel() { return m_MinLevel; };
void Start(); void Start();
void Stop(); void Stop();
/** /**
@ -117,12 +123,14 @@ namespace log {
void SetTimeFormat(std::string format) { m_TimeFormat = format; }; void SetTimeFormat(std::string format) { m_TimeFormat = format; };
#ifndef _WIN32 #ifndef _WIN32
/** /**
* @brief Sets log destination to syslog * @brief Sets log destination to syslog
* @param name Wanted program name * @param name Wanted program name
* @param facility Wanted log category * @param facility Wanted log category
*/ */
void SendTo(const char *name, int facility); void SendTo(const char *name, int facility);
#endif #endif
/** /**
@ -154,25 +162,35 @@ namespace log {
Log &Logger(); Log &Logger();
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 } // 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>
void LogPrint (std::stringstream& s, TValue&& arg) noexcept void LogPrint(std::stringstream &s, TValue &&arg)
noexcept
{ {
s << std::forward<TValue>(arg); s <<
std::forward<TValue>(arg);
} }
#if (__cplusplus < 201703L) // below C++ 17 #if (__cplusplus < 201703L) // below C++ 17
/** internal usage only -- folding args array to single string */ /** internal usage only -- folding args array to single string */
template<typename TValue, typename... TArgs> template<typename TValue, typename... TArgs>
void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept void LogPrint(std::stringstream &s, TValue &&arg, TArgs &&... args)
noexcept
{ {
LogPrint (s, std::forward<TValue>(arg)); LogPrint (s, std::forward<TValue>(arg)
LogPrint (s, std::forward<TArgs>(args)...); );
LogPrint (s, std::forward<TArgs>(args)
...);
} }
#endif #endif
@ -182,10 +200,16 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
* @param args Array of message parts * @param args Array of message parts
*/ */
template<typename... TArgs> template<typename... TArgs>
void LogPrint (LogLevel level, TArgs&&... args) noexcept void LogPrint(LogLevel level, TArgs &&... args)
noexcept
{ {
i2p::log::Log &log = i2p::log::Logger(); i2p::log::Log &log = i2p::log::Logger();
if (level > log.GetLogLevel ()) if (level > log.
GetLogLevel()
)
return; return;
// fold message to single string // fold message to single string
@ -194,12 +218,15 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
(LogPrint (ss, std::forward<TArgs>(args)), ...); (LogPrint (ss, std::forward<TArgs>(args)), ...);
#else #else
LogPrint (ss, std::forward<TArgs>(args)...); LogPrint (ss, std::forward<TArgs>(args)
...);
#endif #endif
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str()); auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
msg->tid = std::this_thread::get_id(); msg->
log.Append(msg); tid = std::this_thread::get_id();
log.
Append(msg);
} }
/** /**
@ -207,7 +234,9 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
* @param args Array of message parts * @param args Array of message parts
*/ */
template<typename... TArgs> template<typename... TArgs>
void ThrowFatal (TArgs&&... args) noexcept void ThrowFatal(TArgs &&... args)
noexcept
{ {
auto f = i2p::log::GetThrowFunction(); auto f = i2p::log::GetThrowFunction();
if (!f) return; if (!f) return;
@ -216,9 +245,15 @@ void ThrowFatal (TArgs&&... args) noexcept
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
(LogPrint (ss, std::forward<TArgs>(args)), ...); (LogPrint (ss, std::forward<TArgs>(args)), ...);
#else #else
LogPrint (ss, std::forward<TArgs>(args)...); LogPrint (ss, std::forward<TArgs>(args)
...);
#endif #endif
f (ss.str ()); f (ss
.
str()
);
} }
#endif // LOG_H__ #endif // LOG_H__

File diff suppressed because it is too large Load diff

View file

@ -22,10 +22,8 @@
#include "RouterInfo.h" #include "RouterInfo.h"
#include "TransportSession.h" #include "TransportSession.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519; const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287; const size_t NTCP2_SESSION_REQUEST_MAX_SIZE = 287;
@ -43,8 +41,7 @@ namespace transport
const int NTCP2_CLOCK_SKEW = 60; // in seconds const int NTCP2_CLOCK_SKEW = 60; // in seconds
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
enum NTCP2BlockType enum NTCP2BlockType {
{
eNTCP2BlkDateTime = 0, eNTCP2BlkDateTime = 0,
eNTCP2BlkOptions, // 1 eNTCP2BlkOptions, // 1
eNTCP2BlkRouterInfo, // 2 eNTCP2BlkRouterInfo, // 2
@ -53,8 +50,7 @@ namespace transport
eNTCP2BlkPadding = 254 eNTCP2BlkPadding = 254
}; };
enum NTCP2TerminationReason enum NTCP2TerminationReason {
{
eNTCP2NormalClose = 0, eNTCP2NormalClose = 0,
eNTCP2TerminationReceived, // 1 eNTCP2TerminationReceived, // 1
eNTCP2IdleTimeout, // 2 eNTCP2IdleTimeout, // 2
@ -78,38 +74,53 @@ namespace transport
// RouterInfo flags // RouterInfo flags
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
struct NTCP2Establisher: private i2p::crypto::NoiseSymmetricState struct NTCP2Establisher : private i2p::crypto::NoiseSymmetricState {
{
NTCP2Establisher(); NTCP2Establisher();
~NTCP2Establisher(); ~NTCP2Establisher();
const uint8_t *GetPub() const { return m_EphemeralKeys->GetPublicKey(); }; const uint8_t *GetPub() const { return m_EphemeralKeys->GetPublicKey(); };
const uint8_t *GetRemotePub() const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob const uint8_t *GetRemotePub() const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob
uint8_t *GetRemotePub() { return m_RemoteEphemeralPublicKey; }; // to set uint8_t *GetRemotePub() { return m_RemoteEphemeralPublicKey; }; // to set
const uint8_t *GetK() const { return m_CK + 32; }; const uint8_t *GetK() const { return m_CK + 32; };
const uint8_t *GetCK() const { return m_CK; }; const uint8_t *GetCK() const { return m_CK; };
const uint8_t *GetH() const { return m_H; }; const uint8_t *GetH() const { return m_H; };
void KDF1Alice(); void KDF1Alice();
void KDF1Bob(); void KDF1Bob();
void KDF2Alice(); void KDF2Alice();
void KDF2Bob(); void KDF2Bob();
void KDF3Alice(); // for SessionConfirmed part 2 void KDF3Alice(); // for SessionConfirmed part 2
void KDF3Bob(); void KDF3Bob();
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH void KeyDerivationFunction1(const uint8_t *pub, i2p::crypto::X25519Keys &priv, const uint8_t *rs,
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate const uint8_t *epub); // for SessionRequest, (pub, priv) for DH
void KeyDerivationFunction2(const uint8_t *sessionRequest, size_t sessionRequestLen,
const uint8_t *epub); // for SessionCreate
void CreateEphemeralKey(); void CreateEphemeralKey();
void CreateSessionRequestMessage(); void CreateSessionRequestMessage();
void CreateSessionCreatedMessage(); void CreateSessionCreatedMessage();
void CreateSessionConfirmedMessagePart1(const uint8_t *nonce); void CreateSessionConfirmedMessagePart1(const uint8_t *nonce);
void CreateSessionConfirmedMessagePart2(const uint8_t *nonce); void CreateSessionConfirmedMessagePart2(const uint8_t *nonce);
bool ProcessSessionRequestMessage(uint16_t &paddingLen, bool &clockSkew); bool ProcessSessionRequestMessage(uint16_t &paddingLen, bool &clockSkew);
bool ProcessSessionCreatedMessage(uint16_t &paddingLen); bool ProcessSessionCreatedMessage(uint16_t &paddingLen);
bool ProcessSessionConfirmedMessagePart1(const uint8_t *nonce); bool ProcessSessionConfirmedMessagePart1(const uint8_t *nonce);
bool ProcessSessionConfirmedMessagePart2(const uint8_t *nonce, uint8_t *m3p2Buf); bool ProcessSessionConfirmedMessagePart2(const uint8_t *nonce, uint8_t *m3p2Buf);
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys; std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
@ -125,24 +136,32 @@ namespace transport
}; };
class NTCP2Server; class NTCP2Server;
class NTCP2Session: public TransportSession, public std::enable_shared_from_this<NTCP2Session>
{ class NTCP2Session : public TransportSession, public std::enable_shared_from_this<NTCP2Session> {
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,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr); std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
~NTCP2Session(); ~NTCP2Session();
void Terminate(); void Terminate();
void TerminateByTimeout(); void TerminateByTimeout();
void Done(); void Done();
void Close() { m_Socket.close(); }; // for accept void Close() { m_Socket.close(); }; // for accept
void DeleteNextReceiveBuffer(uint64_t ts); void DeleteNextReceiveBuffer(uint64_t ts);
boost::asio::ip::tcp::socket &GetSocket() { return m_Socket; }; boost::asio::ip::tcp::socket &GetSocket() { return m_Socket; };
const boost::asio::ip::tcp::endpoint &GetRemoteEndpoint() { return m_RemoteEndpoint; }; const boost::asio::ip::tcp::endpoint &GetRemoteEndpoint() { return m_RemoteEndpoint; };
void SetRemoteEndpoint(const boost::asio::ip::tcp::endpoint &ep) { m_RemoteEndpoint = ep; }; void SetRemoteEndpoint(const boost::asio::ip::tcp::endpoint &ep) { m_RemoteEndpoint = ep; };
bool IsEstablished() const { return m_IsEstablished; }; bool IsEstablished() const { return m_IsEstablished; };
bool IsTerminated() const { return m_IsTerminated; }; bool IsTerminated() const { return m_IsTerminated; };
void ClientLogin(); // Alice void ClientLogin(); // Alice
@ -156,41 +175,70 @@ namespace transport
void Established(); void Established();
void CreateNonce(uint64_t seqn, uint8_t *nonce); void CreateNonce(uint64_t seqn, uint8_t *nonce);
void CreateNextReceivedBuffer(size_t size); void CreateNextReceivedBuffer(size_t size);
void KeyDerivationFunctionDataPhase(); void KeyDerivationFunctionDataPhase();
void SetSipKeys(const uint8_t *sendSipKey, const uint8_t *receiveSipKey); void SetSipKeys(const uint8_t *sendSipKey, const uint8_t *receiveSipKey);
// establish // establish
void SendSessionRequest(); void SendSessionRequest();
void SendSessionCreated(); void SendSessionCreated();
void SendSessionConfirmed(); void SendSessionConfirmed();
void HandleSessionRequestSent(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionRequestSent(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionRequestReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionRequestReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void
HandleSessionRequestPaddingReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionCreatedSent(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionCreatedSent(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionCreatedReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionCreatedReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void
HandleSessionCreatedPaddingReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionConfirmedSent(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionConfirmedSent(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void HandleSessionConfirmedReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleSessionConfirmedReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
// data // data
void ReceiveLength(); void ReceiveLength();
void HandleReceivedLength(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleReceivedLength(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void Receive(); void Receive();
void HandleReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
void ProcessNextFrame(const uint8_t *frame, size_t len); void ProcessNextFrame(const uint8_t *frame, size_t len);
void SetNextSentFrameLength(size_t frameLen, uint8_t *lengthBuf); void SetNextSentFrameLength(size_t frameLen, uint8_t *lengthBuf);
void SendI2NPMsgs(std::vector<std::shared_ptr<I2NPMessage> > &msgs); void SendI2NPMsgs(std::vector<std::shared_ptr<I2NPMessage> > &msgs);
void HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs);
void HandleI2NPMsgsSent(const boost::system::error_code &ecode, std::size_t bytes_transferred,
std::vector<std::shared_ptr<I2NPMessage> > msgs);
void EncryptAndSendNextBuffer(size_t payloadLen); void EncryptAndSendNextBuffer(size_t payloadLen);
void HandleNextFrameSent(const boost::system::error_code &ecode, std::size_t bytes_transferred); void HandleNextFrameSent(const boost::system::error_code &ecode, std::size_t bytes_transferred);
size_t CreatePaddingBlock(size_t msgLen, uint8_t *buf, size_t len); size_t CreatePaddingBlock(size_t msgLen, uint8_t *buf, size_t len);
void SendQueue(); void SendQueue();
void SendRouterInfo(); void SendRouterInfo();
void SendTermination(NTCP2TerminationReason reason); void SendTermination(NTCP2TerminationReason reason);
void SendTerminationAndTerminate(NTCP2TerminationReason reason); void SendTerminationAndTerminate(NTCP2TerminationReason reason);
void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs); void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs);
private: private:
@ -212,8 +260,7 @@ namespace transport
uint16_t m_NextReceivedLen; uint16_t m_NextReceivedLen;
uint8_t *m_NextReceivedBuffer, *m_NextSendBuffer; uint8_t *m_NextReceivedBuffer, *m_NextSendBuffer;
size_t m_NextReceivedBufferSize; size_t m_NextReceivedBufferSize;
union union {
{
uint8_t buf[8]; uint8_t buf[8];
uint16_t key; uint16_t key;
} m_ReceiveIV, m_SendIV; } m_ReceiveIV, m_SendIV;
@ -229,47 +276,60 @@ namespace transport
int m_NextPaddingSize; int m_NextPaddingSize;
}; };
class NTCP2Server: private i2p::util::RunnableServiceWithWork class NTCP2Server : private i2p::util::RunnableServiceWithWork {
{
public: public:
enum ProxyType enum ProxyType {
{
eNoProxy, eNoProxy,
eSocksProxy, eSocksProxy,
eHTTPProxy eHTTPProxy
}; };
NTCP2Server(); NTCP2Server();
~NTCP2Server(); ~NTCP2Server();
void Start(); void Start();
void Stop(); void Stop();
boost::asio::io_service &GetService() { return GetIOService(); }; boost::asio::io_service &GetService() { return GetIOService(); };
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);
std::shared_ptr<NTCP2Session> FindNTCP2Session(const i2p::data::IdentHash &ident); std::shared_ptr<NTCP2Session> FindNTCP2Session(const i2p::data::IdentHash &ident);
void ConnectWithProxy(std::shared_ptr<NTCP2Session> conn); void ConnectWithProxy(std::shared_ptr<NTCP2Session> conn);
void Connect(std::shared_ptr<NTCP2Session> conn); void Connect(std::shared_ptr<NTCP2Session> conn);
bool UsingProxy() const { return m_ProxyType != eNoProxy; }; bool UsingProxy() const { return m_ProxyType != eNoProxy; };
void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass);
void UseProxy(ProxyType proxy, const std::string &address, uint16_t port, const std::string &user,
const std::string &pass);
void SetLocalAddress(const boost::asio::ip::address &localAddress); void SetLocalAddress(const boost::asio::ip::address &localAddress);
private: private:
void HandleAccept(std::shared_ptr<NTCP2Session> conn, const boost::system::error_code &error); void HandleAccept(std::shared_ptr<NTCP2Session> conn, const boost::system::error_code &error);
void HandleAcceptV6(std::shared_ptr<NTCP2Session> conn, const boost::system::error_code &error); void HandleAcceptV6(std::shared_ptr<NTCP2Session> conn, const boost::system::error_code &error);
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect(const boost::system::error_code &ecode, std::shared_ptr<NTCP2Session> conn,
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); std::shared_ptr<boost::asio::deadline_timer> timer);
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleProxyConnect(const boost::system::error_code &ecode, std::shared_ptr<NTCP2Session> conn,
std::shared_ptr<boost::asio::deadline_timer> timer);
void
AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
// timer // timer
void ScheduleTermination(); void ScheduleTermination();
void HandleTerminationTimer(const boost::system::error_code &ecode); void HandleTerminationTimer(const boost::system::error_code &ecode);
private: private:
@ -289,7 +349,10 @@ namespace transport
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl
const decltype(m_NTCP2Sessions)& GetNTCP2Sessions () const { return m_NTCP2Sessions; }; const decltype(m_NTCP2Sessions)
&
GetNTCP2Sessions() const { return m_NTCP2Sessions; };
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -32,10 +32,8 @@
#include "version.h" #include "version.h"
#include "util.h" #include "util.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_ROUTERS = 90;
const int NETDB_MIN_FLOODFILLS = 5; const int NETDB_MIN_FLOODFILLS = 5;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60 * 60; // 1 hour, in seconds
@ -59,46 +57,81 @@ namespace data
/** function for visiting a router info and determining if we want to use it */ /** function for visiting a router info and determining if we want to use it */
typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter; typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter;
class NetDb class NetDb {
{
public: public:
NetDb(); NetDb();
~NetDb(); ~NetDb();
void Start(); void Start();
void Stop(); void Stop();
std::shared_ptr<const RouterInfo> AddRouterInfo(const uint8_t *buf, int len); std::shared_ptr<const RouterInfo> AddRouterInfo(const uint8_t *buf, int len);
bool AddRouterInfo(const IdentHash &ident, const uint8_t *buf, int len); bool AddRouterInfo(const IdentHash &ident, const uint8_t *buf, int len);
bool AddLeaseSet(const IdentHash &ident, const uint8_t *buf, int len); bool AddLeaseSet(const IdentHash &ident, const uint8_t *buf, int len);
bool AddLeaseSet2(const IdentHash &ident, const uint8_t *buf, int len, uint8_t storeType); bool AddLeaseSet2(const IdentHash &ident, const uint8_t *buf, int len, uint8_t storeType);
std::shared_ptr<RouterInfo> FindRouter(const IdentHash &ident) const; std::shared_ptr<RouterInfo> FindRouter(const IdentHash &ident) const;
std::shared_ptr<LeaseSet> FindLeaseSet(const IdentHash &destination) const; std::shared_ptr<LeaseSet> FindLeaseSet(const IdentHash &destination) const;
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, bool direct = true); void RequestDestination(const IdentHash &destination,
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); RequestedDestination::RequestComplete requestComplete = nullptr,
bool direct = true);
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);
void HandleDeliveryStatusMsg(std::shared_ptr<const I2NPMessage> msg); void HandleDeliveryStatusMsg(std::shared_ptr<const I2NPMessage> msg);
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, bool reverse) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo>
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const; GetRandomRouter(std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo>
GetHighBandwidthRandomRouter(std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo>
GetRandomPeerTestRouter(bool v4, const std::set<IdentHash> &excluded) const;
std::shared_ptr<const RouterInfo>
GetRandomSSU2PeerTestRouter(bool v4, const std::set<IdentHash> &excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSUV6Router() const; // TODO: change to v6 peer test later std::shared_ptr<const RouterInfo> GetRandomSSUV6Router() const; // TODO: change to v6 peer test later
std::shared_ptr<const RouterInfo> GetRandomIntroducer(bool v4, const std::set<IdentHash> &excluded) const; std::shared_ptr<const RouterInfo> GetRandomIntroducer(bool v4, const std::set<IdentHash> &excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2Introducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::shared_ptr<const RouterInfo>
GetRandomSSU2Introducer(bool v4, const std::set<IdentHash> &excluded) const;
std::shared_ptr<const RouterInfo>
GetClosestFloodfill(const IdentHash &destination, const std::set<IdentHash> &excluded,
bool closeThanUsOnly = false) const;
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,
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo>
GetClosestNonFloodfill(const IdentHash &destination, const std::set<IdentHash> &excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(FamilyID fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(FamilyID 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);
@ -107,25 +140,35 @@ namespace data
void SetHidden(bool hide); void SetHidden(bool hide);
void Reseed(); void Reseed();
Families &GetFamilies() { return m_Families; }; Families &GetFamilies() { return m_Families; };
// for web interface // for web interface
int GetNumRouters() const { return m_RouterInfos.size(); }; int GetNumRouters() const { return m_RouterInfos.size(); };
int GetNumFloodfills() const { return m_Floodfills.size(); }; int GetNumFloodfills() const { return m_Floodfills.size(); };
int GetNumLeaseSets() const { return m_LeaseSets.size(); }; int GetNumLeaseSets() const { return m_LeaseSets.size(); };
/** visit all lease sets we currently store */ /** visit all lease sets we currently store */
void VisitLeaseSets(LeaseSetVisitor v); void VisitLeaseSets(LeaseSetVisitor v);
/** visit all router infos we have currently on disk, usually insanely expensive, does not access in memory RI */ /** visit all router infos we have currently on disk, usually insanely expensive, does not access in memory RI */
void VisitStoredRouterInfos(RouterInfoVisitor v); void VisitStoredRouterInfos(RouterInfoVisitor v);
/** visit all router infos we have loaded in memory, cheaper than VisitLocalRouterInfos but locks access while visiting */ /** visit all router infos we have loaded in memory, cheaper than VisitLocalRouterInfos but locks access while visiting */
void VisitRouterInfos(RouterInfoVisitor v); void VisitRouterInfos(RouterInfoVisitor v);
/** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
void ClearRouterInfos() { m_RouterInfos.clear(); }; void ClearRouterInfos() { m_RouterInfos.clear(); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
std::shared_ptr<RouterInfo::Buffer>
NewRouterInfoBuffer() { return m_RouterInfoBuffersPool.AcquireSharedMt(); };
void PopulateRouterInfoBuffer(std::shared_ptr<RouterInfo> r); void PopulateRouterInfoBuffer(std::shared_ptr<RouterInfo> r);
std::shared_ptr<Lease> NewLease(const Lease &lease) { return m_LeasesPool.AcquireSharedMt(lease); }; std::shared_ptr<Lease> NewLease(const Lease &lease) { return m_LeasesPool.AcquireSharedMt(lease); };
uint32_t GetPublishReplyToken() const { return m_PublishReplyToken; }; uint32_t GetPublishReplyToken() const { return m_PublishReplyToken; };
@ -133,19 +176,28 @@ namespace data
private: private:
void Load(); void Load();
bool LoadRouterInfo(const std::string &path, uint64_t ts); bool LoadRouterInfo(const std::string &path, uint64_t ts);
void SaveUpdated(); void SaveUpdated();
void Run(); // exploratory thread void Run(); // exploratory thread
void Explore(int numDestinations); void Explore(int numDestinations);
void Publish(); void Publish();
void Flood(const IdentHash &ident, std::shared_ptr<I2NPMessage> floodMsg); void Flood(const IdentHash &ident, std::shared_ptr<I2NPMessage> floodMsg);
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> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter(Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter(Filter filter) const;
@ -169,6 +221,7 @@ namespace data
i2p::fs::HashedStorage m_Storage; i2p::fs::HashedStorage m_Storage;
friend class NetDbRequests; friend class NetDbRequests;
NetDbRequests m_Requests; NetDbRequests m_Requests;
bool m_PersistProfiles; bool m_PersistProfiles;

View file

@ -12,70 +12,64 @@
#include "NetDb.hpp" #include "NetDb.hpp"
#include "NetDbRequests.h" #include "NetDbRequests.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data std::shared_ptr<I2NPMessage>
{ RequestedDestination::CreateRequestMessage(std::shared_ptr<const RouterInfo> router,
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) {
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{
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)
m_ExcludedPeers.insert(router->GetIdentHash()); m_ExcludedPeers.insert(router->GetIdentHash());
m_CreationTime = i2p::util::GetSecondsSinceEpoch(); m_CreationTime = i2p::util::GetSecondsSinceEpoch();
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage(const IdentHash &floodfill) {
{
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); i2p::context.GetRouterInfo().GetIdentHash(), 0, false,
&m_ExcludedPeers);
m_ExcludedPeers.insert(floodfill); m_ExcludedPeers.insert(floodfill);
m_CreationTime = i2p::util::GetSecondsSinceEpoch(); m_CreationTime = i2p::util::GetSecondsSinceEpoch();
return msg; return msg;
} }
void RequestedDestination::ClearExcludedPeers () void RequestedDestination::ClearExcludedPeers() {
{
m_ExcludedPeers.clear(); m_ExcludedPeers.clear();
} }
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r) void RequestedDestination::Success(std::shared_ptr<RouterInfo> r) {
{ if (m_RequestComplete) {
if (m_RequestComplete)
{
m_RequestComplete(r); m_RequestComplete(r);
m_RequestComplete = nullptr; m_RequestComplete = nullptr;
} }
} }
void RequestedDestination::Fail () void RequestedDestination::Fail() {
{ if (m_RequestComplete) {
if (m_RequestComplete)
{
m_RequestComplete(nullptr); m_RequestComplete(nullptr);
m_RequestComplete = nullptr; m_RequestComplete = nullptr;
} }
} }
void NetDbRequests::Start () void NetDbRequests::Start() {
{
} }
void NetDbRequests::Stop () void NetDbRequests::Stop() {
{
m_RequestedDestinations.clear(); m_RequestedDestinations.clear();
} }
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete) std::shared_ptr<RequestedDestination>
{ NetDbRequests::CreateRequest(const IdentHash &destination, bool isExploratory,
RequestedDestination::RequestComplete requestComplete) {
// request RouterInfo directly // request RouterInfo directly
auto dest = std::make_shared<RequestedDestination>(destination, isExploratory); auto dest = std::make_shared<RequestedDestination>(destination, isExploratory);
dest->SetRequestComplete(requestComplete); dest->SetRequestComplete(requestComplete);
@ -87,20 +81,17 @@ namespace data
return dest; return dest;
} }
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r) void NetDbRequests::RequestComplete(const IdentHash &ident, std::shared_ptr<RouterInfo> r) {
{
std::shared_ptr<RequestedDestination> request; std::shared_ptr<RequestedDestination> request;
{ {
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find(ident); auto it = m_RequestedDestinations.find(ident);
if (it != m_RequestedDestinations.end ()) if (it != m_RequestedDestinations.end()) {
{
request = it->second; request = it->second;
m_RequestedDestinations.erase(it); m_RequestedDestinations.erase(it);
} }
} }
if (request) if (request) {
{
if (r) if (r)
request->Success(r); request->Success(r);
else else
@ -108,8 +99,7 @@ namespace data
} }
} }
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest(const IdentHash &ident) const {
{
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find(ident); auto it = m_RequestedDestinations.find(ident);
if (it != m_RequestedDestinations.end()) if (it != m_RequestedDestinations.end())
@ -117,12 +107,10 @@ namespace data
return nullptr; return nullptr;
} }
void NetDbRequests::ManageRequests () void NetDbRequests::ManageRequests() {
{
uint64_t ts = i2p::util::GetSecondsSinceEpoch(); uint64_t ts = i2p::util::GetSecondsSinceEpoch();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) for (auto it = m_RequestedDestinations.begin(); it != m_RequestedDestinations.end();) {
{
auto &dest = it->second; auto &dest = it->second;
bool done = false; bool done = false;
if (ts < dest->GetCreationTime() + 60) // request is worthless after 1 minute if (ts < dest->GetCreationTime() + 60) // request is worthless after 1 minute
@ -130,32 +118,29 @@ namespace data
if (ts > dest->GetCreationTime() + 5) // no response for 5 seconds if (ts > dest->GetCreationTime() + 5) // no response for 5 seconds
{ {
auto count = dest->GetExcludedPeers().size(); auto count = dest->GetExcludedPeers().size();
if (!dest->IsExploratory () && count < 7) if (!dest->IsExploratory() && count < 7) {
{
auto pool = i2p::tunnel::tunnels.GetExploratoryPool(); auto pool = i2p::tunnel::tunnels.GetExploratoryPool();
auto outbound = pool->GetNextOutboundTunnel(); auto outbound = pool->GetNextOutboundTunnel();
auto inbound = pool->GetNextInboundTunnel(); auto inbound = pool->GetNextInboundTunnel();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); auto nextFloodfill = netdb.GetClosestFloodfill(dest->GetDestination(),
dest->GetExcludedPeers());
if (nextFloodfill && outbound && inbound) if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg(nextFloodfill->GetIdentHash(), 0, outbound->SendTunnelDataMsg(nextFloodfill->GetIdentHash(), 0,
dest->CreateRequestMessage(nextFloodfill, inbound)); dest->CreateRequestMessage(nextFloodfill, inbound));
else else {
{
done = true; done = true;
if (!inbound) LogPrint(eLogWarning, "NetDbReq: No inbound tunnels"); if (!inbound) LogPrint(eLogWarning, "NetDbReq: No inbound tunnels");
if (!outbound) LogPrint(eLogWarning, "NetDbReq: No outbound tunnels"); if (!outbound) LogPrint(eLogWarning, "NetDbReq: No outbound tunnels");
if (!nextFloodfill) LogPrint(eLogWarning, "NetDbReq: No more floodfills"); if (!nextFloodfill) LogPrint(eLogWarning, "NetDbReq: No more floodfills");
} }
} } else {
else
{
if (!dest->IsExploratory()) if (!dest->IsExploratory())
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); LogPrint(eLogWarning, "NetDbReq: ", dest->GetDestination().ToBase64(),
" not found after 7 attempts");
done = true; done = true;
} }
} }
} } else // delete obsolete request
else // delete obsolete request
done = true; done = true;
if (done) if (done)

View file

@ -15,33 +15,43 @@
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data class RequestedDestination {
{
class RequestedDestination
{
public: public:
typedef std::function<void(std::shared_ptr<RouterInfo>)> RequestComplete; typedef std::function<void(std::shared_ptr<RouterInfo>)> RequestComplete;
RequestedDestination(const IdentHash &destination, bool isExploratory = false) : RequestedDestination(const IdentHash &destination, bool isExploratory = false) :
m_Destination(destination), m_IsExploratory(isExploratory), m_CreationTime(0) {}; m_Destination(destination), m_IsExploratory(isExploratory), m_CreationTime(0) {};
~RequestedDestination() { if (m_RequestComplete) m_RequestComplete(nullptr); }; ~RequestedDestination() { if (m_RequestComplete) m_RequestComplete(nullptr); };
const IdentHash &GetDestination() const { return m_Destination; }; const IdentHash &GetDestination() const { return m_Destination; };
int GetNumExcludedPeers() const { return m_ExcludedPeers.size(); }; int GetNumExcludedPeers() const { return m_ExcludedPeers.size(); };
const std::set<IdentHash> &GetExcludedPeers() { return m_ExcludedPeers; }; const std::set<IdentHash> &GetExcludedPeers() { return m_ExcludedPeers; };
void ClearExcludedPeers(); void ClearExcludedPeers();
bool IsExploratory() const { return m_IsExploratory; }; bool IsExploratory() const { return m_IsExploratory; };
bool IsExcluded(const IdentHash &ident) const { return m_ExcludedPeers.count(ident); }; bool IsExcluded(const IdentHash &ident) const { return m_ExcludedPeers.count(ident); };
uint64_t GetCreationTime() const { return m_CreationTime; }; uint64_t GetCreationTime() const { return m_CreationTime; };
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
std::shared_ptr<I2NPMessage> CreateRequestMessage(std::shared_ptr<const RouterInfo>,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
std::shared_ptr<I2NPMessage> CreateRequestMessage(const IdentHash &floodfill); std::shared_ptr<I2NPMessage> CreateRequestMessage(const IdentHash &floodfill);
void SetRequestComplete(const RequestComplete &requestComplete) { m_RequestComplete = requestComplete; }; void SetRequestComplete(const RequestComplete &requestComplete) { m_RequestComplete = requestComplete; };
bool IsRequestComplete() const { return m_RequestComplete != nullptr; }; bool IsRequestComplete() const { return m_RequestComplete != nullptr; };
void Success(std::shared_ptr<RouterInfo> r); void Success(std::shared_ptr<RouterInfo> r);
void Fail(); void Fail();
private: private:
@ -53,16 +63,20 @@ namespace data
RequestComplete m_RequestComplete; RequestComplete m_RequestComplete;
}; };
class NetDbRequests class NetDbRequests {
{
public: public:
void Start(); void Start();
void Stop(); void Stop();
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr); std::shared_ptr<RequestedDestination> CreateRequest(const IdentHash &destination, bool isExploratory,
RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestComplete(const IdentHash &ident, std::shared_ptr<RouterInfo> r); void RequestComplete(const IdentHash &ident, std::shared_ptr<RouterInfo> r);
std::shared_ptr<RequestedDestination> FindRequest(const IdentHash &ident) const; std::shared_ptr<RequestedDestination> FindRequest(const IdentHash &ident) const;
void ManageRequests(); void ManageRequests();
private: private:

View file

@ -9,12 +9,9 @@
#include "Poly1305.h" #include "Poly1305.h"
#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);
p.Update(buf, sz); p.Update(buf, sz);
p.Finish(out); p.Finish(out);

View file

@ -8,52 +8,44 @@
#ifndef LIBI2PD_POLY1305_H #ifndef LIBI2PD_POLY1305_H
#define LIBI2PD_POLY1305_H #define LIBI2PD_POLY1305_H
#include <cstdint> #include <cstdint>
#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
{
const std::size_t POLY1305_DIGEST_BYTES = 16; const std::size_t POLY1305_DIGEST_BYTES = 16;
const std::size_t POLY1305_DIGEST_DWORDS = 4; const std::size_t POLY1305_DIGEST_DWORDS = 4;
const std::size_t POLY1305_KEY_BYTES = 32; const std::size_t POLY1305_KEY_BYTES = 32;
const std::size_t POLY1305_KEY_DWORDS = 8; const std::size_t POLY1305_KEY_DWORDS = 8;
const std::size_t POLY1305_BLOCK_BYTES = 16; const std::size_t POLY1305_BLOCK_BYTES = 16;
namespace poly1305 namespace poly1305 {
{ struct LongBlock {
struct LongBlock
{
unsigned long data[17]; unsigned long data[17];
operator unsigned long * ()
{ operator unsigned long *() {
return data; return data;
} }
}; };
struct Block struct Block {
{
unsigned char data[17]; unsigned char data[17];
void Zero() void Zero() {
{
memset(data, 0, sizeof(data)); memset(data, 0, sizeof(data));
} }
operator uint8_t * () operator uint8_t *() {
{
return data; return data;
} }
Block & operator += (const Block & other) Block &operator+=(const Block &other) {
{
unsigned short u; unsigned short u;
unsigned int i; unsigned int i;
for(u = 0, i = 0; i < 17; i++) for (u = 0, i = 0; i < 17; i++) {
{
u += (unsigned short) data[i] + (unsigned short) other.data[i]; u += (unsigned short) data[i] + (unsigned short) other.data[i];
data[i] = (unsigned char) u & 0xff; data[i] = (unsigned char) u & 0xff;
u >>= 8; u >>= 8;
@ -61,8 +53,7 @@ namespace crypto
return *this; return *this;
} }
Block & operator %=(const LongBlock & other) Block &operator%=(const LongBlock &other) {
{
unsigned long u; unsigned long u;
unsigned int i; unsigned int i;
u = 0; u = 0;
@ -84,14 +75,12 @@ namespace crypto
return *this; return *this;
} }
Block & operator = (const Block & other) Block &operator=(const Block &other) {
{
memcpy(data, other.data, sizeof(data)); memcpy(data, other.data, sizeof(data));
return *this; return *this;
} }
Block & operator ~ () Block &operator~() {
{
static const Block minusp = { static const Block minusp = {
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -109,8 +98,7 @@ namespace crypto
return *this; return *this;
} }
void PutKey(const uint64_t * key_l) void PutKey(const uint64_t *key_l) {
{
const uint8_t *key = (const uint8_t *) key_l; const uint8_t *key = (const uint8_t *) key_l;
data[0] = key[0] & 0xff; data[0] = key[0] & 0xff;
data[1] = key[1] & 0xff; data[1] = key[1] & 0xff;
@ -132,28 +120,23 @@ namespace crypto
} }
template<typename Int_t> template<typename Int_t>
void Put(const Int_t * d, uint8_t last=0) void Put(const Int_t *d, uint8_t last = 0) {
{
memcpy(data, d, 16); memcpy(data, d, 16);
data[16] = last; data[16] = last;
} }
}; };
struct Buffer struct Buffer {
{
uint8_t data[POLY1305_BLOCK_BYTES]; uint8_t data[POLY1305_BLOCK_BYTES];
operator uint8_t * () operator uint8_t *() {
{
return data; return data;
} }
}; };
} }
struct Poly1305 struct Poly1305 {
{ Poly1305(const uint64_t *key) {
Poly1305(const uint64_t * key)
{
m_Leftover = 0; m_Leftover = 0;
m_H.Zero(); m_H.Zero();
m_Final = 0; m_Final = 0;
@ -161,11 +144,9 @@ namespace crypto
m_Pad.Put(key + 2); m_Pad.Put(key + 2);
} }
void Update(const uint8_t * buf, size_t sz) void Update(const uint8_t *buf, size_t sz) {
{
// process leftover // process leftover
if(m_Leftover) if (m_Leftover) {
{
size_t want = POLY1305_BLOCK_BYTES - m_Leftover; size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
if (want > sz) want = sz; if (want > sz) want = sz;
memcpy(m_Buffer + m_Leftover, buf, want); memcpy(m_Buffer + m_Leftover, buf, want);
@ -177,23 +158,20 @@ namespace crypto
m_Leftover = 0; m_Leftover = 0;
} }
// process blocks // process blocks
if(sz >= POLY1305_BLOCK_BYTES) if (sz >= POLY1305_BLOCK_BYTES) {
{
size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1)); size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1));
Blocks(buf, want); Blocks(buf, want);
buf += want; buf += want;
sz -= want; sz -= want;
} }
// leftover // leftover
if(sz) if (sz) {
{
memcpy(m_Buffer + m_Leftover, buf, sz); memcpy(m_Buffer + m_Leftover, buf, sz);
m_Leftover += sz; m_Leftover += sz;
} }
} }
void Blocks(const uint8_t * buf, size_t sz) void Blocks(const uint8_t *buf, size_t sz) {
{
const unsigned char hi = m_Final ^ 1; const unsigned char hi = m_Final ^ 1;
while (sz >= POLY1305_BLOCK_BYTES) { while (sz >= POLY1305_BLOCK_BYTES) {
unsigned long u; unsigned long u;
@ -222,11 +200,9 @@ namespace crypto
} }
} }
void Finish(uint64_t * out) void Finish(uint64_t *out) {
{
// process leftovers // process leftovers
if(m_Leftover) if (m_Leftover) {
{
size_t idx = m_Leftover; size_t idx = m_Leftover;
m_Buffer[idx++] = 1; m_Buffer[idx++] = 1;
for (; idx < POLY1305_BLOCK_BYTES; idx++) for (; idx < POLY1305_BLOCK_BYTES; idx++)

View file

@ -14,31 +14,25 @@
#include "Log.h" #include "Log.h"
#include "Profiling.h" #include "Profiling.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt"); i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
RouterProfile::RouterProfile() : RouterProfile::RouterProfile() :
m_LastUpdateTime(boost::posix_time::second_clock::local_time()), m_LastUpdateTime(boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed(0), m_NumTunnelsDeclined(0), m_NumTunnelsNonReplied(0), m_NumTunnelsAgreed(0), m_NumTunnelsDeclined(0), m_NumTunnelsNonReplied(0),
m_NumTimesTaken (0), m_NumTimesRejected (0) m_NumTimesTaken(0), m_NumTimesRejected(0) {
{
} }
boost::posix_time::ptime RouterProfile::GetTime () const boost::posix_time::ptime RouterProfile::GetTime() const {
{
return boost::posix_time::second_clock::local_time(); return boost::posix_time::second_clock::local_time();
} }
void RouterProfile::UpdateTime () void RouterProfile::UpdateTime() {
{
m_LastUpdateTime = GetTime(); m_LastUpdateTime = GetTime();
} }
void RouterProfile::Save (const IdentHash& identHash) void RouterProfile::Save(const IdentHash &identHash) {
{
// fill sections // fill sections
boost::property_tree::ptree participation; boost::property_tree::ptree participation;
participation.put(PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed); participation.put(PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
@ -65,70 +59,59 @@ namespace data
} }
} }
void RouterProfile::Load (const IdentHash& identHash) void RouterProfile::Load(const IdentHash &identHash) {
{
std::string ident = identHash.ToBase64(); std::string ident = identHash.ToBase64();
std::string path = m_ProfilesStorage.Path(ident); std::string path = m_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path)) if (!i2p::fs::Exists(path)) {
{
LogPrint(eLogWarning, "Profiling: No profile yet for ", ident); LogPrint(eLogWarning, "Profiling: No profile yet for ", ident);
return; return;
} }
try try {
{
boost::property_tree::read_ini(path, pt); boost::property_tree::read_ini(path, pt);
} catch (std::exception& ex) } catch (std::exception &ex) {
{
/* boost exception verbose enough */ /* boost exception verbose enough */
LogPrint(eLogError, "Profiling: ", ex.what()); LogPrint(eLogError, "Profiling: ", ex.what());
return; return;
} }
try try {
{
auto t = pt.get(PEER_PROFILE_LAST_UPDATE_TIME, ""); auto t = pt.get(PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length() > 0) if (t.length() > 0)
m_LastUpdateTime = boost::posix_time::time_from_string(t); m_LastUpdateTime = boost::posix_time::time_from_string(t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) if ((GetTime() - m_LastUpdateTime).hours() < PEER_PROFILE_EXPIRATION_TIMEOUT) {
{ try {
try
{
// read participations // read participations
auto participations = pt.get_child(PEER_PROFILE_SECTION_PARTICIPATION); auto participations = pt.get_child(PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get(PEER_PROFILE_PARTICIPATION_AGREED, 0); m_NumTunnelsAgreed = participations.get(PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get(PEER_PROFILE_PARTICIPATION_DECLINED, 0); m_NumTunnelsDeclined = participations.get(PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get(PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); m_NumTunnelsNonReplied = participations.get(PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
} }
catch (boost::property_tree::ptree_bad_path& ex) catch (boost::property_tree::ptree_bad_path &ex) {
{ LogPrint(eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION,
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident); " in profile for ", ident);
} }
try try {
{
// read usage // read usage
auto usage = pt.get_child(PEER_PROFILE_SECTION_USAGE); auto usage = pt.get_child(PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get(PEER_PROFILE_USAGE_TAKEN, 0); m_NumTimesTaken = usage.get(PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get(PEER_PROFILE_USAGE_REJECTED, 0); m_NumTimesRejected = usage.get(PEER_PROFILE_USAGE_REJECTED, 0);
} }
catch (boost::property_tree::ptree_bad_path& ex) catch (boost::property_tree::ptree_bad_path &ex) {
{ LogPrint(eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_USAGE,
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident); " in profile for ", ident);
} }
} } else
else
*this = RouterProfile(); *this = RouterProfile();
} }
catch (std::exception& ex) catch (std::exception &ex) {
{
LogPrint(eLogError, "Profiling: Can't read profile ", ident, " :", ex.what()); LogPrint(eLogError, "Profiling: Can't read profile ", ident, " :", ex.what());
} }
} }
void RouterProfile::TunnelBuildResponse (uint8_t ret) void RouterProfile::TunnelBuildResponse(uint8_t ret) {
{
UpdateTime(); UpdateTime();
if (ret > 0) if (ret > 0)
m_NumTunnelsDeclined++; m_NumTunnelsDeclined++;
@ -136,28 +119,23 @@ namespace data
m_NumTunnelsAgreed++; m_NumTunnelsAgreed++;
} }
void RouterProfile::TunnelNonReplied () void RouterProfile::TunnelNonReplied() {
{
m_NumTunnelsNonReplied++; m_NumTunnelsNonReplied++;
UpdateTime(); UpdateTime();
} }
bool RouterProfile::IsLowPartcipationRate () const bool RouterProfile::IsLowPartcipationRate() const {
{
return 4 * m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate return 4 * m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
} }
bool RouterProfile::IsLowReplyRate () const bool RouterProfile::IsLowReplyRate() const {
{
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined; auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
return m_NumTunnelsNonReplied > 10 * (total + 1); return m_NumTunnelsNonReplied > 10 * (total + 1);
} }
bool RouterProfile::IsBad () bool RouterProfile::IsBad() {
{
auto isBad = IsAlwaysDeclining() || IsLowPartcipationRate() /*|| IsLowReplyRate ()*/; auto isBad = IsAlwaysDeclining() || IsLowPartcipationRate() /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1)) if (isBad && m_NumTimesRejected > 10 * (m_NumTimesTaken + 1)) {
{
// reset profile // reset profile
m_NumTunnelsAgreed = 0; m_NumTunnelsAgreed = 0;
m_NumTunnelsDeclined = 0; m_NumTunnelsDeclined = 0;
@ -168,21 +146,18 @@ namespace data
return isBad; return isBad;
} }
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash) std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash) {
{
auto profile = std::make_shared<RouterProfile>(); auto profile = std::make_shared<RouterProfile>();
profile->Load(identHash); // if possible profile->Load(identHash); // if possible
return profile; return profile;
} }
void InitProfilesStorage () void InitProfilesStorage() {
{
m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir()); m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64); m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
} }
void DeleteObsoleteProfiles () void DeleteObsoleteProfiles() {
{
struct stat st; struct stat st;
std::time_t now = std::time(nullptr); std::time_t now = std::time(nullptr);

View file

@ -13,10 +13,8 @@
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "Identity.h" #include "Identity.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
// sections // sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage"; const char PEER_PROFILE_SECTION_USAGE[] = "usage";
@ -32,28 +30,33 @@ namespace data
const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day) const int PEER_PROFILE_AUTOCLEAN_TIMEOUT = 24 * 3600; // in seconds (1 day)
const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours) const int PEER_PROFILE_AUTOCLEAN_VARIANCE = 3 * 3600; // in seconds (3 hours)
class RouterProfile class RouterProfile {
{
public: public:
RouterProfile(); RouterProfile();
RouterProfile &operator=(const RouterProfile &) = default; RouterProfile &operator=(const RouterProfile &) = default;
void Save(const IdentHash &identHash); void Save(const IdentHash &identHash);
void Load(const IdentHash &identHash); void Load(const IdentHash &identHash);
bool IsBad(); bool IsBad();
void TunnelBuildResponse(uint8_t ret); void TunnelBuildResponse(uint8_t ret);
void TunnelNonReplied(); void TunnelNonReplied();
private: private:
boost::posix_time::ptime GetTime() const; boost::posix_time::ptime GetTime() const;
void UpdateTime(); void UpdateTime();
bool IsAlwaysDeclining() const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; bool IsAlwaysDeclining() const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
bool IsLowPartcipationRate() const; bool IsLowPartcipationRate() const;
bool IsLowReplyRate() const; bool IsLowReplyRate() const;
private: private:
@ -69,7 +72,9 @@ namespace data
}; };
std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash); std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash);
void InitProfilesStorage(); void InitProfilesStorage();
void DeleteObsoleteProfiles(); void DeleteObsoleteProfiles();
} }
} }

View file

@ -17,27 +17,21 @@
#include <functional> #include <functional>
#include <utility> #include <utility>
namespace i2p namespace i2p {
{ namespace util {
namespace util
{
template<typename Element> template<typename Element>
class Queue class Queue {
{
public: public:
void Put (Element e) void Put(Element e) {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
m_Queue.push(std::move(e)); m_Queue.push(std::move(e));
m_NonEmpty.notify_one(); m_NonEmpty.notify_one();
} }
template<template<typename, typename...> class Container, typename... R> template<template<typename, typename...> class Container, typename... R>
void Put (const Container<Element, R...>& vec) void Put(const Container<Element, R...> &vec) {
{ if (!vec.empty()) {
if (!vec.empty ())
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
for (const auto &it: vec) for (const auto &it: vec)
m_Queue.push(std::move(it)); m_Queue.push(std::move(it));
@ -45,74 +39,63 @@ namespace util
} }
} }
Element GetNext () Element GetNext() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
auto el = GetNonThreadSafe(); auto el = GetNonThreadSafe();
if (!el) if (!el) {
{
m_NonEmpty.wait(l); m_NonEmpty.wait(l);
el = GetNonThreadSafe(); el = GetNonThreadSafe();
} }
return el; return el;
} }
Element GetNextWithTimeout (int usec) Element GetNextWithTimeout(int usec) {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
auto el = GetNonThreadSafe(); auto el = GetNonThreadSafe();
if (!el) if (!el) {
{
m_NonEmpty.wait_for(l, std::chrono::milliseconds(usec)); m_NonEmpty.wait_for(l, std::chrono::milliseconds(usec));
el = GetNonThreadSafe(); el = GetNonThreadSafe();
} }
return el; return el;
} }
void Wait () void Wait() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
m_NonEmpty.wait(l); m_NonEmpty.wait(l);
} }
bool Wait (int sec, int usec) bool Wait(int sec, int usec) {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout; return m_NonEmpty.wait_for(l, std::chrono::seconds(sec) + std::chrono::milliseconds(usec)) !=
std::cv_status::timeout;
} }
bool IsEmpty () bool IsEmpty() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
return m_Queue.empty(); return m_Queue.empty();
} }
int GetSize () int GetSize() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
return m_Queue.size(); return m_Queue.size();
} }
void WakeUp() { m_NonEmpty.notify_all(); }; void WakeUp() { m_NonEmpty.notify_all(); };
Element Get () Element Get() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
return GetNonThreadSafe(); return GetNonThreadSafe();
} }
Element Peek () Element Peek() {
{
std::unique_lock <std::mutex> l(m_QueueMutex); std::unique_lock <std::mutex> l(m_QueueMutex);
return GetNonThreadSafe(true); return GetNonThreadSafe(true);
} }
private: private:
Element GetNonThreadSafe (bool peek = false) Element GetNonThreadSafe(bool peek = false) {
{ if (!m_Queue.empty()) {
if (!m_Queue.empty ())
{
auto el = m_Queue.front(); auto el = m_Queue.front();
if (!peek) if (!peek)
m_Queue.pop(); m_Queue.pop();

View file

@ -27,48 +27,40 @@
#include "util.h" #include "util.h"
#include "Config.h" #include "Config.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
Reseeder::Reseeder() Reseeder::Reseeder() {
{
} }
Reseeder::~Reseeder() Reseeder::~Reseeder() {
{
} }
/** /**
@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;
std::string su3FileName; i2p::config::GetOption("reseed.file", su3FileName); i2p::config::GetOption("reseed.file", su3FileName);
std::string zipFileName; i2p::config::GetOption("reseed.zipfile", zipFileName); 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; int num;
if (su3FileName.length() > 8 && su3FileName.substr(0, 8) == "https://") 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) if (num == 0)
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", su3FileName); 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()); int num = ProcessZIPFile(zipFileName.c_str());
if (num == 0) if (num == 0)
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", zipFileName); LogPrint(eLogWarning, "Reseed: Failed to reseed from ", zipFileName);
} } else // bootstrap from reseed servers
else // bootstrap from reseed servers
{ {
int num = ReseedFromServers(); int num = ReseedFromServers();
if (num == 0) if (num == 0)
@ -80,38 +72,38 @@ namespace data
* @brief bootstrap from random server, retry 10 times * @brief bootstrap from random server, retry 10 times
* @return number of entries added to netDb * @return number of entries added to netDb
*/ */
int Reseeder::ReseedFromServers () int Reseeder::ReseedFromServers() {
{ bool ipv6;
bool ipv6; i2p::config::GetOption("ipv6", ipv6); i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv4;
bool yggdrasil; i2p::config::GetOption("meshnets.yggdrasil", yggdrasil); i2p::config::GetOption("ipv4", ipv4);
bool yggdrasil;
i2p::config::GetOption("meshnets.yggdrasil", yggdrasil);
std::vector<std::string> httpsReseedHostList; std::vector<std::string> httpsReseedHostList;
if (ipv4 || ipv6) if (ipv4 || ipv6) {
{ std::string reseedURLs;
std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs); i2p::config::GetOption("reseed.urls", reseedURLs);
if (!reseedURLs.empty()) if (!reseedURLs.empty())
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
} }
std::vector<std::string> yggReseedHostList; std::vector<std::string> yggReseedHostList;
if (yggdrasil && !i2p::util::net::GetYggdrasilAddress ().is_unspecified ()) if (yggdrasil && !i2p::util::net::GetYggdrasilAddress().is_unspecified()) {
{
LogPrint(eLogInfo, "Reseed: Yggdrasil is supported"); LogPrint(eLogInfo, "Reseed: Yggdrasil is supported");
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs); std::string yggReseedURLs;
i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
if (!yggReseedURLs.empty()) if (!yggReseedURLs.empty())
boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on); boost::split(yggReseedHostList, yggReseedURLs, boost::is_any_of(","), boost::token_compress_on);
} }
if (httpsReseedHostList.empty () && yggReseedHostList.empty()) if (httpsReseedHostList.empty() && yggReseedHostList.empty()) {
{
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() + yggReseedHostList.size()); auto ind = rand() % (httpsReseedHostList.size() + yggReseedHostList.size());
bool isHttps = ind < httpsReseedHostList.size(); bool isHttps = ind < httpsReseedHostList.size();
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] : std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
@ -130,58 +122,47 @@ namespace data
* @param url * @param url
* @return number of entries added to netDb * @return number of entries added to netDb
*/ */
int Reseeder::ReseedFromSU3Url (const std::string& url, bool isHttps) int Reseeder::ReseedFromSU3Url(const std::string &url, bool isHttps) {
{
LogPrint(eLogInfo, "Reseed: Downloading SU3 from ", url); LogPrint(eLogInfo, "Reseed: Downloading SU3 from ", url);
std::string su3 = isHttps ? HttpsRequest(url) : YggdrasilRequest(url); std::string su3 = isHttps ? HttpsRequest(url) : YggdrasilRequest(url);
if (su3.length () > 0) if (su3.length() > 0) {
{
std::stringstream s(su3); std::stringstream s(su3);
return ProcessSU3Stream(s); return ProcessSU3Stream(s);
} } else {
else
{
LogPrint(eLogWarning, "Reseed: SU3 download failed"); LogPrint(eLogWarning, "Reseed: SU3 download failed");
return 0; return 0;
} }
} }
int Reseeder::ProcessSU3File (const char * filename) int Reseeder::ProcessSU3File(const char *filename) {
{
std::ifstream s(filename, std::ifstream::binary); std::ifstream s(filename, std::ifstream::binary);
if (s.is_open()) if (s.is_open())
return ProcessSU3Stream(s); return ProcessSU3Stream(s);
else else {
{
LogPrint(eLogError, "Reseed: Can't open file ", filename); LogPrint(eLogError, "Reseed: Can't open file ", filename);
return 0; return 0;
} }
} }
int Reseeder::ProcessZIPFile (const char * filename) int Reseeder::ProcessZIPFile(const char *filename) {
{
std::ifstream s(filename, std::ifstream::binary); std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ()) if (s.is_open()) {
{
s.seekg(0, std::ios::end); s.seekg(0, std::ios::end);
auto len = s.tellg(); auto len = s.tellg();
s.seekg(0, std::ios::beg); s.seekg(0, std::ios::beg);
return ProcessZIPStream(s, len); return ProcessZIPStream(s, len);
} } else {
else
{
LogPrint(eLogError, "Reseed: Can't open file ", filename); LogPrint(eLogError, "Reseed: Can't open file ", filename);
return 0; return 0;
} }
} }
const char SU3_MAGIC_NUMBER[] = "I2Psu3"; const char SU3_MAGIC_NUMBER[] = "I2Psu3";
int Reseeder::ProcessSU3Stream (std::istream& s)
{ int Reseeder::ProcessSU3Stream(std::istream &s) {
char magicNumber[7]; char magicNumber[7];
s.read(magicNumber, 7); // magic number and zero byte 6 s.read(magicNumber, 7); // magic number and zero byte 6
if (strcmp (magicNumber, SU3_MAGIC_NUMBER)) if (strcmp(magicNumber, SU3_MAGIC_NUMBER)) {
{
LogPrint(eLogError, "Reseed: Unexpected SU3 magic number"); LogPrint(eLogError, "Reseed: Unexpected SU3 magic number");
return 0; return 0;
} }
@ -224,16 +205,14 @@ namespace data
s.read(signerID, signerIDLength); // signerID s.read(signerID, signerIDLength); // signerID
signerID[signerIDLength] = 0; signerID[signerIDLength] = 0;
bool verify; i2p::config::GetOption("reseed.verify", verify); bool verify;
if (verify) i2p::config::GetOption("reseed.verify", verify);
{ if (verify) {
//try to verify signature //try to verify signature
auto it = m_SigningKeys.find(signerID); auto it = m_SigningKeys.find(signerID);
if (it != m_SigningKeys.end ()) if (it != m_SigningKeys.end()) {
{
// TODO: implement all signature types // TODO: implement all signature types
if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096) if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096) {
{
size_t pos = s.tellg(); size_t pos = s.tellg();
size_t tbsLen = pos + contentLength; size_t tbsLen = pos + contentLength;
uint8_t *tbs = new uint8_t[tbsLen]; uint8_t *tbs = new uint8_t[tbsLen];
@ -261,18 +240,17 @@ namespace data
else else
verify = false; // verified verify = false; // verified
delete[] enSigBuf; delete[] enSigBuf;
BN_free (s); BN_free (n); BN_free(s);
BN_free(n);
BN_CTX_free(bnctx); BN_CTX_free(bnctx);
} }
delete[] signature; delete[] signature;
delete[] tbs; delete[] tbs;
s.seekg(pos, std::ios::beg); s.seekg(pos, std::ios::beg);
} } else
else
LogPrint(eLogWarning, "Reseed: Signature type ", signatureType, " is not supported"); LogPrint(eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
} } else
else
LogPrint(eLogWarning, "Reseed: Certificate for ", signerID, " not loaded"); LogPrint(eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
} }
@ -289,17 +267,15 @@ namespace data
const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50; const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50; const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008; const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength)
{ int Reseeder::ProcessZIPStream(std::istream &s, uint64_t contentLength) {
int numFiles = 0; int numFiles = 0;
size_t contentPos = s.tellg(); size_t contentPos = s.tellg();
while (!s.eof ()) while (!s.eof()) {
{
uint32_t signature; uint32_t signature;
s.read((char *) &signature, 4); s.read((char *) &signature, 4);
signature = le32toh (signature); signature = le32toh (signature);
if (signature == ZIP_HEADER_SIGNATURE) if (signature == ZIP_HEADER_SIGNATURE) {
{
// next local file // next local file
s.seekg(2, std::ios::cur); // version s.seekg(2, std::ios::cur); // version
uint16_t bitFlag; uint16_t bitFlag;
@ -332,18 +308,17 @@ namespace data
localFileName[fileNameLength] = 0; localFileName[fileNameLength] = 0;
s.seekg(extraFieldLength, std::ios::cur); s.seekg(extraFieldLength, std::ios::cur);
// take care about data descriptor if presented // take care about data descriptor if presented
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) {
{
size_t pos = s.tellg(); size_t pos = s.tellg();
if (!FindZipDataDescriptor (s)) if (!FindZipDataDescriptor(s)) {
{
LogPrint(eLogError, "Reseed: SU3 archive data descriptor not found"); LogPrint(eLogError, "Reseed: SU3 archive data descriptor not found");
return numFiles; return numFiles;
} }
s.read((char *) &crc_32, 4); s.read((char *) &crc_32, 4);
crc_32 = le32toh (crc_32); crc_32 = le32toh (crc_32);
s.read((char *) &compressedSize, 4); s.read((char *) &compressedSize, 4);
compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data compressedSize = le32toh (compressedSize) +
4; // ??? we must consider signature as part of compressed data
s.read((char *) &uncompressedSize, 4); s.read((char *) &uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize); uncompressedSize = le32toh (uncompressedSize);
@ -352,8 +327,7 @@ namespace data
} }
LogPrint(eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes"); LogPrint(eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes");
if (!compressedSize) if (!compressedSize) {
{
LogPrint(eLogWarning, "Reseed: Unexpected size 0. Skipped"); LogPrint(eLogWarning, "Reseed: Unexpected size 0. Skipped");
continue; continue;
} }
@ -371,23 +345,18 @@ namespace data
inflator.next_out = uncompressed; inflator.next_out = uncompressed;
inflator.avail_out = uncompressedSize; inflator.avail_out = uncompressedSize;
int err; int err;
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0) if ((err = inflate(&inflator, Z_SYNC_FLUSH)) >= 0) {
{
uncompressedSize -= inflator.avail_out; uncompressedSize -= inflator.avail_out;
if (crc32 (0, uncompressed, uncompressedSize) == crc_32) if (crc32(0, uncompressed, uncompressedSize) == crc_32) {
{
i2p::data::netdb.AddRouterInfo(uncompressed, uncompressedSize); i2p::data::netdb.AddRouterInfo(uncompressed, uncompressedSize);
numFiles++; numFiles++;
} } else
else
LogPrint(eLogError, "Reseed: CRC32 verification failed"); LogPrint(eLogError, "Reseed: CRC32 verification failed");
} } else
else
LogPrint(eLogError, "Reseed: SU3 decompression error ", err); LogPrint(eLogError, "Reseed: SU3 decompression error ", err);
delete[] uncompressed; delete[] uncompressed;
inflateEnd(&inflator); inflateEnd(&inflator);
} } else // no compression
else // no compression
{ {
i2p::data::netdb.AddRouterInfo(compressed, compressedSize); i2p::data::netdb.AddRouterInfo(compressed, compressedSize);
numFiles++; numFiles++;
@ -395,9 +364,7 @@ namespace data
delete[] compressed; delete[] compressed;
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
s.seekg(12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4) s.seekg(12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
} } else {
else
{
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE) if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
LogPrint(eLogWarning, "Reseed: Missing zip central directory header"); LogPrint(eLogWarning, "Reseed: Missing zip central directory header");
break; // no more files break; // no more files
@ -411,11 +378,12 @@ namespace data
auto ts = i2p::util::GetMillisecondsSinceEpoch(); auto ts = i2p::util::GetMillisecondsSinceEpoch();
int numOutdated = 0; int numOutdated = 0;
i2p::data::netdb.VisitRouterInfos( i2p::data::netdb.VisitRouterInfos(
[&numOutdated, ts](std::shared_ptr<const RouterInfo> r) [&numOutdated, ts](std::shared_ptr<const RouterInfo> r) {
if (r && ts > r->GetTimestamp() +
10 * i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT * 1000LL) // 270 hours
{ {
if (r && ts > r->GetTimestamp () + 10*i2p::data::NETDB_MAX_EXPIRATION_TIMEOUT*1000LL) // 270 hours LogPrint(eLogError, "Reseed: Router ", r->GetIdentHash().ToBase64(), " is outdated by ",
{ (ts - r->GetTimestamp()) / 1000LL / 3600LL, " hours");
LogPrint (eLogError, "Reseed: Router ", r->GetIdentHash().ToBase64 (), " is outdated by ", (ts - r->GetTimestamp ())/1000LL/3600LL, " hours");
numOutdated++; numOutdated++;
} }
}); });
@ -438,42 +406,35 @@ namespace data
} }
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = {0x50, 0x4B, 0x07, 0x08}; const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = {0x50, 0x4B, 0x07, 0x08};
bool Reseeder::FindZipDataDescriptor (std::istream& s)
{ bool Reseeder::FindZipDataDescriptor(std::istream &s) {
size_t nextInd = 0; size_t nextInd = 0;
while (!s.eof ()) while (!s.eof()) {
{
uint8_t nextByte; uint8_t nextByte;
s.read((char *) &nextByte, 1); s.read((char *) &nextByte, 1);
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd]) if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd]) {
{
nextInd++; nextInd++;
if (nextInd >= sizeof(ZIP_DATA_DESCRIPTOR_SIGNATURE)) if (nextInd >= sizeof(ZIP_DATA_DESCRIPTOR_SIGNATURE))
return true; return true;
} } else
else
nextInd = 0; nextInd = 0;
} }
return false; return false;
} }
void Reseeder::LoadCertificate (const std::string& filename) void Reseeder::LoadCertificate(const std::string &filename) {
{
SSL_CTX *ctx = SSL_CTX_new(TLS_method()); SSL_CTX *ctx = SSL_CTX_new(TLS_method());
int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
if (ret) if (ret) {
{
SSL *ssl = SSL_new(ctx); SSL *ssl = SSL_new(ctx);
X509 *cert = SSL_get_certificate(ssl); X509 *cert = SSL_get_certificate(ssl);
// verify // verify
if (cert) if (cert) {
{
// extract issuer name // extract issuer name
char name[100]; char name[100];
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100); X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
char *cn = strstr(name, "CN="); char *cn = strstr(name, "CN=");
if (cn) if (cn) {
{
cn += 3; cn += 3;
char *terminator = strchr(cn, '/'); char *terminator = strchr(cn, '/');
if (terminator) terminator[0] = 0; if (terminator) terminator[0] = 0;
@ -490,14 +451,12 @@ namespace data
LogPrint(eLogError, "Reseed: Can't find CN field in ", filename); LogPrint(eLogError, "Reseed: Can't find CN field in ", filename);
} }
SSL_free(ssl); SSL_free(ssl);
} } else
else
LogPrint(eLogError, "Reseed: Can't open certificate file ", filename); LogPrint(eLogError, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free(ctx); SSL_CTX_free(ctx);
} }
void Reseeder::LoadCertificates () void Reseeder::LoadCertificates() {
{
std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "reseed"; std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "reseed";
std::vector<std::string> files; std::vector<std::string> files;
@ -519,10 +478,10 @@ namespace data
LogPrint(eLogInfo, "Reseed: ", numCertificates, " certificates loaded"); LogPrint(eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
} }
std::string Reseeder::HttpsRequest (const std::string& address) std::string Reseeder::HttpsRequest(const std::string &address) {
{
i2p::http::URL proxyUrl; i2p::http::URL proxyUrl;
std::string proxy; i2p::config::GetOption("reseed.proxy", proxy); std::string proxy;
i2p::config::GetOption("reseed.proxy", proxy);
// check for proxy url // check for proxy url
if (proxy.size()) { if (proxy.size()) {
// parse // parse
@ -558,19 +517,15 @@ namespace data
ctx.set_verify_mode(boost::asio::ssl::context::verify_none); ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
boost::asio::ssl::stream <boost::asio::ip::tcp::socket> s(service, ctx); boost::asio::ssl::stream <boost::asio::ip::tcp::socket> s(service, ctx);
if(proxyUrl.schema.size()) if (proxyUrl.schema.size()) {
{
// proxy connection // proxy connection
auto it = boost::asio::ip::tcp::resolver(service).resolve( auto it = boost::asio::ip::tcp::resolver(service).resolve(
boost::asio::ip::tcp::resolver::query(proxyUrl.host, std::to_string(proxyUrl.port)), ecode); boost::asio::ip::tcp::resolver::query(proxyUrl.host, std::to_string(proxyUrl.port)), ecode);
if(!ecode) if (!ecode) {
{
s.lowest_layer().connect(*it, ecode); s.lowest_layer().connect(*it, ecode);
if(!ecode) if (!ecode) {
{
auto &sock = s.next_layer(); auto &sock = s.next_layer();
if(proxyUrl.schema == "http") if (proxyUrl.schema == "http") {
{
i2p::http::HTTPReq proxyReq; i2p::http::HTTPReq proxyReq;
i2p::http::HTTPRes proxyRes; i2p::http::HTTPRes proxyRes;
proxyReq.method = "CONNECT"; proxyReq.method = "CONNECT";
@ -585,48 +540,42 @@ namespace data
out << proxyReq.to_string(); out << proxyReq.to_string();
boost::asio::write(sock, writebuf.data(), boost::asio::transfer_all(), ecode); boost::asio::write(sock, writebuf.data(), boost::asio::transfer_all(), ecode);
if (ecode) if (ecode) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT write error: ", ecode.message()); LogPrint(eLogError, "Reseed: HTTP CONNECT write error: ", ecode.message());
return ""; return "";
} }
boost::asio::read_until(sock, readbuf, "\r\n\r\n", ecode); boost::asio::read_until(sock, readbuf, "\r\n\r\n", ecode);
if (ecode) if (ecode) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message()); LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message());
return ""; return "";
} }
if(proxyRes.parse(boost::asio::buffer_cast<const char *>(readbuf.data()), readbuf.size()) <= 0) if (proxyRes.parse(boost::asio::buffer_cast<const char *>(readbuf.data()),
{ readbuf.size()) <= 0) {
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply"); LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply");
return ""; return "";
} }
if(proxyRes.code != 200) if (proxyRes.code != 200) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: HTTP CONNECT got bad status: ", proxyRes.code); LogPrint(eLogError, "Reseed: HTTP CONNECT got bad status: ", proxyRes.code);
return ""; return "";
} }
} } else {
else
{
// assume socks if not http, is checked before this for other types // assume socks if not http, is checked before this for other types
// TODO: support username/password auth etc // TODO: support username/password auth etc
uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00}; uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
uint8_t hs_readbuf[2]; uint8_t hs_readbuf[2];
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode); boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(),
if(ecode) ecode);
{ if (ecode) {
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message()); LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
return ""; return "";
} }
boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode); boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
if(ecode) if (ecode) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message()); LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
return ""; return "";
@ -640,8 +589,7 @@ namespace data
buf[3] = 0x03; buf[3] = 0x03;
sz += 4; sz += 4;
size_t hostsz = url.host.size(); size_t hostsz = url.host.size();
if(1 + 2 + hostsz + sz > sizeof(buf)) if (1 + 2 + hostsz + sz > sizeof(buf)) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host); LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
return ""; return "";
@ -652,21 +600,18 @@ namespace data
htobe16buf(buf + sz, url.port); htobe16buf(buf + sz, url.port);
sz += 2; sz += 2;
boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode); boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
if(ecode) if (ecode) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message()); LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
return ""; return "";
} }
boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode); boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
if(ecode) if (ecode) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message()); LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
return ""; return "";
} }
if(buf[1] != 0x00) if (buf[1] != 0x00) {
{
sock.close(); sock.close();
LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1])); LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
return ""; return "";
@ -674,58 +619,46 @@ namespace data
} }
} }
} }
} } else {
else
{
// direct connection // direct connection
auto it = boost::asio::ip::tcp::resolver(service).resolve( auto it = boost::asio::ip::tcp::resolver(service).resolve(
boost::asio::ip::tcp::resolver::query(url.host, std::to_string(url.port)), ecode); boost::asio::ip::tcp::resolver::query(url.host, std::to_string(url.port)), ecode);
if (!ecode) if (!ecode) {
{
bool connected = false; bool connected = false;
boost::asio::ip::tcp::resolver::iterator end; boost::asio::ip::tcp::resolver::iterator end;
while (it != end) while (it != end) {
{
boost::asio::ip::tcp::endpoint ep = *it; boost::asio::ip::tcp::endpoint ep = *it;
if ((ep.address().is_v4() && i2p::context.SupportsV4()) || if ((ep.address().is_v4() && i2p::context.SupportsV4()) ||
(ep.address ().is_v6 () && i2p::context.SupportsV6 ())) (ep.address().is_v6() && i2p::context.SupportsV6())) {
{
s.lowest_layer().connect(ep, ecode); s.lowest_layer().connect(ep, ecode);
if (!ecode) if (!ecode) {
{
connected = true; connected = true;
break; break;
} }
} }
it++; it++;
} }
if (!connected) if (!connected) {
{
LogPrint(eLogError, "Reseed: Failed to connect to ", url.host); LogPrint(eLogError, "Reseed: Failed to connect to ", url.host);
return ""; return "";
} }
} }
} }
if (!ecode) if (!ecode) {
{
SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str()); SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str());
s.handshake(boost::asio::ssl::stream_base::client, ecode); s.handshake(boost::asio::ssl::stream_base::client, ecode);
if (!ecode) if (!ecode) {
{
LogPrint(eLogDebug, "Reseed: Connected to ", url.host, ":", url.port); LogPrint(eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
return ReseedRequest(s, url.to_string()); return ReseedRequest(s, url.to_string());
} } else
else
LogPrint(eLogError, "Reseed: SSL handshake failed: ", ecode.message()); LogPrint(eLogError, "Reseed: SSL handshake failed: ", ecode.message());
} } else
else
LogPrint(eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message()); LogPrint(eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message());
return ""; return "";
} }
template<typename Stream> template<typename Stream>
std::string Reseeder::ReseedRequest (Stream& s, const std::string& uri) std::string Reseeder::ReseedRequest(Stream &s, const std::string &uri) {
{
boost::system::error_code ecode; boost::system::error_code ecode;
i2p::http::HTTPReq req; i2p::http::HTTPReq req;
req.uri = uri; req.uri = uri;
@ -734,7 +667,8 @@ namespace data
s.write_some(boost::asio::buffer(req.to_string())); s.write_some(boost::asio::buffer(req.to_string()));
// read response // read response
std::stringstream rs; std::stringstream rs;
char recv_buf[1024]; size_t l = 0; char recv_buf[1024];
size_t l = 0;
do { do {
l = s.read_some(boost::asio::buffer(recv_buf, sizeof(recv_buf)), ecode); l = s.read_some(boost::asio::buffer(recv_buf, sizeof(recv_buf)), ecode);
if (l) rs.write(recv_buf, l); if (l) rs.write(recv_buf, l);
@ -765,11 +699,9 @@ namespace data
return data; return data;
} }
std::string Reseeder::YggdrasilRequest (const std::string& address) std::string Reseeder::YggdrasilRequest(const std::string &address) {
{
i2p::http::URL url; i2p::http::URL url;
if (!url.parse(address)) if (!url.parse(address)) {
{
LogPrint(eLogError, "Reseed: Failed to parse url: ", address); LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
return ""; return "";
} }
@ -784,12 +716,10 @@ namespace data
auto host = url.host.substr(1, url.host.length() - 2); auto host = url.host.substr(1, url.host.length() - 2);
LogPrint(eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port); LogPrint(eLogDebug, "Reseed: Connecting to Yggdrasil ", url.host, ":", url.port);
s.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v6::from_string(host), url.port), ecode); s.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v6::from_string(host), url.port), ecode);
if (!ecode) if (!ecode) {
{
LogPrint(eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port); LogPrint(eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
return ReseedRequest(s, url.to_string()); return ReseedRequest(s, url.to_string());
} } else
else
LogPrint(eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message()); LogPrint(eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message());
return ""; return "";

View file

@ -16,22 +16,24 @@
#include "Identity.h" #include "Identity.h"
#include "Crypto.h" #include "Crypto.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
class Reseeder class Reseeder {
{
typedef Tag<512> PublicKey; typedef Tag<512> PublicKey;
public: public:
Reseeder(); Reseeder();
~Reseeder(); ~Reseeder();
void Bootstrap(); void Bootstrap();
int ReseedFromServers(); int ReseedFromServers();
int ProcessSU3File(const char *filename); int ProcessSU3File(const char *filename);
int ProcessZIPFile(const char *filename); int ProcessZIPFile(const char *filename);
void LoadCertificates(); void LoadCertificates();
@ -39,15 +41,19 @@ namespace data
private: private:
int ReseedFromSU3Url(const std::string &url, bool isHttps = true); int ReseedFromSU3Url(const std::string &url, bool isHttps = true);
void LoadCertificate(const std::string &filename); void LoadCertificate(const std::string &filename);
int ProcessSU3Stream(std::istream &s); int ProcessSU3Stream(std::istream &s);
int ProcessZIPStream(std::istream &s, uint64_t contentLength); int ProcessZIPStream(std::istream &s, uint64_t contentLength);
bool FindZipDataDescriptor(std::istream &s); bool FindZipDataDescriptor(std::istream &s);
std::string HttpsRequest(const std::string &address); std::string HttpsRequest(const std::string &address);
std::string YggdrasilRequest(const std::string &address); std::string YggdrasilRequest(const std::string &address);
template<typename Stream> template<typename Stream>
std::string ReseedRequest(Stream &s, const std::string &uri); std::string ReseedRequest(Stream &s, const std::string &uri);

File diff suppressed because it is too large Load diff

View file

@ -19,10 +19,8 @@
#include "RouterInfo.h" #include "RouterInfo.h"
#include "Garlic.h" #include "Garlic.h"
namespace i2p namespace i2p {
{ namespace garlic {
namespace garlic
{
class RouterIncomingRatchetSession; class RouterIncomingRatchetSession;
} }
@ -32,8 +30,7 @@ namespace garlic
const char SSU2_KEYS[] = "ssu2.keys"; const char SSU2_KEYS[] = "ssu2.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
enum RouterStatus enum RouterStatus {
{
eRouterStatusOK = 0, eRouterStatusOK = 0,
eRouterStatusTesting = 1, eRouterStatusTesting = 1,
eRouterStatusFirewalled = 2, eRouterStatusFirewalled = 2,
@ -43,27 +40,23 @@ namespace garlic
eRouterStatusMesh = 6 eRouterStatusMesh = 6
}; };
enum RouterError enum RouterError {
{
eRouterErrorNone = 0, eRouterErrorNone = 0,
eRouterErrorClockSkew = 1, eRouterErrorClockSkew = 1,
eRouterErrorOffline = 2, eRouterErrorOffline = 2,
eRouterErrorSymmetricNAT = 3 eRouterErrorSymmetricNAT = 3
}; };
class RouterContext: public i2p::garlic::GarlicDestination class RouterContext : public i2p::garlic::GarlicDestination {
{
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];
}; };
struct SSU2PrivateKeys struct SSU2PrivateKeys {
{
uint8_t staticPublicKey[32]; uint8_t staticPublicKey[32];
uint8_t staticPrivateKey[32]; uint8_t staticPrivateKey[32];
uint8_t intro[32]; uint8_t intro[32];
@ -72,120 +65,192 @@ namespace garlic
public: public:
RouterContext(); RouterContext();
void Init(); void Init();
const i2p::data::PrivateKeys &GetPrivateKeys() const { return m_Keys; }; const i2p::data::PrivateKeys &GetPrivateKeys() const { return m_Keys; };
i2p::data::LocalRouterInfo &GetRouterInfo() { return m_RouterInfo; }; i2p::data::LocalRouterInfo &GetRouterInfo() { return m_RouterInfo; };
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
{ std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo() {
return std::shared_ptr<i2p::data::RouterInfo>(&m_RouterInfo, return std::shared_ptr<i2p::data::RouterInfo>(&m_RouterInfo,
[](i2p::data::RouterInfo *) {}); [](i2p::data::RouterInfo *) {});
} }
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
{ std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination() {
return std::shared_ptr<i2p::garlic::GarlicDestination>(this, return std::shared_ptr<i2p::garlic::GarlicDestination>(this,
[](i2p::garlic::GarlicDestination *) {}); [](i2p::garlic::GarlicDestination *) {});
} }
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 &GetNTCP2StaticKeys(); i2p::crypto::X25519Keys &GetNTCP2StaticKeys();
const uint8_t *GetSSU2StaticPublicKey() const { return m_SSU2Keys ? m_SSU2Keys->staticPublicKey : nullptr; }; const uint8_t *GetSSU2StaticPublicKey() const { return m_SSU2Keys ? m_SSU2Keys->staticPublicKey : nullptr; };
const uint8_t *GetSSU2StaticPrivateKey() const { return m_SSU2Keys ? m_SSU2Keys->staticPrivateKey : nullptr; }; const uint8_t *GetSSU2StaticPrivateKey() const { return m_SSU2Keys ? m_SSU2Keys->staticPrivateKey : nullptr; };
const uint8_t *GetSSU2IntroKey() const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; }; const uint8_t *GetSSU2IntroKey() const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; };
i2p::crypto::X25519Keys &GetSSU2StaticKeys(); i2p::crypto::X25519Keys &GetSSU2StaticKeys();
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; };
uint64_t GetBandwidthLimit() const { return m_BandwidthLimit; }; uint64_t GetBandwidthLimit() const { return m_BandwidthLimit; };
uint64_t GetTransitBandwidthLimit() const { return (m_BandwidthLimit * m_ShareRatio) / 100LL; }; uint64_t GetTransitBandwidthLimit() const { return (m_BandwidthLimit * m_ShareRatio) / 100LL; };
RouterStatus GetStatus() const { return m_Status; }; RouterStatus GetStatus() const { return m_Status; };
void SetStatus(RouterStatus status); void SetStatus(RouterStatus status);
void SetStatusSSU2(RouterStatus status); void SetStatusSSU2(RouterStatus status);
RouterError GetError() const { return m_Error; }; RouterError GetError() const { return m_Error; };
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
void SetError(RouterError error) {
m_Status = eRouterStatusError;
m_Error = error;
};
RouterStatus GetStatusV6() const { return m_StatusV6; }; RouterStatus GetStatusV6() const { return m_StatusV6; };
void SetStatusV6(RouterStatus status); void SetStatusV6(RouterStatus status);
void SetStatusV6SSU2(RouterStatus status); void SetStatusV6SSU2(RouterStatus status);
RouterError GetErrorV6() const { return m_ErrorV6; }; RouterError GetErrorV6() const { return m_ErrorV6; };
void SetErrorV6 (RouterError error) { m_StatusV6 = eRouterStatusError; m_ErrorV6 = error; };
void SetErrorV6(RouterError error) {
m_StatusV6 = eRouterStatusError;
m_ErrorV6 = error;
};
int GetNetID() const { return m_NetID; }; int GetNetID() const { return m_NetID; };
void SetNetID(int netID) { m_NetID = netID; }; void SetNetID(int netID) { m_NetID = netID; };
bool DecryptTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data); bool DecryptTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data);
bool DecryptTunnelShortRequestRecord(const uint8_t *encrypted, uint8_t *data); bool DecryptTunnelShortRequestRecord(const uint8_t *encrypted, uint8_t *data);
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, bool v4, bool v6, bool ygg); void PublishNTCP2Address(int port, bool publish, bool v4, bool v6, bool ygg);
void UpdateNTCP2Address(bool enable); void UpdateNTCP2Address(bool enable);
void PublishSSU2Address(int port, bool publish, bool v4, bool v6); void PublishSSU2Address(int port, bool publish, bool v4, bool v6);
void UpdateSSU2Address(bool enable); void UpdateSSU2Address(bool enable);
void RemoveNTCPAddress(bool v4only = true); // delete NTCP address for older routers. TODO: remove later void RemoveNTCPAddress(bool v4only = true); // delete NTCP address for older routers. TODO: remove later
void RemoveSSUAddress(); // delete SSU address for older routers void RemoveSSUAddress(); // delete SSU address for older routers
bool AddIntroducer(const i2p::data::RouterInfo::Introducer &introducer); bool AddIntroducer(const i2p::data::RouterInfo::Introducer &introducer);
void RemoveIntroducer(const boost::asio::ip::udp::endpoint &e); void RemoveIntroducer(const boost::asio::ip::udp::endpoint &e);
bool AddSSU2Introducer(const i2p::data::RouterInfo::Introducer &introducer, bool v4); bool AddSSU2Introducer(const i2p::data::RouterInfo::Introducer &introducer, bool v4);
void RemoveSSU2Introducer(const i2p::data::IdentHash &h, bool v4); void RemoveSSU2Introducer(const i2p::data::IdentHash &h, bool v4);
void ClearSSU2Introducers(bool v4); void ClearSSU2Introducers(bool v4);
bool IsUnreachable() const; bool IsUnreachable() const;
void SetUnreachable(bool v4, bool v6); void SetUnreachable(bool v4, bool v6);
void SetUnreachableSSU2(bool v4, bool v6); void SetUnreachableSSU2(bool v4, bool v6);
void SetReachable(bool v4, bool v6); void SetReachable(bool v4, bool v6);
bool IsFloodfill() const { return m_IsFloodfill; }; bool IsFloodfill() const { return m_IsFloodfill; };
void SetFloodfill(bool floodfill); void SetFloodfill(bool floodfill);
void SetFamily(const std::string &family); void SetFamily(const std::string &family);
std::string GetFamily() const; std::string GetFamily() const;
void SetBandwidth(int limit); /* in kilobytes */ void SetBandwidth(int limit); /* in kilobytes */
void SetBandwidth(char L); /* by letter */ void SetBandwidth(char L); /* by letter */
void SetShareRatio(int percents); // 0 - 100 void SetShareRatio(int percents); // 0 - 100
bool AcceptsTunnels() const { return m_AcceptsTunnels; }; bool AcceptsTunnels() const { return m_AcceptsTunnels; };
void SetAcceptsTunnels(bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; }; void SetAcceptsTunnels(bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
bool SupportsV6() const { return m_RouterInfo.IsV6(); }; bool SupportsV6() const { return m_RouterInfo.IsV6(); };
bool SupportsV4() const { return m_RouterInfo.IsV4(); }; bool SupportsV4() const { return m_RouterInfo.IsV4(); };
bool SupportsMesh() const { return m_RouterInfo.IsMesh(); }; bool SupportsMesh() const { return m_RouterInfo.IsMesh(); };
void SetSupportsV6(bool supportsV6); void SetSupportsV6(bool supportsV6);
void SetSupportsV4(bool supportsV4); void SetSupportsV4(bool supportsV4);
void SetSupportsMesh(bool supportsmesh, const boost::asio::ip::address_v6 &host); void SetSupportsMesh(bool supportsmesh, const boost::asio::ip::address_v6 &host);
void SetMTU(int mtu, bool v4); void SetMTU(int mtu, bool v4);
i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; };
void UpdateNTCP2V6Address(const boost::asio::ip::address &host); // called from Daemon. TODO: remove void UpdateNTCP2V6Address(const boost::asio::ip::address &host); // called from Daemon. TODO: remove
void UpdateStats(); void UpdateStats();
void UpdateTimestamp(uint64_t ts); // in seconds, called from NetDb before publishing void UpdateTimestamp(uint64_t ts); // in seconds, called from NetDb before publishing
void CleanupDestination(); // garlic destination void CleanupDestination(); // garlic destination
// implements LocalDestination // implements LocalDestination
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 Decrypt(const uint8_t *encrypted, uint8_t *data, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt(const uint8_t *encrypted, uint8_t *data, i2p::data::CryptoKeyType preferredCrypto) const;
void Sign(const uint8_t *buf, int len, uint8_t *signature) const { m_Keys.Sign(buf, len, signature); }; void Sign(const uint8_t *buf, int len, uint8_t *signature) const { m_Keys.Sign(buf, len, signature); };
void SetLeaseSetUpdated() {}; void SetLeaseSetUpdated() {};
// implements GarlicDestination // implements GarlicDestination
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet() { return nullptr; }; std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet() { return nullptr; };
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const; std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const;
// override GarlicDestination // override GarlicDestination
void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
protected: protected:
// 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, uint32_t msgID); bool HandleCloveI2NPMessage(I2NPMessageType typeID, const uint8_t *payload, size_t len, uint32_t msgID);
private: private:
void CreateNewRouter(); void CreateNewRouter();
void NewRouterInfo(); void NewRouterInfo();
void UpdateRouterInfo(); void UpdateRouterInfo();
void NewNTCP2Keys(); void NewNTCP2Keys();
void NewSSU2Keys(); void NewSSU2Keys();
bool IsSSU2Only() const; // SSU2 and no SSU bool IsSSU2Only() const; // SSU2 and no SSU
bool Load(); bool Load();
void SaveKeys(); void SaveKeys();
uint16_t SelectRandomPort() const; uint16_t SelectRandomPort() const;
bool DecryptECIESTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data, size_t clearTextSize); bool DecryptECIESTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data, size_t clearTextSize);

File diff suppressed because it is too large Load diff

View file

@ -21,10 +21,8 @@
#include "Profiling.h" #include "Profiling.h"
#include "Family.h" #include "Family.h"
namespace i2p namespace i2p {
{ namespace data {
namespace data
{
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets"; const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters"; const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
const char ROUTER_INFO_PROPERTY_NETID[] = "netId"; const char ROUTER_INFO_PROPERTY_NETID[] = "netId";
@ -58,12 +56,10 @@ namespace data
const uint8_t COST_SSU2_NON_PUBLISHED = 15; const uint8_t COST_SSU2_NON_PUBLISHED = 15;
const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later const size_t MAX_RI_BUFFER_SIZE = 3072; // if RouterInfo exceeds 3K we consider it as malformed, might extend later
class RouterInfo: public RoutingDestination class RouterInfo : public RoutingDestination {
{
public: public:
enum SupportedTransports enum SupportedTransports {
{
eNTCP2V4 = 0x01, eNTCP2V4 = 0x01,
eNTCP2V6 = 0x02, eNTCP2V6 = 0x02,
eSSUV4 = 0x04, eSSUV4 = 0x04,
@ -75,8 +71,7 @@ namespace data
}; };
typedef uint8_t CompatibleTransports; typedef uint8_t CompatibleTransports;
enum Caps enum Caps {
{
eFloodfill = 0x01, eFloodfill = 0x01,
eHighBandwidth = 0x02, eHighBandwidth = 0x02,
eExtraBandwidth = 0x04, eExtraBandwidth = 0x04,
@ -85,16 +80,14 @@ namespace data
eUnreachable = 0x20 eUnreachable = 0x20
}; };
enum AddressCaps enum AddressCaps {
{
eV4 = 0x01, eV4 = 0x01,
eV6 = 0x02, eV6 = 0x02,
eSSUTesting = 0x04, eSSUTesting = 0x04,
eSSUIntroducer = 0x08 eSSUIntroducer = 0x08
}; };
enum TransportStyle enum TransportStyle {
{
eTransportUnknown = 0, eTransportUnknown = 0,
eTransportNTCP, eTransportNTCP,
eTransportSSU, eTransportSSU,
@ -102,8 +95,7 @@ namespace data
}; };
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
struct Introducer struct Introducer {
{
Introducer() : iPort(0), iExp(0) {}; Introducer() : iPort(0), iExp(0) {};
boost::asio::ip::address iHost; boost::asio::ip::address iHost;
int iPort; int iPort;
@ -112,14 +104,12 @@ namespace data
uint32_t iExp; uint32_t iExp;
}; };
struct SSUExt struct SSUExt {
{
int mtu; int mtu;
std::vector<Introducer> introducers; std::vector<Introducer> introducers;
}; };
struct Address struct Address {
{
TransportStyle transportStyle; TransportStyle transportStyle;
boost::asio::ip::address host; boost::asio::ip::address host;
Tag<32> s, i; // keys, i is first 16 bytes for NTCP2 and 32 bytes intro key for SSU Tag<32> s, i; // keys, i is first 16 bytes for NTCP2 and 32 bytes intro key for SSU
@ -129,133 +119,210 @@ namespace data
bool published = false; bool published = false;
std::unique_ptr<SSUExt> ssu; // not null for SSU std::unique_ptr<SSUExt> ssu; // not null for SSU
bool IsCompatible (const boost::asio::ip::address& other) const bool IsCompatible(const boost::asio::ip::address &other) const {
{
return (IsV4() && other.is_v4()) || return (IsV4() && other.is_v4()) ||
(IsV6() && other.is_v6()); (IsV6() && other.is_v6());
} }
bool operator==(const Address& other) const bool operator==(const Address &other) const {
{
return transportStyle == other.transportStyle && return transportStyle == other.transportStyle &&
host == other.host && port == other.port; host == other.host && port == other.port;
} }
bool operator!=(const Address& other) const bool operator!=(const Address &other) const {
{
return !(*this == other); return !(*this == other);
} }
bool IsNTCP2() const { return transportStyle == eTransportNTCP; }; bool IsNTCP2() const { return transportStyle == eTransportNTCP; };
bool IsSSU2() const { return transportStyle == eTransportSSU2; }; bool IsSSU2() const { return transportStyle == eTransportSSU2; };
bool IsPublishedNTCP2() const { return IsNTCP2() && published; }; bool IsPublishedNTCP2() const { return IsNTCP2() && published; };
bool IsReachableSSU() const { return (bool) ssu && (published || UsesIntroducer()); }; bool IsReachableSSU() const { return (bool) ssu && (published || UsesIntroducer()); };
bool UsesIntroducer() const { return (bool) ssu && !ssu->introducers.empty(); }; bool UsesIntroducer() const { return (bool) ssu && !ssu->introducers.empty(); };
bool IsIntroducer() const { return caps & eSSUIntroducer; }; bool IsIntroducer() const { return caps & eSSUIntroducer; };
bool IsPeerTesting() const { return caps & eSSUTesting; }; bool IsPeerTesting() const { return caps & eSSUTesting; };
bool IsV4() const { return (caps & AddressCaps::eV4) || (host.is_v4() && !host.is_unspecified()); }; bool IsV4() const { return (caps & AddressCaps::eV4) || (host.is_v4() && !host.is_unspecified()); };
bool IsV6() const { return (caps & AddressCaps::eV6) || (host.is_v6() && !host.is_unspecified()); }; bool IsV6() const { return (caps & AddressCaps::eV6) || (host.is_v6() && !host.is_unspecified()); };
}; };
class Buffer: public std::array<uint8_t, MAX_RI_BUFFER_SIZE> class Buffer : public std::array<uint8_t, MAX_RI_BUFFER_SIZE> {
{
public: public:
Buffer() = default; Buffer() = default;
Buffer(const uint8_t *buf, size_t len); Buffer(const uint8_t *buf, size_t len);
}; };
typedef std::vector<std::shared_ptr<Address> > Addresses; typedef std::vector<std::shared_ptr<Address> > Addresses;
RouterInfo(const std::string &fullPath); RouterInfo(const std::string &fullPath);
RouterInfo(const RouterInfo &) = default; RouterInfo(const RouterInfo &) = default;
RouterInfo &operator=(const RouterInfo &) = default; RouterInfo &operator=(const RouterInfo &) = default;
RouterInfo(std::shared_ptr<Buffer> &&buf, size_t len); RouterInfo(std::shared_ptr<Buffer> &&buf, size_t len);
RouterInfo(const uint8_t *buf, size_t len); RouterInfo(const uint8_t *buf, size_t len);
virtual ~RouterInfo(); virtual ~RouterInfo();
std::shared_ptr<const IdentityEx> GetRouterIdentity() const { return m_RouterIdentity; }; std::shared_ptr<const IdentityEx> GetRouterIdentity() const { return m_RouterIdentity; };
void SetRouterIdentity(std::shared_ptr<const IdentityEx> identity); void SetRouterIdentity(std::shared_ptr<const IdentityEx> identity);
std::string GetIdentHashBase64() const { return GetIdentHash().ToBase64(); }; std::string GetIdentHashBase64() const { return GetIdentHash().ToBase64(); };
uint64_t GetTimestamp() const { return m_Timestamp; }; uint64_t GetTimestamp() const { return m_Timestamp; };
int GetVersion() const { return m_Version; }; int GetVersion() const { return m_Version; };
virtual void SetProperty(const std::string &key, const std::string &value) {}; virtual void SetProperty(const std::string &key, const std::string &value) {};
virtual void ClearProperties() {}; virtual void ClearProperties() {};
Addresses& GetAddresses () { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
Addresses &
GetAddresses() { return *m_Addresses; }; // should be called for local RI only, otherwise must return shared_ptr
std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey(const uint8_t *key) const; std::shared_ptr<const Address> GetNTCP2AddressWithStaticKey(const uint8_t *key) const;
std::shared_ptr<const Address> GetSSU2AddressWithStaticKey(const uint8_t *key, bool isV6) const; std::shared_ptr<const Address> GetSSU2AddressWithStaticKey(const uint8_t *key, bool isV6) const;
std::shared_ptr<const Address> GetPublishedNTCP2V4Address() const; std::shared_ptr<const Address> GetPublishedNTCP2V4Address() const;
std::shared_ptr<const Address> GetPublishedNTCP2V6Address() const; std::shared_ptr<const Address> GetPublishedNTCP2V6Address() const;
std::shared_ptr<const Address> GetSSUAddress(bool v4only = true) const; std::shared_ptr<const Address> GetSSUAddress(bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address() const; std::shared_ptr<const Address> GetSSUV6Address() const;
std::shared_ptr<const Address> GetYggdrasilAddress() const; std::shared_ptr<const Address> GetYggdrasilAddress() const;
std::shared_ptr<const Address> GetSSU2V4Address() const; std::shared_ptr<const Address> GetSSU2V4Address() const;
std::shared_ptr<const Address> GetSSU2V6Address() const; std::shared_ptr<const Address> GetSSU2V6Address() const;
std::shared_ptr<const Address> GetSSU2Address(bool v4) const; std::shared_ptr<const Address> GetSSU2Address(bool v4) const;
void AddSSUAddress(const char *host, int port, const uint8_t *key, int mtu = 0); void AddSSUAddress(const char *host, int port, const uint8_t *key, int mtu = 0);
void AddNTCP2Address(const uint8_t *staticKey, const uint8_t *iv, void AddNTCP2Address(const uint8_t *staticKey, const uint8_t *iv,
const boost::asio::ip::address& host = boost::asio::ip::address(), int port = 0, uint8_t caps = 0); const boost::asio::ip::address &host = boost::asio::ip::address(), int port = 0,
uint8_t caps = 0);
void AddSSU2Address(const uint8_t *staticKey, const uint8_t *introKey, uint8_t caps = 0); // non published void AddSSU2Address(const uint8_t *staticKey, const uint8_t *introKey, uint8_t caps = 0); // non published
void AddSSU2Address(const uint8_t *staticKey, const uint8_t *introKey, void AddSSU2Address(const uint8_t *staticKey, const uint8_t *introKey,
const boost::asio::ip::address &host, int port); // published const boost::asio::ip::address &host, int port); // published
bool AddIntroducer(const Introducer &introducer); bool AddIntroducer(const Introducer &introducer);
bool RemoveIntroducer(const boost::asio::ip::udp::endpoint &e); bool RemoveIntroducer(const boost::asio::ip::udp::endpoint &e);
void SetUnreachableAddressesTransportCaps(uint8_t transports); // bitmask of AddressCaps void SetUnreachableAddressesTransportCaps(uint8_t transports); // bitmask of AddressCaps
void UpdateSupportedTransports(); void UpdateSupportedTransports();
bool IsFloodfill() const { return m_Caps & Caps::eFloodfill; }; bool IsFloodfill() const { return m_Caps & Caps::eFloodfill; };
bool IsReachable() const { return m_Caps & Caps::eReachable; }; bool IsReachable() const { return m_Caps & Caps::eReachable; };
bool IsECIES () const { return m_RouterIdentity->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
bool IsECIES() const {
return m_RouterIdentity->GetCryptoKeyType() == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
};
bool IsSSU(bool v4only = true) const; bool IsSSU(bool v4only = true) const;
bool IsSSUV6() const { return m_SupportedTransports & eSSUV6; }; bool IsSSUV6() const { return m_SupportedTransports & eSSUV6; };
bool IsNTCP2(bool v4only = true) const; bool IsNTCP2(bool v4only = true) const;
bool IsNTCP2V6() const { return m_SupportedTransports & eNTCP2V6; }; bool IsNTCP2V6() const { return m_SupportedTransports & eNTCP2V6; };
bool IsSSU2V4() const { return m_SupportedTransports & eSSU2V4; }; bool IsSSU2V4() const { return m_SupportedTransports & eSSU2V4; };
bool IsSSU2V6() const { return m_SupportedTransports & eSSU2V6; }; bool IsSSU2V6() const { return m_SupportedTransports & eSSU2V6; };
bool IsV6() const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); }; bool IsV6() const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
bool IsV4() const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); }; bool IsV4() const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
bool IsMesh() const { return m_SupportedTransports & eNTCP2V6Mesh; }; bool IsMesh() const { return m_SupportedTransports & eNTCP2V6Mesh; };
void EnableV6(); void EnableV6();
void DisableV6(); void DisableV6();
void EnableV4(); void EnableV4();
void DisableV4(); void DisableV4();
void EnableMesh(); void EnableMesh();
void DisableMesh(); void DisableMesh();
bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; };
bool IsReachableFrom (const RouterInfo& other) const { return m_ReachableTransports & other.m_SupportedTransports; }; bool IsCompatible(const RouterInfo &other) const {
return m_SupportedTransports & other.m_SupportedTransports;
};
bool IsReachableFrom(const RouterInfo &other) const {
return m_ReachableTransports & other.m_SupportedTransports;
};
bool IsReachableBy(CompatibleTransports transports) const { return m_ReachableTransports & transports; }; bool IsReachableBy(CompatibleTransports transports) const { return m_ReachableTransports & transports; };
CompatibleTransports GetCompatibleTransports (bool incoming) const { return incoming ? m_ReachableTransports : m_SupportedTransports; };
CompatibleTransports GetCompatibleTransports(bool incoming) const {
return incoming ? m_ReachableTransports : m_SupportedTransports;
};
bool HasValidAddresses() const { return m_SupportedTransports; }; bool HasValidAddresses() const { return m_SupportedTransports; };
bool IsHidden() const { return m_Caps & eHidden; }; bool IsHidden() const { return m_Caps & eHidden; };
bool IsHighBandwidth() const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsHighBandwidth() const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth() const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsExtraBandwidth() const { return m_Caps & RouterInfo::eExtraBandwidth; };
bool IsEligibleFloodfill() const; bool IsEligibleFloodfill() const;
bool IsPeerTesting(bool v4) const; bool IsPeerTesting(bool v4) const;
bool IsSSU2PeerTesting(bool v4) const; bool IsSSU2PeerTesting(bool v4) const;
bool IsIntroducer(bool v4) const; bool IsIntroducer(bool v4) const;
bool IsSSU2Introducer(bool v4) const; bool IsSSU2Introducer(bool v4) const;
uint8_t GetCaps() const { return m_Caps; }; uint8_t GetCaps() const { return m_Caps; };
void SetCaps(uint8_t caps) { m_Caps = caps; }; void SetCaps(uint8_t caps) { m_Caps = caps; };
void SetUnreachable(bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable(bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable() const { return m_IsUnreachable; }; bool IsUnreachable() const { return m_IsUnreachable; };
const uint8_t *GetBuffer() const { return m_Buffer->data(); }; const uint8_t *GetBuffer() const { return m_Buffer->data(); };
const uint8_t *LoadBuffer(const std::string &fullPath); // load if necessary const uint8_t *LoadBuffer(const std::string &fullPath); // load if necessary
size_t GetBufferLen() const { return m_BufferLen; }; size_t GetBufferLen() const { return m_BufferLen; };
bool IsUpdated() const { return m_IsUpdated; }; bool IsUpdated() const { return m_IsUpdated; };
void SetUpdated(bool updated) { m_IsUpdated = updated; }; void SetUpdated(bool updated) { m_IsUpdated = updated; };
bool SaveToFile(const std::string &fullPath); bool SaveToFile(const std::string &fullPath);
std::shared_ptr<RouterProfile> GetProfile() const; std::shared_ptr<RouterProfile> GetProfile() const;
void SaveProfile() { if (m_Profile) m_Profile->Save(GetIdentHash()); }; void SaveProfile() { if (m_Profile) m_Profile->Save(GetIdentHash()); };
void Update(const uint8_t *buf, size_t len); void Update(const uint8_t *buf, size_t len);
void DeleteBuffer() { m_Buffer = nullptr; }; void DeleteBuffer() { 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 */
@ -263,6 +330,7 @@ namespace data
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_RouterIdentity; }; std::shared_ptr<const IdentityEx> GetIdentity() const { return m_RouterIdentity; };
void Encrypt(const uint8_t *data, uint8_t *encrypted) const; void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
bool IsDestination() const { return false; }; bool IsDestination() const { return false; };
@ -270,25 +338,40 @@ namespace data
protected: protected:
RouterInfo(); RouterInfo();
uint8_t *GetBufferPointer(size_t offset = 0) { return m_Buffer->data() + offset; }; uint8_t *GetBufferPointer(size_t offset = 0) { return m_Buffer->data() + offset; };
void UpdateBuffer(const uint8_t *buf, size_t len); void UpdateBuffer(const uint8_t *buf, size_t len);
void SetBufferLen(size_t len) { m_BufferLen = len; }; void SetBufferLen(size_t len) { m_BufferLen = len; };
void RefreshTimestamp(); void RefreshTimestamp();
const Addresses &GetAddresses() const { return *m_Addresses; }; const Addresses &GetAddresses() const { return *m_Addresses; };
CompatibleTransports GetReachableTransports() const { return m_ReachableTransports; }; CompatibleTransports GetReachableTransports() const { return m_ReachableTransports; };
void SetReachableTransports(CompatibleTransports transports) { m_ReachableTransports = transports; }; void SetReachableTransports(CompatibleTransports transports) { m_ReachableTransports = transports; };
private: private:
bool LoadFile(const std::string &fullPath); bool LoadFile(const std::string &fullPath);
void ReadFromFile(const std::string &fullPath); void ReadFromFile(const std::string &fullPath);
void ReadFromStream(std::istream &s); void ReadFromStream(std::istream &s);
void ReadFromBuffer(bool verifySignature); void ReadFromBuffer(bool verifySignature);
size_t ReadString(char *str, size_t len, std::istream &s) const; size_t ReadString(char *str, size_t len, std::istream &s) const;
void ExtractCaps(const char *value); void ExtractCaps(const char *value);
uint8_t ExtractAddressCaps(const char *value) const; uint8_t ExtractAddressCaps(const char *value) const;
template<typename Filter> template<typename Filter>
std::shared_ptr<const Address> GetAddress(Filter filter) const; std::shared_ptr<const Address> GetAddress(Filter filter) const;
virtual std::shared_ptr<Buffer> NewBuffer() const; virtual std::shared_ptr<Buffer> NewBuffer() const;
private: private:
@ -306,27 +389,35 @@ namespace data
mutable std::shared_ptr<RouterProfile> m_Profile; mutable std::shared_ptr<RouterProfile> m_Profile;
}; };
class LocalRouterInfo: public RouterInfo class LocalRouterInfo : public RouterInfo {
{
public: public:
LocalRouterInfo() = default; LocalRouterInfo() = default;
void CreateBuffer(const PrivateKeys &privateKeys); void CreateBuffer(const PrivateKeys &privateKeys);
void UpdateCaps(uint8_t caps); void UpdateCaps(uint8_t caps);
void SetProperty(const std::string &key, const std::string &value) override; void SetProperty(const std::string &key, const std::string &value) override;
void DeleteProperty(const std::string &key); void DeleteProperty(const std::string &key);
std::string GetProperty(const std::string &key) const; std::string GetProperty(const std::string &key) const;
void ClearProperties() override { m_Properties.clear(); }; void ClearProperties() override { m_Properties.clear(); };
bool AddSSU2Introducer(const Introducer &introducer, bool v4); bool AddSSU2Introducer(const Introducer &introducer, bool v4);
bool RemoveSSU2Introducer(const IdentHash &h, bool v4); bool RemoveSSU2Introducer(const IdentHash &h, bool v4);
private: private:
void WriteToStream(std::ostream &s) const; void WriteToStream(std::ostream &s) const;
void UpdateCapsProperty(); void UpdateCapsProperty();
void WriteString(const std::string &str, std::ostream &s) const; void WriteString(const std::string &str, std::ostream &s) const;
std::shared_ptr<Buffer> NewBuffer() const override; std::shared_ptr<Buffer> NewBuffer() const override;
private: private:

File diff suppressed because it is too large Load diff

View file

@ -25,10 +25,8 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "SSUSession.h" #include "SSUSession.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
@ -38,92 +36,138 @@ namespace transport
const size_t SSU_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
const size_t SSU_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU_SOCKET_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
struct SSUPacket struct SSUPacket {
{
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
boost::asio::ip::udp::endpoint from; boost::asio::ip::udp::endpoint from;
size_t len; size_t len;
}; };
class SSUServer class SSUServer {
{
public: public:
SSUServer(int port); SSUServer(int port);
~SSUServer(); ~SSUServer();
void Start(); void Start();
void Stop(); void Stop();
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false,
bool v4only = false);
bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router, bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
void CreateDirectSession(std::shared_ptr<const i2p::data::RouterInfo> router,
boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
std::shared_ptr<SSUSession> FindSession(const boost::asio::ip::udp::endpoint &e) const; std::shared_ptr<SSUSession> FindSession(const boost::asio::ip::udp::endpoint &e) const;
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session(std::shared_ptr<const SSUSession> excluded); std::shared_ptr<SSUSession> GetRandomEstablishedV4Session(std::shared_ptr<const SSUSession> excluded);
std::shared_ptr<SSUSession> GetRandomEstablishedV6Session(std::shared_ptr<const SSUSession> excluded); std::shared_ptr<SSUSession> GetRandomEstablishedV6Session(std::shared_ptr<const SSUSession> excluded);
void DeleteSession(std::shared_ptr<SSUSession> session); void DeleteSession(std::shared_ptr<SSUSession> session);
void DeleteAllSessions(); void DeleteAllSessions();
boost::asio::io_service &GetService() { return m_Service; }; boost::asio::io_service &GetService() { return m_Service; };
i2p::util::MemoryPool<Fragment> &GetFragmentsPool() { return m_FragmentsPool; }; i2p::util::MemoryPool<Fragment> &GetFragmentsPool() { return m_FragmentsPool; };
i2p::util::MemoryPool<IncompleteMessage> &GetIncompleteMessagesPool() { return m_IncompleteMessagesPool; }; i2p::util::MemoryPool<IncompleteMessage> &GetIncompleteMessagesPool() { return m_IncompleteMessagesPool; };
i2p::util::MemoryPool<SentMessage> &GetSentMessagesPool() { return m_SentMessagesPool; }; i2p::util::MemoryPool<SentMessage> &GetSentMessagesPool() { return m_SentMessagesPool; };
uint16_t GetPort() const { return m_Endpoint.port(); }; uint16_t GetPort() const { return m_Endpoint.port(); };
bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; }; bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; };
void SetLocalAddress(const boost::asio::ip::address &localAddress); void SetLocalAddress(const boost::asio::ip::address &localAddress);
void Send(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &to); void Send(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &to);
void AddRelay(uint32_t tag, std::shared_ptr<SSUSession> relay); void AddRelay(uint32_t tag, std::shared_ptr<SSUSession> relay);
void RemoveRelay(uint32_t tag); void RemoveRelay(uint32_t tag);
std::shared_ptr<SSUSession> FindRelaySession(uint32_t tag); std::shared_ptr<SSUSession> FindRelaySession(uint32_t tag);
void RescheduleIntroducersUpdateTimer(); void RescheduleIntroducersUpdateTimer();
void RescheduleIntroducersUpdateTimerV6(); void RescheduleIntroducersUpdateTimerV6();
void NewPeerTest(uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr); void NewPeerTest(uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
PeerTestParticipant GetPeerTestParticipant(uint32_t nonce); PeerTestParticipant GetPeerTestParticipant(uint32_t nonce);
std::shared_ptr<SSUSession> GetPeerTestSession(uint32_t nonce); std::shared_ptr<SSUSession> GetPeerTestSession(uint32_t nonce);
void UpdatePeerTest(uint32_t nonce, PeerTestParticipant role); void UpdatePeerTest(uint32_t nonce, PeerTestParticipant role);
void RemovePeerTest(uint32_t nonce); void RemovePeerTest(uint32_t nonce);
private: private:
void OpenSocket(); void OpenSocket();
void OpenSocketV6(); void OpenSocketV6();
void Run(); void Run();
void RunReceivers(); void RunReceivers();
void RunReceiversV6(); void RunReceiversV6();
void Receive(); void Receive();
void ReceiveV6(); void ReceiveV6();
void HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet);
void HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet); void HandleReceivedFrom(const boost::system::error_code &ecode, std::size_t bytes_transferred,
SSUPacket *packet);
void HandleReceivedFromV6(const boost::system::error_code &ecode, std::size_t bytes_transferred,
SSUPacket *packet);
void HandleReceivedPackets(std::vector<SSUPacket *> packets, void HandleReceivedPackets(std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > *sessions); std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > *sessions);
void CreateSessionThroughIntroducer(std::shared_ptr<const i2p::data::RouterInfo> router, void CreateSessionThroughIntroducer(std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo::Address> address,
bool peerTest = false);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV4Session(Filter filter); std::shared_ptr<SSUSession> GetRandomV4Session(Filter filter);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV6Session(Filter filter); std::shared_ptr<SSUSession> GetRandomV6Session(Filter filter);
std::list<std::shared_ptr<SSUSession> > FindIntroducers (int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash>& excluded); std::list<std::shared_ptr<SSUSession> >
FindIntroducers(int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash> &excluded);
void ScheduleIntroducersUpdateTimer(); void ScheduleIntroducersUpdateTimer();
void ScheduleIntroducersUpdateTimerV6(); void ScheduleIntroducersUpdateTimerV6();
void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4); void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4);
void SchedulePeerTestsCleanupTimer(); void SchedulePeerTestsCleanupTimer();
void HandlePeerTestsCleanupTimer(const boost::system::error_code &ecode); void HandlePeerTestsCleanupTimer(const boost::system::error_code &ecode);
// timer // timer
void ScheduleTermination(); void ScheduleTermination();
void HandleTerminationTimer(const boost::system::error_code &ecode); void HandleTerminationTimer(const boost::system::error_code &ecode);
void ScheduleTerminationV6(); void ScheduleTerminationV6();
void HandleTerminationTimerV6(const boost::system::error_code &ecode); void HandleTerminationTimerV6(const boost::system::error_code &ecode);
private: private:
struct PeerTest struct PeerTest {
{
uint64_t creationTime; uint64_t creationTime;
PeerTestParticipant role; PeerTestParticipant role;
std::shared_ptr<SSUSession> session; // for Bob to Alice std::shared_ptr<SSUSession> session; // for Bob to Alice
@ -150,8 +194,14 @@ namespace transport
public: public:
// for HTTP only // for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)
const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; }; &
GetSessions() const { return m_Sessions; };
const decltype(m_SessionsV6)
&
GetSessionsV6() const { return m_SessionsV6; };
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -13,10 +13,8 @@
#include "util.h" #include "util.h"
#include "SSU2Session.h" #include "SSU2Session.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds
const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds
const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K const size_t SSU2_SOCKET_RECEIVE_BUFFER_SIZE = 0x1FFFF; // 128K
@ -26,67 +24,89 @@ namespace transport
const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes const int SSU2_TO_INTRODUCER_SESSION_EXPIRATION = 4800; // 80 minutes
const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU2_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
class SSU2Server: private i2p::util::RunnableServiceWithWork class SSU2Server : private i2p::util::RunnableServiceWithWork {
{ struct Packet {
struct Packet
{
uint8_t buf[SSU2_MAX_PACKET_SIZE]; uint8_t buf[SSU2_MAX_PACKET_SIZE];
size_t len; size_t len;
boost::asio::ip::udp::endpoint from; boost::asio::ip::udp::endpoint from;
}; };
class ReceiveService: public i2p::util::RunnableService class ReceiveService : public i2p::util::RunnableService {
{
public: public:
ReceiveService(const std::string &name) : RunnableService(name) {}; ReceiveService(const std::string &name) : RunnableService(name) {};
boost::asio::io_service &GetService() { return GetIOService(); }; boost::asio::io_service &GetService() { return GetIOService(); };
void Start() { StartIOService(); }; void Start() { StartIOService(); };
void Stop() { StopIOService(); }; void Stop() { StopIOService(); };
}; };
public: public:
SSU2Server(); SSU2Server();
~SSU2Server() {}; ~SSU2Server() {};
void Start(); void Start();
void Stop(); void Stop();
boost::asio::io_service &GetService() { return GetIOService(); }; boost::asio::io_service &GetService() { return GetIOService(); };
void SetLocalAddress(const boost::asio::ip::address &localAddress); void SetLocalAddress(const boost::asio::ip::address &localAddress);
bool IsSupported(const boost::asio::ip::address &addr) const; bool IsSupported(const boost::asio::ip::address &addr) const;
uint16_t GetPort(bool v4) const; uint16_t GetPort(bool v4) const;
bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; }; bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; };
void AddSession(std::shared_ptr<SSU2Session> session); void AddSession(std::shared_ptr<SSU2Session> session);
void RemoveSession(uint64_t connID); void RemoveSession(uint64_t connID);
void AddSessionByRouterHash(std::shared_ptr<SSU2Session> session); void AddSessionByRouterHash(std::shared_ptr<SSU2Session> session);
bool AddPendingOutgoingSession(std::shared_ptr<SSU2Session> session); bool AddPendingOutgoingSession(std::shared_ptr<SSU2Session> session);
void RemovePendingOutgoingSession(const boost::asio::ip::udp::endpoint &ep); void RemovePendingOutgoingSession(const boost::asio::ip::udp::endpoint &ep);
std::shared_ptr<SSU2Session> FindSession(const i2p::data::IdentHash &ident) const; std::shared_ptr<SSU2Session> FindSession(const i2p::data::IdentHash &ident) const;
std::shared_ptr<SSU2Session> FindPendingOutgoingSession(const boost::asio::ip::udp::endpoint &ep) const; std::shared_ptr<SSU2Session> FindPendingOutgoingSession(const boost::asio::ip::udp::endpoint &ep) const;
std::shared_ptr<SSU2Session> GetRandomSession(i2p::data::RouterInfo::CompatibleTransports remoteTransports, std::shared_ptr<SSU2Session> GetRandomSession(i2p::data::RouterInfo::CompatibleTransports remoteTransports,
const i2p::data::IdentHash &excluded) const; const i2p::data::IdentHash &excluded) const;
void AddRelay(uint32_t tag, std::shared_ptr<SSU2Session> relay); void AddRelay(uint32_t tag, std::shared_ptr<SSU2Session> relay);
void RemoveRelay(uint32_t tag); void RemoveRelay(uint32_t tag);
std::shared_ptr<SSU2Session> FindRelaySession(uint32_t tag); std::shared_ptr<SSU2Session> FindRelaySession(uint32_t tag);
void Send(const uint8_t *header, size_t headerLen, const uint8_t *payload, size_t payloadLen, void Send(const uint8_t *header, size_t headerLen, const uint8_t *payload, size_t payloadLen,
const boost::asio::ip::udp::endpoint &to); const boost::asio::ip::udp::endpoint &to);
void Send(const uint8_t *header, size_t headerLen, const uint8_t *headerX, size_t headerXLen, void Send(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);
bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router, bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router,
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
bool StartPeerTest(std::shared_ptr<const i2p::data::RouterInfo> router, bool v4); bool StartPeerTest(std::shared_ptr<const i2p::data::RouterInfo> router, bool v4);
void UpdateOutgoingToken(const boost::asio::ip::udp::endpoint &ep, uint64_t token, uint32_t exp); void UpdateOutgoingToken(const boost::asio::ip::udp::endpoint &ep, uint64_t token, uint32_t exp);
uint64_t FindOutgoingToken(const boost::asio::ip::udp::endpoint &ep) const; uint64_t FindOutgoingToken(const boost::asio::ip::udp::endpoint &ep) const;
uint64_t GetIncomingToken(const boost::asio::ip::udp::endpoint &ep); uint64_t GetIncomingToken(const boost::asio::ip::udp::endpoint &ep);
std::pair<uint64_t, uint32_t> NewIncomingToken(const boost::asio::ip::udp::endpoint &ep); std::pair<uint64_t, uint32_t> NewIncomingToken(const boost::asio::ip::udp::endpoint &ep);
void RescheduleIntroducersUpdateTimer(); void RescheduleIntroducersUpdateTimer();
void RescheduleIntroducersUpdateTimerV6(); void RescheduleIntroducersUpdateTimerV6();
i2p::util::MemoryPool<SSU2SentPacket> &GetSentPacketsPool() { return m_SentPacketsPool; }; i2p::util::MemoryPool<SSU2SentPacket> &GetSentPacketsPool() { return m_SentPacketsPool; };
@ -94,25 +114,38 @@ namespace transport
private: private:
boost::asio::ip::udp::socket &OpenSocket(const boost::asio::ip::udp::endpoint &localEndpoint); boost::asio::ip::udp::socket &OpenSocket(const boost::asio::ip::udp::endpoint &localEndpoint);
void Receive(boost::asio::ip::udp::socket &socket); void Receive(boost::asio::ip::udp::socket &socket);
void HandleReceivedFrom(const boost::system::error_code &ecode, size_t bytes_transferred, void HandleReceivedFrom(const boost::system::error_code &ecode, size_t bytes_transferred,
Packet *packet, boost::asio::ip::udp::socket &socket); Packet *packet, boost::asio::ip::udp::socket &socket);
void HandleReceivedPacket(Packet *packet); void HandleReceivedPacket(Packet *packet);
void HandleReceivedPackets(std::vector<Packet *> packets); void HandleReceivedPackets(std::vector<Packet *> packets);
void ProcessNextPacket(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint); void ProcessNextPacket(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint);
void ScheduleTermination(); void ScheduleTermination();
void HandleTerminationTimer(const boost::system::error_code &ecode); void HandleTerminationTimer(const boost::system::error_code &ecode);
void ScheduleResend(); void ScheduleResend();
void HandleResendTimer(const boost::system::error_code &ecode); void HandleResendTimer(const boost::system::error_code &ecode);
void ConnectThroughIntroducer(std::shared_ptr<SSU2Session> session); void ConnectThroughIntroducer(std::shared_ptr<SSU2Session> session);
std::list<std::shared_ptr<SSU2Session> > FindIntroducers(int maxNumIntroducers, std::list<std::shared_ptr<SSU2Session> > FindIntroducers(int maxNumIntroducers,
bool v4, const std::set<i2p::data::IdentHash>& excluded) const; bool v4,
const std::set<i2p::data::IdentHash> &excluded) const;
void UpdateIntroducers(bool v4); void UpdateIntroducers(bool v4);
void ScheduleIntroducersUpdateTimer(); void ScheduleIntroducersUpdateTimer();
void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4); void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4);
void ScheduleIntroducersUpdateTimerV6(); void ScheduleIntroducersUpdateTimerV6();
private: private:
@ -137,7 +170,10 @@ namespace transport
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl
const decltype(m_Sessions)& GetSSU2Sessions () const { return m_Sessions; }; const decltype(m_Sessions)
&
GetSSU2Sessions() const { return m_Sessions; };
}; };
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -20,10 +20,8 @@
#include "RouterContext.h" #include "RouterContext.h"
#include "TransportSession.h" #include "TransportSession.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU2_CLOCK_SKEW = 60; // in seconds const int SSU2_CLOCK_SKEW = 60; // in seconds
@ -48,8 +46,7 @@ namespace transport
const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send
const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
enum SSU2MessageType enum SSU2MessageType {
{
eSSU2SessionRequest = 0, eSSU2SessionRequest = 0,
eSSU2SessionCreated = 1, eSSU2SessionCreated = 1,
eSSU2SessionConfirmed = 2, eSSU2SessionConfirmed = 2,
@ -60,8 +57,7 @@ namespace transport
eSSU2HolePunch = 11 eSSU2HolePunch = 11
}; };
enum SSU2BlockType enum SSU2BlockType {
{
eSSU2BlkDateTime = 0, eSSU2BlkDateTime = 0,
eSSU2BlkOptions, // 1 eSSU2BlkOptions, // 1
eSSU2BlkRouterInfo, // 2 eSSU2BlkRouterInfo, // 2
@ -86,8 +82,7 @@ namespace transport
eSSU2BlkPadding = 254 eSSU2BlkPadding = 254
}; };
enum SSU2SessionState enum SSU2SessionState {
{
eSSU2SessionStateUnknown, eSSU2SessionStateUnknown,
eSSU2SessionStateTokenReceived, eSSU2SessionStateTokenReceived,
eSSU2SessionStateSessionRequestSent, eSSU2SessionStateSessionRequestSent,
@ -105,8 +100,7 @@ namespace transport
eSSU2SessionStateTokenRequestReceived eSSU2SessionStateTokenRequestReceived
}; };
enum SSU2PeerTestCode enum SSU2PeerTestCode {
{
eSSU2PeerTestCodeAccept = 0, eSSU2PeerTestCodeAccept = 0,
eSSU2PeerTestCodeBobReasonUnspecified = 1, eSSU2PeerTestCodeBobReasonUnspecified = 1,
eSSU2PeerTestCodeBobNoCharlieAvailable = 2, eSSU2PeerTestCodeBobNoCharlieAvailable = 2,
@ -122,8 +116,7 @@ namespace transport
eSSU2PeerTestCodeUnspecified = 128 eSSU2PeerTestCodeUnspecified = 128
}; };
enum SSU2RelayResponseCode enum SSU2RelayResponseCode {
{
eSSU2RelayResponseCodeAccept = 0, eSSU2RelayResponseCodeAccept = 0,
eSSU2RelayResponseCodeBobRelayTagNotFound = 5, eSSU2RelayResponseCodeBobRelayTagNotFound = 5,
eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65, eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65,
@ -131,8 +124,7 @@ namespace transport
eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70 eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70
}; };
enum SSU2TerminationReason enum SSU2TerminationReason {
{
eSSU2TerminationReasonNormalClose = 0, eSSU2TerminationReasonNormalClose = 0,
eSSU2TerminationReasonTerminationReceived = 1, eSSU2TerminationReasonTerminationReceived = 1,
eSSU2TerminationReasonIdleTimeout = 2, eSSU2TerminationReasonIdleTimeout = 2,
@ -158,10 +150,8 @@ namespace transport
eSSU2TerminationReasonReplacedByNewSession = 22 eSSU2TerminationReasonReplacedByNewSession = 22
}; };
struct SSU2IncompleteMessage struct SSU2IncompleteMessage {
{ struct Fragment {
struct Fragment
{
uint8_t buf[SSU2_MAX_PACKET_SIZE]; uint8_t buf[SSU2_MAX_PACKET_SIZE];
size_t len; size_t len;
bool isLast; bool isLast;
@ -175,8 +165,7 @@ namespace transport
void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize); void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize);
}; };
struct SSU2SentPacket struct SSU2SentPacket {
{
uint8_t payload[SSU2_MAX_PACKET_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = 0; size_t payloadSize = 0;
uint64_t sendTime; // in milliseconds uint64_t sendTime; // in milliseconds
@ -188,14 +177,12 @@ namespace transport
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02; const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
class SSU2Server; class SSU2Server;
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
{ class SSU2Session : public TransportSession, public std::enable_shared_from_this<SSU2Session> {
union Header union Header {
{
uint64_t ll[2]; uint64_t ll[2];
uint8_t buf[16]; uint8_t buf[16];
struct struct {
{
uint64_t connID; uint64_t connID;
uint32_t packetNum; uint32_t packetNum;
uint8_t type; uint8_t type;
@ -203,8 +190,7 @@ namespace transport
} h; } h;
}; };
struct HandshakePacket struct HandshakePacket {
{
Header header; Header header;
uint8_t headerX[48]; // part1 for SessionConfirmed uint8_t headerX[48]; // part1 for SessionConfirmed
uint8_t payload[SSU2_MAX_PACKET_SIZE * 2]; uint8_t payload[SSU2_MAX_PACKET_SIZE * 2];
@ -219,101 +205,179 @@ namespace transport
SSU2Session(SSU2Server &server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr, SSU2Session(SSU2Server &server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr); std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
~SSU2Session(); ~SSU2Session();
void SetRemoteEndpoint(const boost::asio::ip::udp::endpoint &ep) { m_RemoteEndpoint = ep; }; void SetRemoteEndpoint(const boost::asio::ip::udp::endpoint &ep) { m_RemoteEndpoint = ep; };
const boost::asio::ip::udp::endpoint &GetRemoteEndpoint() const { return m_RemoteEndpoint; }; const boost::asio::ip::udp::endpoint &GetRemoteEndpoint() const { return m_RemoteEndpoint; };
i2p::data::RouterInfo::CompatibleTransports GetRemoteTransports() const { return m_RemoteTransports; }; i2p::data::RouterInfo::CompatibleTransports GetRemoteTransports() const { return m_RemoteTransports; };
std::shared_ptr<const i2p::data::RouterInfo::Address> GetAddress() const { return m_Address; }; std::shared_ptr<const i2p::data::RouterInfo::Address> GetAddress() const { return m_Address; };
void SetOnEstablished(OnEstablished e) { m_OnEstablished = e; }; void SetOnEstablished(OnEstablished e) { m_OnEstablished = e; };
OnEstablished GetOnEstablished() const { return m_OnEstablished; }; OnEstablished GetOnEstablished() const { return m_OnEstablished; };
void Connect(); void Connect();
bool Introduce(std::shared_ptr<SSU2Session> session, uint32_t relayTag); bool Introduce(std::shared_ptr<SSU2Session> session, uint32_t relayTag);
void WaitForIntroduction(); void WaitForIntroduction();
void SendPeerTest(); // Alice, Data message void SendPeerTest(); // Alice, Data message
void SendKeepAlive(); void SendKeepAlive();
void RequestTermination(SSU2TerminationReason reason); void RequestTermination(SSU2TerminationReason reason);
void CleanUp(uint64_t ts); void CleanUp(uint64_t ts);
void FlushData(); void FlushData();
void Done() override; void Done() override;
void SendLocalRouterInfo(bool update) override; void SendLocalRouterInfo(bool update) override;
void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) override; void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) override;
uint32_t GetRelayTag() const override { return m_RelayTag; }; uint32_t GetRelayTag() const override { return m_RelayTag; };
void Resend(uint64_t ts); void Resend(uint64_t ts);
bool IsEstablished() const { return m_State == eSSU2SessionStateEstablished; }; bool IsEstablished() const { return m_State == eSSU2SessionStateEstablished; };
uint64_t GetConnID() const { return m_SourceConnID; }; uint64_t GetConnID() const { return m_SourceConnID; };
SSU2SessionState GetState() const { return m_State; }; SSU2SessionState GetState() const { return m_State; };
void SetState(SSU2SessionState state) { m_State = state; }; void SetState(SSU2SessionState state) { m_State = state; };
bool ProcessFirstIncomingMessage(uint64_t connID, uint8_t *buf, size_t len); bool ProcessFirstIncomingMessage(uint64_t connID, uint8_t *buf, size_t len);
bool ProcessSessionCreated(uint8_t *buf, size_t len); bool ProcessSessionCreated(uint8_t *buf, size_t len);
bool ProcessSessionConfirmed(uint8_t *buf, size_t len); bool ProcessSessionConfirmed(uint8_t *buf, size_t len);
bool ProcessRetry(uint8_t *buf, size_t len); bool ProcessRetry(uint8_t *buf, size_t len);
bool ProcessHolePunch(uint8_t *buf, size_t len); bool ProcessHolePunch(uint8_t *buf, size_t len);
bool ProcessPeerTest(uint8_t *buf, size_t len); bool ProcessPeerTest(uint8_t *buf, size_t len);
void ProcessData(uint8_t *buf, size_t len); void ProcessData(uint8_t *buf, size_t len);
private: private:
void Terminate(); void Terminate();
void Established(); void Established();
void ScheduleConnectTimer(); void ScheduleConnectTimer();
void HandleConnectTimer(const boost::system::error_code &ecode); void HandleConnectTimer(const boost::system::error_code &ecode);
void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs); void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs);
bool SendQueue(); // returns true if ack block was sent bool SendQueue(); // returns true if ack block was sent
bool SendFragmentedMessage(std::shared_ptr<I2NPMessage> msg); bool SendFragmentedMessage(std::shared_ptr<I2NPMessage> msg);
void ResendHandshakePacket(); void ResendHandshakePacket();
void ConnectAfterIntroduction(); void ConnectAfterIntroduction();
void ProcessSessionRequest(Header &header, uint8_t *buf, size_t len); void ProcessSessionRequest(Header &header, uint8_t *buf, size_t len);
void ProcessTokenRequest(Header &header, uint8_t *buf, size_t len); void ProcessTokenRequest(Header &header, uint8_t *buf, size_t len);
void SendSessionRequest(uint64_t token = 0); void SendSessionRequest(uint64_t token = 0);
void SendSessionCreated(const uint8_t *X); void SendSessionCreated(const uint8_t *X);
void SendSessionConfirmed(const uint8_t *Y); void SendSessionConfirmed(const uint8_t *Y);
void KDFDataPhase(uint8_t *keydata_ab, uint8_t *keydata_ba); void KDFDataPhase(uint8_t *keydata_ab, uint8_t *keydata_ba);
void SendTokenRequest(); void SendTokenRequest();
void SendRetry(); void SendRetry();
uint32_t SendData(const uint8_t *buf, size_t len); // returns packet num uint32_t SendData(const uint8_t *buf, size_t len); // returns packet num
void SendQuickAck(); void SendQuickAck();
void SendTermination(); void SendTermination();
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token);
void SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey); // PeerTest message void SendHolePunch(uint32_t nonce, const boost::asio::ip::udp::endpoint &ep, const uint8_t *introKey,
uint64_t token);
void SendPeerTest(uint8_t msg, const uint8_t *signedData, size_t signedDataLen,
const uint8_t *introKey); // PeerTest message
void SendPathResponse(const uint8_t *data, size_t len); void SendPathResponse(const uint8_t *data, size_t len);
void HandlePayload(const uint8_t *buf, size_t len); void HandlePayload(const uint8_t *buf, size_t len);
void HandleDateTime(const uint8_t *buf, size_t len); void HandleDateTime(const uint8_t *buf, size_t len);
void HandleAck(const uint8_t *buf, size_t len); void HandleAck(const uint8_t *buf, size_t len);
void HandleAckRange(uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); void HandleAckRange(uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
void HandleAddress(const uint8_t *buf, size_t len); void HandleAddress(const uint8_t *buf, size_t len);
bool ExtractEndpoint(const uint8_t *buf, size_t size, boost::asio::ip::udp::endpoint &ep); bool ExtractEndpoint(const uint8_t *buf, size_t size, boost::asio::ip::udp::endpoint &ep);
size_t CreateEndpoint(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &ep); size_t CreateEndpoint(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &ep);
std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress() const; std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress() const;
void AdjustMaxPayloadSize(); void AdjustMaxPayloadSize();
RouterStatus GetRouterStatus() const; RouterStatus GetRouterStatus() const;
void SetRouterStatus(RouterStatus status) const; void SetRouterStatus(RouterStatus status) const;
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo(const uint8_t *buf, size_t size); std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo(const uint8_t *buf, size_t size);
void CreateNonce(uint64_t seqn, uint8_t *nonce); void CreateNonce(uint64_t seqn, uint8_t *nonce);
bool UpdateReceivePacketNum(uint32_t packetNum); // for Ack, returns false if duplicate bool UpdateReceivePacketNum(uint32_t packetNum); // for Ack, returns false if duplicate
void HandleFirstFragment(const uint8_t *buf, size_t len); void HandleFirstFragment(const uint8_t *buf, size_t len);
void HandleFollowOnFragment(const uint8_t *buf, size_t len); void HandleFollowOnFragment(const uint8_t *buf, size_t len);
bool ConcatOutOfSequenceFragments(std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete bool ConcatOutOfSequenceFragments(std::shared_ptr<SSU2IncompleteMessage> m); // true if message complete
void HandleRelayRequest(const uint8_t *buf, size_t len); void HandleRelayRequest(const uint8_t *buf, size_t len);
void HandleRelayIntro(const uint8_t *buf, size_t len); void HandleRelayIntro(const uint8_t *buf, size_t len);
void HandleRelayResponse(const uint8_t *buf, size_t len); void HandleRelayResponse(const uint8_t *buf, size_t len);
void HandlePeerTest(const uint8_t *buf, size_t len); void HandlePeerTest(const uint8_t *buf, size_t len);
size_t CreateAddressBlock(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &ep); size_t CreateAddressBlock(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &ep);
size_t CreateRouterInfoBlock(uint8_t *buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r); size_t CreateRouterInfoBlock(uint8_t *buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r);
size_t CreateAckBlock(uint8_t *buf, size_t len); size_t CreateAckBlock(uint8_t *buf, size_t len);
size_t CreatePaddingBlock(uint8_t *buf, size_t len, size_t minSize = 0); size_t CreatePaddingBlock(uint8_t *buf, size_t len, size_t minSize = 0);
size_t CreateI2NPBlock(uint8_t *buf, size_t len, std::shared_ptr<I2NPMessage> &&msg); size_t CreateI2NPBlock(uint8_t *buf, size_t len, std::shared_ptr<I2NPMessage> &&msg);
size_t CreateFirstFragmentBlock(uint8_t *buf, size_t len, std::shared_ptr<I2NPMessage> msg); size_t CreateFirstFragmentBlock(uint8_t *buf, size_t len, std::shared_ptr<I2NPMessage> msg);
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
size_t CreateFollowOnFragmentBlock(uint8_t *buf, size_t len, std::shared_ptr<I2NPMessage> msg,
uint8_t &fragmentNum, uint32_t msgID);
size_t CreateRelayIntroBlock(uint8_t *buf, size_t len, const uint8_t *introData, size_t introDataLen); size_t CreateRelayIntroBlock(uint8_t *buf, size_t len, const uint8_t *introData, size_t introDataLen);
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreateRelayResponseBlock(uint8_t *buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce,
uint64_t token, bool v4);
size_t
CreatePeerTestBlock(uint8_t *buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t *routerHash,
const uint8_t *signedData, size_t signedDataLen);
size_t CreatePeerTestBlock(uint8_t *buf, size_t len, uint32_t nonce); // Alice size_t CreatePeerTestBlock(uint8_t *buf, size_t len, uint32_t nonce); // Alice
size_t CreateTerminationBlock(uint8_t *buf, size_t len); size_t CreateTerminationBlock(uint8_t *buf, size_t len);
@ -347,8 +411,7 @@ namespace transport
size_t m_MaxPayloadSize; size_t m_MaxPayloadSize;
}; };
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) inline uint64_t CreateHeaderMask(const uint8_t *kh, const uint8_t *nonce) {
{
uint64_t data = 0; uint64_t data = 0;
i2p::crypto::ChaCha20((uint8_t * ) & data, 8, kh, nonce, (uint8_t * ) & data); i2p::crypto::ChaCha20((uint8_t * ) & data, 8, kh, nonce, (uint8_t * ) & data);
return data; return data;

View file

@ -13,14 +13,10 @@
#include "SSU.h" #include "SSU.h"
#include "SSUData.h" #include "SSUData.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport void IncompleteMessage::AttachNextFragment(const uint8_t *fragment, size_t fragmentSize) {
{ if (msg->len + fragmentSize > msg->maxLen) {
void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
{
if (msg->len + fragmentSize > msg->maxLen)
{
LogPrint(eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough"); LogPrint(eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
auto newMsg = NewI2NPMessage(); auto newMsg = NewI2NPMessage();
*newMsg = *msg; *newMsg = *msg;
@ -34,74 +30,60 @@ namespace transport
SSUData::SSUData(SSUSession &session) : SSUData::SSUData(SSUSession &session) :
m_Session(session), m_ResendTimer(session.GetService()), m_Session(session), m_ResendTimer(session.GetService()),
m_MaxPacketSize(session.IsV6() ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE), m_MaxPacketSize(session.IsV6() ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0) m_PacketSize(m_MaxPacketSize), m_LastMessageReceivedTime(0) {
{
} }
SSUData::~SSUData () SSUData::~SSUData() {
{
} }
void SSUData::Start () void SSUData::Start() {
{
} }
void SSUData::Stop () void SSUData::Stop() {
{
m_ResendTimer.cancel(); m_ResendTimer.cancel();
m_IncompleteMessages.clear(); m_IncompleteMessages.clear();
m_SentMessages.clear(); m_SentMessages.clear();
m_ReceivedMessages.clear(); m_ReceivedMessages.clear();
} }
void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter) void SSUData::AdjustPacketSize(std::shared_ptr<const i2p::data::RouterInfo> remoteRouter) {
{
if (!remoteRouter) return; if (!remoteRouter) return;
auto ssuAddress = remoteRouter->GetSSUAddress(); auto ssuAddress = remoteRouter->GetSSUAddress();
if (ssuAddress && ssuAddress->ssu->mtu) if (ssuAddress && ssuAddress->ssu->mtu) {
{
if (m_Session.IsV6()) if (m_Session.IsV6())
m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
else else
m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; m_PacketSize = ssuAddress->ssu->mtu - IPV4_HEADER_SIZE - UDP_HEADER_SIZE;
if (m_PacketSize > 0) if (m_PacketSize > 0) {
{
// make sure packet size multiple of 16 // make sure packet size multiple of 16
m_PacketSize >>= 4; m_PacketSize >>= 4;
m_PacketSize <<= 4; m_PacketSize <<= 4;
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize; if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
LogPrint(eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize); LogPrint(eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
} } else {
else
{
LogPrint(eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu); LogPrint(eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
m_PacketSize = m_MaxPacketSize; m_PacketSize = m_MaxPacketSize;
} }
} }
} }
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent) void SSUData::UpdatePacketSize(const i2p::data::IdentHash &remoteIdent) {
{
auto routerInfo = i2p::data::netdb.FindRouter(remoteIdent); auto routerInfo = i2p::data::netdb.FindRouter(remoteIdent);
if (routerInfo) if (routerInfo)
AdjustPacketSize(routerInfo); AdjustPacketSize(routerInfo);
} }
void SSUData::ProcessSentMessageAck (uint32_t msgID) void SSUData::ProcessSentMessageAck(uint32_t msgID) {
{
auto it = m_SentMessages.find(msgID); auto it = m_SentMessages.find(msgID);
if (it != m_SentMessages.end ()) if (it != m_SentMessages.end()) {
{
m_SentMessages.erase(it); m_SentMessages.erase(it);
if (m_SentMessages.empty()) if (m_SentMessages.empty())
m_ResendTimer.cancel(); m_ResendTimer.cancel();
} }
} }
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag) void SSUData::ProcessAcks(uint8_t *&buf, uint8_t flag) {
{ if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED) {
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
{
// explicit ACKs // explicit ACKs
uint8_t numAcks = *buf; uint8_t numAcks = *buf;
buf++; buf++;
@ -109,33 +91,27 @@ namespace transport
ProcessSentMessageAck(bufbe32toh(buf + i * 4)); ProcessSentMessageAck(bufbe32toh(buf + i * 4));
buf += numAcks * 4; buf += numAcks * 4;
} }
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED) if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED) {
{
// explicit ACK bitfields // explicit ACK bitfields
uint8_t numBitfields = *buf; uint8_t numBitfields = *buf;
buf++; buf++;
for (int i = 0; i < numBitfields; i++) for (int i = 0; i < numBitfields; i++) {
{
uint32_t msgID = bufbe32toh(buf); uint32_t msgID = bufbe32toh(buf);
buf += 4; // msgID buf += 4; // msgID
auto it = m_SentMessages.find(msgID); auto it = m_SentMessages.find(msgID);
// process individual Ack bitfields // process individual Ack bitfields
bool isNonLast = false; bool isNonLast = false;
int fragment = 0; int fragment = 0;
do do {
{
uint8_t bitfield = *buf; uint8_t bitfield = *buf;
isNonLast = bitfield & 0x80; isNonLast = bitfield & 0x80;
bitfield &= 0x7F; // clear MSB bitfield &= 0x7F; // clear MSB
if (bitfield && it != m_SentMessages.end ()) if (bitfield && it != m_SentMessages.end()) {
{
int numSentFragments = it->second->fragments.size(); int numSentFragments = it->second->fragments.size();
// process bits // process bits
uint8_t mask = 0x01; uint8_t mask = 0x01;
for (int j = 0; j < 7; j++) for (int j = 0; j < 7; j++) {
{ if (bitfield & mask) {
if (bitfield & mask)
{
if (fragment < numSentFragments) if (fragment < numSentFragments)
it->second->fragments[fragment] = nullptr; it->second->fragments[fragment] = nullptr;
} }
@ -144,18 +120,15 @@ namespace transport
} }
} }
buf++; buf++;
} } while (isNonLast);
while (isNonLast);
} }
} }
} }
void SSUData::ProcessFragments (uint8_t * buf) void SSUData::ProcessFragments(uint8_t *buf) {
{
uint8_t numFragments = *buf; // number of fragments uint8_t numFragments = *buf; // number of fragments
buf++; buf++;
for (int i = 0; i < numFragments; i++) for (int i = 0; i < numFragments; i++) {
{
uint32_t msgID = bufbe32toh(buf); // message ID uint32_t msgID = bufbe32toh(buf); // message ID
buf += 4; buf += 4;
uint8_t frag[4] = {0}; uint8_t frag[4] = {0};
@ -165,21 +138,20 @@ namespace transport
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13 uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
bool isLast = fragmentInfo & 0x010000; // bit 16 bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE) if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE) {
{
LogPrint(eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size"); LogPrint(eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
return; return;
} }
// find message with msgID // find message with msgID
auto it = m_IncompleteMessages.find(msgID); auto it = m_IncompleteMessages.find(msgID);
if (it == m_IncompleteMessages.end ()) if (it == m_IncompleteMessages.end()) {
{
// create new message // create new message
auto msg = NewI2NPShortMessage(); auto msg = NewI2NPShortMessage();
msg->len -= I2NP_SHORT_HEADER_SIZE; msg->len -= I2NP_SHORT_HEADER_SIZE;
it = m_IncompleteMessages.insert(std::make_pair(msgID, it = m_IncompleteMessages.insert(std::make_pair(msgID,
m_Session.GetServer ().GetIncompleteMessagesPool ().AcquireShared (std::move (msg)))).first; m_Session.GetServer().GetIncompleteMessagesPool().AcquireShared(
std::move(msg)))).first;
} }
auto &incompleteMessage = it->second; auto &incompleteMessage = it->second;
// mark fragment as received // mark fragment as received
@ -189,49 +161,46 @@ namespace transport
LogPrint(eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64"); LogPrint(eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
// handle current fragment // handle current fragment
if (fragmentNum == incompleteMessage->nextFragmentNum) if (fragmentNum == incompleteMessage->nextFragmentNum) {
{
// expected fragment // expected fragment
incompleteMessage->AttachNextFragment(buf, fragmentSize); incompleteMessage->AttachNextFragment(buf, fragmentSize);
if (!isLast && !incompleteMessage->savedFragments.empty ()) if (!isLast && !incompleteMessage->savedFragments.empty()) {
{
// try saved fragments // try saved fragments
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();) for (auto it1 = incompleteMessage->savedFragments.begin();
{ it1 != incompleteMessage->savedFragments.end();) {
auto &savedFragment = *it1; auto &savedFragment = *it1;
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) {
{
incompleteMessage->AttachNextFragment(savedFragment->buf, savedFragment->len); incompleteMessage->AttachNextFragment(savedFragment->buf, savedFragment->len);
isLast = savedFragment->isLast; isLast = savedFragment->isLast;
incompleteMessage->savedFragments.erase(it1++); incompleteMessage->savedFragments.erase(it1++);
} } else
else
break; break;
} }
if (isLast) if (isLast)
LogPrint(eLogDebug, "SSU: Message ", msgID, " complete"); LogPrint(eLogDebug, "SSU: Message ", msgID, " complete");
} }
} } else {
else
{
if (fragmentNum < incompleteMessage->nextFragmentNum) if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment // duplicate fragment
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored"); LogPrint(eLogWarning, "SSU: Duplicate fragment ", (int) fragmentNum, " of message ", msgID,
else ", ignored");
{ else {
// missing fragment // missing fragment
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID); LogPrint(eLogWarning, "SSU: Missing fragments from ", (int) incompleteMessage->nextFragmentNum,
auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast); " to ", fragmentNum - 1, " of message ", msgID);
auto savedFragment = m_Session.GetServer().GetFragmentsPool().AcquireShared(fragmentNum, buf,
fragmentSize,
isLast);
if (incompleteMessage->savedFragments.insert(savedFragment).second) if (incompleteMessage->savedFragments.insert(savedFragment).second)
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch(); incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch();
else else
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); LogPrint(eLogWarning, "SSU: Fragment ", (int) fragmentNum, " of message ", msgID,
" already saved");
} }
isLast = false; isLast = false;
} }
if (isLast) if (isLast) {
{
// delete incomplete message // delete incomplete message
auto msg = incompleteMessage->msg; auto msg = incompleteMessage->msg;
incompleteMessage->msg = nullptr; incompleteMessage->msg = nullptr;
@ -239,47 +208,35 @@ namespace transport
// process message // process message
SendMsgAck(msgID); SendMsgAck(msgID);
msg->FromSSU(msgID); msg->FromSSU(msgID);
if (m_Session.GetState () == eSessionStateEstablished) if (m_Session.GetState() == eSessionStateEstablished) {
{ if (!m_ReceivedMessages.count(msgID)) {
if (!m_ReceivedMessages.count (msgID))
{
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch(); m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch();
m_ReceivedMessages.emplace(msgID, m_LastMessageReceivedTime); m_ReceivedMessages.emplace(msgID, m_LastMessageReceivedTime);
if (!msg->IsExpired ()) if (!msg->IsExpired()) {
{
m_Handler.PutNextMessage(std::move(msg)); m_Handler.PutNextMessage(std::move(msg));
} } else
else
LogPrint(eLogDebug, "SSU: message expired"); LogPrint(eLogDebug, "SSU: message expired");
} } else
else
LogPrint(eLogWarning, "SSU: Message ", msgID, " already received"); LogPrint(eLogWarning, "SSU: Message ", msgID, " already received");
} } else {
else
{
// we expect DeliveryStatus // we expect DeliveryStatus
if (msg->GetTypeID () == eI2NPDeliveryStatus) if (msg->GetTypeID() == eI2NPDeliveryStatus) {
{
LogPrint(eLogDebug, "SSU: session established"); LogPrint(eLogDebug, "SSU: session established");
m_Session.Established(); m_Session.Established();
} } else
else
LogPrint(eLogError, "SSU: unexpected message ", (int) msg->GetTypeID()); LogPrint(eLogError, "SSU: unexpected message ", (int) msg->GetTypeID());
} }
} } else
else
SendFragmentAck(msgID, incompleteMessage->receivedFragmentsBits); SendFragmentAck(msgID, incompleteMessage->receivedFragmentsBits);
buf += fragmentSize; buf += fragmentSize;
} }
} }
void SSUData::FlushReceivedMessage () void SSUData::FlushReceivedMessage() {
{
m_Handler.Flush(); m_Handler.Flush();
} }
void SSUData::ProcessMessage (uint8_t * buf, size_t len) void SSUData::ProcessMessage(uint8_t *buf, size_t len) {
{
//uint8_t * start = buf; //uint8_t * start = buf;
uint8_t flag = *buf; uint8_t flag = *buf;
buf++; buf++;
@ -288,8 +245,7 @@ namespace transport
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED)) if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
ProcessAcks(buf, flag); ProcessAcks(buf, flag);
// extended data if presented // extended data if presented
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED) if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED) {
{
uint8_t extendedDataSize = *buf; uint8_t extendedDataSize = *buf;
buf++; // size buf++; // size
LogPrint(eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present"); LogPrint(eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
@ -299,11 +255,9 @@ namespace transport
ProcessFragments(buf); ProcessFragments(buf);
} }
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg) void SSUData::Send(std::shared_ptr<i2p::I2NPMessage> msg) {
{
uint32_t msgID = msg->ToSSU(); uint32_t msgID = msg->ToSSU();
if (m_SentMessages.find (msgID) != m_SentMessages.end()) if (m_SentMessages.find(msgID) != m_SentMessages.end()) {
{
LogPrint(eLogWarning, "SSU: message ", msgID, " already sent"); LogPrint(eLogWarning, "SSU: message ", msgID, " already sent");
return; return;
} }
@ -312,19 +266,18 @@ namespace transport
auto ret = m_SentMessages.emplace(msgID, m_Session.GetServer().GetSentMessagesPool().AcquireShared()); auto ret = m_SentMessages.emplace(msgID, m_Session.GetServer().GetSentMessagesPool().AcquireShared());
auto &sentMessage = ret.first->second; auto &sentMessage = ret.first->second;
if (ret.second) if (ret.second) {
{
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch() + RESEND_INTERVAL; sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch() + RESEND_INTERVAL;
sentMessage->numResends = 0; sentMessage->numResends = 0;
} }
auto &fragments = sentMessage->fragments; auto &fragments = sentMessage->fragments;
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) size_t payloadSize =
m_PacketSize - sizeof(SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength(); size_t len = msg->GetLength();
uint8_t *msgBuf = msg->GetSSUHeader(); uint8_t *msgBuf = msg->GetSSUHeader();
uint32_t fragmentNum = 0; uint32_t fragmentNum = 0;
while (len > 0 && fragmentNum <= 127) while (len > 0 && fragmentNum <= 127) {
{
auto fragment = m_Session.GetServer().GetFragmentsPool().AcquireShared(); auto fragment = m_Session.GetServer().GetFragmentsPool().AcquireShared();
fragment->fragmentNum = fragmentNum; fragment->fragmentNum = fragmentNum;
uint8_t *payload = fragment->buf + sizeof(SSUHeader); uint8_t *payload = fragment->buf + sizeof(SSUHeader);
@ -360,27 +313,22 @@ namespace transport
// encrypt message with session key // encrypt message with session key
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, fragment->buf, size, buf); m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
try try {
{
m_Session.Send(buf, size); m_Session.Send(buf, size);
} }
catch (boost::system::system_error& ec) catch (boost::system::system_error &ec) {
{
LogPrint(eLogWarning, "SSU: Can't send data fragment ", ec.what()); LogPrint(eLogWarning, "SSU: Can't send data fragment ", ec.what());
} }
if (!isLast) if (!isLast) {
{
len -= payloadSize; len -= payloadSize;
msgBuf += payloadSize; msgBuf += payloadSize;
} } else
else
len = 0; len = 0;
fragmentNum++; fragmentNum++;
} }
} }
void SSUData::SendMsgAck (uint32_t msgID) void SSUData::SendMsgAck(uint32_t msgID) {
{
uint8_t buf[48 + 18] = {0}; // actual length is 44 = 37 + 7 but pad it to multiple of 16 uint8_t buf[48 + 18] = {0}; // actual length is 44 = 37 + 7 but pad it to multiple of 16
uint8_t *payload = buf + sizeof(SSUHeader); uint8_t *payload = buf + sizeof(SSUHeader);
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag *payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
@ -396,8 +344,7 @@ namespace transport
m_Session.Send(buf, 48); m_Session.Send(buf, 48);
} }
void SSUData::SendFragmentAck (uint32_t msgID, uint64_t bits) void SSUData::SendFragmentAck(uint32_t msgID, uint64_t bits) {
{
if (!bits) return; if (!bits) return;
uint8_t buf[64 + 18] = {0}; uint8_t buf[64 + 18] = {0};
uint8_t *payload = buf + sizeof(SSUHeader); uint8_t *payload = buf + sizeof(SSUHeader);
@ -409,12 +356,12 @@ namespace transport
*(uint32_t * )(payload) = htobe32(msgID); // msgID *(uint32_t * )(payload) = htobe32(msgID); // msgID
payload += 4; payload += 4;
size_t len = 0; size_t len = 0;
while (bits) while (bits) {
{
*payload = (bits & 0x7F); // next 7 bits *payload = (bits & 0x7F); // next 7 bits
bits >>= 7; bits >>= 7;
if (bits) *payload &= 0x80; // 0x80 means non-last if (bits) *payload &= 0x80; // 0x80 means non-last
payload++; len++; payload++;
len++;
} }
*payload = 0; // number of fragments *payload = 0; // number of fragments
len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4 len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
@ -423,88 +370,73 @@ namespace transport
m_Session.Send(buf, len); m_Session.Send(buf, len);
} }
void SSUData::ScheduleResend() void SSUData::ScheduleResend() {
{
m_ResendTimer.cancel(); m_ResendTimer.cancel();
m_ResendTimer.expires_from_now(boost::posix_time::seconds(RESEND_INTERVAL)); m_ResendTimer.expires_from_now(boost::posix_time::seconds(RESEND_INTERVAL));
auto s = m_Session.shared_from_this(); auto s = m_Session.shared_from_this();
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode) m_ResendTimer.async_wait(
{ s->m_Data.HandleResendTimer (ecode); }); [s](const boost::system::error_code &ecode) { s->m_Data.HandleResendTimer(ecode); });
} }
void SSUData::HandleResendTimer (const boost::system::error_code& ecode) void SSUData::HandleResendTimer(const boost::system::error_code &ecode) {
{ if (ecode != boost::asio::error::operation_aborted) {
if (ecode != boost::asio::error::operation_aborted)
{
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
uint32_t ts = i2p::util::GetSecondsSinceEpoch(); uint32_t ts = i2p::util::GetSecondsSinceEpoch();
int numResent = 0; int numResent = 0;
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();) for (auto it = m_SentMessages.begin(); it != m_SentMessages.end();) {
{ if (ts >= it->second->nextResendTime) {
if (ts >= it->second->nextResendTime) if (it->second->numResends < MAX_NUM_RESENDS) {
{
if (it->second->numResends < MAX_NUM_RESENDS)
{
for (auto &f: it->second->fragments) for (auto &f: it->second->fragments)
if (f) if (f) {
{ try {
try
{
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, f->buf, f->len, buf); m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
m_Session.Send(buf, f->len); // resend m_Session.Send(buf, f->len); // resend
numResent++; numResent++;
} }
catch (boost::system::system_error& ec) catch (boost::system::system_error &ec) {
{ LogPrint(eLogWarning, "SSU: Can't resend message ", it->first,
LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ()); " data fragment: ", ec.what());
} }
} }
it->second->numResends++; it->second->numResends++;
it->second->nextResendTime += it->second->numResends * RESEND_INTERVAL; it->second->nextResendTime += it->second->numResends * RESEND_INTERVAL;
++it; ++it;
} } else {
else LogPrint(eLogInfo, "SSU: message ", it->first, " has not been ACKed after ",
{ MAX_NUM_RESENDS, " attempts, deleted");
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
it = m_SentMessages.erase(it); it = m_SentMessages.erase(it);
} }
} } else
else
++it; ++it;
} }
if (m_SentMessages.empty()) return; // nothing to resend if (m_SentMessages.empty()) return; // nothing to resend
if (numResent < MAX_OUTGOING_WINDOW_SIZE) if (numResent < MAX_OUTGOING_WINDOW_SIZE)
ScheduleResend(); ScheduleResend();
else else {
{
LogPrint(eLogError, "SSU: resend window exceeds max size. Session terminated"); LogPrint(eLogError, "SSU: resend window exceeds max size. Session terminated");
m_Session.Close(); m_Session.Close();
} }
} }
} }
void SSUData::CleanUp (uint64_t ts) void SSUData::CleanUp(uint64_t ts) {
{ for (auto it = m_IncompleteMessages.begin(); it != m_IncompleteMessages.end();) {
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT) {
{ LogPrint(eLogWarning, "SSU: message ", it->first, " was not completed in ",
if (ts > it->second->lastFragmentInsertTime + INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT) INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
{
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
it = m_IncompleteMessages.erase(it); it = m_IncompleteMessages.erase(it);
} } else
else
++it; ++it;
} }
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || ts > m_LastMessageReceivedTime + DECAY_INTERVAL) if (m_ReceivedMessages.size() > MAX_NUM_RECEIVED_MESSAGES ||
ts > m_LastMessageReceivedTime + DECAY_INTERVAL)
// decay // decay
m_ReceivedMessages.clear(); m_ReceivedMessages.clear();
else else {
{
// delete old received messages // delete old received messages
for (auto it = m_ReceivedMessages.begin (); it != m_ReceivedMessages.end ();) for (auto it = m_ReceivedMessages.begin(); it != m_ReceivedMessages.end();) {
{
if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT) if (ts > it->second + RECEIVED_MESSAGES_CLEANUP_TIMEOUT)
it = m_ReceivedMessages.erase(it); it = m_ReceivedMessages.erase(it);
else else

View file

@ -21,10 +21,8 @@
#include "RouterInfo.h" #include "RouterInfo.h"
#include "TransportSession.h" #include "TransportSession.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const size_t SSU_MTU_V4 = 1484; const size_t SSU_MTU_V4 = 1484;
const size_t SSU_MTU_V6 = 1488; const size_t SSU_MTU_V6 = 1488;
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
@ -44,28 +42,25 @@ namespace transport
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40; const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80; const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
struct Fragment struct Fragment {
{
int fragmentNum; int fragmentNum;
size_t len; size_t len;
bool isLast; bool isLast;
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
Fragment() = default; Fragment() = default;
Fragment(int n, const uint8_t *b, int l, bool last) : Fragment(int n, const uint8_t *b, int l, bool last) :
fragmentNum(n), len(l), isLast(last) { memcpy(buf, b, len); }; fragmentNum(n), len(l), isLast(last) { memcpy(buf, b, len); };
}; };
struct FragmentCmp struct FragmentCmp {
{ bool operator()(const std::shared_ptr<Fragment> &f1, const std::shared_ptr<Fragment> &f2) const {
bool operator() (const std::shared_ptr<Fragment>& f1, const std::shared_ptr<Fragment>& f2) const
{
return f1->fragmentNum < f2->fragmentNum; return f1->fragmentNum < f2->fragmentNum;
}; };
}; };
struct IncompleteMessage struct IncompleteMessage {
{
std::shared_ptr<I2NPMessage> msg; std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum; int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds uint32_t lastFragmentInsertTime; // in seconds
@ -73,45 +68,57 @@ namespace transport
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments; std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
IncompleteMessage(std::shared_ptr<I2NPMessage> &&m) : msg(m), nextFragmentNum(0), IncompleteMessage(std::shared_ptr<I2NPMessage> &&m) : msg(m), nextFragmentNum(0),
lastFragmentInsertTime (0), receivedFragmentsBits (0) {}; lastFragmentInsertTime(0),
receivedFragmentsBits(0) {};
void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize); void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize);
}; };
struct SentMessage struct SentMessage {
{
std::vector<std::shared_ptr<Fragment> > fragments; std::vector<std::shared_ptr<Fragment> > fragments;
uint32_t nextResendTime; // in seconds uint32_t nextResendTime; // in seconds
int numResends; int numResends;
}; };
class SSUSession; class SSUSession;
class SSUData
{ class SSUData {
public: public:
SSUData(SSUSession &session); SSUData(SSUSession &session);
~SSUData(); ~SSUData();
void Start(); void Start();
void Stop(); void Stop();
void CleanUp(uint64_t ts); void CleanUp(uint64_t ts);
void ProcessMessage(uint8_t *buf, size_t len); void ProcessMessage(uint8_t *buf, size_t len);
void FlushReceivedMessage(); void FlushReceivedMessage();
void Send(std::shared_ptr<i2p::I2NPMessage> msg); void Send(std::shared_ptr<i2p::I2NPMessage> msg);
void AdjustPacketSize(std::shared_ptr<const i2p::data::RouterInfo> remoteRouter); void AdjustPacketSize(std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
void UpdatePacketSize(const i2p::data::IdentHash &remoteIdent); void UpdatePacketSize(const i2p::data::IdentHash &remoteIdent);
private: private:
void SendMsgAck(uint32_t msgID); void SendMsgAck(uint32_t msgID);
void SendFragmentAck(uint32_t msgID, uint64_t bits); void SendFragmentAck(uint32_t msgID, uint64_t bits);
void ProcessAcks(uint8_t *&buf, uint8_t flag); void ProcessAcks(uint8_t *&buf, uint8_t flag);
void ProcessFragments(uint8_t *buf); void ProcessFragments(uint8_t *buf);
void ProcessSentMessageAck(uint32_t msgID); void ProcessSentMessageAck(uint32_t msgID);
void ScheduleResend(); void ScheduleResend();
void HandleResendTimer(const boost::system::error_code &ecode); void HandleResendTimer(const boost::system::error_code &ecode);
private: private:

File diff suppressed because it is too large Load diff

View file

@ -17,19 +17,18 @@
#include "TransportSession.h" #include "TransportSession.h"
#include "SSUData.h" #include "SSUData.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04; const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
struct SSUHeader
{ struct SSUHeader {
uint8_t mac[16]; uint8_t mac[16];
uint8_t iv[16]; uint8_t iv[16];
uint8_t flag; uint8_t flag;
uint8_t time[4]; uint8_t time[4];
uint8_t GetPayloadType() const { return flag >> 4; }; uint8_t GetPayloadType() const { return flag >> 4; };
bool IsExtendedOptions() const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; }; bool IsExtendedOptions() const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
}; };
@ -53,8 +52,7 @@ namespace transport
// extended options // extended options
const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001; const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
enum SessionState enum SessionState {
{
eSessionStateUnknown, eSessionStateUnknown,
eSessionStateIntroduced, eSessionStateIntroduced,
eSessionStateEstablished, eSessionStateEstablished,
@ -62,8 +60,7 @@ namespace transport
eSessionStateFailed eSessionStateFailed
}; };
enum PeerTestParticipant enum PeerTestParticipant {
{
ePeerTestParticipantUnknown = 0, ePeerTestParticipantUnknown = 0,
ePeerTestParticipantAlice1, ePeerTestParticipantAlice1,
ePeerTestParticipantAlice2, ePeerTestParticipantAlice2,
@ -72,82 +69,127 @@ namespace transport
}; };
class SSUServer; class SSUServer;
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{ class SSUSession : public TransportSession, public std::enable_shared_from_this<SSUSession> {
public: public:
SSUSession(SSUServer &server, boost::asio::ip::udp::endpoint &remoteEndpoint, SSUSession(SSUServer &server, boost::asio::ip::udp::endpoint &remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
void ProcessNextMessage(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint); void ProcessNextMessage(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint);
~SSUSession(); ~SSUSession();
void Connect(); void Connect();
void WaitForConnect(); void WaitForConnect();
void Introduce(const i2p::data::RouterInfo::Introducer &introducer, void Introduce(const i2p::data::RouterInfo::Introducer &introducer,
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
void WaitForIntroduction(); void WaitForIntroduction();
void Close(); void Close();
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; };
SSUServer &GetServer() { return m_Server; }; SSUServer &GetServer() { return m_Server; };
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; };
void SendKeepAlive(); void SendKeepAlive();
uint32_t GetRelayTag() const { return m_RelayTag; }; uint32_t GetRelayTag() const { return m_RelayTag; };
const i2p::data::RouterInfo::IntroKey &GetIntroKey() const { return m_IntroKey; }; const i2p::data::RouterInfo::IntroKey &GetIntroKey() const { return m_IntroKey; };
void FlushData(); void FlushData();
void CleanUp(uint64_t ts); void CleanUp(uint64_t ts);
private: private:
boost::asio::io_service &GetService(); boost::asio::io_service &GetService();
void CreateAESandMacKey(const uint8_t *pubKey); void CreateAESandMacKey(const uint8_t *pubKey);
size_t GetSSUHeaderSize(const uint8_t *buf) const; size_t GetSSUHeaderSize(const uint8_t *buf) const;
void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs); void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
void ProcessMessage(uint8_t *buf, size_t len,
const boost::asio::ip::udp::endpoint &senderEndpoint); // call for established session
void ProcessSessionRequest(const uint8_t *buf, size_t len); void ProcessSessionRequest(const uint8_t *buf, size_t len);
void SendSessionRequest(); void SendSessionRequest();
void SendRelayRequest(const i2p::data::RouterInfo::Introducer &introducer, uint32_t nonce); void SendRelayRequest(const i2p::data::RouterInfo::Introducer &introducer, uint32_t nonce);
void ProcessSessionCreated(uint8_t *buf, size_t len); void ProcessSessionCreated(uint8_t *buf, size_t len);
void SendSessionCreated(const uint8_t *x, bool sendRelayTag = true); void SendSessionCreated(const uint8_t *x, bool sendRelayTag = true);
void ProcessSessionConfirmed(const uint8_t *buf, size_t len); void ProcessSessionConfirmed(const uint8_t *buf, size_t len);
void SendSessionConfirmed(const uint8_t *y, const uint8_t *ourAddress, size_t ourAddressLen); void SendSessionConfirmed(const uint8_t *y, const uint8_t *ourAddress, size_t ourAddressLen);
void ProcessRelayRequest(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &from); void ProcessRelayRequest(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &from);
void SendRelayResponse(uint32_t nonce, const boost::asio::ip::udp::endpoint &from, void SendRelayResponse(uint32_t nonce, const boost::asio::ip::udp::endpoint &from,
const uint8_t *introKey, const boost::asio::ip::udp::endpoint &to); const uint8_t *introKey, const boost::asio::ip::udp::endpoint &to);
void SendRelayIntro(std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint &from); void SendRelayIntro(std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint &from);
void ProcessRelayResponse(const uint8_t *buf, size_t len); void ProcessRelayResponse(const uint8_t *buf, size_t len);
void ProcessRelayIntro(const uint8_t *buf, size_t len); void ProcessRelayIntro(const uint8_t *buf, size_t len);
void Established(); void Established();
void ScheduleConnectTimer(); void ScheduleConnectTimer();
void HandleConnectTimer(const boost::system::error_code &ecode); void HandleConnectTimer(const boost::system::error_code &ecode);
void ProcessPeerTest(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint); void ProcessPeerTest(const uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint);
void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
void SendPeerTest(uint32_t nonce, const boost::asio::ip::address &address, uint16_t port,
const uint8_t *introKey, bool toAddress = true, bool sendAddress = true);
void ProcessData(uint8_t *buf, size_t len); void ProcessData(uint8_t *buf, size_t len);
void SendSessionDestroyed(); void SendSessionDestroyed();
void Send(uint8_t type, const uint8_t *payload, size_t len); // with session key void Send(uint8_t type, const uint8_t *payload, size_t len); // with session key
void Send(const uint8_t *buf, size_t size); void Send(const uint8_t *buf, size_t size);
void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *buf, size_t len, const i2p::crypto::AESKey &aesKey, void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *buf, size_t len, const i2p::crypto::AESKey &aesKey,
const uint8_t *iv, const i2p::crypto::MACKey &macKey, uint8_t flag = 0); const uint8_t *iv, const i2p::crypto::MACKey &macKey, uint8_t flag = 0);
void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *buf, size_t len); // with session key void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *buf, size_t len); // with session key
void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *in, size_t len, uint8_t *out); // with session key void FillHeaderAndEncrypt(uint8_t payloadType, uint8_t *in, size_t len, uint8_t *out); // with session key
void Decrypt(uint8_t *buf, size_t len, const i2p::crypto::AESKey &aesKey); void Decrypt(uint8_t *buf, size_t len, const i2p::crypto::AESKey &aesKey);
void DecryptSessionKey(uint8_t *buf, size_t len); void DecryptSessionKey(uint8_t *buf, size_t len);
bool Validate(uint8_t *buf, size_t len, const i2p::crypto::MACKey &macKey); bool Validate(uint8_t *buf, size_t len, const i2p::crypto::MACKey &macKey);
void Reset(); void Reset();
static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size static size_t ExtractIPAddressAndPort(const uint8_t *buf, size_t len, boost::asio::ip::address &ip,
uint16_t &port); // returns actual buf size
private: private:

View file

@ -10,10 +10,8 @@
#include "Log.h" #include "Log.h"
#include "Signature.h" #include "Signature.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto
{
#if OPENSSL_EDDSA #if OPENSSL_EDDSA
EDDSA25519Verifier::EDDSA25519Verifier () EDDSA25519Verifier::EDDSA25519Verifier ()
{ {
@ -38,24 +36,21 @@ namespace crypto
} }
#else #else
EDDSA25519Verifier::EDDSA25519Verifier ()
{ EDDSA25519Verifier::EDDSA25519Verifier() {
} }
EDDSA25519Verifier::~EDDSA25519Verifier () EDDSA25519Verifier::~EDDSA25519Verifier() {
{
} }
void EDDSA25519Verifier::SetPublicKey (const uint8_t * signingKey) void EDDSA25519Verifier::SetPublicKey(const uint8_t *signingKey) {
{
memcpy(m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); memcpy(m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
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];
SHA512_CTX ctx; SHA512_CTX ctx;
SHA512_Init(&ctx); SHA512_Init(&ctx);
@ -66,10 +61,11 @@ namespace crypto
return GetEd25519()->Verify(m_PublicKey, digest, signature); return GetEd25519()->Verify(m_PublicKey, digest, signature);
} }
#endif #endif
EDDSA25519SignerCompat::EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) EDDSA25519SignerCompat::EDDSA25519SignerCompat(const uint8_t *signingPrivateKey,
{ const uint8_t *signingPublicKey) {
// expand key // expand key
Ed25519::ExpandPrivateKey(signingPrivateKey, m_ExpandedPrivateKey); Ed25519::ExpandPrivateKey(signingPrivateKey, m_ExpandedPrivateKey);
// generate and encode public key // generate and encode public key
@ -77,8 +73,7 @@ namespace crypto
auto publicKey = GetEd25519()->GeneratePublicKey(m_ExpandedPrivateKey, ctx); auto publicKey = GetEd25519()->GeneratePublicKey(m_ExpandedPrivateKey, ctx);
GetEd25519()->EncodePublicKey(publicKey, m_PublicKeyEncoded, ctx); GetEd25519()->EncodePublicKey(publicKey, m_PublicKeyEncoded, ctx);
if (signingPublicKey && memcmp (m_PublicKeyEncoded, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH)) if (signingPublicKey && memcmp(m_PublicKeyEncoded, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH)) {
{
// keys don't match, it means older key with 0x1F // keys don't match, it means older key with 0x1F
LogPrint(eLogWarning, "Older EdDSA key detected"); LogPrint(eLogWarning, "Older EdDSA key detected");
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
@ -88,12 +83,10 @@ namespace crypto
BN_CTX_free(ctx); BN_CTX_free(ctx);
} }
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);
} }

View file

@ -19,60 +19,59 @@
#include "Ed25519.h" #include "Ed25519.h"
#include "Gost.h" #include "Gost.h"
namespace i2p namespace i2p {
{ namespace crypto {
namespace crypto class Verifier {
{
class Verifier
{
public: public:
virtual ~Verifier() {}; virtual ~Verifier() {};
virtual bool Verify(const uint8_t *buf, size_t len, const uint8_t *signature) const = 0; virtual bool Verify(const uint8_t *buf, size_t len, const uint8_t *signature) const = 0;
virtual size_t GetPublicKeyLen() const = 0; virtual size_t GetPublicKeyLen() const = 0;
virtual size_t GetSignatureLen() const = 0; virtual size_t GetSignatureLen() const = 0;
virtual size_t GetPrivateKeyLen() const { return GetSignatureLen() / 2; }; virtual size_t GetPrivateKeyLen() const { return GetSignatureLen() / 2; };
virtual void SetPublicKey(const uint8_t *signingKey) = 0; virtual void SetPublicKey(const uint8_t *signingKey) = 0;
}; };
class Signer class Signer {
{
public: public:
virtual ~Signer() {}; virtual ~Signer() {};
virtual void Sign(const uint8_t *buf, int len, uint8_t *signature) const = 0; virtual void Sign(const uint8_t *buf, int len, uint8_t *signature) const = 0;
}; };
const size_t DSA_PUBLIC_KEY_LENGTH = 128; const size_t DSA_PUBLIC_KEY_LENGTH = 128;
const size_t DSA_SIGNATURE_LENGTH = 40; const size_t DSA_SIGNATURE_LENGTH = 40;
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH / 2; const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH / 2;
class DSAVerifier: public Verifier
{ class DSAVerifier : public Verifier {
public: public:
DSAVerifier () DSAVerifier() {
{
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);
} }
~DSAVerifier () ~DSAVerifier() {
{
DSA_free(m_PublicKey); DSA_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 {
{
// calculate SHA1 digest // calculate SHA1 digest
uint8_t digest[20]; uint8_t digest[20];
SHA1(buf, len, digest); SHA1(buf, len, digest);
// signature // signature
DSA_SIG *sig = DSA_SIG_new(); DSA_SIG *sig = DSA_SIG_new();
DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); DSA_SIG_set0(sig, BN_bin2bn(signature, DSA_SIGNATURE_LENGTH / 2, NULL),
BN_bin2bn(signature + DSA_SIGNATURE_LENGTH / 2, DSA_SIGNATURE_LENGTH / 2, NULL));
// DSA verification // DSA verification
int ret = DSA_do_verify(digest, 20, sig, m_PublicKey); int ret = DSA_do_verify(digest, 20, sig, m_PublicKey);
DSA_SIG_free(sig); DSA_SIG_free(sig);
@ -80,6 +79,7 @@ namespace crypto
} }
size_t GetPublicKeyLen() const { return DSA_PUBLIC_KEY_LENGTH; }; size_t GetPublicKeyLen() const { return DSA_PUBLIC_KEY_LENGTH; };
size_t GetSignatureLen() const { return DSA_SIGNATURE_LENGTH; }; size_t GetSignatureLen() const { return DSA_SIGNATURE_LENGTH; };
private: private:
@ -87,24 +87,22 @@ namespace crypto
DSA *m_PublicKey; DSA *m_PublicKey;
}; };
class DSASigner: public Signer class DSASigner : public Signer {
{
public: public:
DSASigner(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey) DSASigner(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey)
// openssl 1.1 always requires DSA public key even for signing // openssl 1.1 always requires DSA public key even for signing
{ {
m_PrivateKey = CreateDSA(); m_PrivateKey = CreateDSA();
DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); DSA_set0_key(m_PrivateKey, BN_bin2bn(signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL),
BN_bin2bn(signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
} }
~DSASigner () ~DSASigner() {
{
DSA_free(m_PrivateKey); DSA_free(m_PrivateKey);
} }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign(const uint8_t *buf, int len, uint8_t *signature) const {
{
uint8_t digest[20]; uint8_t digest[20];
SHA1(buf, len, digest); SHA1(buf, len, digest);
DSA_SIG *sig = DSA_do_sign(digest, 20, m_PrivateKey); DSA_SIG *sig = DSA_do_sign(digest, 20, m_PrivateKey);
@ -120,8 +118,7 @@ namespace crypto
DSA *m_PrivateKey; DSA *m_PrivateKey;
}; };
inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateDSARandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
{
DSA *dsa = CreateDSA(); DSA *dsa = CreateDSA();
DSA_generate_key(dsa); DSA_generate_key(dsa);
const BIGNUM *pub_key, *priv_key; const BIGNUM *pub_key, *priv_key;
@ -131,62 +128,58 @@ namespace crypto
DSA_free(dsa); DSA_free(dsa);
} }
struct SHA256Hash struct SHA256Hash {
{ static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA256(buf, len, digest); SHA256(buf, len, digest);
} }
enum { hashLen = 32 }; enum {
hashLen = 32
};
}; };
struct SHA384Hash struct SHA384Hash {
{ static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA384(buf, len, digest); SHA384(buf, len, digest);
} }
enum { hashLen = 48 }; enum {
hashLen = 48
};
}; };
struct SHA512Hash struct SHA512Hash {
{ static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
SHA512(buf, len, digest); SHA512(buf, len, digest);
} }
enum { hashLen = 64 }; enum {
hashLen = 64
};
}; };
// EcDSA // EcDSA
template<typename Hash, int curve, size_t keyLen> template<typename Hash, int curve, size_t keyLen>
class ECDSAVerifier: public Verifier class ECDSAVerifier : public Verifier {
{
public: public:
ECDSAVerifier () ECDSAVerifier() {
{
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);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
} }
~ECDSAVerifier () ~ECDSAVerifier() {
{
EC_KEY_free(m_PublicKey); EC_KEY_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 {
{
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash(buf, len, digest); Hash::CalculateHash(buf, len, digest);
ECDSA_SIG *sig = ECDSA_SIG_new(); ECDSA_SIG *sig = ECDSA_SIG_new();
@ -200,6 +193,7 @@ namespace crypto
} }
size_t GetPublicKeyLen() const { return keyLen; }; size_t GetPublicKeyLen() const { return keyLen; };
size_t GetSignatureLen() const { return keyLen; }; // signature length = key length size_t GetSignatureLen() const { return keyLen; }; // signature length = key length
@ -209,23 +203,19 @@ namespace crypto
}; };
template<typename Hash, int curve, size_t keyLen> template<typename Hash, int curve, size_t keyLen>
class ECDSASigner: public Signer class ECDSASigner : public Signer {
{
public: public:
ECDSASigner (const uint8_t * signingPrivateKey) ECDSASigner(const uint8_t *signingPrivateKey) {
{
m_PrivateKey = EC_KEY_new_by_curve_name(curve); m_PrivateKey = EC_KEY_new_by_curve_name(curve);
EC_KEY_set_private_key(m_PrivateKey, BN_bin2bn(signingPrivateKey, keyLen / 2, NULL)); EC_KEY_set_private_key(m_PrivateKey, BN_bin2bn(signingPrivateKey, keyLen / 2, NULL));
} }
~ECDSASigner () ~ECDSASigner() {
{
EC_KEY_free(m_PrivateKey); EC_KEY_free(m_PrivateKey);
} }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign(const uint8_t *buf, int len, uint8_t *signature) const {
{
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash(buf, len, digest); Hash::CalculateHash(buf, len, digest);
ECDSA_SIG *sig = ECDSA_do_sign(digest, Hash::hashLen, m_PrivateKey); ECDSA_SIG *sig = ECDSA_do_sign(digest, Hash::hashLen, m_PrivateKey);
@ -242,8 +232,8 @@ namespace crypto
EC_KEY *m_PrivateKey; EC_KEY *m_PrivateKey;
}; };
inline void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void
{ CreateECDSARandomKeys(int curve, size_t keyLen, uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
EC_KEY *signingKey = EC_KEY_new_by_curve_name(curve); EC_KEY *signingKey = EC_KEY_new_by_curve_name(curve);
EC_KEY_generate_key(signingKey); EC_KEY_generate_key(signingKey);
bn2buf(EC_KEY_get0_private_key(signingKey), signingPrivateKey, keyLen / 2); bn2buf(EC_KEY_get0_private_key(signingKey), signingPrivateKey, keyLen / 2);
@ -252,7 +242,8 @@ namespace crypto
EC_KEY_get0_public_key(signingKey), x, y, NULL); EC_KEY_get0_public_key(signingKey), x, y, NULL);
bn2buf(x, signingPublicKey, keyLen / 2); bn2buf(x, signingPublicKey, keyLen / 2);
bn2buf(y, signingPublicKey + keyLen / 2, keyLen / 2); bn2buf(y, signingPublicKey + keyLen / 2, keyLen / 2);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
EC_KEY_free(signingKey); EC_KEY_free(signingKey);
} }
@ -261,8 +252,7 @@ namespace crypto
typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier; typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer; typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP256RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
{
CreateECDSARandomKeys(NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); CreateECDSARandomKeys(NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
} }
@ -271,8 +261,7 @@ namespace crypto
typedef ECDSAVerifier<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Verifier; typedef ECDSAVerifier<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Verifier;
typedef ECDSASigner<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Signer; typedef ECDSASigner<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Signer;
inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP384RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
{
CreateECDSARandomKeys(NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); CreateECDSARandomKeys(NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
} }
@ -281,24 +270,25 @@ namespace crypto
typedef ECDSAVerifier<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Verifier; typedef ECDSAVerifier<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Verifier;
typedef ECDSASigner<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Signer; typedef ECDSASigner<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Signer;
inline void CreateECDSAP521RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP521RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
{
CreateECDSARandomKeys(NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); CreateECDSARandomKeys(NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey);
} }
// EdDSA // EdDSA
class EDDSA25519Verifier: public Verifier class EDDSA25519Verifier : public Verifier {
{
public: public:
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; };
size_t GetSignatureLen() const { return EDDSA25519_SIGNATURE_LENGTH; }; size_t GetSignatureLen() const { return EDDSA25519_SIGNATURE_LENGTH; };
private: private:
@ -311,15 +301,16 @@ namespace crypto
#endif #endif
}; };
class EDDSA25519SignerCompat: public Signer class EDDSA25519SignerCompat : public Signer {
{
public: public:
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:
@ -350,8 +341,7 @@ namespace crypto
#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);
@ -372,24 +362,24 @@ namespace crypto
// ГОСТ Р 34.11 // ГОСТ Р 34.11
struct GOSTR3411_256_Hash struct GOSTR3411_256_Hash {
{ static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
GOSTR3411_2012_256(buf, len, digest); GOSTR3411_2012_256(buf, len, digest);
} }
enum { hashLen = 32 }; enum {
hashLen = 32
};
}; };
struct GOSTR3411_512_Hash struct GOSTR3411_512_Hash {
{ static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{
GOSTR3411_2012_512(buf, len, digest); GOSTR3411_2012_512(buf, len, digest);
} }
enum { hashLen = 64 }; enum {
hashLen = 64
};
}; };
// ГОСТ Р 34.10 // ГОСТ Р 34.10
@ -397,42 +387,44 @@ namespace crypto
const size_t GOSTR3410_512_PUBLIC_KEY_LENGTH = 128; const size_t GOSTR3410_512_PUBLIC_KEY_LENGTH = 128;
template<typename Hash> template<typename Hash>
class GOSTR3410Verifier: public Verifier class GOSTR3410Verifier : public Verifier {
{
public: public:
enum { keyLen = Hash::hashLen }; enum {
keyLen = Hash::hashLen
};
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 {
{
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash(buf, len, digest); Hash::CalculateHash(buf, len, digest);
BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr); BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr);
BIGNUM *r = BN_bin2bn(signature, GetSignatureLen() / 2, NULL); BIGNUM *r = BN_bin2bn(signature, GetSignatureLen() / 2, NULL);
BIGNUM *s = BN_bin2bn(signature + GetSignatureLen() / 2, GetSignatureLen() / 2, NULL); BIGNUM *s = BN_bin2bn(signature + GetSignatureLen() / 2, GetSignatureLen() / 2, NULL);
bool ret = GetGOSTR3410Curve(m_ParamSet)->Verify(m_PublicKey, d, r, s); bool ret = GetGOSTR3410Curve(m_ParamSet)->Verify(m_PublicKey, d, r, s);
BN_free (d); BN_free (r); BN_free (s); BN_free(d);
BN_free(r);
BN_free(s);
return ret; return ret;
} }
size_t GetPublicKeyLen() const { return keyLen * 2; } size_t GetPublicKeyLen() const { return keyLen * 2; }
size_t GetSignatureLen() const { return keyLen * 2; } size_t GetSignatureLen() const { return keyLen * 2; }
private: private:
@ -442,21 +434,21 @@ namespace crypto
}; };
template<typename Hash> template<typename Hash>
class GOSTR3410Signer: public Signer class GOSTR3410Signer : public Signer {
{
public: public:
enum { keyLen = Hash::hashLen }; enum {
keyLen = Hash::hashLen
};
GOSTR3410Signer(GOSTR3410ParamSet paramSet, const uint8_t *signingPrivateKey) : GOSTR3410Signer(GOSTR3410ParamSet paramSet, const uint8_t *signingPrivateKey) :
m_ParamSet (paramSet) m_ParamSet(paramSet) {
{
m_PrivateKey = BN_bin2bn(signingPrivateKey, keyLen, nullptr); m_PrivateKey = BN_bin2bn(signingPrivateKey, keyLen, nullptr);
} }
~GOSTR3410Signer() { BN_free(m_PrivateKey); } ~GOSTR3410Signer() { BN_free(m_PrivateKey); }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign(const uint8_t *buf, int len, uint8_t *signature) const {
{
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash(buf, len, digest); Hash::CalculateHash(buf, len, digest);
BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr); BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr);
@ -464,7 +456,9 @@ namespace crypto
GetGOSTR3410Curve(m_ParamSet)->Sign(m_PrivateKey, d, r, s); GetGOSTR3410Curve(m_ParamSet)->Sign(m_PrivateKey, d, r, s);
bn2buf(r, signature, keyLen); bn2buf(r, signature, keyLen);
bn2buf(s, signature + keyLen, keyLen); bn2buf(s, signature + keyLen, keyLen);
BN_free (d); BN_free (r); BN_free (s); BN_free(d);
BN_free(r);
BN_free(s);
} }
private: private:
@ -473,8 +467,8 @@ namespace crypto
BIGNUM *m_PrivateKey; BIGNUM *m_PrivateKey;
}; };
inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void
{ CreateGOSTR3410RandomKeys(GOSTR3410ParamSet paramSet, uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
const auto &curve = GetGOSTR3410Curve(paramSet); const auto &curve = GetGOSTR3410Curve(paramSet);
auto keyLen = curve->GetKeyLen(); auto keyLen = curve->GetKeyLen();
RAND_bytes(signingPrivateKey, keyLen); RAND_bytes(signingPrivateKey, keyLen);
@ -487,7 +481,8 @@ namespace crypto
EC_POINT_free(pub); EC_POINT_free(pub);
bn2buf(x, signingPublicKey, keyLen); bn2buf(x, signingPublicKey, keyLen);
bn2buf(y, signingPublicKey + keyLen, keyLen); bn2buf(y, signingPublicKey + keyLen, keyLen);
BN_free (x); BN_free (y); BN_free(x);
BN_free(y);
} }
typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier; typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier;
@ -497,22 +492,21 @@ namespace crypto
// RedDSA // RedDSA
typedef EDDSA25519Verifier RedDSA25519Verifier; typedef EDDSA25519Verifier RedDSA25519Verifier;
class RedDSA25519Signer: public Signer
{ class RedDSA25519Signer : public Signer {
public: public:
RedDSA25519Signer (const uint8_t * signingPrivateKey) RedDSA25519Signer(const uint8_t *signingPrivateKey) {
{
memcpy(m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); memcpy(m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
BN_CTX *ctx = BN_CTX_new(); BN_CTX *ctx = BN_CTX_new();
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);
} }
@ -524,8 +518,7 @@ namespace crypto
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
}; };
inline void CreateRedDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateRedDSA25519RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
{
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);

View file

@ -12,32 +12,26 @@
#include "Crypto.h" #include "Crypto.h"
#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;
@ -48,20 +42,17 @@ namespace crypto
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;
@ -81,8 +72,7 @@ namespace crypto
/** 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;
@ -101,8 +91,7 @@ namespace crypto
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)
@ -112,8 +101,7 @@ namespace crypto
buf += 8; buf += 8;
} }
while(left) while (left) {
{
--left; --left;
b |= ((uint64_t)(buf[left])) << (left * 8); b |= ((uint64_t)(buf[left])) << (left * 8);
} }

File diff suppressed because it is too large Load diff

View file

@ -27,14 +27,11 @@
#include "Tunnel.h" #include "Tunnel.h"
#include "util.h" // MemoryPool #include "util.h" // MemoryPool
namespace i2p namespace i2p {
{ namespace client {
namespace client
{
class ClientDestination; class ClientDestination;
} }
namespace stream namespace stream {
{
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001; const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
const uint16_t PACKET_FLAG_CLOSE = 0x0002; const uint16_t PACKET_FLAG_CLOSE = 0x0002;
const uint16_t PACKET_FLAG_RESET = 0x0004; const uint16_t PACKET_FLAG_RESET = 0x0004;
@ -64,81 +61,102 @@ namespace stream
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
const int MAX_RECEIVE_TIMEOUT = 20; // in seconds const int MAX_RECEIVE_TIMEOUT = 20; // in seconds
struct Packet struct Packet {
{
size_t len, offset; size_t len, offset;
uint8_t buf[MAX_PACKET_SIZE]; uint8_t buf[MAX_PACKET_SIZE];
uint64_t sendTime; uint64_t sendTime;
Packet() : len(0), offset(0), sendTime(0) {}; Packet() : len(0), offset(0), sendTime(0) {};
uint8_t *GetBuffer() { return buf + offset; }; uint8_t *GetBuffer() { return buf + offset; };
size_t GetLength() const { return len - offset; }; size_t GetLength() const { return len - offset; };
uint32_t GetSendStreamID() const { return bufbe32toh(buf); }; uint32_t GetSendStreamID() const { return bufbe32toh(buf); };
uint32_t GetReceiveStreamID() const { return bufbe32toh(buf + 4); }; uint32_t GetReceiveStreamID() const { return bufbe32toh(buf + 4); };
uint32_t GetSeqn() const { return bufbe32toh(buf + 8); }; uint32_t GetSeqn() const { return bufbe32toh(buf + 8); };
uint32_t GetAckThrough() const { return bufbe32toh(buf + 12); }; uint32_t GetAckThrough() const { return bufbe32toh(buf + 12); };
uint8_t GetNACKCount() const { return buf[16]; }; uint8_t GetNACKCount() const { return buf[16]; };
uint32_t GetNACK(int i) const { return bufbe32toh(buf + 17 + 4 * i); }; uint32_t GetNACK(int i) const { return bufbe32toh(buf + 17 + 4 * i); };
const uint8_t *GetOption() const { return buf + 17 + GetNACKCount() * 4 + 3; }; // 3 = resendDelay + flags const uint8_t *GetOption() const { return buf + 17 + GetNACKCount() * 4 + 3; }; // 3 = resendDelay + flags
uint16_t GetFlags() const { return bufbe16toh(GetOption() - 2); }; uint16_t GetFlags() const { return bufbe16toh(GetOption() - 2); };
uint16_t GetOptionSize() const { return bufbe16toh(GetOption()); }; uint16_t GetOptionSize() const { return bufbe16toh(GetOption()); };
const uint8_t *GetOptionData() const { return GetOption() + 2; }; const uint8_t *GetOptionData() const { return GetOption() + 2; };
const uint8_t *GetPayload() const { return GetOptionData() + GetOptionSize(); }; const uint8_t *GetPayload() const { return GetOptionData() + GetOptionSize(); };
bool IsSYN() const { return GetFlags() & PACKET_FLAG_SYNCHRONIZE; }; bool IsSYN() const { return GetFlags() & PACKET_FLAG_SYNCHRONIZE; };
bool IsNoAck() const { return GetFlags() & PACKET_FLAG_NO_ACK; }; bool IsNoAck() const { return GetFlags() & PACKET_FLAG_NO_ACK; };
bool IsEcho() const { return GetFlags() & PACKET_FLAG_ECHO; }; bool IsEcho() const { return GetFlags() & PACKET_FLAG_ECHO; };
}; };
struct PacketCmp struct PacketCmp {
{ bool operator()(const Packet *p1, const Packet *p2) const {
bool operator() (const Packet * p1, const Packet * p2) const
{
return p1->GetSeqn() < p2->GetSeqn(); return p1->GetSeqn() < p2->GetSeqn();
}; };
}; };
typedef std::function<void(const boost::system::error_code &ecode)> SendHandler; typedef std::function<void(const boost::system::error_code &ecode)> SendHandler;
struct SendBuffer
{ struct SendBuffer {
uint8_t *buf; uint8_t *buf;
size_t len, offset; size_t len, offset;
SendHandler handler; SendHandler handler;
SendBuffer(const uint8_t *b, size_t l, SendHandler h) : SendBuffer(const uint8_t *b, size_t l, SendHandler h) :
len(l), offset (0), handler(h) len(l), offset(0), handler(h) {
{
buf = new uint8_t[len]; buf = new uint8_t[len];
memcpy(buf, b, len); memcpy(buf, b, len);
} }
SendBuffer(size_t l) : // create empty buffer SendBuffer(size_t l) : // create empty buffer
len(l), offset (0) len(l), offset(0) {
{
buf = new uint8_t[len]; buf = new uint8_t[len];
} }
~SendBuffer ()
{ ~SendBuffer() {
delete[] buf; delete[] buf;
if (handler) handler(boost::system::error_code()); if (handler) handler(boost::system::error_code());
} }
size_t GetRemainingSize() const { return len - offset; }; size_t GetRemainingSize() const { return len - offset; };
const uint8_t *GetRemaningBuffer() const { return buf + offset; }; const uint8_t *GetRemaningBuffer() const { return buf + offset; };
void Cancel () { if (handler) handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); handler = nullptr; };
void Cancel() {
if (handler)
handler(boost::asio::error::make_error_code(boost::asio::error::operation_aborted));
handler = nullptr;
};
}; };
class SendBufferQueue class SendBufferQueue {
{
public: public:
SendBufferQueue() : m_Size(0) {}; SendBufferQueue() : m_Size(0) {};
~SendBufferQueue() { CleanUp(); }; ~SendBufferQueue() { CleanUp(); };
void Add(const uint8_t *buf, size_t len, SendHandler handler); void Add(const uint8_t *buf, size_t len, SendHandler handler);
void Add(std::shared_ptr<SendBuffer> buf); void Add(std::shared_ptr<SendBuffer> buf);
size_t Get(uint8_t *buf, size_t len); size_t Get(uint8_t *buf, size_t len);
size_t GetSize() const { return m_Size; }; size_t GetSize() const { return m_Size; };
bool IsEmpty() const { return m_Buffers.empty(); }; bool IsEmpty() const { return m_Buffers.empty(); };
void CleanUp(); void CleanUp();
private: private:
@ -147,8 +165,7 @@ namespace stream
size_t m_Size; size_t m_Size;
}; };
enum StreamStatus enum StreamStatus {
{
eStreamStatusNew = 0, eStreamStatusNew = 0,
eStreamStatusOpen, eStreamStatusOpen,
eStreamStatusReset, eStreamStatusReset,
@ -158,8 +175,8 @@ namespace stream
}; };
class StreamingDestination; class StreamingDestination;
class Stream: public std::enable_shared_from_this<Stream>
{ class Stream : public std::enable_shared_from_this<Stream> {
public: public:
Stream(boost::asio::io_service &service, StreamingDestination &local, Stream(boost::asio::io_service &service, StreamingDestination &local,
@ -167,37 +184,57 @@ namespace stream
Stream(boost::asio::io_service &service, StreamingDestination &local); // incoming Stream(boost::asio::io_service &service, StreamingDestination &local); // incoming
~Stream(); ~Stream();
uint32_t GetSendStreamID() const { return m_SendStreamID; }; uint32_t GetSendStreamID() const { return m_SendStreamID; };
uint32_t GetRecvStreamID() const { return m_RecvStreamID; }; uint32_t GetRecvStreamID() const { return m_RecvStreamID; };
std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet() const { return m_RemoteLeaseSet; }; std::shared_ptr<const i2p::data::LeaseSet> GetRemoteLeaseSet() const { return m_RemoteLeaseSet; };
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity() const { return m_RemoteIdentity; }; std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity() const { return m_RemoteIdentity; };
bool IsOpen() const { return m_Status == eStreamStatusOpen; }; bool IsOpen() const { return m_Status == eStreamStatusOpen; };
bool IsEstablished() const { return m_SendStreamID; }; bool IsEstablished() const { return m_SendStreamID; };
StreamStatus GetStatus() const { return m_Status; }; StreamStatus GetStatus() const { return m_Status; };
StreamingDestination &GetLocalDestination() { return m_LocalDestination; }; StreamingDestination &GetLocalDestination() { return m_LocalDestination; };
void HandleNextPacket(Packet *packet); void HandleNextPacket(Packet *packet);
void HandlePing(Packet *packet); void HandlePing(Packet *packet);
size_t Send(const uint8_t *buf, size_t len); size_t Send(const uint8_t *buf, size_t len);
void AsyncSend(const uint8_t *buf, size_t len, SendHandler handler); void AsyncSend(const uint8_t *buf, size_t len, SendHandler handler);
void SendPing(); void SendPing();
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void AsyncReceive(const Buffer &buffer, ReceiveHandler handler, int timeout = 0); void AsyncReceive(const Buffer &buffer, ReceiveHandler handler, int timeout = 0);
size_t ReadSome(uint8_t *buf, size_t len) { return ConcatenatePackets(buf, len); }; size_t ReadSome(uint8_t *buf, size_t len) { return ConcatenatePackets(buf, len); };
void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); }; void AsyncClose() { m_Service.post(std::bind(&Stream::Close, shared_from_this())); };
/** only call close from destination thread, use Stream::AsyncClose for other threads */ /** only call close from destination thread, use Stream::AsyncClose for other threads */
void Close(); void Close();
void Cancel() { m_ReceiveTimer.cancel(); }; void Cancel() { m_ReceiveTimer.cancel(); };
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; };
size_t GetSendQueueSize() const { return m_SentPackets.size(); }; size_t GetSendQueueSize() const { return m_SentPackets.size(); };
size_t GetReceiveQueueSize() const { return m_ReceiveQueue.size(); }; size_t GetReceiveQueueSize() const { return m_ReceiveQueue.size(); };
size_t GetSendBufferSize() const { return m_SendBuffer.GetSize(); }; size_t GetSendBufferSize() const { return m_SendBuffer.GetSize(); };
int GetWindowSize() const { return m_WindowSize; }; int GetWindowSize() const { return m_WindowSize; };
int GetRTT() const { return m_RTT; }; int GetRTT() const { return m_RTT; };
void Terminate(bool deleteFromDestination = true); void Terminate(bool deleteFromDestination = true);
@ -207,25 +244,38 @@ namespace stream
void CleanUp(); void CleanUp();
void SendBuffer(); void SendBuffer();
void SendQuickAck(); void SendQuickAck();
void SendClose(); void SendClose();
bool SendPacket(Packet *packet); bool SendPacket(Packet *packet);
void SendPackets(const std::vector<Packet *> &packets); void SendPackets(const std::vector<Packet *> &packets);
void SendUpdatedLeaseSet(); void SendUpdatedLeaseSet();
void SavePacket(Packet *packet); void SavePacket(Packet *packet);
void ProcessPacket(Packet *packet); void ProcessPacket(Packet *packet);
bool ProcessOptions(uint16_t flags, Packet *packet); bool ProcessOptions(uint16_t flags, Packet *packet);
void ProcessAck(Packet *packet); void ProcessAck(Packet *packet);
size_t ConcatenatePackets(uint8_t *buf, size_t len); size_t ConcatenatePackets(uint8_t *buf, size_t len);
void UpdateCurrentRemoteLease(bool expired = false); void UpdateCurrentRemoteLease(bool expired = false);
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout); void
HandleReceiveTimer(const boost::system::error_code &ecode, const Buffer &buffer, ReceiveHandler handler,
int remainingTimeout);
void ScheduleResend(); void ScheduleResend();
void HandleResendTimer(const boost::system::error_code &ecode); void HandleResendTimer(const boost::system::error_code &ecode);
void HandleAckSendTimer(const boost::system::error_code &ecode); void HandleAckSendTimer(const boost::system::error_code &ecode);
private: private:
@ -257,42 +307,60 @@ namespace stream
size_t m_MTU; size_t m_MTU;
}; };
class StreamingDestination: public std::enable_shared_from_this<StreamingDestination> class StreamingDestination : public std::enable_shared_from_this<StreamingDestination> {
{
public: public:
typedef std::function<void(std::shared_ptr<Stream>)> Acceptor; typedef std::function<void(std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0, bool gzip = false); StreamingDestination(std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0,
bool gzip = false);
~StreamingDestination(); ~StreamingDestination();
void Start(); void Start();
void Stop(); void Stop();
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); std::shared_ptr<Stream>
CreateNewOutgoingStream(std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void SendPing(std::shared_ptr<const i2p::data::LeaseSet> remote); void SendPing(std::shared_ptr<const i2p::data::LeaseSet> remote);
void DeleteStream(std::shared_ptr<Stream> stream); void DeleteStream(std::shared_ptr<Stream> stream);
bool DeleteStream(uint32_t recvStreamID); bool DeleteStream(uint32_t recvStreamID);
void SetAcceptor(const Acceptor &acceptor); void SetAcceptor(const Acceptor &acceptor);
void ResetAcceptor(); void ResetAcceptor();
bool IsAcceptorSet() const { return m_Acceptor != nullptr; }; bool IsAcceptorSet() const { return m_Acceptor != nullptr; };
void AcceptOnce(const Acceptor &acceptor); void AcceptOnce(const Acceptor &acceptor);
void AcceptOnceAcceptor(std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev); void AcceptOnceAcceptor(std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
std::shared_ptr<i2p::client::ClientDestination> GetOwner() const { return m_Owner; }; std::shared_ptr<i2p::client::ClientDestination> GetOwner() const { return m_Owner; };
void SetOwner(std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; }; void SetOwner(std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
uint16_t GetLocalPort() const { return m_LocalPort; }; uint16_t GetLocalPort() const { return m_LocalPort; };
void HandleDataMessagePayload(const uint8_t *buf, size_t len); void HandleDataMessagePayload(const uint8_t *buf, size_t len);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t toPort, bool checksum = true);
std::shared_ptr<I2NPMessage>
CreateDataMessage(const uint8_t *payload, size_t len, uint16_t toPort, bool checksum = true);
Packet *NewPacket() { return m_PacketsPool.Acquire(); } Packet *NewPacket() { return m_PacketsPool.Acquire(); }
void DeletePacket(Packet *p) { return m_PacketsPool.Release(p); } void DeletePacket(Packet *p) { return m_PacketsPool.Release(p); }
private: private:
void HandleNextPacket(Packet *packet); void HandleNextPacket(Packet *packet);
std::shared_ptr<Stream> CreateNewIncomingStream(uint32_t receiveStreamID); std::shared_ptr<Stream> CreateNewIncomingStream(uint32_t receiveStreamID);
void HandlePendingIncomingTimer(const boost::system::error_code &ecode); void HandlePendingIncomingTimer(const boost::system::error_code &ecode);
private: private:
@ -318,28 +386,28 @@ namespace stream
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator; std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
// for HTTP only // for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; }; const decltype(m_Streams)
&
GetStreams() const { return m_Streams; };
}; };
//------------------------------------------------- //-------------------------------------------------
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void Stream::AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout) void Stream::AsyncReceive(const Buffer &buffer, ReceiveHandler handler, int timeout) {
{
auto s = shared_from_this(); auto s = shared_from_this();
m_Service.post ([s, buffer, handler, timeout](void) m_Service.post([s, buffer, handler, timeout](void) {
{
if (!s->m_ReceiveQueue.empty() || s->m_Status == eStreamStatusReset) if (!s->m_ReceiveQueue.empty() || s->m_Status == eStreamStatusReset)
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0); s->HandleReceiveTimer(boost::asio::error::make_error_code(boost::asio::error::operation_aborted),
else buffer, handler, 0);
{ else {
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout; int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
s->m_ReceiveTimer.expires_from_now(boost::posix_time::seconds(t)); s->m_ReceiveTimer.expires_from_now(boost::posix_time::seconds(t));
int left = timeout - t; int left = timeout - t;
auto self = s->shared_from_this(); auto self = s->shared_from_this();
self->m_ReceiveTimer.async_wait( self->m_ReceiveTimer.async_wait(
[self, buffer, handler, left](const boost::system::error_code & ec) [self, buffer, handler, left](const boost::system::error_code &ec) {
{
self->HandleReceiveTimer(ec, buffer, handler, left); self->HandleReceiveTimer(ec, buffer, handler, left);
}); });
} }
@ -347,26 +415,24 @@ namespace stream
} }
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout) void
{ Stream::HandleReceiveTimer(const boost::system::error_code &ecode, const Buffer &buffer, ReceiveHandler handler,
size_t received = ConcatenatePackets (boost::asio::buffer_cast<uint8_t *>(buffer), boost::asio::buffer_size(buffer)); int remainingTimeout) {
size_t received = ConcatenatePackets(boost::asio::buffer_cast<uint8_t *>(buffer),
boost::asio::buffer_size(buffer));
if (received > 0) if (received > 0)
handler(boost::system::error_code(), received); handler(boost::system::error_code(), received);
else if (ecode == boost::asio::error::operation_aborted) else if (ecode == boost::asio::error::operation_aborted) {
{
// timeout not expired // timeout not expired
if (m_Status == eStreamStatusReset) if (m_Status == eStreamStatusReset)
handler(boost::asio::error::make_error_code(boost::asio::error::connection_reset), 0); handler(boost::asio::error::make_error_code(boost::asio::error::connection_reset), 0);
else else
handler(boost::asio::error::make_error_code(boost::asio::error::operation_aborted), 0); handler(boost::asio::error::make_error_code(boost::asio::error::operation_aborted), 0);
} } else {
else
{
// timeout expired // timeout expired
if (remainingTimeout <= 0) if (remainingTimeout <= 0)
handler(boost::asio::error::make_error_code(boost::asio::error::timed_out), received); handler(boost::asio::error::make_error_code(boost::asio::error::timed_out), received);
else else {
{
// itermediate interrupt // itermediate interrupt
SendUpdatedLeaseSet(); // send our leaseset if applicable SendUpdatedLeaseSet(); // send our leaseset if applicable
AsyncReceive(buffer, handler, remainingTimeout); AsyncReceive(buffer, handler, remainingTimeout);

View file

@ -17,66 +17,65 @@
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
BOOST_STATIC_ASSERT_MSG(sz % 8 == 0, "Tag size must be multiple of 8 bytes"); % 8 == 0, "Tag size must be multiple of 8 bytes");
public: public:
Tag() = default; Tag() = default;
Tag(const uint8_t *buf) { memcpy(m_Buf, 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); } 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 !(*this == other); }
bool operator<(const Tag &other) const { return memcmp(m_Buf, other.m_Buf, sz) < 0; } bool operator<(const Tag &other) const { return memcmp(m_Buf, other.m_Buf, sz) < 0; }
uint8_t *operator()() { return m_Buf; } uint8_t *operator()() { return m_Buf; }
const uint8_t *operator()() const { return m_Buf; } const uint8_t *operator()() const { return m_Buf; }
operator uint8_t *() { return m_Buf; } operator uint8_t *() { return m_Buf; }
operator const uint8_t *() const { return m_Buf; } operator const uint8_t *() const { return m_Buf; }
const uint8_t *data() const { return m_Buf; } const uint8_t *data() const { return m_Buf; }
const uint64_t *GetLL() const { return ll; } const uint64_t *GetLL() const { return ll; }
bool IsZero () const bool IsZero() const {
{
for (size_t i = 0; i < sz / 8; ++i) for (size_t i = 0; i < sz / 8; ++i)
if (ll[i]) return false; if (ll[i]) return false;
return true; return true;
} }
void Fill(uint8_t c) void Fill(uint8_t c) {
{
memset(m_Buf, c, sz); memset(m_Buf, c, sz);
} }
void Randomize() void Randomize() {
{
RAND_bytes(m_Buf, sz); RAND_bytes(m_Buf, sz);
} }
std::string ToBase64 (size_t len = sz) const std::string ToBase64(size_t len = sz) const {
{
char str[sz * 2]; char str[sz * 2];
size_t l = i2p::data::ByteStreamToBase64(m_Buf, len, str, sz * 2); size_t l = i2p::data::ByteStreamToBase64(m_Buf, len, str, sz * 2);
return std::string(str, str + l); return std::string(str, str + l);
} }
std::string ToBase32 (size_t len = sz) const std::string ToBase32(size_t len = sz) const {
{
char str[sz * 2]; char str[sz * 2];
size_t l = i2p::data::ByteStreamToBase32(m_Buf, len, str, sz * 2); size_t l = i2p::data::ByteStreamToBase32(m_Buf, len, str, sz * 2);
return std::string(str, str + l); return std::string(str, str + l);
} }
size_t FromBase32 (const std::string& s) size_t FromBase32(const std::string &s) {
{
return i2p::data::Base32ToByteStream(s.c_str(), s.length(), m_Buf, sz); return i2p::data::Base32ToByteStream(s.c_str(), s.length(), m_Buf, sz);
} }
size_t FromBase64 (const std::string& s) size_t FromBase64(const std::string &s) {
{
return i2p::data::Base64ToByteStream(s.c_str(), s.length(), m_Buf, sz); return i2p::data::Base64ToByteStream(s.c_str(), s.length(), m_Buf, sz);
} }
@ -91,13 +90,11 @@ namespace data {
} // 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];
} }
}; };

View file

@ -27,85 +27,67 @@
#endif #endif
#endif #endif
namespace i2p namespace i2p {
{ namespace util {
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 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 uint32_t GetLocalMinutesSinceEpoch () static uint32_t GetLocalMinutesSinceEpoch() {
{
return std::chrono::duration_cast<std::chrono::minutes>( return std::chrono::duration_cast<std::chrono::minutes>(
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 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::system::error_code ec; boost::system::error_code ec;
auto it = boost::asio::ip::udp::resolver(service).resolve( auto it = boost::asio::ip::udp::resolver(service).resolve(
boost::asio::ip::udp::resolver::query(address, "ntp"), ec); boost::asio::ip::udp::resolver::query(address, "ntp"), ec);
if (!ec) if (!ec) {
{
bool found = false; bool found = false;
boost::asio::ip::udp::resolver::iterator end; boost::asio::ip::udp::resolver::iterator end;
boost::asio::ip::udp::endpoint ep; boost::asio::ip::udp::endpoint ep;
while (it != end) while (it != end) {
{
ep = *it; ep = *it;
if (!ep.address ().is_unspecified ()) if (!ep.address().is_unspecified()) {
{ if (ep.address().is_v4()) {
if (ep.address ().is_v4 ())
{
if (i2p::context.SupportsV4()) found = true; if (i2p::context.SupportsV4()) found = true;
} } else if (ep.address().is_v6()) {
else if (ep.address ().is_v6 ()) if (i2p::util::net::IsYggdrasilAddress(ep.address())) {
{
if (i2p::util::net::IsYggdrasilAddress (ep.address ()))
{
if (i2p::context.SupportsMesh()) found = true; if (i2p::context.SupportsMesh()) found = true;
} } else if (i2p::context.SupportsV6()) found = true;
else if (i2p::context.SupportsV6 ()) found = true;
} }
} }
if (found) break; if (found) break;
it++; it++;
} }
if (!found) if (!found) {
{
LogPrint(eLogError, "Timestamp: can't find compatible address for ", address); LogPrint(eLogError, "Timestamp: can't find compatible address for ", address);
return; return;
} }
boost::asio::ip::udp::socket socket(service); boost::asio::ip::udp::socket socket(service);
socket.open(ep.protocol(), ec); socket.open(ep.protocol(), ec);
if (!ec) if (!ec) {
{
uint8_t buf[48];// 48 bytes NTP request/response uint8_t buf[48];// 48 bytes NTP request/response
memset(buf, 0, 48); memset(buf, 0, 48);
htobe32buf(buf, (3 << 27) | (3 << 24)); // RFC 4330 htobe32buf(buf, (3 << 27) | (3 << 24)); // RFC 4330
size_t len = 0; size_t len = 0;
try try {
{
socket.send_to(boost::asio::buffer(buf, 48), ep); socket.send_to(boost::asio::buffer(buf, 48), ep);
int i = 0; int i = 0;
while (!socket.available() && i < 10) // 10 seconds max while (!socket.available() && i < 10) // 10 seconds max
@ -116,129 +98,106 @@ namespace util
if (socket.available()) if (socket.available())
len = socket.receive_from(boost::asio::buffer(buf, 48), ep); len = socket.receive_from(boost::asio::buffer(buf, 48), ep);
} }
catch (std::exception& e) catch (std::exception &e) {
{
LogPrint(eLogError, "Timestamp: NTP error: ", e.what()); LogPrint(eLogError, "Timestamp: NTP error: ", e.what());
} }
if (len >= 8) if (len >= 8) {
{
auto ourTs = GetLocalSecondsSinceEpoch(); auto ourTs = GetLocalSecondsSinceEpoch();
uint32_t ts = bufbe32toh(buf + 32); uint32_t ts = bufbe32toh(buf + 32);
if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900
g_TimeOffset = ts - ourTs; g_TimeOffset = ts - ourTs;
LogPrint (eLogInfo, "Timestamp: ", address, " time offset from system time is ", g_TimeOffset, " seconds"); LogPrint(eLogInfo, "Timestamp: ", address, " time offset from system time is ", g_TimeOffset,
" seconds");
} }
} } else
else
LogPrint(eLogError, "Timestamp: Couldn't open UDP socket"); LogPrint(eLogError, "Timestamp: Couldn't open UDP socket");
} } else
else
LogPrint(eLogError, "Timestamp: Couldn't resolve address ", address); LogPrint(eLogError, "Timestamp: Couldn't resolve address ", address);
} }
NTPTimeSync::NTPTimeSync (): m_IsRunning (false), m_Timer (m_Service) NTPTimeSync::NTPTimeSync() : m_IsRunning(false), m_Timer(m_Service) {
{
i2p::config::GetOption("nettime.ntpsyncinterval", m_SyncInterval); i2p::config::GetOption("nettime.ntpsyncinterval", m_SyncInterval);
std::string ntpservers; i2p::config::GetOption("nettime.ntpservers", ntpservers); std::string ntpservers;
i2p::config::GetOption("nettime.ntpservers", ntpservers);
boost::split(m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on); boost::split(m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on);
} }
NTPTimeSync::~NTPTimeSync () NTPTimeSync::~NTPTimeSync() {
{
Stop(); Stop();
} }
void NTPTimeSync::Start() void NTPTimeSync::Start() {
{ if (m_NTPServersList.size() > 0) {
if (m_NTPServersList.size () > 0)
{
m_IsRunning = true; m_IsRunning = true;
LogPrint(eLogInfo, "Timestamp: NTP time sync starting"); LogPrint(eLogInfo, "Timestamp: NTP time sync starting");
m_Service.post(std::bind(&NTPTimeSync::Sync, this)); m_Service.post(std::bind(&NTPTimeSync::Sync, this));
m_Thread.reset(new std::thread(std::bind(&NTPTimeSync::Run, this))); m_Thread.reset(new std::thread(std::bind(&NTPTimeSync::Run, this)));
} } else
else
LogPrint(eLogWarning, "Timestamp: No NTP server found"); LogPrint(eLogWarning, "Timestamp: No NTP server found");
} }
void NTPTimeSync::Stop () void NTPTimeSync::Stop() {
{ if (m_IsRunning) {
if (m_IsRunning)
{
LogPrint(eLogInfo, "Timestamp: NTP time sync stopping"); LogPrint(eLogInfo, "Timestamp: NTP time sync stopping");
m_IsRunning = false; m_IsRunning = false;
m_Timer.cancel(); m_Timer.cancel();
m_Service.stop(); m_Service.stop();
if (m_Thread) if (m_Thread) {
{
m_Thread->join(); m_Thread->join();
m_Thread.reset(nullptr); m_Thread.reset(nullptr);
} }
} }
} }
void NTPTimeSync::Run () void NTPTimeSync::Run() {
{
i2p::util::SetThreadName("Timesync"); i2p::util::SetThreadName("Timesync");
while (m_IsRunning) while (m_IsRunning) {
{ try {
try
{
m_Service.run(); m_Service.run();
} }
catch (std::exception& ex) catch (std::exception &ex) {
{
LogPrint(eLogError, "Timestamp: NTP time sync exception: ", ex.what()); LogPrint(eLogError, "Timestamp: NTP time sync exception: ", ex.what());
} }
} }
} }
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) {
{
m_Timer.expires_from_now(boost::posix_time::hours(m_SyncInterval)); m_Timer.expires_from_now(boost::posix_time::hours(m_SyncInterval));
m_Timer.async_wait ([this](const boost::system::error_code& ecode) m_Timer.async_wait([this](const boost::system::error_code &ecode) {
{
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Sync(); Sync();
}); });
} }
} }
uint64_t GetMillisecondsSinceEpoch () uint64_t GetMillisecondsSinceEpoch() {
{
return GetLocalMillisecondsSinceEpoch() + g_TimeOffset * 1000; return GetLocalMillisecondsSinceEpoch() + g_TimeOffset * 1000;
} }
uint64_t GetSecondsSinceEpoch () uint64_t GetSecondsSinceEpoch() {
{
return GetLocalSecondsSinceEpoch() + g_TimeOffset; return GetLocalSecondsSinceEpoch() + g_TimeOffset;
} }
uint32_t GetMinutesSinceEpoch () uint32_t GetMinutesSinceEpoch() {
{
return GetLocalMinutesSinceEpoch() + g_TimeOffset / 60; return GetLocalMinutesSinceEpoch() + g_TimeOffset / 60;
} }
uint32_t GetHoursSinceEpoch () uint32_t GetHoursSinceEpoch() {
{
return GetLocalHoursSinceEpoch() + g_TimeOffset / 3600; return GetLocalHoursSinceEpoch() + g_TimeOffset / 3600;
} }
void GetCurrentDate (char * date) void GetCurrentDate(char *date) {
{
GetDateString(GetSecondsSinceEpoch(), date); GetDateString(GetSecondsSinceEpoch(), date);
} }
void GetDateString (uint64_t timestamp, char * date) void GetDateString(uint64_t timestamp, char *date) {
{
using clock = std::chrono::system_clock; using clock = std::chrono::system_clock;
auto t = clock::to_time_t(clock::time_point(std::chrono::seconds(timestamp))); auto t = clock::to_time_t(clock::time_point(std::chrono::seconds(timestamp)));
struct tm tm; struct tm tm;
@ -251,8 +210,7 @@ namespace util
#endif #endif
} }
void AdjustTimeOffset (int64_t offset) void AdjustTimeOffset(int64_t offset) {
{
g_TimeOffset += offset; g_TimeOffset += offset;
} }
} }

View file

@ -15,32 +15,36 @@
#include <string> #include <string>
#include <boost/asio.hpp> #include <boost/asio.hpp>
namespace i2p namespace i2p {
{ namespace util {
namespace util
{
uint64_t GetMillisecondsSinceEpoch(); uint64_t GetMillisecondsSinceEpoch();
uint64_t GetSecondsSinceEpoch(); uint64_t GetSecondsSinceEpoch();
uint32_t GetMinutesSinceEpoch(); uint32_t GetMinutesSinceEpoch();
uint32_t GetHoursSinceEpoch(); uint32_t GetHoursSinceEpoch();
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
void AdjustTimeOffset(int64_t offset); // in seconds from current void AdjustTimeOffset(int64_t offset); // in seconds from current
class NTPTimeSync class NTPTimeSync {
{
public: public:
NTPTimeSync(); NTPTimeSync();
~NTPTimeSync(); ~NTPTimeSync();
void Start(); void Start();
void Stop(); void Stop();
private: private:
void Run(); void Run();
void Sync(); void Sync();
private: private:

View file

@ -15,30 +15,24 @@
#include "Transports.h" #include "Transports.h"
#include "TransitTunnel.h" #include "TransitTunnel.h"
namespace i2p 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) {
{
m_Encryption.SetKeys(layerKey, ivKey); m_Encryption.SetKeys(layerKey, ivKey);
} }
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) void TransitTunnel::EncryptTunnelMsg(std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) {
{
m_Encryption.Encrypt(in->GetPayload() + 4, out->GetPayload() + 4); m_Encryption.Encrypt(in->GetPayload() + 4, out->GetPayload() + 4);
i2p::transport::transports.UpdateTotalTransitTransmittedBytes(TUNNEL_DATA_MSG_SIZE); i2p::transport::transports.UpdateTotalTransitTransmittedBytes(TUNNEL_DATA_MSG_SIZE);
} }
TransitTunnelParticipant::~TransitTunnelParticipant () TransitTunnelParticipant::~TransitTunnelParticipant() {
{
} }
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) void TransitTunnelParticipant::HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg) {
{
EncryptTunnelMsg(tunnelMsg, tunnelMsg); EncryptTunnelMsg(tunnelMsg, tunnelMsg);
m_NumTransmittedBytes += tunnelMsg->GetLength(); m_NumTransmittedBytes += tunnelMsg->GetLength();
@ -47,10 +41,8 @@ namespace tunnel
m_TunnelDataMsgs.push_back(tunnelMsg); m_TunnelDataMsgs.push_back(tunnelMsg);
} }
void TransitTunnelParticipant::FlushTunnelDataMsgs () void TransitTunnelParticipant::FlushTunnelDataMsgs() {
{ if (!m_TunnelDataMsgs.empty()) {
if (!m_TunnelDataMsgs.empty ())
{
auto num = m_TunnelDataMsgs.size(); auto num = m_TunnelDataMsgs.size();
if (num > 1) if (num > 1)
LogPrint(eLogDebug, "TransitTunnel: ", GetTunnelID(), "->", GetNextTunnelID(), " ", num); LogPrint(eLogDebug, "TransitTunnel: ", GetTunnelID(), "->", GetNextTunnelID(), " ", num);
@ -59,18 +51,15 @@ namespace tunnel
} }
} }
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void TransitTunnel::SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg) {
{
LogPrint(eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID()); LogPrint(eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID());
} }
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) void TransitTunnel::HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg) {
{
LogPrint(eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID()); LogPrint(eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID());
} }
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void TransitTunnelGateway::SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg) {
{
TunnelMessageBlock block; TunnelMessageBlock block;
block.deliveryType = eDeliveryTypeLocal; block.deliveryType = eDeliveryTypeLocal;
block.data = msg; block.data = msg;
@ -78,14 +67,12 @@ namespace tunnel
m_Gateway.PutTunnelDataMsg(block); m_Gateway.PutTunnelDataMsg(block);
} }
void TransitTunnelGateway::FlushTunnelDataMsgs () void TransitTunnelGateway::FlushTunnelDataMsgs() {
{
std::unique_lock<std::mutex> l(m_SendMutex); std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendBuffer(); m_Gateway.SendBuffer();
} }
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg) {
{
auto newMsg = CreateEmptyTunnelDataMsg(true); auto newMsg = CreateEmptyTunnelDataMsg(true);
EncryptTunnelMsg(tunnelMsg, newMsg); EncryptTunnelMsg(tunnelMsg, newMsg);
@ -96,22 +83,19 @@ 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)
{
LogPrint(eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created"); LogPrint(eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelEndpoint>(receiveTunnelID, nextIdent, nextTunnelID, layerKey,
} ivKey);
else if (isGateway) } else if (isGateway) {
{
LogPrint(eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created"); LogPrint(eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelGateway>(receiveTunnelID, nextIdent, nextTunnelID, layerKey,
} ivKey);
else } else {
{
LogPrint(eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created"); LogPrint(eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelParticipant>(receiveTunnelID, nextIdent, nextTunnelID, layerKey,
ivKey);
} }
} }
} }

View file

@ -19,12 +19,9 @@
#include "TunnelGateway.h" #include "TunnelGateway.h"
#include "TunnelBase.h" #include "TunnelBase.h"
namespace i2p namespace i2p {
{ namespace tunnel {
namespace tunnel class TransitTunnel : public TunnelBase {
{
class TransitTunnel: public TunnelBase
{
public: public:
TransitTunnel(uint32_t receiveTunnelID, TransitTunnel(uint32_t receiveTunnelID,
@ -35,15 +32,17 @@ namespace tunnel
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg);
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg); void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
void EncryptTunnelMsg(std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); void EncryptTunnelMsg(std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
private: private:
i2p::crypto::TunnelEncryption m_Encryption; i2p::crypto::TunnelEncryption m_Encryption;
}; };
class TransitTunnelParticipant: public TransitTunnel class TransitTunnelParticipant : public TransitTunnel {
{
public: public:
TransitTunnelParticipant(uint32_t receiveTunnelID, TransitTunnelParticipant(uint32_t receiveTunnelID,
@ -51,10 +50,13 @@ namespace tunnel
const uint8_t *layerKey, const uint8_t *ivKey) : const uint8_t *layerKey, const uint8_t *ivKey) :
TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_NumTransmittedBytes(0) {}; layerKey, ivKey), m_NumTransmittedBytes(0) {};
~TransitTunnelParticipant(); ~TransitTunnelParticipant();
size_t GetNumTransmittedBytes() const { return m_NumTransmittedBytes; }; size_t GetNumTransmittedBytes() const { return m_NumTransmittedBytes; };
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg); void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
void FlushTunnelDataMsgs(); void FlushTunnelDataMsgs();
private: private:
@ -63,8 +65,7 @@ namespace tunnel
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs; std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
}; };
class TransitTunnelGateway: public TransitTunnel class TransitTunnelGateway : public TransitTunnel {
{
public: public:
TransitTunnelGateway(uint32_t receiveTunnelID, TransitTunnelGateway(uint32_t receiveTunnelID,
@ -74,7 +75,9 @@ namespace tunnel
layerKey, ivKey), m_Gateway(this) {}; layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg);
void FlushTunnelDataMsgs(); void FlushTunnelDataMsgs();
size_t GetNumTransmittedBytes() const { return m_Gateway.GetNumSentBytes(); }; size_t GetNumTransmittedBytes() const { return m_Gateway.GetNumSentBytes(); };
private: private:
@ -83,8 +86,7 @@ namespace tunnel
TunnelGateway m_Gateway; TunnelGateway m_Gateway;
}; };
class TransitTunnelEndpoint: public TransitTunnel class TransitTunnelEndpoint : public TransitTunnel {
{
public: public:
TransitTunnelEndpoint(uint32_t receiveTunnelID, TransitTunnelEndpoint(uint32_t receiveTunnelID,
@ -96,6 +98,7 @@ namespace tunnel
void Cleanup() { m_Endpoint.Cleanup(); } void Cleanup() { m_Endpoint.Cleanup(); }
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg); void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
size_t GetNumTransmittedBytes() const { return m_Endpoint.GetNumReceivedBytes(); } size_t GetNumTransmittedBytes() const { return m_Endpoint.GetNumReceivedBytes(); }
private: private:

View file

@ -20,47 +20,39 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Timestamp.h" #include "Timestamp.h"
namespace i2p namespace i2p {
{ namespace transport {
namespace transport
{
const size_t IPV4_HEADER_SIZE = 20; const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40; const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8; const size_t UDP_HEADER_SIZE = 8;
class SignedData class SignedData {
{
public: public:
SignedData() {} SignedData() {}
SignedData (const SignedData& other)
{ SignedData(const SignedData &other) {
m_Stream << other.m_Stream.rdbuf(); m_Stream << other.m_Stream.rdbuf();
} }
void Reset () void Reset() {
{
m_Stream.str(""); m_Stream.str("");
} }
void Insert (const uint8_t * buf, size_t len) void Insert(const uint8_t *buf, size_t len) {
{
m_Stream.write((char *) buf, len); m_Stream.write((char *) buf, len);
} }
template<typename T> template<typename T>
void Insert (T t) void Insert(T t) {
{
m_Stream.write((char *) &t, sizeof(T)); m_Stream.write((char *) &t, sizeof(T));
} }
bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const bool Verify(std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t *signature) const {
{
return ident->Verify((const uint8_t *) m_Stream.str().c_str(), m_Stream.str().size(), signature); return ident->Verify((const uint8_t *) m_Stream.str().c_str(), m_Stream.str().size(), signature);
} }
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const void Sign(const i2p::data::PrivateKeys &keys, uint8_t *signature) const {
{
keys.Sign((const uint8_t *) m_Stream.str().c_str(), m_Stream.str().size(), signature); keys.Sign((const uint8_t *) m_Stream.str().c_str(), m_Stream.str().size(), signature);
} }
@ -69,49 +61,58 @@ namespace transport
std::stringstream m_Stream; std::stringstream m_Stream;
}; };
class TransportSession class TransportSession {
{
public: public:
TransportSession(std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout) : TransportSession(std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout) :
m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_NumSentBytes(0), m_NumReceivedBytes(0), m_IsOutgoing(router),
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()) m_TerminationTimeout(terminationTimeout),
{ m_LastActivityTimestamp(i2p::util::GetSecondsSinceEpoch()) {
if (router) if (router)
m_RemoteIdentity = router->GetRouterIdentity(); m_RemoteIdentity = router->GetRouterIdentity();
m_CreationTime = m_LastActivityTimestamp; m_CreationTime = m_LastActivityTimestamp;
} }
virtual ~TransportSession() {}; virtual ~TransportSession() {};
virtual void Done() = 0; virtual void Done() = 0;
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; };
size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; };
bool IsOutgoing() const { return m_IsOutgoing; }; bool IsOutgoing() const { return m_IsOutgoing; };
int GetTerminationTimeout() const { return m_TerminationTimeout; }; int GetTerminationTimeout() const { return m_TerminationTimeout; };
void SetTerminationTimeout(int terminationTimeout) { m_TerminationTimeout = terminationTimeout; }; void SetTerminationTimeout(int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); }; bool IsTerminationTimeoutExpired(uint64_t ts) const {
return ts >= m_LastActivityTimestamp + GetTerminationTimeout();
};
uint32_t GetCreationTime() const { return m_CreationTime; }; uint32_t GetCreationTime() const { return m_CreationTime; };
void SetCreationTime(uint32_t ts) { m_CreationTime = ts; }; // for introducers void SetCreationTime(uint32_t ts) { m_CreationTime = ts; }; // for introducers
virtual uint32_t GetRelayTag() const { return 0; }; virtual uint32_t GetRelayTag() const { return 0; };
virtual void SendLocalRouterInfo(bool update = false) { SendI2NPMessages({CreateDatabaseStoreMsg()}); }; virtual void SendLocalRouterInfo(bool update = false) { SendI2NPMessages({CreateDatabaseStoreMsg()}); };
virtual void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) = 0; virtual void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) = 0;
protected: protected:

File diff suppressed because it is too large Load diff

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