mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-30 12:47:48 +02:00
Reformat code
This commit is contained in:
parent
3ddb370718
commit
55534ea002
140 changed files with 46068 additions and 48277 deletions
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Afrikaans localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace afrikaans // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -71,9 +69,9 @@ namespace afrikaans // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Armenian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace armenian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -205,9 +203,9 @@ namespace armenian // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
// Simplified Chinese localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace chinese // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -207,9 +205,9 @@ namespace chinese // language namespace
|
|||
{"", {""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -15,10 +15,8 @@
|
|||
// English localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace english // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -40,9 +38,9 @@ namespace english // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// French localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace french // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -201,9 +199,9 @@ namespace french // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// German localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace german // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -206,9 +204,9 @@ namespace german // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
18
i18n/I18N.h
18
i18n/I18N.h
|
@ -11,12 +11,9 @@
|
|||
|
||||
#include "ClientContext.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
inline void SetLanguage(const std::string &lang)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
inline void SetLanguage(const std::string &lang) {
|
||||
const auto it = i2p::i18n::languages.find(lang);
|
||||
if (it == i2p::i18n::languages.end()) // fallback
|
||||
i2p::client::context.SetLanguage(i2p::i18n::english::GetLocale());
|
||||
|
@ -24,21 +21,18 @@ namespace i18n
|
|||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
||||
template<typename... TArgs>
|
||||
std::string tr (TArgs&&... args)
|
||||
{
|
||||
std::string tr(TArgs &&... args) {
|
||||
return i2p::i18n::translate(std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,9 @@
|
|||
#ifndef __I18N_LANGS_H__
|
||||
#define __I18N_LANGS_H__
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
class Locale
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
class Locale {
|
||||
public:
|
||||
Locale(
|
||||
const std::string &language,
|
||||
|
@ -24,33 +21,25 @@ namespace i18n
|
|||
) : m_Language(language), m_Strings(strings), m_Plurals(plurals), m_Formula(formula) {};
|
||||
|
||||
// Get activated language name for webconsole
|
||||
std::string GetLanguage() const
|
||||
{
|
||||
std::string GetLanguage() const {
|
||||
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);
|
||||
if (it == m_Strings.end())
|
||||
{
|
||||
if (it == m_Strings.end()) {
|
||||
return arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
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);
|
||||
if (it == m_Plurals.end()) // not found, fallback to english
|
||||
{
|
||||
return n == 1 ? arg : arg2;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
int form = m_Formula(n);
|
||||
return it->second[form];
|
||||
}
|
||||
|
@ -63,8 +52,7 @@ namespace i18n
|
|||
std::function<int(int)> m_Formula;
|
||||
};
|
||||
|
||||
struct langData
|
||||
{
|
||||
struct langData {
|
||||
std::string LocaleName; // localized name
|
||||
std::string ShortCode; // short language code, like "en"
|
||||
std::function<std::shared_ptr<const i2p::i18n::Locale>(void)> LocaleFunc;
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Russian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace russian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -26,7 +24,8 @@ namespace russian // language namespace
|
|||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
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
|
||||
|
@ -205,9 +204,9 @@ namespace russian // language namespace
|
|||
{"", {"", "", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Turkmen localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace turkmen // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -205,9 +203,9 @@ namespace turkmen // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Ukrainian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace ukrainian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -26,7 +24,8 @@ namespace ukrainian // language namespace
|
|||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
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
|
||||
|
@ -205,9 +204,9 @@ namespace ukrainian // language namespace
|
|||
{"", {"", "", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
// Ukrainian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace uzbek // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
|
@ -205,9 +203,9 @@ namespace uzbek // language namespace
|
|||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale()
|
||||
{
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals, [] (int n)->int { return plural(n); });
|
||||
std::shared_ptr<const i2p::i18n::Locale> GetLocale() {
|
||||
return std::make_shared<i2p::i18n::Locale>(language, strings, plurals,
|
||||
[](int n) -> int { return plural(n); });
|
||||
}
|
||||
|
||||
} // language
|
||||
|
|
|
@ -11,10 +11,8 @@
|
|||
|
||||
#include "Base.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
static const char T32[32] =
|
||||
{
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
|
@ -23,8 +21,7 @@ namespace data
|
|||
'y', 'z', '2', '3', '4', '5', '6', '7',
|
||||
};
|
||||
|
||||
const char * GetBase32SubstitutionTable ()
|
||||
{
|
||||
const char *GetBase32SubstitutionTable() {
|
||||
return T32;
|
||||
}
|
||||
|
||||
|
@ -50,8 +47,7 @@ namespace data
|
|||
'4', '5', '6', '7', '8', '9', '-', '~'
|
||||
};
|
||||
|
||||
const char * GetBase64SubstitutionTable ()
|
||||
{
|
||||
const char *GetBase64SubstitutionTable() {
|
||||
return T64;
|
||||
}
|
||||
|
||||
|
@ -82,8 +78,7 @@ namespace data
|
|||
size_t InCount, /* Number of bytes in the input buffer */
|
||||
char *OutBuffer, /* output buffer */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
{
|
||||
) {
|
||||
unsigned char *ps;
|
||||
unsigned char *pd;
|
||||
unsigned char acc_1;
|
||||
|
@ -104,8 +99,7 @@ namespace data
|
|||
if (outCount > len) return 0;
|
||||
|
||||
pd = (unsigned char *) OutBuffer;
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
for (i = 0; i < n; i++) {
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1 << 4) & 0x30;
|
||||
acc_1 >>= 2; /* base64 digit #1 */
|
||||
|
@ -121,8 +115,7 @@ namespace data
|
|||
acc_2 &= 0x3f; /* base64 digit #4 */
|
||||
*pd++ = T64[acc_2];
|
||||
}
|
||||
if ( m == 1 )
|
||||
{
|
||||
if (m == 1) {
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
|
||||
acc_1 >>= 2; /* base64 digit #1 */
|
||||
|
@ -131,9 +124,7 @@ namespace data
|
|||
*pd++ = P64;
|
||||
*pd++ = P64;
|
||||
|
||||
}
|
||||
else if ( m == 2 )
|
||||
{
|
||||
} else if (m == 2) {
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1 << 4) & 0x3f;
|
||||
acc_1 >>= 2; /* base64 digit #1 */
|
||||
|
@ -165,8 +156,7 @@ namespace data
|
|||
size_t InCount, /* Number of input bytes */
|
||||
uint8_t *OutBuffer, /* output buffer length */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
{
|
||||
) {
|
||||
unsigned char *ps;
|
||||
unsigned char *pd;
|
||||
unsigned char acc_1;
|
||||
|
@ -197,8 +187,7 @@ namespace data
|
|||
|
||||
pd = OutBuffer;
|
||||
auto endOfOutBuffer = OutBuffer + outCount;
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
for (i = 0; i < n; i++) {
|
||||
acc_1 = iT64[*ps++];
|
||||
acc_2 = iT64[*ps++];
|
||||
acc_1 <<= 2;
|
||||
|
@ -222,8 +211,7 @@ namespace data
|
|||
return outCount;
|
||||
}
|
||||
|
||||
size_t Base64EncodingBufferSize (const size_t input_size)
|
||||
{
|
||||
size_t Base64EncodingBufferSize(const size_t input_size) {
|
||||
auto d = div(input_size, 3);
|
||||
if (d.rem)
|
||||
d.quot++;
|
||||
|
@ -231,8 +219,7 @@ namespace data
|
|||
return 4 * d.quot;
|
||||
}
|
||||
|
||||
std::string ToBase64Standard (const std::string& in)
|
||||
{
|
||||
std::string ToBase64Standard(const std::string &in) {
|
||||
auto len = Base64EncodingBufferSize(in.length());
|
||||
char *str = new char[len + 1];
|
||||
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;
|
||||
isFirstTime = 0;
|
||||
for (i = 0; i < 256; i++) iT64[i] = -1;
|
||||
|
@ -267,12 +253,10 @@ namespace data
|
|||
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;
|
||||
size_t ret = 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char ch = inBuf[i];
|
||||
if (ch >= '2' && ch <= '7') // digit
|
||||
ch = (ch - '2') + 26; // 26 means a-z
|
||||
|
@ -283,8 +267,7 @@ namespace data
|
|||
|
||||
tmp |= ch;
|
||||
bits += 5;
|
||||
if (bits >= 8)
|
||||
{
|
||||
if (bits >= 8) {
|
||||
if (ret >= outLen) return ret;
|
||||
outBuf[ret] = tmp >> (bits - 8);
|
||||
bits -= 8;
|
||||
|
@ -295,22 +278,17 @@ namespace data
|
|||
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;
|
||||
int bits = 8, tmp = inBuf[0];
|
||||
while (ret < outLen && (bits > 0 || pos < len))
|
||||
{
|
||||
if (bits < 5)
|
||||
{
|
||||
if (pos < len)
|
||||
{
|
||||
while (ret < outLen && (bits > 0 || pos < len)) {
|
||||
if (bits < 5) {
|
||||
if (pos < len) {
|
||||
tmp <<= 8;
|
||||
tmp |= inBuf[pos] & 0xFF;
|
||||
pos++;
|
||||
bits += 8;
|
||||
}
|
||||
else // last byte
|
||||
} else // last byte
|
||||
{
|
||||
tmp <<= (5 - bits);
|
||||
bits = 5;
|
||||
|
|
|
@ -16,11 +16,15 @@
|
|||
namespace i2p {
|
||||
namespace data {
|
||||
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);
|
||||
|
||||
const char *GetBase32SubstitutionTable();
|
||||
|
||||
const char *GetBase64SubstitutionTable();
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,12 +20,9 @@
|
|||
#include "Signature.h"
|
||||
#include "Blinding.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
static EC_POINT * BlindPublicKeyECDSA (const EC_GROUP * group, const EC_POINT * pub, const uint8_t * seed)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
static EC_POINT *BlindPublicKeyECDSA(const EC_GROUP *group, const EC_POINT *pub, const uint8_t *seed) {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -43,8 +40,8 @@ namespace data
|
|||
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_start(ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -60,8 +57,9 @@ namespace data
|
|||
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 *y = BN_bin2bn(pub + publicKeyLen / 2, publicKeyLen / 2, NULL);
|
||||
EC_POINT *p = EC_POINT_new(group);
|
||||
|
@ -72,11 +70,12 @@ namespace data
|
|||
EC_POINT_free(p1);
|
||||
i2p::crypto::bn2buf(x, blindedPub, 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 *a1 = BN_new();
|
||||
BlindPrivateKeyECDSA(group, a, seed, a1);
|
||||
|
@ -92,31 +91,29 @@ namespace data
|
|||
EC_POINT_free(p);
|
||||
i2p::crypto::bn2buf(x, blindedPub, 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>
|
||||
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
|
||||
{
|
||||
size_t publicKeyLength = 0;
|
||||
EC_GROUP *group = nullptr;
|
||||
switch (sigType)
|
||||
{
|
||||
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
{
|
||||
switch (sigType) {
|
||||
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256: {
|
||||
publicKeyLength = i2p::crypto::ECDSAP256_KEY_LENGTH;
|
||||
group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
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;
|
||||
group = EC_GROUP_new_by_curve_name(NID_secp384r1);
|
||||
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;
|
||||
group = EC_GROUP_new_by_curve_name(NID_secp521r1);
|
||||
break;
|
||||
|
@ -124,8 +121,7 @@ namespace data
|
|||
default:
|
||||
LogPrint(eLogError, "Blinding: Signature type ", (int) sigType, " is not ECDSA");
|
||||
}
|
||||
if (group)
|
||||
{
|
||||
if (group) {
|
||||
blind(publicKeyLength, group, key, seed, std::forward<Args>(args)...);
|
||||
EC_GROUP_free(group);
|
||||
}
|
||||
|
@ -139,8 +135,7 @@ namespace data
|
|||
const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04;
|
||||
|
||||
BlindedPublicKey::BlindedPublicKey(std::shared_ptr<const IdentityEx> identity, bool clientAuth) :
|
||||
m_IsClientAuth (clientAuth)
|
||||
{
|
||||
m_IsClientAuth(clientAuth) {
|
||||
if (!identity) return;
|
||||
auto len = identity->GetSigningPublicKeyLen();
|
||||
m_PublicKey.resize(len);
|
||||
|
@ -157,48 +152,49 @@ namespace data
|
|||
{
|
||||
uint8_t addr[40]; // TODO: define length from b33
|
||||
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);
|
||||
return;
|
||||
}
|
||||
uint32_t checksum = crc32(0, addr + 3, l - 3);
|
||||
// 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];
|
||||
size_t offset = 1;
|
||||
if (flags & B33_TWO_BYTES_SIGTYPE_FLAG) // two bytes signatures
|
||||
{
|
||||
m_SigType = bufbe16toh (addr + offset); offset += 2;
|
||||
m_BlindedSigType = bufbe16toh (addr + offset); offset += 2;
|
||||
}
|
||||
else // one byte sig
|
||||
m_SigType = bufbe16toh(addr + offset);
|
||||
offset += 2;
|
||||
m_BlindedSigType = bufbe16toh(addr + offset);
|
||||
offset += 2;
|
||||
} else // one byte sig
|
||||
{
|
||||
m_SigType = addr[offset]; offset++;
|
||||
m_BlindedSigType = addr[offset]; offset++;
|
||||
m_SigType = addr[offset];
|
||||
offset++;
|
||||
m_BlindedSigType = addr[offset];
|
||||
offset++;
|
||||
}
|
||||
m_IsClientAuth = flags & B33_PER_CLIENT_AUTH_FLAG;
|
||||
|
||||
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier(i2p::data::IdentityEx::CreateVerifier(m_SigType));
|
||||
if (blindedVerifier)
|
||||
{
|
||||
if (blindedVerifier) {
|
||||
auto len = blindedVerifier->GetPublicKeyLen();
|
||||
if (offset + len <= l)
|
||||
{
|
||||
if (offset + len <= l) {
|
||||
m_PublicKey.resize(len);
|
||||
memcpy(m_PublicKey.data(), addr + offset, len);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Blinding: Public key in b33 address is too short for signature type ", (int)m_SigType);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Blinding: Public key in b33 address is too short for signature type ",
|
||||
(int) m_SigType);
|
||||
} else
|
||||
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
|
||||
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;
|
||||
if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG;
|
||||
addr[0] = flags; // flags
|
||||
|
@ -207,51 +203,54 @@ namespace data
|
|||
memcpy(addr + 3, m_PublicKey.data(), m_PublicKey.size());
|
||||
uint32_t checksum = crc32(0, addr + 3, m_PublicKey.size());
|
||||
// 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);
|
||||
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
|
||||
// stA = signature type of A, 2 bytes big endian
|
||||
uint16_t stA = htobe16(GetSigType());
|
||||
// stA1 = signature type of blinded A, 2 bytes big endian
|
||||
uint16_t stA1 = htobe16(GetBlindedSigType());
|
||||
// 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];
|
||||
GetCredential(credential);
|
||||
// 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());
|
||||
uint8_t salt[32];
|
||||
//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);
|
||||
}
|
||||
|
||||
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];
|
||||
GenerateAlpha(date, seed);
|
||||
|
||||
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_SHA384_P384:
|
||||
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;
|
||||
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
|
@ -264,24 +263,23 @@ namespace data
|
|||
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];
|
||||
GenerateAlpha(date, seed);
|
||||
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_SHA384_P384:
|
||||
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;
|
||||
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
|
||||
i2p::crypto::GetEd25519()->BlindPrivateKey(priv, seed, blindedPriv, blindedPub);
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
{
|
||||
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: {
|
||||
uint8_t exp[64];
|
||||
i2p::crypto::Ed25519::ExpandPrivateKey(priv, exp);
|
||||
i2p::crypto::GetEd25519()->BlindPrivateKey(exp, seed, blindedPriv, blindedPub);
|
||||
|
@ -294,8 +292,8 @@ namespace data
|
|||
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_Init(&ctx);
|
||||
SHA256_Update(&ctx, p.c_str(), p.length());
|
||||
|
@ -304,29 +302,25 @@ namespace data
|
|||
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;
|
||||
uint8_t blinded[128];
|
||||
size_t publicKeyLength = 0;
|
||||
if (date)
|
||||
publicKeyLength = GetBlindedKey(date, blinded);
|
||||
else
|
||||
{
|
||||
else {
|
||||
char currentDate[9];
|
||||
i2p::util::GetCurrentDate(currentDate);
|
||||
publicKeyLength = GetBlindedKey(currentDate, blinded);
|
||||
}
|
||||
if (publicKeyLength)
|
||||
{
|
||||
if (publicKeyLength) {
|
||||
auto stA1 = htobe16(m_BlindedSigType);
|
||||
SHA256_CTX ctx;
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, (const uint8_t *) &stA1, 2);
|
||||
SHA256_Update(&ctx, blinded, publicKeyLength);
|
||||
SHA256_Final((uint8_t *) hash, &ctx);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Blinding: Blinded key type ", (int) m_BlindedSigType, " is not supported");
|
||||
return hash;
|
||||
}
|
||||
|
|
|
@ -14,34 +14,41 @@
|
|||
#include <vector>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
class BlindedPublicKey // for encrypted LS2
|
||||
{
|
||||
public:
|
||||
|
||||
BlindedPublicKey(std::shared_ptr<const IdentityEx> identity, bool clientAuth = false);
|
||||
|
||||
BlindedPublicKey(const std::string &b33); // from b33 without .b32.i2p
|
||||
std::string ToB33() const;
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKey.data(); };
|
||||
|
||||
size_t GetPublicKeyLen() const { return m_PublicKey.size(); };
|
||||
|
||||
SigningKeyType GetSigType() const { return m_SigType; };
|
||||
|
||||
SigningKeyType GetBlindedSigType() const { return m_BlindedSigType; };
|
||||
|
||||
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
|
||||
size_t GetBlindedKey (const char * date, uint8_t * blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length
|
||||
size_t BlindPrivateKey (const uint8_t * priv, const char * date, uint8_t * blindedPriv, uint8_t * blindedPub) const; // date is 8 chars "YYYYMMDD", return public key length
|
||||
i2p::data::IdentHash GetStoreHash (const char * date = nullptr) const; // date is 8 chars "YYYYMMDD", use current if null
|
||||
size_t GetBlindedKey(const char *date,
|
||||
uint8_t *blindedKey) const; // date is 8 chars "YYYYMMDD", return public key length
|
||||
size_t BlindPrivateKey(const uint8_t *priv, const char *date, uint8_t *blindedPriv,
|
||||
uint8_t *blindedPub) const; // date is 8 chars "YYYYMMDD", return public key length
|
||||
i2p::data::IdentHash
|
||||
GetStoreHash(const char *date = nullptr) const; // date is 8 chars "YYYYMMDD", use current if null
|
||||
|
||||
private:
|
||||
|
||||
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 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:
|
||||
|
||||
|
|
|
@ -11,31 +11,25 @@
|
|||
#include <array>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
|
||||
/** @brief decaying bloom filter implementation */
|
||||
class DecayingBloomFilter : public IBloomFilter
|
||||
{
|
||||
class DecayingBloomFilter : public IBloomFilter {
|
||||
public:
|
||||
|
||||
DecayingBloomFilter(const std::size_t size)
|
||||
{
|
||||
DecayingBloomFilter(const std::size_t size) {
|
||||
m_Size = size;
|
||||
m_Data = new uint8_t[size];
|
||||
}
|
||||
|
||||
/** @brief implements IBloomFilter::~IBloomFilter */
|
||||
~DecayingBloomFilter()
|
||||
{
|
||||
~DecayingBloomFilter() {
|
||||
delete[] m_Data;
|
||||
}
|
||||
|
||||
/** @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;
|
||||
uint8_t mask;
|
||||
Get(data, len, idx, mask);
|
||||
|
@ -45,16 +39,14 @@ namespace util
|
|||
}
|
||||
|
||||
/** @brief implements IBloomFilter::Decay */
|
||||
void Decay()
|
||||
{
|
||||
void Decay() {
|
||||
// reset bloom filter buffer
|
||||
memset(m_Data, 0, m_Size);
|
||||
}
|
||||
|
||||
private:
|
||||
/** @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;
|
||||
uint8_t digest[32];
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,22 +8,22 @@
|
|||
|
||||
#ifndef BLOOM_FILTER_H_
|
||||
#define BLOOM_FILTER_H_
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
|
||||
/** @brief interface for bloom filter */
|
||||
struct IBloomFilter
|
||||
{
|
||||
struct IBloomFilter {
|
||||
|
||||
/** @brief destructor */
|
||||
virtual ~IBloomFilter() {};
|
||||
|
||||
/** @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;
|
||||
|
||||
/** @brief optionally decay old entries */
|
||||
virtual void Decay() = 0;
|
||||
};
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
*/
|
||||
|
||||
#include "CPU.h"
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#ifndef bit_AES
|
||||
|
@ -20,15 +22,12 @@
|
|||
#endif
|
||||
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
namespace i2p {
|
||||
namespace cpu {
|
||||
bool aesni = 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__)
|
||||
int info[4];
|
||||
__cpuid(0, info[0], info[1], info[2], info[3]);
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
#ifndef LIBI2PD_CPU_H
|
||||
#define LIBI2PD_CPU_H
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
namespace i2p {
|
||||
namespace cpu {
|
||||
extern bool aesni;
|
||||
extern bool avx;
|
||||
|
||||
|
|
|
@ -13,22 +13,17 @@
|
|||
#include "ChaCha20.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace chacha
|
||||
{
|
||||
void u32t8le(uint32_t v, uint8_t * p)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
namespace chacha {
|
||||
void u32t8le(uint32_t v, uint8_t *p) {
|
||||
p[0] = v & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 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];
|
||||
|
||||
value = (value << 8) | p[2];
|
||||
|
@ -38,35 +33,34 @@ uint32_t u8t32le(const uint8_t * p)
|
|||
return value;
|
||||
}
|
||||
|
||||
uint32_t rotl32(uint32_t x, int n)
|
||||
{
|
||||
uint32_t rotl32(uint32_t x, int n) {
|
||||
return x << n | (x >> (-n & 31));
|
||||
}
|
||||
|
||||
void quarterround(uint32_t *x, int a, int b, int c, int d)
|
||||
{
|
||||
x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16);
|
||||
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12);
|
||||
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 quarterround(uint32_t *x, int a, int b, int c, int d) {
|
||||
x[a] += x[b];
|
||||
x[d] = rotl32(x[d] ^ x[a], 16);
|
||||
x[c] += x[d];
|
||||
x[b] = rotl32(x[b] ^ x[c], 12);
|
||||
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;
|
||||
for (i = 0; i < 16; i++)
|
||||
u32t8le(st.data[i], data + (i << 2));
|
||||
}
|
||||
|
||||
void block (Chacha20State &input, int rounds)
|
||||
{
|
||||
void block(Chacha20State &input, int rounds) {
|
||||
int i;
|
||||
Chacha20State x;
|
||||
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, 1, 5, 9, 13);
|
||||
quarterround(x.data, 2, 6, 10, 14);
|
||||
|
@ -80,8 +74,7 @@ void block (Chacha20State &input, int rounds)
|
|||
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[1] = 0x3320646e;
|
||||
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);
|
||||
}
|
||||
|
||||
void Chacha20SetCounter (Chacha20State& state, uint32_t counter)
|
||||
{
|
||||
void Chacha20SetCounter(Chacha20State &state, uint32_t counter) {
|
||||
state.data[12] = htole32 (counter);
|
||||
state.offset = 0;
|
||||
}
|
||||
|
||||
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
|
||||
{
|
||||
if (state.offset > 0)
|
||||
{
|
||||
void Chacha20Encrypt(Chacha20State &state, uint8_t *buf, size_t sz) {
|
||||
if (state.offset > 0) {
|
||||
// previous block if any
|
||||
auto s = chacha::blocksize - state.offset;
|
||||
if (sz < s) s = sz;
|
||||
|
@ -114,14 +104,11 @@ void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
|
|||
state.offset += s;
|
||||
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);
|
||||
state.data[12]++;
|
||||
for (size_t j = i; j < i + chacha::blocksize; j++)
|
||||
{
|
||||
if (j >= sz)
|
||||
{
|
||||
for (size_t j = i; j < i + chacha::blocksize; j++) {
|
||||
if (j >= sz) {
|
||||
state.offset = j & 0x3F; // % 64
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#ifndef LIBI2PD_CHACHA20_H
|
||||
#define LIBI2PD_CHACHA20_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <inttypes.h>
|
||||
|
@ -17,22 +18,21 @@
|
|||
#include "Crypto.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
const std::size_t CHACHA20_KEY_BYTES = 32;
|
||||
const std::size_t CHACHA20_NOUNCE_BYTES = 12;
|
||||
|
||||
namespace chacha
|
||||
{
|
||||
constexpr std::size_t blocksize = 64;
|
||||
namespace chacha {
|
||||
constexpr std::size_t
|
||||
blocksize = 64;
|
||||
constexpr int rounds = 20;
|
||||
|
||||
struct Chacha20State;
|
||||
struct Chacha20Block
|
||||
{
|
||||
|
||||
struct Chacha20Block {
|
||||
Chacha20Block() {};
|
||||
|
||||
Chacha20Block(Chacha20Block &&) = delete;
|
||||
|
||||
uint8_t data[blocksize];
|
||||
|
@ -40,29 +40,30 @@ namespace chacha
|
|||
void operator<<(const Chacha20State &st);
|
||||
};
|
||||
|
||||
struct Chacha20State
|
||||
{
|
||||
struct Chacha20State {
|
||||
Chacha20State() : offset(0) {};
|
||||
|
||||
Chacha20State(Chacha20State &&) = delete;
|
||||
|
||||
Chacha20State & operator += (const Chacha20State & other)
|
||||
{
|
||||
Chacha20State &operator+=(const Chacha20State &other) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
data[i] += other.data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Copy(const Chacha20State & other)
|
||||
{
|
||||
void Copy(const Chacha20State &other) {
|
||||
memcpy(data, other.data, sizeof(uint32_t) * 16);
|
||||
}
|
||||
|
||||
uint32_t data[16];
|
||||
Chacha20Block block;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
void Chacha20Init(Chacha20State &state, const uint8_t *nonce, const uint8_t *key, uint32_t counter);
|
||||
|
||||
void Chacha20SetCounter(Chacha20State &state, uint32_t counter);
|
||||
|
||||
void Chacha20Encrypt(Chacha20State &state, uint8_t *buf, size_t sz); // encrypt buf in place
|
||||
} // namespace chacha
|
||||
} // namespace crypto
|
||||
|
|
|
@ -28,41 +28,61 @@ namespace config {
|
|||
options_description m_OptionsDesc;
|
||||
variables_map m_Options;
|
||||
|
||||
void Init()
|
||||
{
|
||||
void Init() {
|
||||
options_description general("General options");
|
||||
general.add_options()
|
||||
("help", "Show this message")
|
||||
("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)")
|
||||
("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)")
|
||||
("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d")
|
||||
("certsdir", value<std::string>()->default_value(""), "Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates")
|
||||
("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)")
|
||||
("conf", value<std::string>()->default_value(""),
|
||||
"Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)")
|
||||
("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)")
|
||||
("tunnelsdir", value<std::string>()->default_value(""),
|
||||
"Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d")
|
||||
("certsdir", value<std::string>()->default_value(""),
|
||||
"Path to certificates used for verifying .su3, families (default: ~/.i2pd/certificates or /var/lib/i2pd/certificates")
|
||||
("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")
|
||||
("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")
|
||||
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
||||
("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")
|
||||
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||
("nat", bool_switch()->default_value(true),
|
||||
"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)")
|
||||
("address4", value<std::string>()->default_value(""), "Local address to bind ipv4 transport sockets to")
|
||||
("ipv6", bool_switch()->default_value(false), "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)")
|
||||
("address4", value<std::string>()->default_value(""),
|
||||
"Local address to bind ipv4 transport sockets to")
|
||||
("ipv6", bool_switch()->default_value(false),
|
||||
"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")
|
||||
("daemon", bool_switch()->default_value(false), "Router will go to background after start (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)")
|
||||
("daemon", bool_switch()->default_value(false),
|
||||
"Router will go to background after start (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)")
|
||||
("bandwidth", value<std::string>()->default_value(""), "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)")
|
||||
("bandwidth", value<std::string>()->default_value(""),
|
||||
"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")
|
||||
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
|
||||
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
|
||||
|
@ -75,13 +95,15 @@ namespace config {
|
|||
|
||||
options_description limits("Limits options");
|
||||
limits.add_options()
|
||||
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
|
||||
("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.coresize", value<uint32_t>()->default_value(0),
|
||||
"Maximum size of corefile in Kb (0 - use system limit)")
|
||||
("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.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");
|
||||
httpserver.add_options()
|
||||
|
@ -90,92 +112,119 @@ namespace config {
|
|||
("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.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.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
|
||||
("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");
|
||||
httpproxy.add_options()
|
||||
("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.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>()->
|
||||
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
|
||||
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
|
||||
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
|
||||
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
|
||||
("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")
|
||||
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519),
|
||||
"Signature type for new keys. 7 (EdDSA) by default")
|
||||
("httpproxy.inbound.length", value<std::string>()->default_value("3"),
|
||||
"HTTP proxy inbound tunnel length")
|
||||
("httpproxy.outbound.length", value<std::string>()->default_value("3"),
|
||||
"HTTP proxy outbound tunnel length")
|
||||
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"),
|
||||
"HTTP proxy inbound tunnels quantity")
|
||||
("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.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.leaseSetEncType", value<std::string>()->default_value("0,4"), "Local destination's LeaseSet encryption type")
|
||||
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key")
|
||||
;
|
||||
("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("3"),
|
||||
"Local destination's LeaseSet type")
|
||||
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0,4"),
|
||||
"Local destination's LeaseSet encryption type")
|
||||
("httpproxy.i2cp.leaseSetPrivKey", value<std::string>()->default_value(""), "LeaseSet private key");
|
||||
|
||||
options_description socksproxy("SOCKS Proxy options");
|
||||
socksproxy.add_options()
|
||||
("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.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>()->
|
||||
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
|
||||
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
|
||||
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
|
||||
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
|
||||
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
|
||||
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy inbound tunnels length variance")
|
||||
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy outbound tunnels length variance")
|
||||
("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")
|
||||
;
|
||||
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519),
|
||||
"Signature type for new keys. 7 (EdDSA) by default")
|
||||
("socksproxy.inbound.length", value<std::string>()->default_value("3"),
|
||||
"SOCKS proxy inbound tunnel length")
|
||||
("socksproxy.outbound.length", value<std::string>()->default_value("3"),
|
||||
"SOCKS proxy outbound tunnel length")
|
||||
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"),
|
||||
"SOCKS proxy inbound tunnels quantity")
|
||||
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"),
|
||||
"SOCKS proxy outbound tunnels quantity")
|
||||
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"),
|
||||
"SOCKS proxy inbound tunnels length variance")
|
||||
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"),
|
||||
"SOCKS proxy outbound tunnels length variance")
|
||||
("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");
|
||||
sam.add_options()
|
||||
("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.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");
|
||||
bob.add_options()
|
||||
("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.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");
|
||||
i2cp.add_options()
|
||||
("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.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");
|
||||
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.port", value<uint16_t>()->default_value(7650), "I2PCP listen port")
|
||||
("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.key", value<std::string>()->default_value("i2pcontrol.key.pem"), "I2PCP connection certificate key")
|
||||
;
|
||||
("i2pcontrol.cert", value<std::string>()->default_value("i2pcontrol.crt.pem"),
|
||||
"I2PCP connection certificate")
|
||||
("i2pcontrol.key", value<std::string>()->default_value("i2pcontrol.key.pem"),
|
||||
"I2PCP connection certificate key");
|
||||
|
||||
bool upnp_default = false;
|
||||
#if (defined(USE_UPNP) && (defined(WIN32_APP) || defined(ANDROID)))
|
||||
|
@ -183,9 +232,10 @@ namespace config {
|
|||
#endif
|
||||
options_description upnp("UPnP options");
|
||||
upnp.add_options()
|
||||
("upnp.enabled", value<bool>()->default_value(upnp_default), "Enable or disable UPnP: automatic port forwarding")
|
||||
("upnp.name", value<std::string>()->default_value("I2Pd"), "Name i2pd appears in UPnP forwarding list")
|
||||
;
|
||||
("upnp.enabled", value<bool>()->default_value(upnp_default),
|
||||
"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");
|
||||
precomputation.add_options()
|
||||
|
@ -195,17 +245,21 @@ namespace config {
|
|||
#else
|
||||
value<bool>()->default_value(true),
|
||||
#endif
|
||||
"Enable or disable elgamal precomputation table")
|
||||
;
|
||||
"Enable or disable elgamal precomputation table");
|
||||
|
||||
options_description reseed("Reseed options");
|
||||
reseed.add_options()
|
||||
("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.floodfill", value<std::string>()->default_value(""), "Path to router info of floodfill to reseed from")
|
||||
("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.threshold", value<uint16_t>()->default_value(25),
|
||||
"Minimum number of known routers before requesting reseed")
|
||||
("reseed.floodfill", value<std::string>()->default_value(""),
|
||||
"Path to router info of floodfill to reseed from")
|
||||
("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(
|
||||
"https://reseed2.i2p.net/,"
|
||||
"https://reseed.diva.exchange/,"
|
||||
|
@ -225,59 +279,61 @@ namespace config {
|
|||
"http://[320:8936:ec1a:31f1::216]/,"
|
||||
"http://[306:3834:97b9:a00a::1]/,"
|
||||
"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");
|
||||
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(
|
||||
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
|
||||
), "AddressBook subscription URL for initial setup")
|
||||
("addressbook.subscriptions", value<std::string>()->default_value(
|
||||
"http://reg.i2p/hosts.txt"
|
||||
), "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");
|
||||
trust.add_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.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
|
||||
options_description websocket("Websocket Options");
|
||||
websocket.add_options()
|
||||
("websockets.enabled", value<bool>()->default_value(false), "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");
|
||||
exploratory.add_options()
|
||||
("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.inbound.quantity", value<int>()->default_value(3), "Exploratory inbound tunnels quantity")
|
||||
("exploratory.outbound.quantity", value<int>()->default_value(3), "Exploratory outbound tunnels quantity")
|
||||
;
|
||||
("exploratory.outbound.length", value<int>()->default_value(2),
|
||||
"Exploratory outbound tunnel length")
|
||||
("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");
|
||||
ntcp2.add_options()
|
||||
("ntcp2.enabled", value<bool>()->default_value(true), "Enable 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.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");
|
||||
ssu2.add_options()
|
||||
("ssu2.enabled", value<bool>()->default_value(false), "Enable 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");
|
||||
nettime.add_options()
|
||||
|
@ -288,28 +344,31 @@ namespace config {
|
|||
"2.pool.ntp.org,"
|
||||
"3.pool.ntp.org"
|
||||
), "Comma separated list of NTP servers")
|
||||
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)")
|
||||
("nettime.frompeers", value<bool>()->default_value(true), "Sync clock from transport peers (default: enabled)")
|
||||
;
|
||||
("nettime.ntpsyncinterval", value<int>()->default_value(72),
|
||||
"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");
|
||||
persist.add_options()
|
||||
("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");
|
||||
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.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")
|
||||
;
|
||||
("cpuext.aesni", bool_switch()->default_value(true),
|
||||
"Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
|
||||
("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");
|
||||
meshnets.add_options()
|
||||
("meshnets.yggdrasil", bool_switch()->default_value(false), "Support transports through the Yggdrasil (default: false)")
|
||||
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
|
||||
;
|
||||
("meshnets.yggdrasil", bool_switch()->default_value(false),
|
||||
"Support transports through the Yggdrasil (default: false)")
|
||||
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish");
|
||||
|
||||
#ifdef __linux__
|
||||
options_description unix_specific("UNIX-specific options");
|
||||
|
@ -347,33 +406,28 @@ namespace config {
|
|||
;
|
||||
}
|
||||
|
||||
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown)
|
||||
{
|
||||
try
|
||||
{
|
||||
void ParseCmdline(int argc, char *argv[], bool ignoreUnknown) {
|
||||
try {
|
||||
auto style = boost::program_options::command_line_style::unix_style
|
||||
| boost::program_options::command_line_style::allow_long_disguise;
|
||||
style &= ~boost::program_options::command_line_style::allow_guessing;
|
||||
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
|
||||
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());
|
||||
std::cerr << "args: " << e.what() << std::endl;
|
||||
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 << m_OptionsDesc;
|
||||
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 << "Boost 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;
|
||||
|
||||
std::ifstream config(path, std::ios::in);
|
||||
|
||||
if (!config.is_open())
|
||||
{
|
||||
if (!config.is_open()) {
|
||||
ThrowFatal("Missing or unreadable config file: ", path);
|
||||
std::cerr << "missing/unreadable config file: " << path << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
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());
|
||||
std::cerr << e.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
};
|
||||
}
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
void Finalize() {
|
||||
notify(m_Options);
|
||||
}
|
||||
|
||||
bool IsDefault(const char *name)
|
||||
{
|
||||
bool IsDefault(const char *name) {
|
||||
if (!m_Options.count(name))
|
||||
throw "try to check non-existent option";
|
||||
|
||||
|
@ -431,16 +479,14 @@ namespace config {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GetOptionAsAny(const char *name, boost::any& value)
|
||||
{
|
||||
bool GetOptionAsAny(const char *name, boost::any &value) {
|
||||
if (!m_Options.count(name))
|
||||
return false;
|
||||
value = m_Options[name];
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,8 +80,7 @@ namespace config {
|
|||
* Example: uint16_t port; GetOption("sam.port", port);
|
||||
*/
|
||||
template<typename T>
|
||||
bool GetOption(const char *name, T& value)
|
||||
{
|
||||
bool GetOption(const char *name, T &value) {
|
||||
if (!m_Options.count(name))
|
||||
return false;
|
||||
value = m_Options[name].as<T>();
|
||||
|
@ -89,12 +88,12 @@ namespace config {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool GetOptionAsAny(const char *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);
|
||||
*/
|
||||
template<typename T>
|
||||
bool SetOption(const char *name, const T& value)
|
||||
{
|
||||
bool SetOption(const char *name, const T &value) {
|
||||
if (!m_Options.count(name))
|
||||
return false;
|
||||
m_Options.at(name).value() = value;
|
||||
|
|
|
@ -16,22 +16,24 @@
|
|||
#include <openssl/crypto.h>
|
||||
#include "TunnelBase.h"
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#if OPENSSL_HKDF
|
||||
#include <openssl/kdf.h>
|
||||
#endif
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
|
||||
#include "ChaCha20.h"
|
||||
#include "Poly1305.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include "Crypto.h"
|
||||
#include "Ed25519.h"
|
||||
#include "I2PEndian.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
const uint8_t elgp_[256] =
|
||||
{
|
||||
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;
|
||||
|
||||
struct CryptoConstants
|
||||
{
|
||||
struct CryptoConstants {
|
||||
// DH/ElGamal
|
||||
BIGNUM *elgp;
|
||||
BIGNUM *elgg;
|
||||
|
@ -101,8 +102,7 @@ namespace crypto
|
|||
BIGNUM *rsae;
|
||||
|
||||
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();
|
||||
BN_bin2bn(elgp_, 256, elgp);
|
||||
elgg = BN_new();
|
||||
|
@ -117,20 +117,22 @@ namespace crypto
|
|||
BN_set_word(rsae, rsae_);
|
||||
}
|
||||
|
||||
~CryptoConstants ()
|
||||
{
|
||||
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
||||
~CryptoConstants() {
|
||||
BN_free(elgp);
|
||||
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_);
|
||||
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);
|
||||
if (offset < 0) return false;
|
||||
BN_bn2bin(bn, buf + offset);
|
||||
|
@ -140,8 +142,8 @@ namespace crypto
|
|||
|
||||
// RSA
|
||||
#define rsae GetCryptoConstants ().rsae
|
||||
const BIGNUM * GetRSAE ()
|
||||
{
|
||||
|
||||
const BIGNUM *GetRSAE() {
|
||||
return rsae;
|
||||
}
|
||||
|
||||
|
@ -149,8 +151,8 @@ namespace crypto
|
|||
#define dsap GetCryptoConstants ().dsap
|
||||
#define dsaq GetCryptoConstants ().dsaq
|
||||
#define dsag GetCryptoConstants ().dsag
|
||||
DSA * CreateDSA ()
|
||||
{
|
||||
|
||||
DSA *CreateDSA() {
|
||||
DSA *dsa = DSA_new();
|
||||
DSA_set0_pqg(dsa, BN_dup(dsap), BN_dup(dsaq), BN_dup(dsag));
|
||||
DSA_set0_key(dsa, NULL, NULL);
|
||||
|
@ -168,6 +170,7 @@ namespace crypto
|
|||
#define elgg GetCryptoConstants ().elgg
|
||||
|
||||
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
|
||||
{
|
||||
if (len <= 0) return;
|
||||
|
@ -176,15 +179,13 @@ namespace crypto
|
|||
BN_MONT_CTX_set(g_MontCtx, elgp, ctx);
|
||||
auto montCtx = BN_MONT_CTX_new();
|
||||
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();
|
||||
if (!i)
|
||||
BN_to_montgomery(table[0][0], elgg, montCtx, ctx);
|
||||
else
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
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 j = 0; j < 255; j++)
|
||||
{
|
||||
for (int j = 0; j < 255; j++) {
|
||||
BN_free(table[i][j]);
|
||||
table[i][j] = nullptr;
|
||||
}
|
||||
|
@ -211,14 +210,11 @@ namespace crypto
|
|||
auto montCtx = BN_MONT_CTX_new();
|
||||
BN_MONT_CTX_copy(montCtx, g_MontCtx);
|
||||
BIGNUM *res = nullptr;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (res)
|
||||
{
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (res) {
|
||||
if (exp[i])
|
||||
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]);
|
||||
}
|
||||
if (res)
|
||||
|
@ -227,8 +223,7 @@ namespace crypto
|
|||
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);
|
||||
uint8_t *buf = new uint8_t[len];
|
||||
BN_bn2bin(exp, buf);
|
||||
|
@ -241,27 +236,23 @@ namespace crypto
|
|||
|
||||
// DH
|
||||
|
||||
DHKeys::DHKeys ()
|
||||
{
|
||||
DHKeys::DHKeys() {
|
||||
m_DH = DH_new();
|
||||
DH_set0_pqg(m_DH, BN_dup(elgp), NULL, BN_dup(elgg));
|
||||
DH_set0_key(m_DH, NULL, NULL);
|
||||
}
|
||||
|
||||
DHKeys::~DHKeys ()
|
||||
{
|
||||
DHKeys::~DHKeys() {
|
||||
DH_free(m_DH);
|
||||
}
|
||||
|
||||
void DHKeys::GenerateKeys ()
|
||||
{
|
||||
void DHKeys::GenerateKeys() {
|
||||
BIGNUM *priv_key = NULL, *pub_key = NULL;
|
||||
#if !defined(__x86_64__) // use short exponent for non x64
|
||||
priv_key = BN_new();
|
||||
BN_rand(priv_key, ELGAMAL_SHORT_EXPONENT_NUM_BITS, 0, 1);
|
||||
#endif
|
||||
if (g_ElggTable)
|
||||
{
|
||||
if (g_ElggTable) {
|
||||
#if defined(__x86_64__)
|
||||
priv_key = BN_new ();
|
||||
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);
|
||||
DH_set0_key(m_DH, pub_key, priv_key);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
DH_set0_key(m_DH, NULL, priv_key);
|
||||
DH_generate_key(m_DH);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
DH_compute_key(shared, pk, m_DH);
|
||||
BN_free(pk);
|
||||
}
|
||||
|
||||
// x25519
|
||||
X25519Keys::X25519Keys ()
|
||||
{
|
||||
X25519Keys::X25519Keys() {
|
||||
#if OPENSSL_X25519
|
||||
m_Ctx = EVP_PKEY_CTX_new_id (NID_X25519, NULL);
|
||||
m_Pkey = nullptr;
|
||||
|
@ -299,8 +286,7 @@ namespace crypto
|
|||
#endif
|
||||
}
|
||||
|
||||
X25519Keys::X25519Keys (const uint8_t * priv, const uint8_t * pub)
|
||||
{
|
||||
X25519Keys::X25519Keys(const uint8_t *priv, const uint8_t *pub) {
|
||||
#if OPENSSL_X25519
|
||||
m_Pkey = EVP_PKEY_new_raw_private_key (EVP_PKEY_X25519, NULL, priv, 32);
|
||||
m_Ctx = EVP_PKEY_CTX_new (m_Pkey, NULL);
|
||||
|
@ -321,8 +307,7 @@ namespace crypto
|
|||
#endif
|
||||
}
|
||||
|
||||
X25519Keys::~X25519Keys ()
|
||||
{
|
||||
X25519Keys::~X25519Keys() {
|
||||
#if OPENSSL_X25519
|
||||
EVP_PKEY_CTX_free (m_Ctx);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
|
@ -331,8 +316,7 @@ namespace crypto
|
|||
#endif
|
||||
}
|
||||
|
||||
void X25519Keys::GenerateKeys ()
|
||||
{
|
||||
void X25519Keys::GenerateKeys() {
|
||||
#if OPENSSL_X25519
|
||||
if (m_Pkey)
|
||||
{
|
||||
|
@ -351,8 +335,7 @@ namespace crypto
|
|||
#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 OPENSSL_X25519
|
||||
EVP_PKEY_derive_init (m_Ctx);
|
||||
|
@ -368,8 +351,7 @@ namespace crypto
|
|||
return true;
|
||||
}
|
||||
|
||||
void X25519Keys::GetPrivateKey (uint8_t * priv) const
|
||||
{
|
||||
void X25519Keys::GetPrivateKey(uint8_t *priv) const {
|
||||
#if OPENSSL_X25519
|
||||
size_t len = 32;
|
||||
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
|
||||
|
@ -378,8 +360,7 @@ namespace crypto
|
|||
#endif
|
||||
}
|
||||
|
||||
void X25519Keys::SetPrivateKey (const uint8_t * priv, bool calculatePublic)
|
||||
{
|
||||
void X25519Keys::SetPrivateKey(const uint8_t *priv, bool calculatePublic) {
|
||||
#if OPENSSL_X25519
|
||||
if (m_Ctx) EVP_PKEY_CTX_free (m_Ctx);
|
||||
if (m_Pkey) EVP_PKEY_free (m_Pkey);
|
||||
|
@ -398,8 +379,7 @@ namespace crypto
|
|||
}
|
||||
|
||||
// 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_start(ctx);
|
||||
// everything, but a, because a might come from table
|
||||
|
@ -417,8 +397,7 @@ namespace crypto
|
|||
BIGNUM *a;
|
||||
if (g_ElggTable)
|
||||
a = ElggPow(k, g_ElggTable, ctx);
|
||||
else
|
||||
{
|
||||
else {
|
||||
a = BN_new();
|
||||
BN_mod_exp(a, elgg, k, elgp, ctx);
|
||||
}
|
||||
|
@ -446,13 +425,13 @@ namespace crypto
|
|||
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_start(ctx);
|
||||
BIGNUM *x = BN_CTX_get(ctx), *a = BN_CTX_get(ctx), *b = BN_CTX_get(ctx);
|
||||
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 + 258, 256, b);
|
||||
// m = b*(a^x mod p) mod p
|
||||
|
@ -464,8 +443,7 @@ namespace crypto
|
|||
BN_CTX_free(ctx);
|
||||
uint8_t hash[32];
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
|
@ -473,8 +451,7 @@ namespace crypto
|
|||
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)
|
||||
RAND_bytes (priv, 256);
|
||||
#else
|
||||
|
@ -495,8 +472,7 @@ namespace crypto
|
|||
}
|
||||
|
||||
// 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_start(ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -522,7 +498,8 @@ namespace crypto
|
|||
SHA256(keyBuf, len, shared);
|
||||
// create buffer
|
||||
uint8_t m[256];
|
||||
m[0] = 0xFF; m[255] = 0xFF;
|
||||
m[0] = 0xFF;
|
||||
m[255] = 0xFF;
|
||||
memcpy(m + 33, data, 222);
|
||||
SHA256(m + 33, 222, m + 1);
|
||||
// encrypt
|
||||
|
@ -536,8 +513,7 @@ namespace crypto
|
|||
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;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
|
@ -549,8 +525,7 @@ namespace crypto
|
|||
BN_bin2bn(encrypted + 1, len, x);
|
||||
BN_bin2bn(encrypted + 1 + len, len, y);
|
||||
auto p = EC_POINT_new(curve);
|
||||
if (EC_POINT_set_affine_coordinates_GFp (curve, p, x, y, nullptr))
|
||||
{
|
||||
if (EC_POINT_set_affine_coordinates_GFp(curve, p, x, y, nullptr)) {
|
||||
auto s = EC_POINT_new(curve);
|
||||
EC_POINT_mul(curve, s, nullptr, p, key, ctx);
|
||||
EC_POINT_get_affine_coordinates_GFp(curve, s, x, y, nullptr);
|
||||
|
@ -570,14 +545,11 @@ namespace crypto
|
|||
SHA256(m + 33, 222, hash);
|
||||
if (!memcmp(m + 1, hash, 32))
|
||||
memcpy(data, m + 33, 222);
|
||||
else
|
||||
{
|
||||
else {
|
||||
LogPrint(eLogError, "ECIES decrypt hash doesn't match");
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogError, "ECIES decrypt point is invalid");
|
||||
ret = false;
|
||||
}
|
||||
|
@ -588,8 +560,7 @@ namespace crypto
|
|||
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();
|
||||
BIGNUM *q = BN_new();
|
||||
EC_GROUP_get_order(curve, q, ctx);
|
||||
|
@ -758,8 +729,7 @@ namespace crypto
|
|||
"aesenclast 224(%["#sched"]), %%xmm0 \n"
|
||||
#endif
|
||||
|
||||
void ECBEncryption::Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
void ECBEncryption::Encrypt(const ChipherBlock *in, ChipherBlock *out) {
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -797,8 +767,7 @@ namespace crypto
|
|||
"aesdeclast (%["#sched"]), %%xmm0 \n"
|
||||
#endif
|
||||
|
||||
void ECBDecryption::Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
void ECBDecryption::Decrypt(const ChipherBlock *in, ChipherBlock *out) {
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -824,8 +793,7 @@ namespace crypto
|
|||
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
||||
#endif
|
||||
|
||||
void ECBEncryption::SetKey (const AESKey& key)
|
||||
{
|
||||
void ECBEncryption::SetKey(const AESKey &key) {
|
||||
#ifdef __AES__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -838,8 +806,7 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
void ECBDecryption::SetKey (const AESKey& key)
|
||||
{
|
||||
void ECBDecryption::SetKey(const AESKey &key) {
|
||||
#ifdef __AES__
|
||||
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__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -898,8 +864,7 @@ namespace crypto
|
|||
else
|
||||
#endif
|
||||
{
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
*m_LastBlock.GetChipherBlock() ^= in[i];
|
||||
m_ECBEncryption.Encrypt(m_LastBlock.GetChipherBlock(), m_LastBlock.GetChipherBlock());
|
||||
out[i] = *m_LastBlock.GetChipherBlock();
|
||||
|
@ -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
|
||||
int numBlocks = len >> 4;
|
||||
if (numBlocks > 0)
|
||||
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__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -939,8 +902,7 @@ namespace crypto
|
|||
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__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -968,8 +930,7 @@ namespace crypto
|
|||
else
|
||||
#endif
|
||||
{
|
||||
for (int i = 0; i < numBlocks; i++)
|
||||
{
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
ChipherBlock tmp = in[i];
|
||||
m_ECBDecryption.Decrypt(in + i, out + i);
|
||||
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;
|
||||
if (numBlocks > 0)
|
||||
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__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -1009,8 +968,7 @@ namespace crypto
|
|||
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__
|
||||
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__
|
||||
if(i2p::cpu::aesni)
|
||||
{
|
||||
|
@ -1094,8 +1051,9 @@ namespace crypto
|
|||
|
||||
// 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 (encrypt && len < msgLen + 16) return false;
|
||||
bool ret = true;
|
||||
|
@ -1134,13 +1092,12 @@ namespace crypto
|
|||
// create Poly1305 hash
|
||||
Poly1305 polyHash(polyKey);
|
||||
if (!ad) adLen = 0;
|
||||
uint8_t padding[16]; memset (padding, 0, 16);
|
||||
if (ad)
|
||||
{
|
||||
uint8_t padding[16];
|
||||
memset(padding, 0, 16);
|
||||
if (ad) {
|
||||
polyHash.Update(ad, adLen);// additional authenticated data
|
||||
auto rem = adLen & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
if (rem) {
|
||||
// padding1
|
||||
rem = 16 - rem;
|
||||
polyHash.Update(padding, rem);
|
||||
|
@ -1150,20 +1107,16 @@ namespace crypto
|
|||
Chacha20SetCounter(state, 1);
|
||||
if (buf != msg)
|
||||
memcpy(buf, msg, msgLen);
|
||||
if (encrypt)
|
||||
{
|
||||
if (encrypt) {
|
||||
chacha::Chacha20Encrypt(state, buf, msgLen); // encrypt
|
||||
polyHash.Update(buf, msgLen); // after encryption
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
polyHash.Update(buf, msgLen); // before decryption
|
||||
chacha::Chacha20Encrypt(state, buf, msgLen); // decrypt
|
||||
}
|
||||
|
||||
auto rem = msgLen & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
if (rem) {
|
||||
// padding2
|
||||
rem = 16 - rem;
|
||||
polyHash.Update(padding, rem);
|
||||
|
@ -1176,8 +1129,7 @@ namespace crypto
|
|||
if (encrypt)
|
||||
// calculate Poly1305 tag and write in after encrypted data
|
||||
polyHash.Finish((uint64_t * )(buf + msgLen));
|
||||
else
|
||||
{
|
||||
else {
|
||||
uint64_t tag[4];
|
||||
// calculate Poly1305 tag
|
||||
polyHash.Finish(tag);
|
||||
|
@ -1187,8 +1139,8 @@ namespace crypto
|
|||
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 OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
int outlen = 0;
|
||||
|
@ -1212,8 +1164,7 @@ namespace crypto
|
|||
// encrypt buffers
|
||||
Chacha20SetCounter(state, 1);
|
||||
size_t size = 0;
|
||||
for (const auto& it: bufs)
|
||||
{
|
||||
for (const auto &it: bufs) {
|
||||
chacha::Chacha20Encrypt(state, it.first, it.second);
|
||||
polyHash.Update(it.first, it.second); // after encryption
|
||||
size += it.second;
|
||||
|
@ -1222,8 +1173,7 @@ namespace crypto
|
|||
uint8_t padding[16];
|
||||
memset(padding, 0, 16);
|
||||
auto rem = size & 0x0F; // %16
|
||||
if (rem)
|
||||
{
|
||||
if (rem) {
|
||||
// padding2
|
||||
rem = 16 - rem;
|
||||
polyHash.Update(padding, rem);
|
||||
|
@ -1237,8 +1187,7 @@ namespace crypto
|
|||
#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
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
|
||||
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,
|
||||
uint8_t * out, size_t outLen)
|
||||
{
|
||||
uint8_t *out, size_t outLen) {
|
||||
#if OPENSSL_HKDF
|
||||
EVP_PKEY_CTX * pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF, nullptr);
|
||||
EVP_PKEY_derive_init (pctx);
|
||||
|
@ -1281,14 +1229,17 @@ namespace crypto
|
|||
EVP_PKEY_derive (pctx, out, &outLen);
|
||||
EVP_PKEY_CTX_free (pctx);
|
||||
#else
|
||||
uint8_t prk[32]; unsigned int len;
|
||||
uint8_t prk[32];
|
||||
unsigned int len;
|
||||
HMAC(EVP_sha256(), salt, 32, key, keyLen, prk, &len);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
@ -1296,8 +1247,7 @@ namespace crypto
|
|||
|
||||
// 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_Init(&ctx);
|
||||
SHA256_Update(&ctx, m_H, 32);
|
||||
|
@ -1305,8 +1255,7 @@ namespace crypto
|
|||
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_Init(&ctx);
|
||||
SHA256_Update(&ctx, m_H, 32);
|
||||
|
@ -1315,15 +1264,13 @@ namespace crypto
|
|||
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);
|
||||
// new ck is m_CK[0:31], key is m_CK[32:63]
|
||||
}
|
||||
|
||||
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)
|
||||
memcpy(state.m_CK, ck, 32);
|
||||
SHA256_CTX ctx;
|
||||
|
@ -1333,58 +1280,68 @@ namespace crypto
|
|||
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 uint8_t hh[32] =
|
||||
{
|
||||
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
|
||||
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54
|
||||
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d,
|
||||
0xc1,
|
||||
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15,
|
||||
0x54
|
||||
}; // hh = SHA256(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] =
|
||||
{
|
||||
0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed,
|
||||
0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71
|
||||
0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7,
|
||||
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")
|
||||
static const uint8_t hh[32] =
|
||||
{
|
||||
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5,
|
||||
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e
|
||||
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05,
|
||||
0xb5,
|
||||
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d,
|
||||
0x1e
|
||||
}; // SHA256 (protocolNameHash)
|
||||
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] =
|
||||
{
|
||||
0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed, 0xf4,
|
||||
0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81, 0x32
|
||||
0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed,
|
||||
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")
|
||||
static const uint8_t hh[32] =
|
||||
{
|
||||
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53,
|
||||
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33
|
||||
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4,
|
||||
0x53,
|
||||
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc,
|
||||
0x33
|
||||
}; // SHA256 (protocolNameHash)
|
||||
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] =
|
||||
{
|
||||
0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba,
|
||||
0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c
|
||||
0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d,
|
||||
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
|
||||
static const uint8_t hh[32] =
|
||||
{
|
||||
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32,
|
||||
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
|
||||
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52,
|
||||
0x32,
|
||||
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b,
|
||||
0x5c
|
||||
}; // SHA256 (protocolNameHash)
|
||||
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);
|
||||
#if LEGACY_OPENSSL
|
||||
SSL_library_init();
|
||||
|
@ -1413,8 +1369,7 @@ namespace crypto
|
|||
for (int i = 0; i < numLocks; i++)
|
||||
m_OpenSSLMutexes.emplace_back (new std::mutex);
|
||||
CRYPTO_set_locking_callback (OpensslLockingCallback);*/
|
||||
if (precomputation)
|
||||
{
|
||||
if (precomputation) {
|
||||
#if defined(__x86_64__)
|
||||
g_ElggTable = new BIGNUM * [ELGAMAL_FULL_EXPONENT_NUM_BYTES][255];
|
||||
PrecalculateElggTable (g_ElggTable, ELGAMAL_FULL_EXPONENT_NUM_BYTES);
|
||||
|
@ -1425,10 +1380,8 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
void TerminateCrypto ()
|
||||
{
|
||||
if (g_ElggTable)
|
||||
{
|
||||
void TerminateCrypto() {
|
||||
if (g_ElggTable) {
|
||||
DestroyElggTable(g_ElggTable,
|
||||
#if defined(__x86_64__)
|
||||
ELGAMAL_FULL_EXPONENT_NUM_BYTES
|
||||
|
@ -1436,7 +1389,8 @@ namespace crypto
|
|||
ELGAMAL_SHORT_EXPONENT_NUM_BYTES
|
||||
#endif
|
||||
);
|
||||
delete[] g_ElggTable; g_ElggTable = nullptr;
|
||||
delete[] g_ElggTable;
|
||||
g_ElggTable = nullptr;
|
||||
}
|
||||
/* CRYPTO_set_locking_callback (nullptr);
|
||||
m_OpenSSLMutexes.clear ();*/
|
||||
|
|
185
libi2pd/Crypto.h
185
libi2pd/Crypto.h
|
@ -50,10 +50,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
bool bn2buf(const BIGNUM *bn, uint8_t *buf, size_t len);
|
||||
|
||||
// DSA
|
||||
|
@ -63,15 +61,17 @@ namespace crypto
|
|||
const BIGNUM *GetRSAE();
|
||||
|
||||
// DH
|
||||
class DHKeys
|
||||
{
|
||||
class DHKeys {
|
||||
public:
|
||||
|
||||
DHKeys();
|
||||
|
||||
~DHKeys();
|
||||
|
||||
void GenerateKeys();
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKey; };
|
||||
|
||||
void Agree(const uint8_t *pub, uint8_t *shared);
|
||||
|
||||
private:
|
||||
|
@ -81,21 +81,26 @@ namespace crypto
|
|||
};
|
||||
|
||||
// x25519
|
||||
class X25519Keys
|
||||
{
|
||||
class X25519Keys {
|
||||
public:
|
||||
|
||||
X25519Keys();
|
||||
|
||||
X25519Keys(const uint8_t *priv, const uint8_t *pub); // if pub is null, derive from priv
|
||||
~X25519Keys();
|
||||
|
||||
void GenerateKeys();
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKey; };
|
||||
|
||||
void GetPrivateKey(uint8_t *priv) const;
|
||||
|
||||
void SetPrivateKey(const uint8_t *priv, bool calculatePublic = false);
|
||||
|
||||
bool Agree(const uint8_t *pub, uint8_t *shared);
|
||||
|
||||
bool IsElligatorIneligible() const { return m_IsElligatorIneligible; }
|
||||
|
||||
void SetElligatorIneligible() { m_IsElligatorIneligible = true; }
|
||||
|
||||
private:
|
||||
|
@ -112,22 +117,26 @@ namespace crypto
|
|||
};
|
||||
|
||||
// ElGamal
|
||||
void ElGamalEncrypt (const uint8_t * key, const uint8_t * 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 ElGamalEncrypt(const uint8_t *key, const uint8_t *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);
|
||||
|
||||
// ECIES
|
||||
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * 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 ECIESEncrypt(const EC_GROUP *curve, const EC_POINT *key, const uint8_t *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);
|
||||
|
||||
// HMAC
|
||||
typedef i2p::data::Tag<32> MACKey;
|
||||
|
||||
void HMACMD5Digest(uint8_t *msg, size_t len, const MACKey &key, uint8_t *digest);
|
||||
|
||||
// AES
|
||||
struct ChipherBlock
|
||||
{
|
||||
struct ChipherBlock {
|
||||
uint8_t buf[16];
|
||||
|
||||
void operator^=(const ChipherBlock &other) // XOR
|
||||
|
@ -136,9 +145,7 @@ namespace crypto
|
|||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
reinterpret_cast<uint32_t *>(buf)[i] ^= reinterpret_cast<const uint32_t *>(other.buf)[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
for (int i = 0; i < 16; i++)
|
||||
buf[i] ^= other.buf[i];
|
||||
}
|
||||
|
@ -152,8 +159,7 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
AESAlignedBuffer ()
|
||||
{
|
||||
AESAlignedBuffer() {
|
||||
m_Buf = m_UnalignedBuffer;
|
||||
uint8_t rem = ((size_t) m_Buf) & 0x0f;
|
||||
if (rem)
|
||||
|
@ -161,8 +167,11 @@ namespace crypto
|
|||
}
|
||||
|
||||
operator uint8_t *() { return m_Buf; };
|
||||
|
||||
operator const uint8_t *() const { return m_Buf; };
|
||||
|
||||
ChipherBlock *GetChipherBlock() { return (ChipherBlock *) m_Buf; };
|
||||
|
||||
const ChipherBlock *GetChipherBlock() const { return (const ChipherBlock *) m_Buf; };
|
||||
|
||||
private:
|
||||
|
@ -192,6 +201,7 @@ namespace crypto
|
|||
#ifdef __AES__
|
||||
class ECBEncryption: public ECBCryptoAESNI
|
||||
#else
|
||||
|
||||
class ECBEncryption
|
||||
#endif
|
||||
{
|
||||
|
@ -208,19 +218,21 @@ namespace crypto
|
|||
#ifdef __AES__
|
||||
class ECBDecryption: public ECBCryptoAESNI
|
||||
#else
|
||||
|
||||
class ECBDecryption
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey(const AESKey &key);
|
||||
|
||||
void Decrypt(const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
private:
|
||||
AES_KEY m_Key;
|
||||
};
|
||||
|
||||
class CBCEncryption
|
||||
{
|
||||
class CBCEncryption {
|
||||
public:
|
||||
|
||||
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 Encrypt(int numBlocks, const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
void Encrypt(const uint8_t *in, std::size_t len, uint8_t *out);
|
||||
|
||||
void Encrypt(const uint8_t *in, uint8_t *out); // one block
|
||||
|
||||
ECBEncryption &ECB() { return m_ECBEncryption; }
|
||||
|
@ -242,8 +256,7 @@ namespace crypto
|
|||
ECBEncryption m_ECBEncryption;
|
||||
};
|
||||
|
||||
class CBCDecryption
|
||||
{
|
||||
class CBCDecryption {
|
||||
public:
|
||||
|
||||
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 Decrypt(int numBlocks, const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
void Decrypt(const uint8_t *in, std::size_t len, uint8_t *out);
|
||||
|
||||
void Decrypt(const uint8_t *in, uint8_t *out); // one block
|
||||
|
||||
ECBDecryption &ECB() { return m_ECBDecryption; }
|
||||
|
@ -268,8 +283,7 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
|
||||
m_LayerEncryption.SetKey(layerKey);
|
||||
m_IVEncryption.SetKey(ivKey);
|
||||
}
|
||||
|
@ -286,8 +300,7 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
|
||||
m_LayerDecryption.SetKey(layerKey);
|
||||
m_IVDecryption.SetKey(ivKey);
|
||||
}
|
||||
|
@ -301,25 +314,30 @@ namespace crypto
|
|||
};
|
||||
|
||||
// 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
|
||||
void ChaCha20(const uint8_t *msg, size_t msgLen, const uint8_t *key, const uint8_t *nonce, uint8_t *out);
|
||||
|
||||
// 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
|
||||
|
||||
struct NoiseSymmetricState
|
||||
{
|
||||
struct NoiseSymmetricState {
|
||||
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
|
||||
|
||||
void MixHash(const uint8_t *buf, size_t len);
|
||||
|
||||
void MixHash(const std::vector<std::pair<uint8_t *, size_t> > &bufs);
|
||||
|
||||
void MixKey(const uint8_t *sharedSecret);
|
||||
};
|
||||
|
||||
|
@ -330,79 +348,108 @@ namespace crypto
|
|||
|
||||
// init and terminate
|
||||
void InitCrypto(bool precomputation, bool aesni, bool avx, bool force);
|
||||
|
||||
void TerminateCrypto();
|
||||
}
|
||||
}
|
||||
|
||||
// take care about openssl below 1.1.0
|
||||
#if LEGACY_OPENSSL
|
||||
|
||||
// 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->q) BN_free(d->q);
|
||||
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->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 int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
|
||||
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 int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) {
|
||||
if (sig->r) BN_free(sig->r);
|
||||
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->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->e) BN_free(r->e);
|
||||
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->q) BN_free(dh->q);
|
||||
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->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)
|
||||
{ return pkey->pkey.rsa; }
|
||||
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 EVP_MD_CTX *EVP_MD_CTX_new ()
|
||||
{ return EVP_MD_CTX_create(); }
|
||||
inline void EVP_MD_CTX_free (EVP_MD_CTX *ctx)
|
||||
{ EVP_MD_CTX_destroy (ctx); }
|
||||
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) { return pkey->pkey.rsa; }
|
||||
|
||||
inline EVP_MD_CTX *EVP_MD_CTX_new() { return EVP_MD_CTX_create(); }
|
||||
|
||||
inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { EVP_MD_CTX_destroy(ctx); }
|
||||
|
||||
// ssl
|
||||
#define TLS_method TLSv1_method
|
||||
|
|
|
@ -11,74 +11,62 @@
|
|||
#include "Gost.h"
|
||||
#include "CryptoKey.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
ElGamalEncryptor::ElGamalEncryptor (const uint8_t * pub)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
ElGamalEncryptor::ElGamalEncryptor(const uint8_t *pub) {
|
||||
memcpy(m_PublicKey, pub, 256);
|
||||
}
|
||||
|
||||
void ElGamalEncryptor::Encrypt (const uint8_t * data, uint8_t * encrypted)
|
||||
{
|
||||
void ElGamalEncryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
|
||||
ElGamalEncrypt(m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
|
||||
{
|
||||
ElGamalDecryptor::ElGamalDecryptor(const uint8_t *priv) {
|
||||
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);
|
||||
}
|
||||
|
||||
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_PublicKey = EC_POINT_new(m_Curve);
|
||||
BIGNUM *x = BN_bin2bn(pub, 32, nullptr);
|
||||
BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr);
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(m_Curve, m_PublicKey, x, y, nullptr))
|
||||
LogPrint(eLogError, "ECICS P256 invalid public key");
|
||||
BN_free (x); BN_free (y);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
}
|
||||
|
||||
ECIESP256Encryptor::~ECIESP256Encryptor ()
|
||||
{
|
||||
ECIESP256Encryptor::~ECIESP256Encryptor() {
|
||||
if (m_Curve) EC_GROUP_free(m_Curve);
|
||||
if (m_PublicKey) EC_POINT_free(m_PublicKey);
|
||||
}
|
||||
|
||||
void ECIESP256Encryptor::Encrypt (const uint8_t * data, uint8_t * encrypted)
|
||||
{
|
||||
void ECIESP256Encryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
|
||||
if (m_Curve && m_PublicKey)
|
||||
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_PrivateKey = BN_bin2bn(priv, 32, nullptr);
|
||||
}
|
||||
|
||||
ECIESP256Decryptor::~ECIESP256Decryptor ()
|
||||
{
|
||||
ECIESP256Decryptor::~ECIESP256Decryptor() {
|
||||
if (m_Curve) EC_GROUP_free(m_Curve);
|
||||
if (m_PrivateKey) BN_free(m_PrivateKey);
|
||||
}
|
||||
|
||||
bool ECIESP256Decryptor::Decrypt (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
bool ECIESP256Decryptor::Decrypt(const uint8_t *encrypted, uint8_t *data) {
|
||||
if (m_Curve && m_PrivateKey)
|
||||
return ECIESDecrypt(m_Curve, m_PrivateKey, encrypted, data);
|
||||
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_POINT *p = nullptr;
|
||||
BIGNUM *key = nullptr;
|
||||
|
@ -92,52 +80,47 @@ namespace crypto
|
|||
bn2buf(y, pub + 32, 32);
|
||||
RAND_bytes(pub + 64, 192);
|
||||
EC_POINT_free(p);
|
||||
BN_free (x); BN_free (y);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
EC_GROUP_free(curve);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub)
|
||||
{
|
||||
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor(const uint8_t *pub) {
|
||||
auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA);
|
||||
m_PublicKey = EC_POINT_new(curve->GetGroup());
|
||||
BIGNUM *x = BN_bin2bn(pub, 32, nullptr);
|
||||
BIGNUM *y = BN_bin2bn(pub + 32, 32, nullptr);
|
||||
if (!EC_POINT_set_affine_coordinates_GFp(curve->GetGroup(), m_PublicKey, x, y, nullptr))
|
||||
LogPrint(eLogError, "ECICS GOST R 34.10 invalid public key");
|
||||
BN_free (x); BN_free (y);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor ()
|
||||
{
|
||||
ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor() {
|
||||
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)
|
||||
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);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor ()
|
||||
{
|
||||
ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor() {
|
||||
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)
|
||||
return ECIESDecrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PrivateKey, encrypted, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
void CreateECIESGOSTR3410RandomKeys(uint8_t *priv, uint8_t *pub) {
|
||||
auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA);
|
||||
EC_POINT *p = nullptr;
|
||||
BIGNUM *key = nullptr;
|
||||
|
@ -151,31 +134,27 @@ namespace crypto
|
|||
bn2buf(y, pub + 32, 32);
|
||||
RAND_bytes(pub + 64, 192);
|
||||
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);
|
||||
}
|
||||
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub)
|
||||
{
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt(const uint8_t *, uint8_t *pub) {
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
void CreateECIESX25519AEADRatchetRandomKeys(uint8_t *priv, uint8_t *pub) {
|
||||
X25519Keys k;
|
||||
k.GenerateKeys();
|
||||
k.GetPrivateKey(priv);
|
||||
|
|
|
@ -12,24 +12,23 @@
|
|||
#include <inttypes.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
class CryptoKeyEncryptor
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
class CryptoKeyEncryptor {
|
||||
public:
|
||||
|
||||
virtual ~CryptoKeyEncryptor() {};
|
||||
|
||||
virtual void Encrypt(const uint8_t *data, uint8_t *encrypted) = 0;
|
||||
};
|
||||
|
||||
class CryptoKeyDecryptor
|
||||
{
|
||||
class CryptoKeyDecryptor {
|
||||
public:
|
||||
|
||||
virtual ~CryptoKeyDecryptor() {};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
@ -39,6 +38,7 @@ namespace crypto
|
|||
public:
|
||||
|
||||
ElGamalEncryptor(const uint8_t *pub);
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override; // 222 bytes data, 514 bytes encrypted
|
||||
|
||||
private:
|
||||
|
@ -51,6 +51,7 @@ namespace crypto
|
|||
public:
|
||||
|
||||
ElGamalDecryptor(const uint8_t *priv);
|
||||
|
||||
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override; // 514 bytes encrypted, 222 bytes data
|
||||
size_t GetPublicKeyLen() const override { return 256; };
|
||||
|
||||
|
@ -61,12 +62,13 @@ namespace crypto
|
|||
|
||||
// ECIES P256
|
||||
|
||||
class ECIESP256Encryptor: public CryptoKeyEncryptor
|
||||
{
|
||||
class ECIESP256Encryptor : public CryptoKeyEncryptor {
|
||||
public:
|
||||
|
||||
ECIESP256Encryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESP256Encryptor();
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
|
||||
|
||||
private:
|
||||
|
@ -76,13 +78,15 @@ namespace crypto
|
|||
};
|
||||
|
||||
|
||||
class ECIESP256Decryptor: public CryptoKeyDecryptor
|
||||
{
|
||||
class ECIESP256Decryptor : public CryptoKeyDecryptor {
|
||||
public:
|
||||
|
||||
ECIESP256Decryptor(const uint8_t *priv);
|
||||
|
||||
~ECIESP256Decryptor();
|
||||
|
||||
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
|
||||
|
||||
size_t GetPublicKeyLen() const override { return 64; };
|
||||
|
||||
private:
|
||||
|
@ -95,12 +99,13 @@ namespace crypto
|
|||
|
||||
// ECIES GOST R 34.10
|
||||
|
||||
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
|
||||
{
|
||||
class ECIESGOSTR3410Encryptor : public CryptoKeyEncryptor {
|
||||
public:
|
||||
|
||||
ECIESGOSTR3410Encryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESGOSTR3410Encryptor();
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
|
||||
|
||||
private:
|
||||
|
@ -109,13 +114,15 @@ namespace crypto
|
|||
};
|
||||
|
||||
|
||||
class ECIESGOSTR3410Decryptor: public CryptoKeyDecryptor
|
||||
{
|
||||
class ECIESGOSTR3410Decryptor : public CryptoKeyDecryptor {
|
||||
public:
|
||||
|
||||
ECIESGOSTR3410Decryptor(const uint8_t *priv);
|
||||
|
||||
~ECIESGOSTR3410Decryptor();
|
||||
|
||||
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
|
||||
|
||||
size_t GetPublicKeyLen() const override { return 64; };
|
||||
|
||||
private:
|
||||
|
@ -127,12 +134,13 @@ namespace crypto
|
|||
|
||||
// ECIES-X25519-AEAD-Ratchet
|
||||
|
||||
class ECIESX25519AEADRatchetEncryptor: public CryptoKeyEncryptor
|
||||
{
|
||||
class ECIESX25519AEADRatchetEncryptor : public CryptoKeyEncryptor {
|
||||
public:
|
||||
|
||||
ECIESX25519AEADRatchetEncryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESX25519AEADRatchetEncryptor() {};
|
||||
|
||||
void Encrypt(const uint8_t *, uint8_t *pub) override;
|
||||
// copies m_PublicKey to pub
|
||||
|
||||
|
@ -141,15 +149,18 @@ namespace crypto
|
|||
uint8_t m_PublicKey[32];
|
||||
};
|
||||
|
||||
class ECIESX25519AEADRatchetDecryptor: public CryptoKeyDecryptor
|
||||
{
|
||||
class ECIESX25519AEADRatchetDecryptor : public CryptoKeyDecryptor {
|
||||
public:
|
||||
|
||||
ECIESX25519AEADRatchetDecryptor(const uint8_t *priv, bool calculatePublic = false);
|
||||
|
||||
~ECIESX25519AEADRatchetDecryptor() {};
|
||||
|
||||
bool Decrypt(const uint8_t *epub, uint8_t *sharedSecret) override;
|
||||
|
||||
// agree with static and return in sharedSecret (32 bytes)
|
||||
size_t GetPublicKeyLen() const override { return 32; };
|
||||
|
||||
const uint8_t *GetPubicKey() const { return m_StaticKeys.GetPublicKey(); };
|
||||
|
||||
private:
|
||||
|
|
|
@ -14,13 +14,10 @@
|
|||
#include "Destination.h"
|
||||
#include "Datagram.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace datagram
|
||||
{
|
||||
namespace i2p {
|
||||
namespace datagram {
|
||||
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)
|
||||
m_Deflator.reset(new i2p::data::GzipDeflator);
|
||||
|
||||
|
@ -30,80 +27,76 @@ namespace datagram
|
|||
m_Signature.resize(m_Owner->GetIdentity()->GetSignatureLen());
|
||||
}
|
||||
|
||||
DatagramDestination::~DatagramDestination ()
|
||||
{
|
||||
DatagramDestination::~DatagramDestination() {
|
||||
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);
|
||||
SendDatagram(session, payload, len, fromPort, toPort);
|
||||
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);
|
||||
SendRawDatagram(session, payload, len, fromPort, toPort);
|
||||
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);
|
||||
}
|
||||
|
||||
void DatagramDestination::SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort)
|
||||
{
|
||||
if (session)
|
||||
{
|
||||
if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
void
|
||||
DatagramDestination::SendDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
|
||||
uint16_t fromPort, uint16_t toPort) {
|
||||
if (session) {
|
||||
if (m_Owner->GetIdentity()->GetSigningKeyType() == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) {
|
||||
uint8_t hash[32];
|
||||
SHA256(payload, len, hash);
|
||||
m_Owner->Sign(hash, 32, m_Signature.data());
|
||||
}
|
||||
else
|
||||
} else
|
||||
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
|
||||
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)
|
||||
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)
|
||||
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;
|
||||
size_t identityLen = identity.FromBuffer(buf, len);
|
||||
const uint8_t *signature = buf + identityLen;
|
||||
size_t headerLen = identityLen + identity.GetSignatureLen();
|
||||
|
||||
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];
|
||||
SHA256(buf + headerLen, len - headerLen, hash);
|
||||
verified = identity.Verify(hash, 32, signature);
|
||||
}
|
||||
else
|
||||
} else
|
||||
verified = identity.Verify(buf + headerLen, len - headerLen, signature);
|
||||
|
||||
if (verified)
|
||||
{
|
||||
if (verified) {
|
||||
auto h = identity.GetIdentHash();
|
||||
auto session = ObtainSession(h);
|
||||
session->Ack();
|
||||
|
@ -112,21 +105,19 @@ namespace datagram
|
|||
r(identity, fromPort, toPort, buf + headerLen, len - headerLen);
|
||||
else
|
||||
LogPrint(eLogWarning, "DatagramDestination: no receiver for port ", toPort);
|
||||
}
|
||||
else
|
||||
} else
|
||||
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)
|
||||
m_RawReceiver(fromPort, toPort, buf, len);
|
||||
else
|
||||
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);
|
||||
Receiver r = m_Receiver;
|
||||
auto itr = m_ReceiversByPorts.find(port);
|
||||
|
@ -135,26 +126,23 @@ namespace datagram
|
|||
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
|
||||
uint8_t uncompressed[MAX_DATAGRAM_SIZE];
|
||||
size_t uncompressedLen = m_Inflator.Inflate(buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
||||
if (uncompressedLen)
|
||||
{
|
||||
if (uncompressedLen) {
|
||||
if (isRaw)
|
||||
HandleRawDatagram(fromPort, toPort, uncompressed, uncompressedLen);
|
||||
else
|
||||
HandleDatagram(fromPort, toPort, uncompressed, uncompressedLen);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "Datagram: decompression failed");
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage(
|
||||
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;
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared();
|
||||
uint8_t *buf = msg->GetPayload();
|
||||
|
@ -165,43 +153,37 @@ namespace datagram
|
|||
else
|
||||
size = i2p::data::GzipNoCompression(payloads, buf, msg->maxLen - msg->len);
|
||||
|
||||
if (size)
|
||||
{
|
||||
if (size) {
|
||||
htobe32buf(msg->GetPayload(), size); // length
|
||||
htobe16buf(buf + 4, fromPort); // source 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->FillI2NPMessageHeader(eI2NPData, 0, checksum);
|
||||
}
|
||||
else
|
||||
} else
|
||||
msg = nullptr;
|
||||
return msg;
|
||||
}
|
||||
|
||||
void DatagramDestination::CleanUp ()
|
||||
{
|
||||
void DatagramDestination::CleanUp() {
|
||||
if (m_Sessions.empty()) return;
|
||||
auto now = i2p::util::GetMillisecondsSinceEpoch();
|
||||
LogPrint(eLogDebug, "DatagramDestination: clean up sessions");
|
||||
std::unique_lock<std::mutex> lock(m_SessionsMutex);
|
||||
// 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
|
||||
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());
|
||||
it->second->Stop();
|
||||
it = m_Sessions.erase(it); // we are expired
|
||||
}
|
||||
else
|
||||
} else
|
||||
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::lock_guard<std::mutex> lock(m_SessionsMutex);
|
||||
auto itr = m_Sessions.find(identity);
|
||||
|
@ -216,11 +198,10 @@ namespace datagram
|
|||
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);
|
||||
for ( auto & item : m_Sessions)
|
||||
{
|
||||
for (auto &item: m_Sessions) {
|
||||
if (item.first == remote) return std::make_shared<DatagramSession::Info>(item.second->GetSessionInfo());
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -230,21 +211,17 @@ namespace datagram
|
|||
const i2p::data::IdentHash &remoteIdent) :
|
||||
m_LocalDestination(localDestination),
|
||||
m_RemoteIdent(remoteIdent),
|
||||
m_RequestingLS(false)
|
||||
{
|
||||
m_RequestingLS(false) {
|
||||
}
|
||||
|
||||
void DatagramSession::Start ()
|
||||
{
|
||||
void DatagramSession::Start() {
|
||||
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
|
||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
|
||||
if (msg || m_SendQueue.empty())
|
||||
|
@ -254,8 +231,7 @@ namespace datagram
|
|||
FlushSendQueue();
|
||||
}
|
||||
|
||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||
{
|
||||
DatagramSession::Info DatagramSession::GetSessionInfo() const {
|
||||
if (!m_RoutingSession)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
|
||||
|
@ -264,21 +240,18 @@ namespace datagram
|
|||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
auto lease = routingPath->remoteLease;
|
||||
auto tunnel = routingPath->outboundTunnel;
|
||||
if(lease)
|
||||
{
|
||||
if (lease) {
|
||||
if (tunnel)
|
||||
return DatagramSession::Info(lease->tunnelGateway, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||
else
|
||||
return DatagramSession::Info(lease->tunnelGateway, nullptr, m_LastUse);
|
||||
}
|
||||
else if(tunnel)
|
||||
} else if (tunnel)
|
||||
return DatagramSession::Info(nullptr, tunnel->GetEndpointIdentHash(), m_LastUse);
|
||||
else
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
}
|
||||
|
||||
void DatagramSession::Ack()
|
||||
{
|
||||
void DatagramSession::Ack() {
|
||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch();
|
||||
auto path = GetSharedRoutingPath();
|
||||
if (path)
|
||||
|
@ -287,24 +260,21 @@ namespace datagram
|
|||
SendMsg(nullptr); // send empty message in case if we have some data to send
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
|
||||
{
|
||||
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired ())
|
||||
{
|
||||
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath() {
|
||||
if (!m_RemoteLeaseSet || m_RemoteLeaseSet->IsExpired()) {
|
||||
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
|
||||
if (!m_RemoteLeaseSet)
|
||||
{
|
||||
if(!m_RequestingLS)
|
||||
{
|
||||
if (!m_RemoteLeaseSet) {
|
||||
if (!m_RequestingLS) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ())
|
||||
{
|
||||
if (!m_RoutingSession || m_RoutingSession->IsTerminated() || !m_RoutingSession->IsReadyToSend()) {
|
||||
bool found = false;
|
||||
for (auto &it: m_PendingRoutingSessions)
|
||||
if (it->GetOwner() && m_RoutingSession->IsReadyToSend()) // found established session
|
||||
|
@ -314,8 +284,7 @@ namespace datagram
|
|||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (!found) {
|
||||
m_RoutingSession = m_LocalDestination->GetRoutingSession(m_RemoteLeaseSet, true);
|
||||
if (!m_RoutingSession->GetOwner() || !m_RoutingSession->IsReadyToSend())
|
||||
m_PendingRoutingSessions.push_back(m_RoutingSession);
|
||||
|
@ -324,74 +293,62 @@ namespace datagram
|
|||
|
||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||
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);
|
||||
path = nullptr;
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
if (path->outboundTunnel && !path->outboundTunnel->IsEstablished ())
|
||||
{
|
||||
if (path) {
|
||||
if (path->outboundTunnel && !path->outboundTunnel->IsEstablished()) {
|
||||
// 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)
|
||||
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
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
if (m_RemoteLeaseSet) {
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeasesExcluding(
|
||||
[&](const i2p::data::Lease& l) -> bool
|
||||
{
|
||||
[&](const i2p::data::Lease &l) -> bool {
|
||||
return l.tunnelID == path->remoteLease->tunnelID;
|
||||
});
|
||||
auto sz = ls.size();
|
||||
if (sz)
|
||||
{
|
||||
if (sz) {
|
||||
auto idx = rand() % sz;
|
||||
path->remoteLease = ls[idx];
|
||||
}
|
||||
else
|
||||
} else
|
||||
m_RoutingSession->SetSharedRoutingPath(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// no current path, make one
|
||||
path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
|
||||
|
||||
if (m_RemoteLeaseSet)
|
||||
{
|
||||
if (m_RemoteLeaseSet) {
|
||||
// pick random next good lease
|
||||
auto ls = m_RemoteLeaseSet->GetNonExpiredLeases();
|
||||
auto sz = ls.size();
|
||||
if (sz)
|
||||
{
|
||||
if (sz) {
|
||||
auto idx = rand() % sz;
|
||||
path->remoteLease = ls[idx];
|
||||
}
|
||||
else
|
||||
} else
|
||||
return nullptr;
|
||||
|
||||
auto leaseRouter = i2p::data::netdb.FindRouter(path->remoteLease->tunnelGateway);
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// no remote lease set currently, bail
|
||||
LogPrint(eLogWarning, "DatagramSession: no remote lease set found for ", m_RemoteIdent.ToBase32());
|
||||
return nullptr;
|
||||
|
@ -401,8 +358,7 @@ namespace datagram
|
|||
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;
|
||||
if (!ls) return;
|
||||
// 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;
|
||||
}
|
||||
|
||||
void DatagramSession::FlushSendQueue ()
|
||||
{
|
||||
void DatagramSession::FlushSendQueue() {
|
||||
if (m_SendQueue.empty()) return;
|
||||
std::vector<i2p::tunnel::TunnelMessageBlock> send;
|
||||
auto routingPath = GetSharedRoutingPath();
|
||||
// if we don't have a routing path we will drop all queued messages
|
||||
if(routingPath && routingPath->outboundTunnel && routingPath->remoteLease)
|
||||
{
|
||||
for (const auto & msg : m_SendQueue)
|
||||
{
|
||||
if (routingPath && routingPath->outboundTunnel && routingPath->remoteLease) {
|
||||
for (const auto &msg: m_SendQueue) {
|
||||
auto m = m_RoutingSession->WrapSingleMessage(msg);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -20,14 +20,11 @@
|
|||
#include "I2NPProtocol.h"
|
||||
#include "Garlic.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
namespace i2p {
|
||||
namespace client {
|
||||
class ClientDestination;
|
||||
}
|
||||
namespace datagram
|
||||
{
|
||||
namespace datagram {
|
||||
// milliseconds for max session idle time
|
||||
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
|
||||
|
@ -43,14 +40,15 @@ namespace datagram
|
|||
// max 64 messages buffered in send queue for each datagram session
|
||||
const size_t DATAGRAM_SEND_QUEUE_MAX_SIZE = 64;
|
||||
|
||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession>
|
||||
{
|
||||
class DatagramSession : public std::enable_shared_from_this<DatagramSession> {
|
||||
|
||||
public:
|
||||
|
||||
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent);
|
||||
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||
const i2p::data::IdentHash &remoteIdent);
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
|
||||
|
@ -59,19 +57,21 @@ namespace datagram
|
|||
|
||||
/** send an i2np message to remote endpoint for this session */
|
||||
void SendMsg(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void FlushSendQueue();
|
||||
|
||||
/** get the last time in milliseconds for when we used this datagram session */
|
||||
uint64_t LastActivity() const { return m_LastUse; }
|
||||
|
||||
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> OBEP;
|
||||
const uint64_t activity;
|
||||
|
||||
Info() : IBGW(nullptr), OBEP(nullptr), activity(0) {}
|
||||
|
||||
Info(const uint8_t *ibgw, const uint8_t *obep, const uint64_t a) :
|
||||
activity(a) {
|
||||
if (ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
|
||||
|
@ -104,34 +104,61 @@ namespace datagram
|
|||
typedef std::shared_ptr<DatagramSession> DatagramSession_ptr;
|
||||
|
||||
const size_t MAX_DATAGRAM_SIZE = 32768;
|
||||
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 (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver;
|
||||
|
||||
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 (uint16_t
|
||||
fromPort,
|
||||
uint16_t toPort,
|
||||
const uint8_t *buf, size_t
|
||||
len)>
|
||||
RawReceiver;
|
||||
|
||||
public:
|
||||
|
||||
DatagramDestination(std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip);
|
||||
|
||||
~DatagramDestination();
|
||||
|
||||
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
|
||||
void
|
||||
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
|
||||
|
||||
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 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 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 ResetReceiver (uint16_t port) { std::lock_guard<std::mutex> lock(m_ReceiversMutex); m_ReceiversByPorts.erase (port); };
|
||||
void SetReceiver(const Receiver &receiver, uint16_t 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 ResetRawReceiver() { m_RawReceiver = nullptr; };
|
||||
|
||||
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<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);
|
||||
|
||||
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);
|
||||
|
||||
/** 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
|
@ -28,10 +28,8 @@
|
|||
#include "Datagram.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
namespace i2p {
|
||||
namespace client {
|
||||
const uint8_t PROTOCOL_TYPE_STREAMING = 6;
|
||||
const uint8_t PROTOCOL_TYPE_DATAGRAM = 17;
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
// leaseSet = nullptr means not found
|
||||
struct LeaseSetRequest
|
||||
{
|
||||
struct LeaseSetRequest {
|
||||
LeaseSetRequest(boost::asio::io_service &service) : requestTime(0), requestTimeoutTimer(service) {};
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
uint64_t requestTime;
|
||||
|
@ -104,8 +101,7 @@ namespace client
|
|||
std::shared_ptr<i2p::tunnel::InboundTunnel> replyTunnel;
|
||||
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);
|
||||
requestComplete.clear();
|
||||
}
|
||||
|
@ -113,71 +109,115 @@ namespace client
|
|||
|
||||
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();
|
||||
|
||||
const std::string &GetNickname() const { return m_Nickname; };
|
||||
|
||||
boost::asio::io_service &GetService() { return m_Service; };
|
||||
|
||||
virtual void Start();
|
||||
|
||||
virtual void Stop();
|
||||
|
||||
/** i2cp reconfigure */
|
||||
virtual bool Reconfigure(std::map<std::string, std::string> i2cpOpts);
|
||||
|
||||
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);
|
||||
|
||||
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 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
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet();
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const { return m_Pool; }
|
||||
|
||||
// override GarlicDestination
|
||||
bool SubmitSessionKey(const uint8_t *key, const uint8_t *tag);
|
||||
|
||||
void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag);
|
||||
|
||||
void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void SetLeaseSetUpdated();
|
||||
|
||||
bool IsPublic() const { return m_IsPublic; };
|
||||
|
||||
void SetPublic(bool pub) { m_IsPublic = pub; };
|
||||
|
||||
protected:
|
||||
|
||||
// implements GarlicDestination
|
||||
void HandleI2NPMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
bool HandleCloveI2NPMessage(I2NPMessageType typeID, const uint8_t *payload, size_t len, uint32_t msgID);
|
||||
|
||||
void SetLeaseSet(std::shared_ptr<const i2p::data::LocalLeaseSet> newLeaseSet);
|
||||
|
||||
int GetLeaseSetType() const { return m_LeaseSetType; };
|
||||
|
||||
void SetLeaseSetType(int leaseSetType) { m_LeaseSetType = leaseSetType; };
|
||||
|
||||
int GetAuthType() const { return m_AuthType; };
|
||||
|
||||
virtual void CleanupDestination() {}; // additional clean up in derived classes
|
||||
// I2CP
|
||||
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:
|
||||
|
||||
void UpdateLeaseSet();
|
||||
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSetMt();
|
||||
|
||||
void Publish();
|
||||
|
||||
void HandlePublishConfirmationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void HandlePublishVerificationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void HandlePublishDelayTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void HandleDatabaseStoreMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
void HandleDatabaseSearchReplyMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
void HandleDeliveryStatusMessage(uint32_t msgID);
|
||||
|
||||
void RequestLeaseSet (const i2p::data::IdentHash& dest, RequestComplete requestComplete, std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||
bool SendLeaseSetRequest (const i2p::data::IdentHash& dest, std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill, std::shared_ptr<LeaseSetRequest> request);
|
||||
void RequestLeaseSet(const i2p::data::IdentHash &dest, RequestComplete requestComplete,
|
||||
std::shared_ptr<const i2p::data::BlindedPublicKey> requestedBlindedKey = nullptr);
|
||||
|
||||
bool SendLeaseSetRequest(const i2p::data::IdentHash &dest,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> nextFloodfill,
|
||||
std::shared_ptr<LeaseSetRequest> request);
|
||||
|
||||
void HandleRequestTimoutTimer(const boost::system::error_code &ecode, const i2p::data::IdentHash &dest);
|
||||
|
||||
void HandleCleanupTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void CleanupRemoteLeaseSets();
|
||||
|
||||
i2p::data::CryptoKeyType GetPreferredCryptoType() const;
|
||||
|
||||
private:
|
||||
|
@ -205,21 +245,31 @@ namespace client
|
|||
|
||||
// for HTTP only
|
||||
int GetNumRemoteLeaseSets() const { return m_RemoteLeaseSets.size(); };
|
||||
const decltype(m_RemoteLeaseSets)& GetLeaseSets () const { return m_RemoteLeaseSets; };
|
||||
bool IsEncryptedLeaseSet () const { return m_LeaseSetType == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; };
|
||||
const decltype(m_RemoteLeaseSets)
|
||||
&
|
||||
|
||||
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; };
|
||||
};
|
||||
|
||||
class ClientDestination: public LeaseSetDestination
|
||||
{
|
||||
struct EncryptionKey
|
||||
{
|
||||
class ClientDestination : public LeaseSetDestination {
|
||||
struct EncryptionKey {
|
||||
uint8_t pub[256], priv[256];
|
||||
i2p::data::CryptoKeyType keyType;
|
||||
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 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,
|
||||
bool isPublic, const std::map<std::string, std::string> *params = nullptr);
|
||||
|
||||
~ClientDestination();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
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); };
|
||||
|
||||
// ref counter
|
||||
int Acquire() { return ++m_RefCounter; };
|
||||
|
||||
int Release() { return --m_RefCounter; };
|
||||
|
||||
int GetRefCounter() const { return m_RefCounter; };
|
||||
|
||||
// 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> RemoveStreamingDestination(int port);
|
||||
|
||||
// following methods operate with default streaming destination
|
||||
void CreateStream (StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash& dest, 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
|
||||
CreateStream(StreamRequestComplete streamRequestComplete, const i2p::data::IdentHash &dest, 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(std::shared_ptr<const i2p::data::BlindedPublicKey> to);
|
||||
|
||||
void AcceptStreams(const i2p::stream::StreamingDestination::Acceptor &acceptor);
|
||||
|
||||
void StopAcceptingStreams();
|
||||
|
||||
bool IsAcceptingStreams() const;
|
||||
|
||||
void AcceptOnce(const i2p::stream::StreamingDestination::Acceptor &acceptor);
|
||||
|
||||
int GetStreamingAckDelay() const { return m_StreamingAckDelay; }
|
||||
|
||||
bool IsStreamingAnswerPings() const { return m_IsStreamingAnswerPings; }
|
||||
|
||||
// datagram
|
||||
i2p::datagram::DatagramDestination *GetDatagramDestination() const { return m_DatagramDestination; };
|
||||
|
||||
i2p::datagram::DatagramDestination *CreateDatagramDestination(bool gzip = true);
|
||||
|
||||
// implements LocalDestination
|
||||
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(); };
|
||||
|
||||
bool SupportsEncryptionType(i2p::data::CryptoKeyType keyType) const;
|
||||
|
||||
const uint8_t *GetEncryptionPublicKey(i2p::data::CryptoKeyType keyType) const;
|
||||
|
||||
protected:
|
||||
|
||||
void CleanupDestination();
|
||||
|
||||
// I2CP
|
||||
void HandleDataMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
void CreateNewLeaseSet(const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels);
|
||||
|
||||
private:
|
||||
|
@ -279,7 +356,9 @@ namespace client
|
|||
std::shared_ptr<ClientDestination> GetSharedFromThis() {
|
||||
return std::static_pointer_cast<ClientDestination>(shared_from_this());
|
||||
}
|
||||
|
||||
void PersistTemporaryKeys(EncryptionKey *keys, bool isSingleKey);
|
||||
|
||||
void ReadAuthKey(const std::string &group, const std::map<std::string, std::string> *params);
|
||||
|
||||
private:
|
||||
|
@ -303,17 +382,20 @@ namespace client
|
|||
|
||||
// for HTTP only
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams() const;
|
||||
|
||||
bool DeleteStream(uint32_t recvStreamID);
|
||||
};
|
||||
|
||||
class RunnableClientDestination: private i2p::util::RunnableService, public ClientDestination
|
||||
{
|
||||
class RunnableClientDestination : private i2p::util::RunnableService, public ClientDestination {
|
||||
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();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,10 +21,8 @@
|
|||
#include "Garlic.h"
|
||||
#include "Tag.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace garlic
|
||||
{
|
||||
namespace i2p {
|
||||
namespace garlic {
|
||||
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_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 */
|
||||
// - 16 /* I2NP header */ - 16 /* poly hash */ - 8 /* tag */ - 4 /* garlic length */
|
||||
|
||||
class RatchetTagSet
|
||||
{
|
||||
class RatchetTagSet {
|
||||
public:
|
||||
|
||||
RatchetTagSet() {};
|
||||
|
||||
virtual ~RatchetTagSet() {};
|
||||
|
||||
void DHInitialize(const uint8_t *rootKey, const uint8_t *k);
|
||||
|
||||
void NextSessionTagRatchet();
|
||||
|
||||
uint64_t GetNextSessionTag();
|
||||
|
||||
const uint8_t *GetNextRootKey() const { return m_NextRootKey; };
|
||||
|
||||
int GetNextIndex() const { return m_NextIndex; };
|
||||
|
||||
void GetSymmKey(int index, uint8_t *key);
|
||||
|
||||
void DeleteSymmKey(int index);
|
||||
|
||||
int GetTagSetID() const { return m_TagSetID; };
|
||||
|
||||
void SetTagSetID(int tagsetID) { m_TagSetID = tagsetID; };
|
||||
|
||||
private:
|
||||
|
@ -68,23 +73,28 @@ namespace garlic
|
|||
};
|
||||
|
||||
class ECIESX25519AEADRatchetSession;
|
||||
|
||||
class ReceiveRatchetTagSet : public RatchetTagSet,
|
||||
public std::enable_shared_from_this<ReceiveRatchetTagSet>
|
||||
{
|
||||
public std::enable_shared_from_this<ReceiveRatchetTagSet> {
|
||||
public:
|
||||
|
||||
ReceiveRatchetTagSet(std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false) :
|
||||
m_Session(session), m_IsNS(isNS) {};
|
||||
|
||||
bool IsNS() const { return m_IsNS; };
|
||||
|
||||
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession() { return m_Session; };
|
||||
|
||||
void SetTrimBehind(int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
|
||||
|
||||
int GetTrimBehind() const { return m_TrimBehindIndex; };
|
||||
|
||||
void Expire();
|
||||
|
||||
bool IsExpired(uint64_t ts) const;
|
||||
|
||||
virtual bool IsIndexExpired(int index) const;
|
||||
|
||||
virtual bool HandleNextMessage(uint8_t *buf, size_t len, int index);
|
||||
|
||||
private:
|
||||
|
@ -95,13 +105,13 @@ namespace garlic
|
|||
uint64_t m_ExpirationTimestamp = 0;
|
||||
};
|
||||
|
||||
class SymmetricKeyTagSet: public ReceiveRatchetTagSet
|
||||
{
|
||||
class SymmetricKeyTagSet : public ReceiveRatchetTagSet {
|
||||
public:
|
||||
|
||||
SymmetricKeyTagSet(GarlicDestination *destination, const uint8_t *key);
|
||||
|
||||
bool IsIndexExpired(int index) const { return false; };
|
||||
|
||||
bool HandleNextMessage(uint8_t *buf, size_t len, int index);
|
||||
|
||||
private:
|
||||
|
@ -110,8 +120,7 @@ namespace garlic
|
|||
uint8_t m_Key[32];
|
||||
};
|
||||
|
||||
enum ECIESx25519BlockType
|
||||
{
|
||||
enum ECIESx25519BlockType {
|
||||
eECIESx25519BlkDateTime = 0,
|
||||
eECIESx25519BlkSessionID = 1,
|
||||
eECIESx25519BlkTermination = 4,
|
||||
|
@ -129,10 +138,8 @@ namespace garlic
|
|||
|
||||
class ECIESX25519AEADRatchetSession : public GarlicRoutingSession,
|
||||
private i2p::crypto::NoiseSymmetricState,
|
||||
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
|
||||
{
|
||||
enum SessionState
|
||||
{
|
||||
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> {
|
||||
enum SessionState {
|
||||
eSessionStateNew = 0,
|
||||
eSessionStateNewSessionReceived,
|
||||
eSessionStateNewSessionSent,
|
||||
|
@ -141,8 +148,7 @@ namespace garlic
|
|||
eSessionStateOneTime
|
||||
};
|
||||
|
||||
struct DHRatchet
|
||||
{
|
||||
struct DHRatchet {
|
||||
int keyID = 0;
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> key;
|
||||
uint8_t remote[32]; // last remote public key
|
||||
|
@ -152,36 +158,55 @@ namespace garlic
|
|||
public:
|
||||
|
||||
ECIESX25519AEADRatchetSession(GarlicDestination *owner, bool attachLeaseSetNS);
|
||||
|
||||
~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> WrapOneTimeMessage(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
const uint8_t *GetRemoteStaticKey() const { return m_RemoteStaticKey; }
|
||||
|
||||
void SetRemoteStaticKey(const uint8_t *key) { memcpy(m_RemoteStaticKey, key, 32); }
|
||||
|
||||
void Terminate() { m_IsTerminated = true; }
|
||||
|
||||
void SetDestination(const i2p::data::IdentHash &dest) // TODO:
|
||||
{
|
||||
if (!m_Destination) m_Destination.reset(new i2p::data::IdentHash(dest));
|
||||
}
|
||||
|
||||
bool CheckExpired(uint64_t ts); // true is expired
|
||||
bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; }
|
||||
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
||||
bool CanBeRestarted(uint64_t ts) const {
|
||||
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 IsReadyToSend() const { return m_State != eSessionStateNewSessionSent; };
|
||||
|
||||
bool IsTerminated() const { return m_IsTerminated; }
|
||||
|
||||
uint64_t GetLastActivityTimestamp() const { return m_LastActivityTimestamp; };
|
||||
|
||||
protected:
|
||||
|
||||
i2p::crypto::NoiseSymmetricState &GetNoiseState() { return *this; };
|
||||
|
||||
void SetNoiseState(const i2p::crypto::NoiseSymmetricState &state) { GetNoiseState() = state; };
|
||||
|
||||
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:
|
||||
|
||||
|
@ -189,20 +214,34 @@ namespace garlic
|
|||
void InitNewSessionTagset(std::shared_ptr<RatchetTagSet> tagsetNsr) const;
|
||||
|
||||
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 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);
|
||||
|
||||
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 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 NewNextSendRatchet();
|
||||
|
||||
private:
|
||||
|
@ -225,19 +264,20 @@ namespace garlic
|
|||
|
||||
// for HTTP only
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
// single session for all incoming messages
|
||||
class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession
|
||||
{
|
||||
class RouterIncomingRatchetSession : public ECIESX25519AEADRatchetSession {
|
||||
public:
|
||||
|
||||
RouterIncomingRatchetSession(const i2p::crypto::NoiseSymmetricState &initState);
|
||||
|
||||
bool HandleNextMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; };
|
||||
|
||||
private:
|
||||
|
@ -245,8 +285,11 @@ namespace garlic
|
|||
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> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
|
||||
std::shared_ptr<I2NPMessage>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,12 +11,9 @@
|
|||
#include "Crypto.h"
|
||||
#include "Ed25519.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
Ed25519::Ed25519 ()
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
Ed25519::Ed25519() {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *tmp = BN_new();
|
||||
|
||||
|
@ -62,8 +59,7 @@ namespace crypto
|
|||
|
||||
// precalculate Bi256 table
|
||||
Bi256Carry = {Bx, By}; // B
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
for (int i = 0; i < 32; i++) {
|
||||
Bi256[i][0] = Bi256Carry; // first point
|
||||
for (int j = 1; j < 128; j++)
|
||||
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)),
|
||||
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
|
||||
Bi256Carry (other.Bi256Carry)
|
||||
{
|
||||
d(BN_dup(other.d)), I(BN_dup(other.I)),
|
||||
two_252_2(BN_dup(other.two_252_2)),
|
||||
Bi256Carry(other.Bi256Carry) {
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int j = 0; j < 128; j++)
|
||||
Bi256[i][j] = other.Bi256[i][j];
|
||||
}
|
||||
|
||||
Ed25519::~Ed25519 ()
|
||||
{
|
||||
Ed25519::~Ed25519() {
|
||||
BN_free(q);
|
||||
BN_free(l);
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
BIGNUM *h = DecodeBN<64>(digest);
|
||||
// signature 0..31 - R, 32..63 - S
|
||||
|
@ -130,20 +121,22 @@ namespace crypto
|
|||
}
|
||||
|
||||
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();
|
||||
// calculate r
|
||||
SHA512_CTX 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
|
||||
uint8_t digest[64];
|
||||
SHA512_Final(digest, &ctx);
|
||||
BIGNUM *r = DecodeBN<32>(digest); // DecodeBN<64> (digest); // for test vectors
|
||||
// calculate R
|
||||
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 (Mul (B, r, bnCtx), R); // for test vectors
|
||||
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 (Mul (B, r, bnCtx), R); // for test vectors
|
||||
// calculate S
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, R, EDDSA25519_SIGNATURE_LENGTH / 2); // R
|
||||
|
@ -157,13 +150,14 @@ namespace crypto
|
|||
BN_mod_add(h, h, r, l, bnCtx); // %l
|
||||
memcpy(signature, R, EDDSA25519_SIGNATURE_LENGTH / 2);
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
// T = 80 random bytes
|
||||
uint8_t T[80];
|
||||
|
@ -180,7 +174,8 @@ namespace crypto
|
|||
BN_mod(r, r, l, bnCtx); // % l
|
||||
EncodeBN(r, digest, 32);
|
||||
// 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);
|
||||
// calculate S
|
||||
SHA512_Init(&ctx);
|
||||
|
@ -195,12 +190,13 @@ namespace crypto
|
|||
BN_mod_add(h, h, r, l, bnCtx); // %l
|
||||
memcpy(signature, R, EDDSA25519_SIGNATURE_LENGTH / 2);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
// y3 = (y1*y2+x1*x2)*(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);
|
||||
BIGNUM *t1 = p1.t, *t2 = p2.t;
|
||||
if (!t1) { 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); }
|
||||
if (!t1) {
|
||||
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, t3, d, ctx); // C = d*t1*t2
|
||||
|
||||
if (p1.z)
|
||||
{
|
||||
if (p1.z) {
|
||||
if (p2.z)
|
||||
BN_mul(z3, p1.z, p2.z, ctx); // D = z1*z2
|
||||
else
|
||||
BN_copy(z3, p1.z); // D = z1
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (p2.z)
|
||||
BN_copy(z3, p2.z); // D = z2
|
||||
else
|
||||
|
@ -252,8 +251,7 @@ namespace crypto
|
|||
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);
|
||||
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
|
||||
if (p.t)
|
||||
BN_sqr(t2, p.t, ctx); // t2 = t^2
|
||||
else
|
||||
{
|
||||
else {
|
||||
BN_mul(t2, p.x, p.y, ctx); // t = x*y
|
||||
BN_sqr(t2, t2, ctx); // t2 = t^2
|
||||
}
|
||||
|
@ -290,16 +287,14 @@ namespace crypto
|
|||
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();
|
||||
BN_zero (zero); BN_one (one);
|
||||
BN_zero(zero);
|
||||
BN_one(one);
|
||||
EDDSAPoint res{zero, one};
|
||||
if (!BN_is_zero (e))
|
||||
{
|
||||
if (!BN_is_zero(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);
|
||||
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
|
||||
{
|
||||
BIGNUM *zero = BN_new(), *one = BN_new();
|
||||
BN_zero (zero); BN_one (one);
|
||||
BN_zero(zero);
|
||||
BN_one(one);
|
||||
EDDSAPoint res{zero, one};
|
||||
bool carry = false;
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t x = e[i];
|
||||
if (carry)
|
||||
{
|
||||
if (x < 255)
|
||||
{
|
||||
if (carry) {
|
||||
if (x < 255) {
|
||||
x++;
|
||||
carry = false;
|
||||
}
|
||||
else
|
||||
} else
|
||||
x = 0;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
if (x > 0) {
|
||||
if (x <= 128)
|
||||
res = Sum(res, Bi256[i][x - 1], ctx);
|
||||
else
|
||||
{
|
||||
else {
|
||||
res = Sum(res, -Bi256[i][255 - x], ctx); // -Bi[256-x]
|
||||
carry = true;
|
||||
}
|
||||
|
@ -341,22 +331,18 @@ namespace crypto
|
|||
return res;
|
||||
}
|
||||
|
||||
EDDSAPoint Ed25519::Normalize (const EDDSAPoint& p, BN_CTX * ctx) const
|
||||
{
|
||||
if (p.z)
|
||||
{
|
||||
EDDSAPoint Ed25519::Normalize(const EDDSAPoint &p, BN_CTX *ctx) const {
|
||||
if (p.z) {
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
BN_mod_inverse(y, p.z, q, ctx);
|
||||
BN_mod_mul(x, p.x, y, q, ctx); // x = x/z
|
||||
BN_mod_mul(y, p.y, y, q, ctx); // y = y/z
|
||||
return EDDSAPoint{x, y};
|
||||
}
|
||||
else
|
||||
} else
|
||||
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);
|
||||
BIGNUM *x2 = BN_CTX_get(ctx), *y2 = BN_CTX_get(ctx), *tmp = BN_CTX_get(ctx);
|
||||
BN_sqr(x2, p.x, ctx); // x^2
|
||||
|
@ -373,8 +359,7 @@ namespace crypto
|
|||
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);
|
||||
BIGNUM *y2 = BN_CTX_get(ctx), *xx = BN_CTX_get(ctx);
|
||||
BN_sqr(y2, y, ctx); // y^2
|
||||
|
@ -398,8 +383,7 @@ namespace crypto
|
|||
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
|
||||
uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
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)
|
||||
BN_sub(x, q, x); // x = q - x
|
||||
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};
|
||||
if (!IsOnCurve(p, ctx))
|
||||
LogPrint(eLogError, "Decoded point is not on 25519");
|
||||
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);
|
||||
if (BN_is_bit_set(p.x, 0)) // highest bit
|
||||
buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
|
||||
}
|
||||
|
||||
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
|
||||
uint8_t buf1[len];
|
||||
for (size_t i = 0; i < len / 2; i++) // invert bytes
|
||||
|
@ -445,8 +428,7 @@ namespace crypto
|
|||
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);
|
||||
// To Little Endian
|
||||
for (size_t i = 0; i < len / 2; i++) // invert bytes
|
||||
|
@ -458,25 +440,30 @@ namespace crypto
|
|||
}
|
||||
|
||||
#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);
|
||||
auto x1 = BN_CTX_get (ctx); BN_copy (x1, u);
|
||||
auto x2 = BN_CTX_get (ctx); BN_one (x2);
|
||||
auto z2 = BN_CTX_get (ctx); BN_zero (z2);
|
||||
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);
|
||||
auto x1 = BN_CTX_get(ctx);
|
||||
BN_copy(x1, u);
|
||||
auto x2 = BN_CTX_get(ctx);
|
||||
BN_one(x2);
|
||||
auto z2 = BN_CTX_get(ctx);
|
||||
BN_zero(z2);
|
||||
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;
|
||||
auto bits = BN_num_bits(k);
|
||||
while(bits)
|
||||
{
|
||||
while (bits) {
|
||||
--bits;
|
||||
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
|
||||
swap ^= k_t;
|
||||
if (swap)
|
||||
{
|
||||
if (swap) {
|
||||
std::swap(x2, x3);
|
||||
std::swap(z2, z3);
|
||||
}
|
||||
|
@ -500,8 +487,7 @@ namespace crypto
|
|||
BN_mod_mul(z3, x1, z2, q, ctx);
|
||||
BN_mod_mul(z2, tmp1, tmp0, q, ctx);
|
||||
}
|
||||
if (swap)
|
||||
{
|
||||
if (swap) {
|
||||
std::swap(x2, x3);
|
||||
std::swap(z2, z3);
|
||||
}
|
||||
|
@ -512,33 +498,40 @@ namespace crypto
|
|||
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);
|
||||
uint8_t k[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 *q1 = ScalarMul(p1, n, ctx);
|
||||
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
|
||||
{
|
||||
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9);
|
||||
void Ed25519::ScalarMulB(const uint8_t *e, uint8_t *buf, BN_CTX *ctx) const {
|
||||
BIGNUM *p1 = BN_new();
|
||||
BN_set_word(p1, 9);
|
||||
uint8_t k[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 *q1 = ScalarMul(p1, n, ctx);
|
||||
EncodeBN(q1, buf, 32);
|
||||
BN_free (p1); BN_free (n); BN_free (q1);
|
||||
BN_free(p1);
|
||||
BN_free(n);
|
||||
BN_free(q1);
|
||||
}
|
||||
|
||||
#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();
|
||||
// calculate alpha = seed mod l
|
||||
BIGNUM *alpha = DecodeBN<64>(seed); // seed is in Little Endian
|
||||
|
@ -552,8 +545,8 @@ namespace crypto
|
|||
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();
|
||||
// calculate alpha = seed mod l
|
||||
BIGNUM *alpha = DecodeBN<64>(seed); // seed is in Little Endian
|
||||
|
@ -566,20 +559,19 @@ namespace crypto
|
|||
// A' = DERIVE_PUBLIC(a')
|
||||
auto A1 = MulB(blindedPriv, ctx);
|
||||
EncodePublicKey(A1, blindedPub, ctx);
|
||||
BN_free (alpha); BN_free (p);
|
||||
BN_free(alpha);
|
||||
BN_free(p);
|
||||
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);
|
||||
expandedKey[0] &= 0xF8; // drop last 3 bits
|
||||
expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits
|
||||
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];
|
||||
RAND_bytes(seed, 32);
|
||||
BIGNUM *p = DecodeBN<32>(seed);
|
||||
|
@ -591,10 +583,9 @@ namespace crypto
|
|||
}
|
||||
|
||||
static std::unique_ptr<Ed25519> g_Ed25519;
|
||||
std::unique_ptr<Ed25519>& GetEd25519 ()
|
||||
{
|
||||
if (!g_Ed25519)
|
||||
{
|
||||
|
||||
std::unique_ptr<Ed25519> &GetEd25519() {
|
||||
if (!g_Ed25519) {
|
||||
auto c = new Ed25519();
|
||||
if (!g_Ed25519) // make sure it was not created already
|
||||
g_Ed25519.reset(c);
|
||||
|
|
|
@ -13,59 +13,74 @@
|
|||
#include <openssl/bn.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
struct EDDSAPoint
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
struct EDDSAPoint {
|
||||
BIGNUM *x{nullptr};
|
||||
BIGNUM *y{nullptr};
|
||||
BIGNUM *z{nullptr};
|
||||
BIGNUM *t{nullptr}; // projective coordinates
|
||||
|
||||
EDDSAPoint() {}
|
||||
|
||||
EDDSAPoint(const EDDSAPoint &other) { *this = other; }
|
||||
|
||||
EDDSAPoint(EDDSAPoint &&other) { *this = std::move(other); }
|
||||
|
||||
EDDSAPoint(BIGNUM *x1, BIGNUM *y1, BIGNUM *z1 = nullptr, BIGNUM *t1 = nullptr)
|
||||
: x(x1)
|
||||
, y(y1)
|
||||
, z(z1)
|
||||
, t(t1)
|
||||
{}
|
||||
~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); }
|
||||
: x(x1), y(y1), z(z1), t(t1) {}
|
||||
|
||||
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;
|
||||
~EDDSAPoint() {
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
BN_free(z);
|
||||
BN_free(t);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
EDDSAPoint& operator=(const EDDSAPoint& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
BN_free (x); x = other.x ? BN_dup (other.x) : nullptr;
|
||||
BN_free (y); y = other.y ? BN_dup (other.y) : nullptr;
|
||||
BN_free (z); z = other.z ? BN_dup (other.z) : nullptr;
|
||||
BN_free (t); t = other.t ? BN_dup (other.t) : nullptr;
|
||||
EDDSAPoint &operator=(const EDDSAPoint &other) {
|
||||
if (this != &other) {
|
||||
BN_free(x);
|
||||
x = other.x ? BN_dup(other.x) : nullptr;
|
||||
BN_free(y);
|
||||
y = other.y ? BN_dup(other.y) : nullptr;
|
||||
BN_free(z);
|
||||
z = other.z ? BN_dup(other.z) : nullptr;
|
||||
BN_free(t);
|
||||
t = other.t ? BN_dup(other.t) : nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
EDDSAPoint operator-() const
|
||||
{
|
||||
EDDSAPoint operator-() const {
|
||||
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 (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};
|
||||
}
|
||||
};
|
||||
|
@ -73,51 +88,77 @@ namespace crypto
|
|||
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
|
||||
const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
|
||||
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
|
||||
class Ed25519
|
||||
{
|
||||
|
||||
class Ed25519 {
|
||||
public:
|
||||
|
||||
Ed25519();
|
||||
|
||||
Ed25519(const Ed25519 &other);
|
||||
|
||||
~Ed25519();
|
||||
|
||||
EDDSAPoint GeneratePublicKey(const uint8_t *expandedPrivateKey, 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;
|
||||
|
||||
#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;
|
||||
|
||||
#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;
|
||||
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
|
||||
|
||||
private:
|
||||
|
||||
EDDSAPoint Sum(const EDDSAPoint &p1, const EDDSAPoint &p2, 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 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;
|
||||
|
||||
bool IsOnCurve(const EDDSAPoint &p, BN_CTX *ctx) const;
|
||||
|
||||
BIGNUM *RecoverX(const BIGNUM *y, BN_CTX *ctx) const;
|
||||
|
||||
EDDSAPoint DecodePoint(const uint8_t *buf, BN_CTX *ctx) const;
|
||||
|
||||
void EncodePoint(const EDDSAPoint &p, uint8_t *buf) const;
|
||||
|
||||
template<int len>
|
||||
BIGNUM *DecodeBN(const uint8_t *buf) const;
|
||||
|
||||
void EncodeBN(const BIGNUM *bn, uint8_t *buf, size_t len) const;
|
||||
|
||||
#if !OPENSSL_X25519
|
||||
|
||||
// for x25519
|
||||
BIGNUM *ScalarMul(const BIGNUM *p, const BIGNUM *e, BN_CTX *ctx) const;
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
@ -10,24 +10,29 @@
|
|||
#include "Crypto.h"
|
||||
#include "Elligator.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
|
||||
Elligator2::Elligator2 ()
|
||||
{
|
||||
Elligator2::Elligator2() {
|
||||
// TODO: share with Ed22519
|
||||
p = BN_new();
|
||||
// 2^255-19
|
||||
BN_set_bit(p, 255); // 2^255
|
||||
BN_sub_word(p, 19);
|
||||
p38 = BN_dup (p); BN_add_word (p38, 3); BN_div_word (p38, 8); // (p+3)/8
|
||||
p12 = BN_dup (p); BN_sub_word (p12, 1); BN_div_word (p12, 2); // (p-1)/2
|
||||
p14 = BN_dup (p); BN_sub_word (p14, 1); BN_div_word (p14, 4); // (p-1)/4
|
||||
p38 = BN_dup(p);
|
||||
BN_add_word(p38, 3);
|
||||
BN_div_word(p38, 8); // (p+3)/8
|
||||
p12 = BN_dup(p);
|
||||
BN_sub_word(p12, 1);
|
||||
BN_div_word(p12, 2); // (p-1)/2
|
||||
p14 = BN_dup(p);
|
||||
BN_sub_word(p14, 1);
|
||||
BN_div_word(p14, 4); // (p-1)/4
|
||||
|
||||
A = BN_new (); BN_set_word (A, 486662);
|
||||
nA = BN_new (); BN_sub (nA, p, A);
|
||||
A = BN_new();
|
||||
BN_set_word(A, 486662);
|
||||
nA = BN_new();
|
||||
BN_sub(nA, p, A);
|
||||
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
// calculate sqrt(-1)
|
||||
|
@ -35,21 +40,27 @@ namespace crypto
|
|||
BN_set_word(sqrtn1, 2);
|
||||
BN_mod_exp(sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
|
||||
|
||||
u = BN_new (); BN_set_word (u, 2);
|
||||
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx);
|
||||
u = BN_new();
|
||||
BN_set_word(u, 2);
|
||||
iu = BN_new();
|
||||
BN_mod_inverse(iu, u, p, ctx);
|
||||
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
Elligator2::~Elligator2 ()
|
||||
{
|
||||
BN_free (p); BN_free (p38); BN_free (p12); BN_free (p14);
|
||||
BN_free (sqrtn1); BN_free (A); BN_free (nA);
|
||||
BN_free (u); BN_free (iu);
|
||||
Elligator2::~Elligator2() {
|
||||
BN_free(p);
|
||||
BN_free(p38);
|
||||
BN_free(p12);
|
||||
BN_free(p14);
|
||||
BN_free(sqrtn1);
|
||||
BN_free(A);
|
||||
BN_free(nA);
|
||||
BN_free(u);
|
||||
BN_free(iu);
|
||||
}
|
||||
|
||||
bool Elligator2::Encode (const uint8_t * key, uint8_t * encoded, bool highY, bool random) const
|
||||
{
|
||||
bool Elligator2::Encode(const uint8_t *key, uint8_t *encoded, bool highY, bool random) const {
|
||||
bool ret = true;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
|
@ -61,31 +72,28 @@ namespace crypto
|
|||
key1[31 - i] = key[i];
|
||||
}
|
||||
|
||||
BIGNUM * x = BN_CTX_get (ctx); BN_bin2bn (key1, 32, x);
|
||||
BIGNUM * xA = BN_CTX_get (ctx); BN_add (xA, x, A); // x + A
|
||||
BIGNUM *x = BN_CTX_get(ctx);
|
||||
BN_bin2bn(key1, 32, x);
|
||||
BIGNUM *xA = BN_CTX_get(ctx);
|
||||
BN_add(xA, x, A); // x + A
|
||||
BN_sub(xA, p, xA); // p - (x + A)
|
||||
|
||||
BIGNUM *uxxA = BN_CTX_get(ctx); // u*x*xA
|
||||
BN_mod_mul(uxxA, u, x, p, ctx);
|
||||
BN_mod_mul(uxxA, uxxA, xA, p, ctx);
|
||||
|
||||
if (Legendre (uxxA, ctx) != -1)
|
||||
{
|
||||
if (Legendre(uxxA, ctx) != -1) {
|
||||
uint8_t randByte = 0; // random highest bits and high y
|
||||
if (random)
|
||||
{
|
||||
if (random) {
|
||||
RAND_bytes(&randByte, 1);
|
||||
highY = randByte & 0x01;
|
||||
}
|
||||
|
||||
BIGNUM *r = BN_CTX_get(ctx);
|
||||
if (highY)
|
||||
{
|
||||
if (highY) {
|
||||
BN_mod_inverse(r, x, p, ctx);
|
||||
BN_mod_mul(r, r, xA, p, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
BN_mod_inverse(r, xA, p, ctx);
|
||||
BN_mod_mul(r, r, x, p, ctx);
|
||||
}
|
||||
|
@ -102,8 +110,7 @@ namespace crypto
|
|||
encoded[i] = encoded[31 - i];
|
||||
encoded[31 - i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
ret = false;
|
||||
|
||||
BN_CTX_end(ctx);
|
||||
|
@ -111,8 +118,7 @@ namespace crypto
|
|||
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;
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
|
@ -125,12 +131,14 @@ namespace crypto
|
|||
}
|
||||
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
|
||||
{
|
||||
// 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_add_word(v, 1);
|
||||
BN_mod_inverse(v, v, p, ctx);
|
||||
|
@ -139,7 +147,8 @@ namespace crypto
|
|||
BIGNUM *vpA = BN_CTX_get(ctx);
|
||||
BN_add(vpA, v, A); // v + A
|
||||
// t = v^3+A*v^2+v = v^2*(v+A)+v
|
||||
BIGNUM * t = BN_CTX_get (ctx); BN_mod_sqr (t, v, p, ctx);
|
||||
BIGNUM *t = BN_CTX_get(ctx);
|
||||
BN_mod_sqr(t, v, p, ctx);
|
||||
BN_mod_mul(t, t, vpA, p, ctx);
|
||||
BN_mod_add(t, t, v, p, ctx);
|
||||
|
||||
|
@ -147,8 +156,7 @@ namespace crypto
|
|||
BIGNUM *x = BN_CTX_get(ctx);
|
||||
if (legendre == 1)
|
||||
BN_copy(x, v);
|
||||
else
|
||||
{
|
||||
else {
|
||||
BN_sub(x, p, v);
|
||||
BN_mod_sub(x, x, A, p, ctx);
|
||||
}
|
||||
|
@ -160,8 +168,7 @@ namespace crypto
|
|||
key[i] = key[31 - i];
|
||||
key[31 - i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
ret = false;
|
||||
|
||||
BN_CTX_end(ctx);
|
||||
|
@ -170,8 +177,7 @@ namespace crypto
|
|||
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);
|
||||
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)
|
||||
|
@ -184,8 +190,7 @@ namespace crypto
|
|||
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
|
||||
if (BN_is_zero(a)) return 0;
|
||||
BIGNUM *r = BN_CTX_get(ctx);
|
||||
|
@ -198,10 +203,9 @@ namespace crypto
|
|||
}
|
||||
|
||||
static std::unique_ptr<Elligator2> g_Elligator;
|
||||
std::unique_ptr<Elligator2>& GetElligator ()
|
||||
{
|
||||
if (!g_Elligator)
|
||||
{
|
||||
|
||||
std::unique_ptr<Elligator2> &GetElligator() {
|
||||
if (!g_Elligator) {
|
||||
auto el = new Elligator2();
|
||||
if (!g_Elligator) // make sure it was not created already
|
||||
g_Elligator.reset(el);
|
||||
|
|
|
@ -13,24 +13,24 @@
|
|||
#include <memory>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
|
||||
class Elligator2
|
||||
{
|
||||
class Elligator2 {
|
||||
public:
|
||||
|
||||
Elligator2();
|
||||
|
||||
~Elligator2();
|
||||
|
||||
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;
|
||||
|
||||
private:
|
||||
|
||||
void SquareRoot(const BIGNUM *x, BIGNUM *r, BN_CTX *ctx) const;
|
||||
|
||||
int Legendre(const BIGNUM *a, BN_CTX *ctx) const; // a/p
|
||||
|
||||
private:
|
||||
|
|
|
@ -158,15 +158,12 @@ namespace fs {
|
|||
}
|
||||
|
||||
void SetCertsDir(const std::string &cmdline_certsdir) {
|
||||
if (cmdline_certsdir != "")
|
||||
{
|
||||
if (cmdline_certsdir != "") {
|
||||
if (cmdline_certsdir[cmdline_certsdir.length() - 1] == '/')
|
||||
certsDir = cmdline_certsdir.substr(0, cmdline_certsdir.size() - 1); // strip trailing slash
|
||||
else
|
||||
certsDir = cmdline_certsdir;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
certsDir = i2p::fs::DataDirPath("certificates");
|
||||
}
|
||||
return;
|
||||
|
@ -208,8 +205,7 @@ namespace fs {
|
|||
return boost::filesystem::exists(path);
|
||||
}
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path)
|
||||
{
|
||||
uint32_t GetLastUpdateTime(const std::string &path) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
return 0;
|
||||
boost::system::error_code ec;
|
||||
|
@ -223,8 +219,7 @@ namespace fs {
|
|||
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)))
|
||||
return true;
|
||||
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::recursive_directory_iterator it(p);
|
||||
boost::filesystem::recursive_directory_iterator end;
|
||||
|
|
15
libi2pd/FS.h
15
libi2pd/FS.h
|
@ -35,8 +35,7 @@ namespace fs {
|
|||
* std::vector<std::string> files;
|
||||
* h.Traverse(files); <- finds all files in storage and saves in given vector
|
||||
*/
|
||||
class HashedStorage
|
||||
{
|
||||
class HashedStorage {
|
||||
protected:
|
||||
|
||||
std::string root; /**< path to storage with it's name included */
|
||||
|
@ -48,27 +47,36 @@ namespace fs {
|
|||
public:
|
||||
|
||||
typedef std::function<void(const std::string &)> FilenameVisitor;
|
||||
|
||||
HashedStorage(const char *n, const char *p1, const char *p2, const char *s) :
|
||||
name(n), prefix1(p1), prefix2(p2), suffix(s) {};
|
||||
|
||||
/** create subdirs in storage */
|
||||
bool Init(const char *chars, size_t cnt);
|
||||
|
||||
const std::string &GetRoot() const { return root; }
|
||||
|
||||
const std::string &GetName() const { return name; }
|
||||
|
||||
/** set directory where to place storage directory */
|
||||
void SetPlace(const std::string &path);
|
||||
|
||||
/** path to file with given ident */
|
||||
std::string Path(const std::string &ident) const;
|
||||
|
||||
/** remove file by ident */
|
||||
void Remove(const std::string &ident);
|
||||
|
||||
/** find all files in storage and store list in provided vector */
|
||||
void Traverse(std::vector <std::string> &files);
|
||||
|
||||
/** visit every file in this storage with a visitor */
|
||||
void Iterate(FilenameVisitor v);
|
||||
};
|
||||
|
||||
/** @brief Returns current application name, default 'i2pd' */
|
||||
const std::string &GetAppName();
|
||||
|
||||
/** @brief Set application name, affects autodetection of datadir */
|
||||
void SetAppName(const std::string &name);
|
||||
|
||||
|
@ -168,8 +176,7 @@ namespace fs {
|
|||
}
|
||||
|
||||
template<typename Storage, typename... Filename>
|
||||
std::string StorageRootPath (const Storage& storage, Filename... filenames)
|
||||
{
|
||||
std::string StorageRootPath(const Storage &storage, Filename... filenames) {
|
||||
std::stringstream s("");
|
||||
s << storage.GetRoot();
|
||||
_ExpandPath(s, filenames...);
|
||||
|
|
|
@ -15,68 +15,55 @@
|
|||
#include "Family.h"
|
||||
#include "Config.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
Families::Families ()
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
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());
|
||||
int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
|
||||
if (ret)
|
||||
{
|
||||
if (ret) {
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
X509 *cert = SSL_get_certificate(ssl);
|
||||
if (cert)
|
||||
{
|
||||
if (cert) {
|
||||
std::shared_ptr<i2p::crypto::Verifier> verifier;
|
||||
// extract issuer name
|
||||
char name[100];
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
|
||||
char *cn = strstr(name, "CN=");
|
||||
if (cn)
|
||||
{
|
||||
if (cn) {
|
||||
cn += 3;
|
||||
char *family = strstr(cn, ".family");
|
||||
if (family) family[0] = 0;
|
||||
}
|
||||
auto pkey = X509_get_pubkey(cert);
|
||||
int keyType = EVP_PKEY_base_id(pkey);
|
||||
switch (keyType)
|
||||
{
|
||||
switch (keyType) {
|
||||
case EVP_PKEY_DSA:
|
||||
// TODO:
|
||||
break;
|
||||
case EVP_PKEY_EC:
|
||||
{
|
||||
case EVP_PKEY_EC: {
|
||||
EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey);
|
||||
if (ecKey)
|
||||
{
|
||||
if (ecKey) {
|
||||
auto group = EC_KEY_get0_group(ecKey);
|
||||
if (group)
|
||||
{
|
||||
if (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];
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp(group,
|
||||
EC_KEY_get0_public_key(ecKey), x, y, NULL);
|
||||
i2p::crypto::bn2buf(x, signingKey, 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->SetPublicKey(signingKey);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
EC_KEY_free(ecKey);
|
||||
|
@ -91,14 +78,12 @@ namespace data
|
|||
m_SigningKeys.emplace(cn, std::make_pair(verifier, m_SigningKeys.size() + 1));
|
||||
}
|
||||
SSL_free(ssl);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Family: Can't open certificate file ", filename);
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void Families::LoadCertificates ()
|
||||
{
|
||||
void Families::LoadCertificates() {
|
||||
std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "family";
|
||||
|
||||
std::vector<std::string> files;
|
||||
|
@ -121,12 +106,10 @@ namespace data
|
|||
}
|
||||
|
||||
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];
|
||||
size_t len = family.length(), signatureLen = strlen(signature);
|
||||
if (len + 32 > 100)
|
||||
{
|
||||
if (len + 32 > 100) {
|
||||
LogPrint(eLogError, "Family: ", family, " is too long");
|
||||
return false;
|
||||
}
|
||||
|
@ -142,33 +125,27 @@ namespace data
|
|||
return true;
|
||||
}
|
||||
|
||||
FamilyID Families::GetFamilyID (const std::string& family) const
|
||||
{
|
||||
FamilyID Families::GetFamilyID(const std::string &family) const {
|
||||
auto it = m_SigningKeys.find(family);
|
||||
if (it != m_SigningKeys.end())
|
||||
return it->second.second;
|
||||
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"));
|
||||
std::string sig;
|
||||
SSL_CTX *ctx = SSL_CTX_new(TLS_method());
|
||||
int ret = SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
|
||||
if (ret)
|
||||
{
|
||||
if (ret) {
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
EVP_PKEY *pkey = SSL_get_privatekey(ssl);
|
||||
EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey);
|
||||
if (ecKey)
|
||||
{
|
||||
if (ecKey) {
|
||||
auto group = EC_KEY_get0_group(ecKey);
|
||||
if (group)
|
||||
{
|
||||
if (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];
|
||||
i2p::crypto::bn2buf(EC_KEY_get0_private_key(ecKey), signingPrivateKey, 32);
|
||||
i2p::crypto::ECDSAP256Signer signer(signingPrivateKey);
|
||||
|
@ -183,14 +160,12 @@ namespace data
|
|||
b64[len] = 0;
|
||||
sig = b64;
|
||||
delete[] b64;
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
}
|
||||
SSL_free(ssl);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Family: Can't open keys file: ", filename);
|
||||
SSL_CTX_free(ctx);
|
||||
return sig;
|
||||
|
|
|
@ -15,20 +15,22 @@
|
|||
#include "Signature.h"
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
typedef int FamilyID;
|
||||
class Families
|
||||
{
|
||||
|
||||
class Families {
|
||||
public:
|
||||
|
||||
Families();
|
||||
|
||||
~Families();
|
||||
|
||||
void LoadCertificates();
|
||||
|
||||
bool VerifyFamily(const std::string &family, const IdentHash &ident,
|
||||
const char *signature, const char *key = nullptr) const;
|
||||
|
||||
FamilyID GetFamilyID(const std::string &family) const;
|
||||
|
||||
private:
|
||||
|
|
File diff suppressed because it is too large
Load diff
131
libi2pd/Garlic.h
131
libi2pd/Garlic.h
|
@ -22,26 +22,21 @@
|
|||
#include "Queue.h"
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
namespace i2p {
|
||||
namespace tunnel {
|
||||
class OutboundTunnel;
|
||||
}
|
||||
|
||||
namespace garlic
|
||||
{
|
||||
namespace garlic {
|
||||
|
||||
enum GarlicDeliveryType
|
||||
{
|
||||
enum GarlicDeliveryType {
|
||||
eGarlicDeliveryTypeLocal = 0,
|
||||
eGarlicDeliveryTypeDestination = 1,
|
||||
eGarlicDeliveryTypeRouter = 2,
|
||||
eGarlicDeliveryTypeTunnel = 3
|
||||
};
|
||||
|
||||
struct ElGamalBlock
|
||||
{
|
||||
struct ElGamalBlock {
|
||||
uint8_t sessionKey[32];
|
||||
uint8_t preIV[32];
|
||||
uint8_t padding[158];
|
||||
|
@ -54,28 +49,33 @@ namespace garlic
|
|||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
|
||||
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() = default;
|
||||
|
||||
SessionTag(const SessionTag &) = default;
|
||||
|
||||
SessionTag &operator=(const SessionTag &) = default;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
SessionTag(SessionTag &&) = default;
|
||||
|
||||
SessionTag &operator=(SessionTag &&) = default;
|
||||
|
||||
#endif
|
||||
uint32_t creationTime; // seconds since epoch
|
||||
};
|
||||
|
||||
// AESDecryption is associated with session tags and store key
|
||||
class AESDecryption: public i2p::crypto::CBCDecryption
|
||||
{
|
||||
class AESDecryption : public i2p::crypto::CBCDecryption {
|
||||
public:
|
||||
|
||||
AESDecryption (const uint8_t * key): m_Key (key)
|
||||
{
|
||||
AESDecryption(const uint8_t *key) : m_Key(key) {
|
||||
SetKey(key);
|
||||
}
|
||||
|
||||
const i2p::crypto::AESKey &GetKey() const { return m_Key; };
|
||||
|
||||
private:
|
||||
|
@ -83,8 +83,7 @@ namespace garlic
|
|||
i2p::crypto::AESKey m_Key;
|
||||
};
|
||||
|
||||
struct GarlicRoutingPath
|
||||
{
|
||||
struct GarlicRoutingPath {
|
||||
std::shared_ptr<i2p::tunnel::OutboundTunnel> outboundTunnel;
|
||||
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||
int rtt; // RTT
|
||||
|
@ -93,12 +92,11 @@ namespace garlic
|
|||
};
|
||||
|
||||
class GarlicDestination;
|
||||
class GarlicRoutingSession
|
||||
{
|
||||
|
||||
class GarlicRoutingSession {
|
||||
protected:
|
||||
|
||||
enum LeaseSetUpdateStatus
|
||||
{
|
||||
enum LeaseSetUpdateStatus {
|
||||
eLeaseSetUpToDate = 0,
|
||||
eLeaseSetUpdated,
|
||||
eLeaseSetSubmitted,
|
||||
|
@ -108,37 +106,54 @@ namespace garlic
|
|||
public:
|
||||
|
||||
GarlicRoutingSession(GarlicDestination *owner, bool attachLeaseSet);
|
||||
|
||||
GarlicRoutingSession();
|
||||
|
||||
virtual ~GarlicRoutingSession();
|
||||
|
||||
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 MessageConfirmed(uint32_t msgID);
|
||||
|
||||
virtual bool IsRatchets() const { return false; };
|
||||
|
||||
virtual bool IsReadyToSend() const { return true; };
|
||||
|
||||
virtual bool IsTerminated() const { return !GetOwner(); };
|
||||
|
||||
virtual uint64_t GetLastActivityTimestamp() const { return 0; }; // non-zero for rathets only
|
||||
|
||||
void SetLeaseSetUpdated ()
|
||||
{
|
||||
void SetLeaseSetUpdated() {
|
||||
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
||||
};
|
||||
|
||||
bool IsLeaseSetNonConfirmed() const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
||||
|
||||
bool IsLeaseSetUpdated() const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
|
||||
|
||||
uint64_t GetLeaseSetSubmissionTime() const { return m_LeaseSetSubmissionTime; }
|
||||
|
||||
void CleanupUnconfirmedLeaseSet(uint64_t ts);
|
||||
|
||||
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath();
|
||||
|
||||
void SetSharedRoutingPath(std::shared_ptr<GarlicRoutingPath> path);
|
||||
|
||||
GarlicDestination *GetOwner() const { return m_Owner; }
|
||||
|
||||
void SetOwner(GarlicDestination *owner) { m_Owner = owner; }
|
||||
|
||||
protected:
|
||||
|
||||
LeaseSetUpdateStatus GetLeaseSetUpdateStatus() const { return m_LeaseSetUpdateStatus; }
|
||||
|
||||
void SetLeaseSetUpdateStatus(LeaseSetUpdateStatus status) { m_LeaseSetUpdateStatus = status; }
|
||||
|
||||
uint32_t GetLeaseSetUpdateMsgID() const { return m_LeaseSetUpdateMsgID; }
|
||||
|
||||
void SetLeaseSetUpdateMsgID(uint32_t msgID) { m_LeaseSetUpdateMsgID = msgID; }
|
||||
|
||||
void SetLeaseSetSubmissionTime(uint64_t ts) { m_LeaseSetSubmissionTime = ts; }
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg(uint32_t msgID);
|
||||
|
@ -158,14 +173,14 @@ namespace garlic
|
|||
// for HTTP only
|
||||
virtual size_t GetNumOutgoingTags() const { return 0; };
|
||||
};
|
||||
|
||||
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
|
||||
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>
|
||||
{
|
||||
struct UnconfirmedTags
|
||||
{
|
||||
class ElGamalAESSession : public GarlicRoutingSession, public std::enable_shared_from_this<ElGamalAESSession> {
|
||||
struct UnconfirmedTags {
|
||||
UnconfirmedTags(int n) : numTags(n), tagsCreationTime(0) { sessionTags = new SessionTag[numTags]; };
|
||||
|
||||
~UnconfirmedTags() { delete[] sessionTags; };
|
||||
uint32_t msgID;
|
||||
int numTags;
|
||||
|
@ -175,25 +190,33 @@ namespace garlic
|
|||
|
||||
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);
|
||||
|
||||
ElGamalAESSession(const uint8_t *sessionKey, const SessionTag &sessionTag); // one time encryption
|
||||
~ElGamalAESSession() {};
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapSingleMessage(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
bool MessageConfirmed(uint32_t msgID);
|
||||
|
||||
bool CleanupExpiredTags(); // returns true if something left
|
||||
bool CleanupUnconfirmedTags(); // returns true if something has been deleted
|
||||
|
||||
private:
|
||||
|
||||
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 CreateDeliveryStatusClove(uint8_t *buf, uint32_t msgID);
|
||||
|
||||
void TagsConfirmed(uint32_t msgID);
|
||||
|
||||
UnconfirmedTags *GenerateSessionTags();
|
||||
|
||||
private:
|
||||
|
@ -212,33 +235,45 @@ namespace garlic
|
|||
// for HTTP only
|
||||
size_t GetNumOutgoingTags() const { return m_SessionTags.size(); };
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ElGamalAESSession> ElGamalAESSessionPtr;
|
||||
|
||||
class ECIESX25519AEADRatchetSession;
|
||||
|
||||
typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr;
|
||||
|
||||
class ReceiveRatchetTagSet;
|
||||
|
||||
typedef std::shared_ptr<ReceiveRatchetTagSet> ReceiveRatchetTagSetPtr;
|
||||
struct ECIESX25519AEADRatchetIndexTagset
|
||||
{
|
||||
struct ECIESX25519AEADRatchetIndexTagset {
|
||||
int index;
|
||||
ReceiveRatchetTagSetPtr tagset;
|
||||
};
|
||||
|
||||
class GarlicDestination: public i2p::data::LocalDestination
|
||||
{
|
||||
class GarlicDestination : public i2p::data::LocalDestination {
|
||||
public:
|
||||
|
||||
GarlicDestination();
|
||||
|
||||
~GarlicDestination();
|
||||
|
||||
void CleanUp();
|
||||
|
||||
void SetNumTags(int numTags) { m_NumTags = numTags; };
|
||||
|
||||
int GetNumTags() const { return m_NumTags; };
|
||||
|
||||
void SetNumRatchetInboundTags(int numTags) { m_NumRatchetInboundTags = numTags; };
|
||||
|
||||
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 RemoveDeliveryStatusSession(uint32_t msgID);
|
||||
|
||||
std::shared_ptr<I2NPMessage> WrapMessageForRouter(std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
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 void SubmitECIESx25519Key(const uint8_t *key, uint64_t tag); // from different thread
|
||||
void DeliveryStatusSent(GarlicRoutingSessionPtr session, uint32_t msgID);
|
||||
|
||||
uint64_t AddECIESx25519SessionNextTag(ReceiveRatchetTagSetPtr tagset);
|
||||
|
||||
void AddECIESx25519Session(const uint8_t *staticKey, ECIESX25519AEADRatchetSessionPtr session);
|
||||
|
||||
void RemoveECIESx25519Session(const uint8_t *staticKey);
|
||||
|
||||
void HandleECIESx25519GarlicClove(const uint8_t *buf, size_t len);
|
||||
|
||||
uint8_t *GetPayloadBuffer();
|
||||
|
||||
virtual void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
virtual void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
virtual void SetLeaseSetUpdated();
|
||||
|
||||
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
|
||||
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 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 HandleDeliveryStatusMessage(uint32_t msgID);
|
||||
|
||||
void SaveTags();
|
||||
|
||||
void LoadTags();
|
||||
|
||||
private:
|
||||
|
||||
void HandleAESBlock(uint8_t *buf, size_t len, std::shared_ptr<AESDecryption> decryption,
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||
|
||||
void HandleGarlicPayload(uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||
|
||||
private:
|
||||
|
@ -299,9 +346,17 @@ namespace garlic
|
|||
|
||||
// for HTTP only
|
||||
size_t GetNumIncomingTags() const { return m_Tags.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();
|
||||
|
|
130
libi2pd/Gost.cpp
130
libi2pd/Gost.cpp
|
@ -14,15 +14,12 @@
|
|||
#include "I2PEndian.h"
|
||||
#include "Gost.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
|
||||
// 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);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
m_Group = EC_GROUP_new_curve_GFp(p, a, b, ctx);
|
||||
|
@ -34,13 +31,11 @@ namespace crypto
|
|||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
GOSTR3410Curve::~GOSTR3410Curve ()
|
||||
{
|
||||
GOSTR3410Curve::~GOSTR3410Curve() {
|
||||
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();
|
||||
auto p = EC_POINT_new(m_Group);
|
||||
EC_POINT_mul(m_Group, p, n, nullptr, nullptr, ctx);
|
||||
|
@ -48,20 +43,17 @@ namespace crypto
|
|||
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);
|
||||
}
|
||||
|
||||
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_set_affine_coordinates_GFp(m_Group, p, x, y, nullptr);
|
||||
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_start(ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -79,8 +71,7 @@ namespace crypto
|
|||
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_start(ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -105,15 +96,14 @@ namespace crypto
|
|||
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
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
EC_POINT *C = EC_POINT_new(m_Group); // C = k*P = (rx, ry)
|
||||
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_mul(m_Group, S, s, nullptr, nullptr, ctx);
|
||||
BIGNUM *q = BN_CTX_get(ctx);
|
||||
|
@ -137,8 +127,7 @@ namespace crypto
|
|||
return Q;
|
||||
}
|
||||
|
||||
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
static GOSTR3410Curve *CreateGOSTR3410Curve(GOSTR3410ParamSet paramSet) {
|
||||
// a, b, p, q, x, y
|
||||
static const char *params[eGOSTR3410NumParamSets][6] =
|
||||
{
|
||||
|
@ -168,15 +157,19 @@ namespace crypto
|
|||
BN_hex2bn(&x, params[paramSet][4]);
|
||||
BN_hex2bn(&y, params[paramSet][5]);
|
||||
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;
|
||||
}
|
||||
|
||||
static std::array <std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
|
||||
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
if (!g_GOSTR3410Curves[paramSet])
|
||||
{
|
||||
|
||||
std::unique_ptr <GOSTR3410Curve> &GetGOSTR3410Curve(GOSTR3410ParamSet paramSet) {
|
||||
if (!g_GOSTR3410Curves[paramSet]) {
|
||||
auto c = CreateGOSTR3410Curve(paramSet);
|
||||
if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already
|
||||
g_GOSTR3410Curves[paramSet].reset(c);
|
||||
|
@ -783,28 +776,24 @@ namespace crypto
|
|||
uint8_t buf[64];
|
||||
uint64_t ll[8];
|
||||
|
||||
GOST3411Block operator^(const GOST3411Block& other) const
|
||||
{
|
||||
GOST3411Block operator^(const GOST3411Block &other) const {
|
||||
GOST3411Block ret;
|
||||
for (int i = 0; i < 8; i++)
|
||||
ret.ll[i] = ll[i] ^ other.ll[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
GOST3411Block operator^(const uint64_t * other) const
|
||||
{
|
||||
GOST3411Block operator^(const uint64_t *other) const {
|
||||
GOST3411Block ret;
|
||||
for (int i = 0; i < 8; i++)
|
||||
ret.ll[i] = ll[i] ^ other[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
GOST3411Block operator+(const GOST3411Block& other) const
|
||||
{
|
||||
GOST3411Block operator+(const GOST3411Block &other) const {
|
||||
GOST3411Block ret;
|
||||
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;
|
||||
ret.buf[i] = sum;
|
||||
carry = sum >> 8;
|
||||
|
@ -812,10 +801,8 @@ namespace crypto
|
|||
return ret;
|
||||
}
|
||||
|
||||
void Add (uint32_t c)
|
||||
{
|
||||
for (int i = 63; i >= 0; i--)
|
||||
{
|
||||
void Add(uint32_t c) {
|
||||
for (int i = 63; i >= 0; i--) {
|
||||
if (!c) return;
|
||||
c += buf[i];
|
||||
buf[i] = c;
|
||||
|
@ -823,11 +810,9 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
void F ()
|
||||
{
|
||||
void F() {
|
||||
uint64_t res[8];
|
||||
for (int b=0; b<8; b++)
|
||||
{
|
||||
for (int b = 0; b < 8; b++) {
|
||||
uint64_t r;
|
||||
r = T0[buf[b + 56]];
|
||||
r ^= T1[buf[b + 48]];
|
||||
|
@ -842,12 +827,10 @@ namespace crypto
|
|||
memcpy(buf, res, 64);
|
||||
}
|
||||
|
||||
GOST3411Block E (const GOST3411Block& m)
|
||||
{
|
||||
GOST3411Block E(const GOST3411Block &m) {
|
||||
GOST3411Block k = *this;
|
||||
GOST3411Block res = k ^ m;
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
for (int i = 0; i < 12; i++) {
|
||||
res.F();
|
||||
k = k ^ C_[i];
|
||||
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;
|
||||
res.F();
|
||||
res = res.E(m);
|
||||
|
@ -867,8 +849,7 @@ namespace crypto
|
|||
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
|
||||
GOST3411Block h, N, s, m;
|
||||
memcpy(h.buf, iv, 64);
|
||||
|
@ -876,8 +857,7 @@ namespace crypto
|
|||
memset(s.buf, 0, 64);
|
||||
size_t l = len;
|
||||
// stage 2
|
||||
while (l >= 64)
|
||||
{
|
||||
while (l >= 64) {
|
||||
memcpy(m.buf, buf + l - 64, 64); // TODO
|
||||
h = gN(N, h, m);
|
||||
N.Add(512);
|
||||
|
@ -886,8 +866,7 @@ namespace crypto
|
|||
}
|
||||
// stage 3
|
||||
size_t padding = 64 - l;
|
||||
if (padding)
|
||||
{
|
||||
if (padding) {
|
||||
memset(m.buf, 0, padding - 1);
|
||||
m.buf[padding - 1] = 1;
|
||||
}
|
||||
|
@ -905,8 +884,7 @@ namespace crypto
|
|||
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];
|
||||
memset(iv, 1, 64);
|
||||
uint8_t h[64];
|
||||
|
@ -914,33 +892,28 @@ namespace crypto
|
|||
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];
|
||||
memset(iv, 0, 64);
|
||||
H(iv, buf, len, digest);
|
||||
}
|
||||
|
||||
// reverse order
|
||||
struct GOSTR3411_2012_CTX
|
||||
{
|
||||
struct GOSTR3411_2012_CTX {
|
||||
GOST3411Block h, N, s, m;
|
||||
size_t len;
|
||||
bool is512;
|
||||
};
|
||||
|
||||
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ()
|
||||
{
|
||||
GOSTR3411_2012_CTX *GOSTR3411_2012_CTX_new() {
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
memset(iv, is512 ? 0 : 1, 64);
|
||||
memcpy(ctx->h.buf, iv, 64);
|
||||
|
@ -950,8 +923,7 @@ namespace crypto
|
|||
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 (ctx->len > 0) // something left from buffer
|
||||
{
|
||||
|
@ -959,17 +931,19 @@ namespace crypto
|
|||
if (len < l) l = len;
|
||||
for (size_t i = 0; i < l; i++)
|
||||
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->N.Add(512);
|
||||
ctx->s = ctx->m + ctx->s;
|
||||
}
|
||||
while (len >= 64)
|
||||
{
|
||||
while (len >= 64) {
|
||||
for (size_t i = 0; i < 64; i++)
|
||||
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->N.Add(512);
|
||||
ctx->s = ctx->m + ctx->s;
|
||||
|
@ -982,12 +956,10 @@ namespace crypto
|
|||
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;
|
||||
size_t padding = 64 - ctx->len;
|
||||
if (padding)
|
||||
{
|
||||
if (padding) {
|
||||
memset(m.buf, 0, padding - 1);
|
||||
m.buf[padding - 1] = 1;
|
||||
}
|
||||
|
|
|
@ -12,15 +12,12 @@
|
|||
#include <memory>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
|
||||
// ГОСТ Р 34.10
|
||||
|
||||
enum GOSTR3410ParamSet
|
||||
{
|
||||
enum GOSTR3410ParamSet {
|
||||
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
|
||||
// XchA = A, XchB = C
|
||||
//eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0
|
||||
|
@ -29,21 +26,29 @@ namespace crypto
|
|||
eGOSTR3410NumParamSets
|
||||
};
|
||||
|
||||
class GOSTR3410Curve
|
||||
{
|
||||
class GOSTR3410Curve {
|
||||
public:
|
||||
|
||||
GOSTR3410Curve(BIGNUM *a, BIGNUM *b, BIGNUM *p, BIGNUM *q, BIGNUM *x, BIGNUM *y);
|
||||
|
||||
~GOSTR3410Curve();
|
||||
|
||||
size_t GetKeyLen() const { return m_KeyLen; };
|
||||
|
||||
const EC_GROUP *GetGroup() const { return m_Group; };
|
||||
|
||||
EC_POINT *MulP(const BIGNUM *n) const;
|
||||
|
||||
bool GetXY(const EC_POINT *p, BIGNUM *x, 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);
|
||||
|
||||
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:
|
||||
|
||||
|
@ -55,14 +60,20 @@ namespace crypto
|
|||
|
||||
// Big Endian
|
||||
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);
|
||||
|
||||
// Little Endian
|
||||
struct GOSTR3411_2012_CTX;
|
||||
|
||||
GOSTR3411_2012_CTX *GOSTR3411_2012_CTX_new();
|
||||
|
||||
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_Finish(uint8_t *digest, GOSTR3411_2012_CTX *ctx);
|
||||
|
||||
void GOSTR3411_2012_CTX_free(GOSTR3411_2012_CTX *ctx);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,40 +13,32 @@
|
|||
#include "I2PEndian.h"
|
||||
#include "Gzip.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
const size_t GZIP_CHUNK_SIZE = 16384;
|
||||
|
||||
GzipInflator::GzipInflator (): m_IsDirty (false)
|
||||
{
|
||||
GzipInflator::GzipInflator() : m_IsDirty(false) {
|
||||
memset(&m_Inflator, 0, sizeof(m_Inflator));
|
||||
inflateInit2(&m_Inflator, MAX_WBITS + 16); // gzip
|
||||
}
|
||||
|
||||
GzipInflator::~GzipInflator ()
|
||||
{
|
||||
GzipInflator::~GzipInflator() {
|
||||
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 (in[10] == 0x01) // non compressed
|
||||
{
|
||||
size_t len = bufle16toh(in + 11);
|
||||
if (len + 23 < inLen)
|
||||
{
|
||||
if (len + 23 < inLen) {
|
||||
LogPrint(eLogError, "Gzip: Incorrect length");
|
||||
return 0;
|
||||
}
|
||||
if (len > outLen) len = outLen;
|
||||
memcpy(out, in + 15, len);
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (m_IsDirty) inflateReset(&m_Inflator);
|
||||
m_IsDirty = true;
|
||||
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;
|
||||
uint8_t *out = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||
m_Inflator.avail_in = inLen;
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
do {
|
||||
m_Inflator.next_out = out;
|
||||
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
|
||||
ret = inflate(&m_Inflator, Z_NO_FLUSH);
|
||||
if (ret < 0)
|
||||
{
|
||||
if (ret < 0) {
|
||||
inflateEnd(&m_Inflator);
|
||||
os.setstate(std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
while (!in.eof ())
|
||||
{
|
||||
while (!in.eof()) {
|
||||
in.read((char *) buf, GZIP_CHUNK_SIZE);
|
||||
Inflate(buf, in.gcount(), out);
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
GzipDeflator::GzipDeflator (): m_IsDirty (false)
|
||||
{
|
||||
GzipDeflator::GzipDeflator() : m_IsDirty(false) {
|
||||
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);
|
||||
}
|
||||
|
||||
void GzipDeflator::SetCompressionLevel (int level)
|
||||
{
|
||||
void GzipDeflator::SetCompressionLevel(int level) {
|
||||
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);
|
||||
m_IsDirty = true;
|
||||
m_Deflator.next_in = const_cast<uint8_t *>(in);
|
||||
|
@ -122,8 +105,7 @@ namespace data
|
|||
m_Deflator.next_out = out;
|
||||
m_Deflator.avail_out = outLen;
|
||||
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
|
||||
return outLen - m_Deflator.avail_out;
|
||||
}
|
||||
|
@ -132,24 +114,21 @@ namespace data
|
|||
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);
|
||||
m_IsDirty = true;
|
||||
size_t offset = 0;
|
||||
int err;
|
||||
for (const auto& it: bufs)
|
||||
{
|
||||
for (const auto &it: bufs) {
|
||||
m_Deflator.next_in = const_cast<uint8_t *>(it.first);
|
||||
m_Deflator.avail_in = it.second;
|
||||
m_Deflator.next_out = out + offset;
|
||||
m_Deflator.avail_out = outLen - offset;
|
||||
auto flush = (it == bufs.back()) ? Z_FINISH : Z_NO_FLUSH;
|
||||
err = deflate(&m_Deflator, flush);
|
||||
if (err)
|
||||
{
|
||||
if (flush && err == Z_STREAM_END)
|
||||
{
|
||||
if (err) {
|
||||
if (flush && err == Z_STREAM_END) {
|
||||
out[9] = 0xff; // OS is always unknown
|
||||
return outLen - m_Deflator.avail_out;
|
||||
}
|
||||
|
@ -162,8 +141,7 @@ namespace data
|
|||
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};
|
||||
if (outLen < (size_t) inLen + 23) return 0;
|
||||
memcpy(out, gzipHeader, 11);
|
||||
|
@ -175,14 +153,13 @@ namespace data
|
|||
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};
|
||||
memcpy(out, gzipHeader, 11);
|
||||
uint32_t crc = 0;
|
||||
size_t len = 0, len1;
|
||||
for (const auto& it: bufs)
|
||||
{
|
||||
for (const auto &it: bufs) {
|
||||
len1 = len;
|
||||
len += it.second;
|
||||
if (outLen < len + 23) return 0;
|
||||
|
|
|
@ -12,20 +12,20 @@
|
|||
#include <zlib.h>
|
||||
#include <vector>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
class GzipInflator
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
class GzipInflator {
|
||||
public:
|
||||
|
||||
GzipInflator();
|
||||
|
||||
~GzipInflator();
|
||||
|
||||
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 */
|
||||
void Inflate(const uint8_t *in, size_t inLen, std::ostream &os);
|
||||
|
||||
void Inflate(std::istream &in, std::ostream &out);
|
||||
|
||||
private:
|
||||
|
@ -34,15 +34,17 @@ namespace data
|
|||
bool m_IsDirty;
|
||||
};
|
||||
|
||||
class GzipDeflator
|
||||
{
|
||||
class GzipDeflator {
|
||||
public:
|
||||
|
||||
GzipDeflator();
|
||||
|
||||
~GzipDeflator();
|
||||
|
||||
void SetCompressionLevel(int level);
|
||||
|
||||
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);
|
||||
|
||||
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 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
|
||||
} // i2p
|
||||
|
||||
|
|
153
libi2pd/HTTP.cpp
153
libi2pd/HTTP.cpp
|
@ -14,13 +14,12 @@
|
|||
#include "Base.h"
|
||||
#include "HTTP.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
namespace i2p {
|
||||
namespace http {
|
||||
const std::vector <std::string> HTTP_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 = {
|
||||
"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 len = 1; /*: */
|
||||
std::size_t max = line.length();
|
||||
|
@ -119,8 +117,7 @@ namespace http
|
|||
auto pos_b = url.find(']', pos_p);
|
||||
if (pos_b == std::string::npos) return false;
|
||||
pos_c = url.find_first_of(":/", pos_b);
|
||||
}
|
||||
else
|
||||
} else
|
||||
pos_c = url.find_first_of(":/", pos_p);
|
||||
if (pos_c == std::string::npos) {
|
||||
/* only hostname, without post and path */
|
||||
|
@ -224,8 +221,7 @@ namespace http
|
|||
return out;
|
||||
}
|
||||
|
||||
bool URL::is_i2p() const
|
||||
{
|
||||
bool URL::is_i2p() const {
|
||||
return host.rfind(".i2p") == (host.size() - 4);
|
||||
}
|
||||
|
||||
|
@ -254,7 +250,9 @@ namespace http
|
|||
}
|
||||
|
||||
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 eol = 0, pos = 0;
|
||||
URL url;
|
||||
|
@ -280,9 +278,7 @@ namespace http
|
|||
uri = tokens[1];
|
||||
version = tokens[2];
|
||||
expect = HEADER_LINE;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length() > 0)
|
||||
|
@ -297,40 +293,33 @@ namespace http
|
|||
return eoh + strlen(HTTP_EOH);
|
||||
}
|
||||
|
||||
void HTTPReq::write(std::ostream & o)
|
||||
{
|
||||
void HTTPReq::write(std::ostream &o) {
|
||||
o << method << " " << uri << " " << version << CRLF;
|
||||
for (auto &h: headers)
|
||||
o << h.first << ": " << h.second << CRLF;
|
||||
o << CRLF;
|
||||
}
|
||||
|
||||
std::string HTTPReq::to_string()
|
||||
{
|
||||
std::string HTTPReq::to_string() {
|
||||
std::stringstream ss;
|
||||
write(ss);
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
if (it.first == name)
|
||||
{
|
||||
if (it.first == name) {
|
||||
it.second = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
|
||||
{
|
||||
for (auto it = headers.begin (); it != headers.end ();)
|
||||
{
|
||||
void HTTPReq::RemoveHeader(const std::string &name, const std::string &exempt) {
|
||||
for (auto it = headers.begin(); it != headers.end();) {
|
||||
if (!it->first.compare(0, name.length(), name) && it->first != exempt)
|
||||
it = headers.erase(it);
|
||||
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)
|
||||
if (it.first == name)
|
||||
return it.second;
|
||||
return "";
|
||||
}
|
||||
|
||||
bool HTTPRes::is_chunked() const
|
||||
{
|
||||
bool HTTPRes::is_chunked() const {
|
||||
auto it = headers.find("Transfer-Encoding");
|
||||
if (it == headers.end())
|
||||
return false;
|
||||
|
@ -356,8 +343,7 @@ namespace http
|
|||
return false;
|
||||
}
|
||||
|
||||
bool HTTPRes::is_gzipped(bool includingI2PGzip) const
|
||||
{
|
||||
bool HTTPRes::is_gzipped(bool includingI2PGzip) const {
|
||||
auto it = headers.find("Content-Encoding");
|
||||
if (it == headers.end())
|
||||
return false; /* no header */
|
||||
|
@ -368,8 +354,7 @@ namespace http
|
|||
return false;
|
||||
}
|
||||
|
||||
long int HTTPMsg::content_length() const
|
||||
{
|
||||
long int HTTPMsg::content_length() const {
|
||||
unsigned long int length = 0;
|
||||
auto it = headers.find("Content-Length");
|
||||
if (it == headers.end())
|
||||
|
@ -387,7 +372,9 @@ namespace http
|
|||
}
|
||||
|
||||
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 eol = 0, pos = 0;
|
||||
|
||||
|
@ -450,41 +437,74 @@ namespace http
|
|||
const char *HTTPCodeToStatus(int code) {
|
||||
const char *ptr;
|
||||
switch (code) {
|
||||
case 105: ptr = "Name Not Resolved"; break;
|
||||
case 105:
|
||||
ptr = "Name Not Resolved";
|
||||
break;
|
||||
/* success */
|
||||
case 200: ptr = "OK"; break;
|
||||
case 206: ptr = "Partial Content"; break;
|
||||
case 200:
|
||||
ptr = "OK";
|
||||
break;
|
||||
case 206:
|
||||
ptr = "Partial Content";
|
||||
break;
|
||||
/* redirect */
|
||||
case 301: ptr = "Moved Permanently"; break;
|
||||
case 302: ptr = "Found"; break;
|
||||
case 304: ptr = "Not Modified"; break;
|
||||
case 307: ptr = "Temporary Redirect"; break;
|
||||
case 301:
|
||||
ptr = "Moved Permanently";
|
||||
break;
|
||||
case 302:
|
||||
ptr = "Found";
|
||||
break;
|
||||
case 304:
|
||||
ptr = "Not Modified";
|
||||
break;
|
||||
case 307:
|
||||
ptr = "Temporary Redirect";
|
||||
break;
|
||||
/* client error */
|
||||
case 400: ptr = "Bad Request"; break;
|
||||
case 401: ptr = "Unauthorized"; 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;
|
||||
case 400:
|
||||
ptr = "Bad Request";
|
||||
break;
|
||||
case 401:
|
||||
ptr = "Unauthorized";
|
||||
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 */
|
||||
case 500: ptr = "Internal Server Error"; break;
|
||||
case 502: ptr = "Bad Gateway"; break;
|
||||
case 503: ptr = "Not Implemented"; break;
|
||||
case 504: ptr = "Gateway Timeout"; break;
|
||||
default: ptr = "Unknown Status"; break;
|
||||
case 500:
|
||||
ptr = "Internal Server Error";
|
||||
break;
|
||||
case 502:
|
||||
ptr = "Bad Gateway";
|
||||
break;
|
||||
case 503:
|
||||
ptr = "Not Implemented";
|
||||
break;
|
||||
case 504:
|
||||
ptr = "Gateway Timeout";
|
||||
break;
|
||||
default:
|
||||
ptr = "Unknown Status";
|
||||
break;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
if (c == '\0' && !allow_null)
|
||||
{
|
||||
if (c == '\0' && !allow_null) {
|
||||
pos += 3;
|
||||
continue;
|
||||
}
|
||||
|
@ -494,11 +514,9 @@ namespace http
|
|||
return decoded;
|
||||
}
|
||||
|
||||
bool MergeChunkedResponse (std::istream& in, std::ostream& out)
|
||||
{
|
||||
bool MergeChunkedResponse(std::istream &in, std::ostream &out) {
|
||||
std::string hexLen;
|
||||
while (!in.eof ())
|
||||
{
|
||||
while (!in.eof()) {
|
||||
std::getline(in, hexLen);
|
||||
errno = 0;
|
||||
long int len = strtoul(hexLen.c_str(), (char **) NULL, 16);
|
||||
|
@ -517,8 +535,7 @@ namespace http
|
|||
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 "";
|
||||
return "Basic " + i2p::data::ToBase64Standard(user + ":" + pass);
|
||||
}
|
||||
|
|
|
@ -16,17 +16,14 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
namespace i2p {
|
||||
namespace http {
|
||||
const char CRLF[] = "\r\n"; /**< HTTP line terminator */
|
||||
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_VERSIONS; /**< list of valid HTTP versions */
|
||||
|
||||
struct URL
|
||||
{
|
||||
struct URL {
|
||||
std::string schema;
|
||||
std::string user;
|
||||
std::string pass;
|
||||
|
@ -43,6 +40,7 @@ namespace http
|
|||
* @return true on success, false on invalid url
|
||||
*/
|
||||
bool parse(const char *str, std::size_t len = 0);
|
||||
|
||||
bool parse(const std::string &url);
|
||||
|
||||
/**
|
||||
|
@ -63,20 +61,20 @@ namespace http
|
|||
bool is_i2p() const;
|
||||
};
|
||||
|
||||
struct HTTPMsg
|
||||
{
|
||||
struct HTTPMsg {
|
||||
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, const char *value, bool replace = false);
|
||||
|
||||
void del_header(const char *name);
|
||||
|
||||
/** @brief Returns declared message length or -1 if unknown */
|
||||
long int content_length() const;
|
||||
};
|
||||
|
||||
struct HTTPReq
|
||||
{
|
||||
struct HTTPReq {
|
||||
std::list <std::pair<std::string, std::string>> headers;
|
||||
std::string version;
|
||||
std::string method;
|
||||
|
@ -90,16 +88,22 @@ namespace http
|
|||
* @note Positive return value is a size of header
|
||||
*/
|
||||
int parse(const char *buf, size_t len);
|
||||
|
||||
int parse(const std::string &buf);
|
||||
|
||||
/** @brief Serialize HTTP request to string */
|
||||
std::string to_string();
|
||||
|
||||
void write(std::ostream &o);
|
||||
|
||||
void AddHeader(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, ""); };
|
||||
|
||||
std::string GetHeader(const std::string &name) const;
|
||||
};
|
||||
|
||||
|
@ -124,6 +128,7 @@ namespace http
|
|||
* @note Positive return value is a size of header
|
||||
*/
|
||||
int parse(const char *buf, size_t len);
|
||||
|
||||
int parse(const std::string &buf);
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,30 +24,24 @@
|
|||
|
||||
using namespace i2p::transport;
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage ()
|
||||
{
|
||||
namespace i2p {
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage() {
|
||||
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> >();
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage(bool 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();
|
||||
}
|
||||
|
||||
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID, bool checksum)
|
||||
{
|
||||
void I2NPMessage::FillI2NPMessageHeader(I2NPMessageType msgType, uint32_t replyMsgID, bool checksum) {
|
||||
SetTypeID(msgType);
|
||||
if (!replyMsgID) RAND_bytes((uint8_t * ) & replyMsgID, 4);
|
||||
SetMsgID(replyMsgID);
|
||||
|
@ -56,23 +50,22 @@ namespace i2p
|
|||
if (checksum) UpdateChks();
|
||||
}
|
||||
|
||||
void I2NPMessage::RenewI2NPMessageHeader ()
|
||||
{
|
||||
void I2NPMessage::RenewI2NPMessageHeader() {
|
||||
uint32_t msgID;
|
||||
RAND_bytes((uint8_t * ) & msgID, 4);
|
||||
SetMsgID(msgID);
|
||||
SetExpiration(i2p::util::GetMillisecondsSinceEpoch() + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
{
|
||||
bool I2NPMessage::IsExpired() const {
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
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);
|
||||
if (msg->Concat(buf, len) < len)
|
||||
LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length ", msg->maxLen);
|
||||
|
@ -80,22 +73,19 @@ namespace i2p
|
|||
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();
|
||||
if (msg->offset + len < msg->maxLen)
|
||||
{
|
||||
if (msg->offset + len < msg->maxLen) {
|
||||
memcpy(msg->GetBuffer(), buf, len);
|
||||
msg->len = msg->offset + len;
|
||||
msg->from = from;
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "I2NP: Message length ", len, " exceeds max length");
|
||||
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;
|
||||
auto newMsg = NewI2NPMessage(msg->len);
|
||||
newMsg->offset = msg->offset;
|
||||
|
@ -103,16 +93,13 @@ namespace i2p
|
|||
return newMsg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg(uint32_t msgID) {
|
||||
auto m = NewI2NPShortMessage();
|
||||
uint8_t *buf = m->GetPayload();
|
||||
if (msgID)
|
||||
{
|
||||
if (msgID) {
|
||||
htobe32buf(buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
|
||||
htobe64buf(buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::util::GetMillisecondsSinceEpoch());
|
||||
}
|
||||
else // for SSU establishment
|
||||
} else // for SSU establishment
|
||||
{
|
||||
RAND_bytes((uint8_t * ) & msgID, 4);
|
||||
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,
|
||||
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();
|
||||
uint8_t *buf = m->GetPayload();
|
||||
memcpy(buf, key, 32); // key
|
||||
|
@ -133,31 +120,24 @@ namespace i2p
|
|||
memcpy(buf, from, 32); // from
|
||||
buf += 32;
|
||||
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
|
||||
htobe32buf(buf + 1, replyTunnelID);
|
||||
buf += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
*buf = flag; // flag
|
||||
buf++;
|
||||
}
|
||||
|
||||
if (excludedPeers)
|
||||
{
|
||||
if (excludedPeers) {
|
||||
int cnt = excludedPeers->size();
|
||||
htobe16buf(buf, cnt);
|
||||
buf += 2;
|
||||
for (auto& it: *excludedPeers)
|
||||
{
|
||||
for (auto &it: *excludedPeers) {
|
||||
memcpy(buf, it, 32);
|
||||
buf += 32;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// nothing to exclude
|
||||
htobuf16(buf, 0);
|
||||
buf += 2;
|
||||
|
@ -170,9 +150,9 @@ namespace i2p
|
|||
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg(const i2p::data::IdentHash &dest,
|
||||
const std::set<i2p::data::IdentHash> &excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
|
||||
const uint8_t * replyTag, bool replyECIES)
|
||||
{
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
||||
const uint8_t *replyKey,
|
||||
const uint8_t *replyTag, bool replyECIES) {
|
||||
int cnt = excludedFloodfills.size();
|
||||
auto m = cnt > 7 ? NewI2NPMessage() : NewI2NPShortMessage();
|
||||
uint8_t *buf = m->GetPayload();
|
||||
|
@ -187,17 +167,14 @@ namespace i2p
|
|||
buf += 4;
|
||||
|
||||
// excluded
|
||||
if (cnt > 512)
|
||||
{
|
||||
if (cnt > 512) {
|
||||
LogPrint(eLogWarning, "I2NP: Too many peers to exclude ", cnt, " for DatabaseLookup");
|
||||
cnt = 0;
|
||||
}
|
||||
htobe16buf(buf, cnt);
|
||||
buf += 2;
|
||||
if (cnt > 0)
|
||||
{
|
||||
for (auto& it: excludedFloodfills)
|
||||
{
|
||||
if (cnt > 0) {
|
||||
for (auto &it: excludedFloodfills) {
|
||||
memcpy(buf, it, 32);
|
||||
buf += 32;
|
||||
}
|
||||
|
@ -205,13 +182,10 @@ namespace i2p
|
|||
// encryption
|
||||
memcpy(buf, replyKey, 32);
|
||||
buf[32] = 1; // 1 tag
|
||||
if (replyECIES)
|
||||
{
|
||||
if (replyECIES) {
|
||||
memcpy(buf + 33, replyTag, 8); // 8 bytes tag
|
||||
buf += 41;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
memcpy(buf + 33, replyTag, 32); // 32 bytes tag
|
||||
buf += 65;
|
||||
}
|
||||
|
@ -222,8 +196,7 @@ namespace i2p
|
|||
}
|
||||
|
||||
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();
|
||||
uint8_t *buf = m->GetPayload();
|
||||
size_t len = 0;
|
||||
|
@ -231,8 +204,7 @@ namespace i2p
|
|||
len += 32;
|
||||
buf[len] = routers.size();
|
||||
len++;
|
||||
for (const auto& it: routers)
|
||||
{
|
||||
for (const auto &it: routers) {
|
||||
memcpy(buf + len, it, 32);
|
||||
len += 32;
|
||||
}
|
||||
|
@ -244,13 +216,12 @@ namespace i2p
|
|||
}
|
||||
|
||||
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
|
||||
router = context.GetSharedRouterInfo();
|
||||
|
||||
if (!router->GetBuffer ())
|
||||
{
|
||||
if (!router->GetBuffer()) {
|
||||
LogPrint(eLogError, "I2NP: Invalid RouterInfo buffer for DatabaseStore");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -262,17 +233,13 @@ namespace i2p
|
|||
payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo
|
||||
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
|
||||
uint8_t *buf = payload + DATABASE_STORE_HEADER_SIZE;
|
||||
if (replyToken)
|
||||
{
|
||||
if (replyTunnel)
|
||||
{
|
||||
if (replyToken) {
|
||||
if (replyTunnel) {
|
||||
htobe32buf(buf, replyTunnel->GetNextTunnelID());
|
||||
buf += 4; // reply tunnelID
|
||||
memcpy(buf, replyTunnel->GetNextIdentHash(), 32);
|
||||
buf += 32; // reply tunnel gateway
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
memset(buf, 0, 4); // zero tunnelID means direct reply
|
||||
buf += 4;
|
||||
memcpy(buf, context.GetIdentHash(), 32);
|
||||
|
@ -286,25 +253,22 @@ namespace i2p
|
|||
size_t size = 0;
|
||||
if (router->GetBufferLen() + (buf - payload) <= 940) // fits one tunnel message
|
||||
size = i2p::data::GzipNoCompression(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len);
|
||||
else
|
||||
{
|
||||
else {
|
||||
i2p::data::GzipDeflator deflator;
|
||||
size = deflator.Deflate(router->GetBuffer(), router->GetBufferLen(), buf, m->maxLen - m->len);
|
||||
}
|
||||
if (size)
|
||||
{
|
||||
if (size) {
|
||||
htobe16buf(sizePtr, size); // size
|
||||
m->len += size;
|
||||
}
|
||||
else
|
||||
} else
|
||||
m = nullptr;
|
||||
if (m)
|
||||
m->FillI2NPMessageHeader(eI2NPDatabaseStore);
|
||||
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;
|
||||
auto m = NewI2NPShortMessage();
|
||||
uint8_t *payload = m->GetPayload();
|
||||
|
@ -319,8 +283,9 @@ namespace i2p
|
|||
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;
|
||||
auto m = NewI2NPShortMessage();
|
||||
uint8_t *payload = m->GetPayload();
|
||||
|
@ -328,16 +293,13 @@ namespace i2p
|
|||
payload[DATABASE_STORE_TYPE_OFFSET] = leaseSet->GetStoreType(); // LeaseSet or LeaseSet2
|
||||
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
|
||||
size_t size = DATABASE_STORE_HEADER_SIZE;
|
||||
if (replyToken && replyTunnel)
|
||||
{
|
||||
if (replyTunnel)
|
||||
{
|
||||
if (replyToken && replyTunnel) {
|
||||
if (replyTunnel) {
|
||||
htobe32buf(payload + size, replyTunnel->GetNextTunnelID());
|
||||
size += 4; // reply tunnelID
|
||||
memcpy(payload + size, replyTunnel->GetNextIdentHash(), 32);
|
||||
size += 32; // reply tunnel gateway
|
||||
}
|
||||
else
|
||||
} else
|
||||
htobe32buf(payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
|
||||
}
|
||||
memcpy(payload + size, leaseSet->GetBuffer(), leaseSet->GetBufferLen());
|
||||
|
@ -347,43 +309,38 @@ namespace i2p
|
|||
return m;
|
||||
}
|
||||
|
||||
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
bool IsRouterInfoMsg(std::shared_ptr<I2NPMessage> msg) {
|
||||
if (!msg || msg->GetTypeID() != eI2NPDatabaseStore) return false;
|
||||
return !msg->GetPayload()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||
}
|
||||
|
||||
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
|
||||
{
|
||||
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels)
|
||||
{
|
||||
void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels) {
|
||||
if (maxNumTransitTunnels > 0 && g_MaxNumTransitTunnels != maxNumTransitTunnels) {
|
||||
LogPrint(eLogDebug, "I2NP: Max number of transit tunnels set to ", maxNumTransitTunnels);
|
||||
g_MaxNumTransitTunnels = maxNumTransitTunnels;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GetMaxNumTransitTunnels ()
|
||||
{
|
||||
uint16_t GetMaxNumTransitTunnels() {
|
||||
return g_MaxNumTransitTunnels;
|
||||
}
|
||||
|
||||
static bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
static bool HandleBuildRequestRecords(int num, uint8_t *records, uint8_t *clearText) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
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");
|
||||
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;
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels() &&
|
||||
i2p::tunnel::tunnels.GetTransitTunnels().size() <= g_MaxNumTransitTunnels &&
|
||||
!i2p::transport::transports.IsBandwidthExceeded() &&
|
||||
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
{
|
||||
!i2p::transport::transports.IsTransitBandwidthExceeded()) {
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel(
|
||||
bufbe32toh(clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_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_ENDPOINT_FLAG);
|
||||
i2p::tunnel::tunnels.AddTransitTunnel(transitTunnel);
|
||||
}
|
||||
else
|
||||
} else
|
||||
retCode = 30; // always reject with bandwidth reason (30)
|
||||
|
||||
memset(record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
// encrypt reply
|
||||
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;
|
||||
if (j == i)
|
||||
{
|
||||
if (j == i) {
|
||||
uint8_t nonce[12];
|
||||
memset(nonce, 0, 12);
|
||||
auto &noiseState = i2p::context.GetCurrentNoiseState();
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
encryption.SetKey(clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV(clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
|
@ -429,132 +382,111 @@ namespace i2p
|
|||
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];
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel(replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
if (tunnel) {
|
||||
// endpoint of inbound tunnel
|
||||
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");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddInboundTunnel(tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||
{
|
||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
if (HandleBuildRequestRecords(num, buf + 1, clearText)) {
|
||||
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] &
|
||||
TUNNEL_BUILD_RECORD_ENDPOINT_FLAG) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
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,
|
||||
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
bufbe32toh(clearText +
|
||||
ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
} else
|
||||
transports.SendMessage(clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
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");
|
||||
}
|
||||
|
||||
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];
|
||||
LogPrint(eLogDebug, "I2NP: TunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel(replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
if (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");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddOutboundTunnel(tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID(), " has been declined");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
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];
|
||||
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);
|
||||
return;
|
||||
}
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel(replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
if (tunnel) {
|
||||
// endpoint of inbound tunnel
|
||||
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");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateEstablished);
|
||||
i2p::tunnel::tunnels.AddInboundTunnel(tunnel);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID(), " has been declined");
|
||||
tunnel->SetState(i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const uint8_t *record = buf + 1;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
if (!memcmp (record, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
|
||||
{
|
||||
for (int i = 0; i < num; i++) {
|
||||
if (!memcmp(record, (const uint8_t *) i2p::context.GetRouterInfo().GetIdentHash(), 16)) {
|
||||
LogPrint(eLogDebug, "I2NP: Short request record ", i, " is ours");
|
||||
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);
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}
|
||||
auto &noiseState = i2p::context.GetCurrentNoiseState();
|
||||
|
@ -564,12 +496,10 @@ namespace i2p
|
|||
i2p::crypto::HKDF(noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
|
||||
memcpy(layerKey, noiseState.m_CK + 32, 32);
|
||||
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);
|
||||
memcpy(ivKey, noiseState.m_CK + 32, 32);
|
||||
}
|
||||
else
|
||||
} else
|
||||
memcpy(ivKey, noiseState.m_CK, 32);
|
||||
|
||||
// check if we accept this tunnel
|
||||
|
@ -579,8 +509,7 @@ namespace i2p
|
|||
i2p::transport::transports.IsBandwidthExceeded() ||
|
||||
i2p::transport::transports.IsTransitBandwidthExceeded())
|
||||
retCode = 30;
|
||||
if (!retCode)
|
||||
{
|
||||
if (!retCode) {
|
||||
// create new transit tunnel
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel(
|
||||
bufbe32toh(clearText + SHORT_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
|
@ -596,30 +525,28 @@ namespace i2p
|
|||
uint8_t nonce[12];
|
||||
memset(nonce, 0, 12);
|
||||
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 #
|
||||
if (j == i)
|
||||
{
|
||||
if (j == i) {
|
||||
memset(reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||
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");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
i2p::crypto::ChaCha20(reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
|
||||
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
|
||||
}
|
||||
// send reply
|
||||
if (isEndpoint)
|
||||
{
|
||||
if (isEndpoint) {
|
||||
auto replyMsg = NewI2NPShortMessage();
|
||||
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(),
|
||||
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);
|
||||
// we send it to reply tunnel
|
||||
transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateTunnelGatewayMsg(
|
||||
bufbe32toh(clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
i2p::garlic::WrapECIESX25519Message(replyMsg,
|
||||
noiseState.m_CK + 32, tag)));
|
||||
} else {
|
||||
// IBGW is local
|
||||
uint32_t tunnelID = bufbe32toh(clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET);
|
||||
auto tunnel = i2p::tunnel::tunnels.GetTunnel(tunnelID);
|
||||
|
@ -641,27 +568,25 @@ namespace i2p
|
|||
else
|
||||
LogPrint(eLogWarning, "I2NP: Tunnel ", tunnelID, " not found for short tunnel build reply");
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
transports.SendMessage(clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage(eI2NPShortTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
bufbe32toh(clearText +
|
||||
SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
return;
|
||||
}
|
||||
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);
|
||||
msg->Concat(buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
|
||||
msg->FillI2NPMessageHeader(eI2NPTunnelData);
|
||||
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);
|
||||
htobe32buf(msg->GetPayload(), tunnelID);
|
||||
msg->len += 4; // tunnelID
|
||||
|
@ -670,15 +595,13 @@ namespace i2p
|
|||
return msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (bool endpoint)
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg(bool endpoint) {
|
||||
auto msg = NewI2NPTunnelMessage(endpoint);
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
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);
|
||||
uint8_t *payload = msg->GetPayload();
|
||||
htobe32buf(payload + TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET, tunnelID);
|
||||
|
@ -690,10 +613,8 @@ namespace i2p
|
|||
return msg;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE)
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg) {
|
||||
if (msg->offset >= I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE) {
|
||||
// message is capable to be used without copying
|
||||
uint8_t *payload = msg->GetBuffer() - TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
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->FillI2NPMessageHeader(eI2NPTunnelGateway);
|
||||
return msg;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return CreateTunnelGatewayMsg(tunnelID, msg->GetBuffer(), msg->GetLength());
|
||||
}
|
||||
|
||||
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);
|
||||
size_t gatewayMsgOffset = I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
msg->offset += gatewayMsgOffset;
|
||||
|
@ -727,26 +646,21 @@ namespace i2p
|
|||
return msg;
|
||||
}
|
||||
|
||||
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len)
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE_OFFSET + 2)
|
||||
{
|
||||
size_t GetI2NPMessageLength(const uint8_t *msg, size_t len) {
|
||||
if (len < I2NP_HEADER_SIZE_OFFSET + 2) {
|
||||
LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header");
|
||||
return len;
|
||||
}
|
||||
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);
|
||||
l = len;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len)
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE)
|
||||
{
|
||||
void HandleI2NPMessage(uint8_t *msg, size_t len) {
|
||||
if (len < I2NP_HEADER_SIZE) {
|
||||
LogPrint(eLogError, "I2NP: Message length ", len, " is smaller than header");
|
||||
return;
|
||||
}
|
||||
|
@ -756,13 +670,11 @@ namespace i2p
|
|||
uint8_t *buf = msg + I2NP_HEADER_SIZE;
|
||||
auto size = bufbe16toh(msg + I2NP_HEADER_SIZE_OFFSET);
|
||||
len -= I2NP_HEADER_SIZE;
|
||||
if (size > len)
|
||||
{
|
||||
if (size > len) {
|
||||
LogPrint(eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
|
||||
size = len;
|
||||
}
|
||||
switch (typeID)
|
||||
{
|
||||
switch (typeID) {
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg(msgID, buf, size);
|
||||
break;
|
||||
|
@ -786,22 +698,18 @@ namespace i2p
|
|||
}
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
void HandleI2NPMessage(std::shared_ptr<I2NPMessage> msg) {
|
||||
if (msg) {
|
||||
uint8_t typeID = msg->GetTypeID();
|
||||
LogPrint(eLogDebug, "I2NP: Handling message with type ", (int) typeID);
|
||||
switch (typeID)
|
||||
{
|
||||
switch (typeID) {
|
||||
case eI2NPTunnelData:
|
||||
i2p::tunnel::tunnels.PostTunnelData(msg);
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
i2p::tunnel::tunnels.PostTunnelData(msg);
|
||||
break;
|
||||
case eI2NPGarlic:
|
||||
{
|
||||
case eI2NPGarlic: {
|
||||
if (msg->from && msg->from->GetTunnelPool())
|
||||
msg->from->GetTunnelPool()->ProcessGarlicMessage(msg);
|
||||
else
|
||||
|
@ -814,8 +722,7 @@ namespace i2p
|
|||
// forward to netDb
|
||||
i2p::data::netdb.PostI2NPMsg(msg);
|
||||
break;
|
||||
case eI2NPDeliveryStatus:
|
||||
{
|
||||
case eI2NPDeliveryStatus: {
|
||||
if (msg->from && msg->from->GetTunnelPool())
|
||||
msg->from->GetTunnelPool()->ProcessDeliveryStatus(msg);
|
||||
else
|
||||
|
@ -837,17 +744,13 @@ namespace i2p
|
|||
}
|
||||
}
|
||||
|
||||
I2NPMessagesHandler::~I2NPMessagesHandler ()
|
||||
{
|
||||
I2NPMessagesHandler::~I2NPMessagesHandler() {
|
||||
Flush();
|
||||
}
|
||||
|
||||
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage>&& msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
switch (msg->GetTypeID ())
|
||||
{
|
||||
void I2NPMessagesHandler::PutNextMessage(std::shared_ptr<I2NPMessage> &&msg) {
|
||||
if (msg) {
|
||||
switch (msg->GetTypeID()) {
|
||||
case eI2NPTunnelData:
|
||||
m_TunnelMsgs.push_back(msg);
|
||||
break;
|
||||
|
@ -860,15 +763,12 @@ namespace i2p
|
|||
}
|
||||
}
|
||||
|
||||
void I2NPMessagesHandler::Flush ()
|
||||
{
|
||||
if (!m_TunnelMsgs.empty ())
|
||||
{
|
||||
void I2NPMessagesHandler::Flush() {
|
||||
if (!m_TunnelMsgs.empty()) {
|
||||
i2p::tunnel::tunnels.PostTunnelData(m_TunnelMsgs);
|
||||
m_TunnelMsgs.clear();
|
||||
}
|
||||
if (!m_TunnelGatewayMsgs.empty ())
|
||||
{
|
||||
if (!m_TunnelGatewayMsgs.empty()) {
|
||||
i2p::tunnel::tunnels.PostTunnelData(m_TunnelGatewayMsgs);
|
||||
m_TunnelGatewayMsgs.clear();
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "LeaseSet.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i2p {
|
||||
// I2NP header
|
||||
const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
|
||||
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_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_EXPIRATION_OFFSET = 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_REQUEST_EXPIRATION_OFFSET =
|
||||
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_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_RET_OFFSET = 201;
|
||||
|
||||
enum I2NPMessageType
|
||||
{
|
||||
enum I2NPMessageType {
|
||||
eI2NPDummyMsg = 0,
|
||||
eI2NPDatabaseStore = 1,
|
||||
eI2NPDatabaseLookup = 2,
|
||||
|
@ -132,9 +132,9 @@ namespace i2p
|
|||
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
|
||||
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
namespace tunnel {
|
||||
class InboundTunnel;
|
||||
|
||||
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_CLOCK_SKEW = 60 * 1000; // 1 minute in milliseconds
|
||||
|
||||
struct I2NPMessage
|
||||
{
|
||||
struct I2NPMessage {
|
||||
uint8_t *buf;
|
||||
size_t len, offset, maxLen;
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
||||
|
@ -154,19 +153,32 @@ namespace tunnel
|
|||
|
||||
// header accessors
|
||||
uint8_t *GetHeader() { return GetBuffer(); };
|
||||
|
||||
const uint8_t *GetHeader() const { return GetBuffer(); };
|
||||
|
||||
void SetTypeID(uint8_t typeID) { GetHeader()[I2NP_HEADER_TYPEID_OFFSET] = typeID; };
|
||||
|
||||
uint8_t GetTypeID() const { return GetHeader()[I2NP_HEADER_TYPEID_OFFSET]; };
|
||||
|
||||
void SetMsgID(uint32_t msgID) { htobe32buf(GetHeader() + I2NP_HEADER_MSGID_OFFSET, msgID); };
|
||||
|
||||
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); };
|
||||
|
||||
void SetSize(uint16_t size) { htobe16buf(GetHeader() + I2NP_HEADER_SIZE_OFFSET, size); };
|
||||
|
||||
uint16_t GetSize() const { return bufbe16toh(GetHeader() + I2NP_HEADER_SIZE_OFFSET); };
|
||||
|
||||
void UpdateSize() { SetSize(GetPayloadLength()); };
|
||||
|
||||
void SetChks(uint8_t chks) { GetHeader()[I2NP_HEADER_CHKS_OFFSET] = chks; };
|
||||
void UpdateChks ()
|
||||
{
|
||||
|
||||
void UpdateChks() {
|
||||
uint8_t hash[32];
|
||||
SHA256(GetPayload(), GetPayloadLength(), hash);
|
||||
GetHeader()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
||||
|
@ -174,25 +186,27 @@ namespace tunnel
|
|||
|
||||
// payload
|
||||
uint8_t *GetPayload() { return GetBuffer() + I2NP_HEADER_SIZE; };
|
||||
|
||||
const uint8_t *GetPayload() const { return GetBuffer() + I2NP_HEADER_SIZE; };
|
||||
|
||||
uint8_t *GetBuffer() { return buf + offset; };
|
||||
|
||||
const uint8_t *GetBuffer() const { return buf + offset; };
|
||||
|
||||
size_t GetLength() const { return len - offset; };
|
||||
|
||||
size_t GetPayloadLength() const { return GetLength() - I2NP_HEADER_SIZE; };
|
||||
|
||||
void Align (size_t alignment)
|
||||
{
|
||||
void Align(size_t alignment) {
|
||||
if (len + alignment > maxLen) return;
|
||||
size_t rem = ((size_t) GetBuffer()) % alignment;
|
||||
if (rem)
|
||||
{
|
||||
if (rem) {
|
||||
offset += (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
|
||||
if (len + len1 > maxLen) len1 = maxLen - len;
|
||||
memcpy(buf + len, buf1, len1);
|
||||
|
@ -200,8 +214,7 @@ namespace tunnel
|
|||
return len1;
|
||||
}
|
||||
|
||||
I2NPMessage& operator=(const I2NPMessage& other)
|
||||
{
|
||||
I2NPMessage &operator=(const I2NPMessage &other) {
|
||||
memcpy(buf + offset, other.buf + other.offset, other.GetLength());
|
||||
len = offset + other.GetLength();
|
||||
from = other.from;
|
||||
|
@ -210,6 +223,7 @@ namespace tunnel
|
|||
|
||||
// for SSU only
|
||||
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
|
||||
{
|
||||
const uint8_t *ssu = GetSSUHeader();
|
||||
|
@ -219,21 +233,25 @@ namespace tunnel
|
|||
SetSize(len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks(0);
|
||||
}
|
||||
|
||||
uint32_t ToSSU() // return msgID
|
||||
{
|
||||
uint8_t header[I2NP_HEADER_SIZE];
|
||||
memcpy(header, GetHeader(), I2NP_HEADER_SIZE);
|
||||
uint8_t *ssu = GetSSUHeader();
|
||||
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);
|
||||
return bufbe32toh(header + I2NP_HEADER_MSGID_OFFSET);
|
||||
}
|
||||
|
||||
// for NTCP2 only
|
||||
uint8_t *GetNTCP2Header() { return GetPayload() - I2NP_NTCP2_HEADER_SIZE; };
|
||||
|
||||
size_t GetNTCP2Length() const { return GetPayloadLength() + I2NP_NTCP2_HEADER_SIZE; };
|
||||
void FromNTCP2 ()
|
||||
{
|
||||
|
||||
void FromNTCP2() {
|
||||
const uint8_t *ntcp2 = GetNTCP2Header();
|
||||
memcpy(GetHeader() + I2NP_HEADER_TYPEID_OFFSET, ntcp2 + I2NP_HEADER_TYPEID_OFFSET, 5); // typeid + msgid
|
||||
SetExpiration(bufbe32toh(ntcp2 + I2NP_HEADER_EXPIRATION_OFFSET) * 1000LL);
|
||||
|
@ -241,67 +259,98 @@ namespace tunnel
|
|||
SetChks(0);
|
||||
}
|
||||
|
||||
void ToNTCP2 ()
|
||||
{
|
||||
void ToNTCP2() {
|
||||
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
|
||||
}
|
||||
|
||||
void FillI2NPMessageHeader(I2NPMessageType msgType, uint32_t replyMsgID = 0, bool checksum = true);
|
||||
|
||||
void RenewI2NPMessageHeader();
|
||||
|
||||
bool IsExpired() const;
|
||||
};
|
||||
|
||||
template<int sz>
|
||||
struct I2NPMessageBuffer: public I2NPMessage
|
||||
{
|
||||
I2NPMessageBuffer () { buf = m_Buffer; maxLen = sz; };
|
||||
struct I2NPMessageBuffer : public I2NPMessage {
|
||||
I2NPMessageBuffer() {
|
||||
buf = m_Buffer;
|
||||
maxLen = sz;
|
||||
};
|
||||
uint8_t m_Buffer[sz + 32]; // 16 alignment + 16 padding
|
||||
};
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage();
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage();
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage(bool endpoint);
|
||||
|
||||
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> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
|
||||
std::shared_ptr<I2NPMessage>
|
||||
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> CreateDeliveryStatusMsg(uint32_t msgID);
|
||||
|
||||
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,
|
||||
const std::set<i2p::data::IdentHash> &excludedFloodfills,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
|
||||
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
|
||||
const uint8_t *replyKey, const uint8_t *replyTag,
|
||||
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);
|
||||
|
||||
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> 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, I2NPMessageType msgType,
|
||||
const uint8_t *buf, size_t len, uint32_t replyMsgID = 0);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg(uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
size_t GetI2NPMessageLength(const uint8_t *msg, size_t len);
|
||||
|
||||
void HandleI2NPMessage(uint8_t *msg, size_t len);
|
||||
|
||||
void HandleI2NPMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
class I2NPMessagesHandler
|
||||
{
|
||||
class I2NPMessagesHandler {
|
||||
public:
|
||||
|
||||
~I2NPMessagesHandler();
|
||||
|
||||
void PutNextMessage(std::shared_ptr<I2NPMessage> &&msg);
|
||||
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
|
@ -310,7 +359,9 @@ namespace tunnel
|
|||
};
|
||||
|
||||
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
|
||||
|
||||
void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels);
|
||||
|
||||
uint16_t GetMaxNumTransitTunnels();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,39 +14,35 @@
|
|||
#include "LittleBigEndian.h"
|
||||
|
||||
#ifdef NEEDS_LOCAL_ENDIAN
|
||||
uint16_t htobe16(uint16_t int16)
|
||||
{
|
||||
|
||||
uint16_t htobe16(uint16_t int16) {
|
||||
BigEndian<uint16_t> u16(int16);
|
||||
return u16.raw_value;
|
||||
}
|
||||
|
||||
uint32_t htobe32(uint32_t int32)
|
||||
{
|
||||
uint32_t htobe32(uint32_t int32) {
|
||||
BigEndian<uint32_t> u32(int32);
|
||||
return u32.raw_value;
|
||||
}
|
||||
|
||||
uint64_t htobe64(uint64_t int64)
|
||||
{
|
||||
uint64_t htobe64(uint64_t int64) {
|
||||
BigEndian<uint64_t> u64(int64);
|
||||
return u64.raw_value;
|
||||
}
|
||||
|
||||
uint16_t be16toh(uint16_t big16)
|
||||
{
|
||||
uint16_t be16toh(uint16_t big16) {
|
||||
LittleEndian<uint16_t> u16(big16);
|
||||
return u16.raw_value;
|
||||
}
|
||||
|
||||
uint32_t be32toh(uint32_t big32)
|
||||
{
|
||||
uint32_t be32toh(uint32_t big32) {
|
||||
LittleEndian<uint32_t> u32(big32);
|
||||
return u32.raw_value;
|
||||
}
|
||||
|
||||
uint64_t be64toh(uint64_t big64)
|
||||
{
|
||||
uint64_t be64toh(uint64_t big64) {
|
||||
LittleEndian<uint64_t> u64(big64);
|
||||
return u64.raw_value;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#ifndef I2PENDIAN_H__
|
||||
#define I2PENDIAN_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -53,13 +54,19 @@
|
|||
|
||||
#else
|
||||
#define NEEDS_LOCAL_ENDIAN
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
uint16_t htobe16(uint16_t int16);
|
||||
|
||||
uint32_t htobe32(uint32_t int32);
|
||||
|
||||
uint64_t htobe64(uint64_t int64);
|
||||
|
||||
uint16_t be16toh(uint16_t big16);
|
||||
|
||||
uint32_t be32toh(uint32_t big32);
|
||||
|
||||
uint64_t be64toh(uint64_t big64);
|
||||
|
||||
// assume LittleEndine
|
||||
|
@ -72,99 +79,81 @@ uint64_t be64toh(uint64_t big64);
|
|||
|
||||
#endif
|
||||
|
||||
inline uint16_t buf16toh(const void *buf)
|
||||
{
|
||||
inline uint16_t buf16toh(const void *buf) {
|
||||
uint16_t b16;
|
||||
memcpy(&b16, buf, sizeof(uint16_t));
|
||||
return b16;
|
||||
}
|
||||
|
||||
inline uint32_t buf32toh(const void *buf)
|
||||
{
|
||||
inline uint32_t buf32toh(const void *buf) {
|
||||
uint32_t b32;
|
||||
memcpy(&b32, buf, sizeof(uint32_t));
|
||||
return b32;
|
||||
}
|
||||
|
||||
inline uint64_t buf64toh(const void *buf)
|
||||
{
|
||||
inline uint64_t buf64toh(const void *buf) {
|
||||
uint64_t b64;
|
||||
memcpy(&b64, buf, sizeof(uint64_t));
|
||||
return b64;
|
||||
}
|
||||
|
||||
inline uint16_t bufbe16toh(const void *buf)
|
||||
{
|
||||
inline uint16_t bufbe16toh(const void *buf) {
|
||||
return be16toh(buf16toh(buf));
|
||||
}
|
||||
|
||||
inline uint32_t bufbe32toh(const void *buf)
|
||||
{
|
||||
inline uint32_t bufbe32toh(const void *buf) {
|
||||
return be32toh(buf32toh(buf));
|
||||
}
|
||||
|
||||
inline uint64_t bufbe64toh(const void *buf)
|
||||
{
|
||||
inline uint64_t bufbe64toh(const void *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));
|
||||
}
|
||||
|
||||
inline void htobuf32(void *buf, uint32_t b32)
|
||||
{
|
||||
inline void htobuf32(void *buf, uint32_t b32) {
|
||||
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));
|
||||
}
|
||||
|
||||
inline void htobe16buf(void *buf, uint16_t big16)
|
||||
{
|
||||
inline void htobe16buf(void *buf, uint16_t 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));
|
||||
}
|
||||
|
||||
inline void htobe64buf(void *buf, uint64_t big64)
|
||||
{
|
||||
inline void htobe64buf(void *buf, uint64_t 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));
|
||||
}
|
||||
|
||||
inline void htole32buf(void *buf, uint32_t big32)
|
||||
{
|
||||
inline void htole32buf(void *buf, uint32_t 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));
|
||||
}
|
||||
|
||||
inline uint16_t bufle16toh(const void *buf)
|
||||
{
|
||||
inline uint16_t bufle16toh(const void *buf) {
|
||||
return le16toh(buf16toh(buf));
|
||||
}
|
||||
|
||||
inline uint32_t bufle32toh(const void *buf)
|
||||
{
|
||||
inline uint32_t bufle32toh(const void *buf) {
|
||||
return le32toh(buf32toh(buf));
|
||||
}
|
||||
|
||||
inline uint64_t bufle64toh(const void *buf)
|
||||
{
|
||||
inline uint64_t bufle64toh(const void *buf) {
|
||||
return le64toh(buf64toh(buf));
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,9 @@
|
|||
#include "Timestamp.h"
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
Identity& Identity::operator=(const Keys& keys)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
Identity &Identity::operator=(const Keys &keys) {
|
||||
// copy public and signing keys together
|
||||
memcpy(publicKey, keys.publicKey, sizeof(publicKey));
|
||||
memcpy(signingKey, keys.signingKey, sizeof(signingKey));
|
||||
|
@ -25,8 +22,7 @@ namespace data
|
|||
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) {
|
||||
// buffer too small, don't overflow
|
||||
return 0;
|
||||
|
@ -35,49 +31,40 @@ namespace data
|
|||
return DEFAULT_IDENTITY_SIZE;
|
||||
}
|
||||
|
||||
IdentHash Identity::Hash () const
|
||||
{
|
||||
IdentHash Identity::Hash() const {
|
||||
IdentHash hash;
|
||||
SHA256(publicKey, DEFAULT_IDENTITY_SIZE, hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx() :
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
m_ExtendedLen(0) {
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
||||
{
|
||||
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||
{
|
||||
IdentityEx::IdentityEx(const uint8_t *publicKey, const uint8_t *signingKey, SigningKeyType type,
|
||||
CryptoKeyType cryptoType) {
|
||||
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) {
|
||||
memcpy(m_StandardIdentity.publicKey, publicKey, 32);
|
||||
RAND_bytes(m_StandardIdentity.publicKey + 32, 224);
|
||||
}
|
||||
else
|
||||
} else
|
||||
memcpy(m_StandardIdentity.publicKey, publicKey, 256);
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1) {
|
||||
size_t excessLen = 0;
|
||||
uint8_t *excessBuf = nullptr;
|
||||
switch (type)
|
||||
{
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
{
|
||||
switch (type) {
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: {
|
||||
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
|
||||
RAND_bytes(m_StandardIdentity.signingKey, padding);
|
||||
memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
|
||||
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
|
||||
RAND_bytes(m_StandardIdentity.signingKey, padding);
|
||||
memcpy(m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH);
|
||||
break;
|
||||
}
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
|
||||
{
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: {
|
||||
memcpy(m_StandardIdentity.signingKey, signingKey, 128);
|
||||
excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132 - 128
|
||||
excessBuf = new uint8_t[excessLen];
|
||||
|
@ -90,23 +77,22 @@ namespace data
|
|||
LogPrint(eLogError, "Identity: RSA signing key type ", (int) type, " is not supported");
|
||||
break;
|
||||
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
|
||||
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;
|
||||
}
|
||||
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256:
|
||||
{
|
||||
case SIGNING_KEY_TYPE_GOSTR3410_CRYPTO_PRO_A_GOSTR3411_256: {
|
||||
// 256
|
||||
size_t padding = 128 - i2p::crypto::GOSTR3410_256_PUBLIC_KEY_LENGTH; // 64 = 128 - 64
|
||||
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;
|
||||
}
|
||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512:
|
||||
{
|
||||
case SIGNING_KEY_TYPE_GOSTR3410_TC26_A_512_GOSTR3411_512: {
|
||||
// 512
|
||||
// no padding, key length is 128
|
||||
memcpy(m_StandardIdentity.signingKey, signingKey, i2p::crypto::GOSTR3410_512_PUBLIC_KEY_LENGTH);
|
||||
|
@ -122,10 +108,8 @@ namespace data
|
|||
// fill extended buffer
|
||||
htobe16buf(m_ExtendedBuffer, type);
|
||||
htobe16buf(m_ExtendedBuffer + 2, cryptoType);
|
||||
if (excessLen && excessBuf)
|
||||
{
|
||||
if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4)
|
||||
{
|
||||
if (excessLen && excessBuf) {
|
||||
if (excessLen > MAX_EXTENDED_BUFFER_SIZE - 4) {
|
||||
LogPrint(eLogError, "Identity: Unexpected excessive signing key len ", excessLen);
|
||||
excessLen = MAX_EXTENDED_BUFFER_SIZE - 4;
|
||||
}
|
||||
|
@ -134,8 +118,7 @@ namespace data
|
|||
}
|
||||
// calculate ident hash
|
||||
RecalculateIdentHash();
|
||||
}
|
||||
else // DSA-SHA1
|
||||
} else // DSA-SHA1
|
||||
{
|
||||
memcpy(m_StandardIdentity.signingKey, signingKey, sizeof(m_StandardIdentity.signingKey));
|
||||
memset(m_StandardIdentity.certificate, 0, sizeof(m_StandardIdentity.certificate));
|
||||
|
@ -145,8 +128,7 @@ namespace data
|
|||
CreateVerifier();
|
||||
}
|
||||
|
||||
void IdentityEx::RecalculateIdentHash(uint8_t * buf)
|
||||
{
|
||||
void IdentityEx::RecalculateIdentHash(uint8_t *buf) {
|
||||
bool dofree = buf == nullptr;
|
||||
size_t sz = GetFullLen();
|
||||
if (!buf)
|
||||
|
@ -158,36 +140,30 @@ namespace data
|
|||
}
|
||||
|
||||
IdentityEx::IdentityEx(const uint8_t *buf, size_t len) :
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
m_ExtendedLen(0) {
|
||||
FromBuffer(buf, len);
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx(const IdentityEx &other) :
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
m_ExtendedLen(0) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
IdentityEx::IdentityEx(const Identity &standard) :
|
||||
m_ExtendedLen (0)
|
||||
{
|
||||
m_ExtendedLen(0) {
|
||||
*this = standard;
|
||||
}
|
||||
|
||||
IdentityEx::~IdentityEx ()
|
||||
{
|
||||
IdentityEx::~IdentityEx() {
|
||||
delete m_Verifier;
|
||||
}
|
||||
|
||||
IdentityEx& IdentityEx::operator=(const IdentityEx& other)
|
||||
{
|
||||
IdentityEx &IdentityEx::operator=(const IdentityEx &other) {
|
||||
memcpy(&m_StandardIdentity, &other.m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
|
||||
m_IdentHash = other.m_IdentHash;
|
||||
|
||||
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;
|
||||
memcpy(m_ExtendedBuffer, other.m_ExtendedBuffer, m_ExtendedLen);
|
||||
}
|
||||
|
@ -198,8 +174,7 @@ namespace data
|
|||
return *this;
|
||||
}
|
||||
|
||||
IdentityEx& IdentityEx::operator=(const Identity& standard)
|
||||
{
|
||||
IdentityEx &IdentityEx::operator=(const Identity &standard) {
|
||||
m_StandardIdentity = standard;
|
||||
m_IdentHash = m_StandardIdentity.Hash();
|
||||
|
||||
|
@ -211,31 +186,25 @@ namespace data
|
|||
return *this;
|
||||
}
|
||||
|
||||
size_t IdentityEx::FromBuffer (const uint8_t * buf, size_t len)
|
||||
{
|
||||
if (len < DEFAULT_IDENTITY_SIZE)
|
||||
{
|
||||
size_t IdentityEx::FromBuffer(const uint8_t *buf, size_t len) {
|
||||
if (len < DEFAULT_IDENTITY_SIZE) {
|
||||
LogPrint(eLogError, "Identity: Buffer length ", len, " is too small");
|
||||
return 0;
|
||||
}
|
||||
memcpy(&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
|
||||
|
||||
m_ExtendedLen = bufbe16toh(m_StandardIdentity.certificate + 1);
|
||||
if (m_ExtendedLen)
|
||||
{
|
||||
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len)
|
||||
{
|
||||
if (m_ExtendedLen) {
|
||||
if (m_ExtendedLen + DEFAULT_IDENTITY_SIZE <= len) {
|
||||
if (m_ExtendedLen > MAX_EXTENDED_BUFFER_SIZE) m_ExtendedLen = MAX_EXTENDED_BUFFER_SIZE;
|
||||
memcpy(m_ExtendedBuffer, buf + DEFAULT_IDENTITY_SIZE, m_ExtendedLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ", len - DEFAULT_IDENTITY_SIZE);
|
||||
} else {
|
||||
LogPrint(eLogError, "Identity: Certificate length ", m_ExtendedLen, " exceeds buffer length ",
|
||||
len - DEFAULT_IDENTITY_SIZE);
|
||||
m_ExtendedLen = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
m_ExtendedLen = 0;
|
||||
SHA256(buf, GetFullLen(), m_IdentHash);
|
||||
|
||||
|
@ -245,8 +214,7 @@ namespace data
|
|||
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();
|
||||
if (fullLen > len) return 0; // buffer is too small and may overflow somewhere else
|
||||
memcpy(buf, &m_StandardIdentity, DEFAULT_IDENTITY_SIZE);
|
||||
|
@ -255,16 +223,14 @@ namespace data
|
|||
return fullLen;
|
||||
}
|
||||
|
||||
size_t IdentityEx::FromBase64(const std::string& s)
|
||||
{
|
||||
size_t IdentityEx::FromBase64(const std::string &s) {
|
||||
const size_t slen = s.length();
|
||||
std::vector<uint8_t> buf(slen); // binary data can't exceed base64
|
||||
const size_t len = Base64ToByteStream(s.c_str(), slen, buf.data(), slen);
|
||||
return FromBuffer(buf.data(), len);
|
||||
}
|
||||
|
||||
std::string IdentityEx::ToBase64 () const
|
||||
{
|
||||
std::string IdentityEx::ToBase64() const {
|
||||
const size_t bufLen = GetFullLen();
|
||||
const size_t strLen = Base64EncodingBufferSize(bufLen);
|
||||
std::vector<uint8_t> buf(bufLen);
|
||||
|
@ -274,68 +240,59 @@ namespace data
|
|||
return std::string(str.data(), l1);
|
||||
}
|
||||
|
||||
size_t IdentityEx::GetSigningPublicKeyLen () const
|
||||
{
|
||||
size_t IdentityEx::GetSigningPublicKeyLen() const {
|
||||
if (!m_Verifier) CreateVerifier();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetPublicKeyLen();
|
||||
return 128;
|
||||
}
|
||||
|
||||
const uint8_t * IdentityEx::GetSigningPublicKeyBuffer () const
|
||||
{
|
||||
const uint8_t *IdentityEx::GetSigningPublicKeyBuffer() const {
|
||||
auto keyLen = GetSigningPublicKeyLen();
|
||||
if (keyLen > 128) return nullptr; // P521
|
||||
return m_StandardIdentity.signingKey + 128 - keyLen;
|
||||
}
|
||||
|
||||
size_t IdentityEx::GetSigningPrivateKeyLen () const
|
||||
{
|
||||
size_t IdentityEx::GetSigningPrivateKeyLen() const {
|
||||
if (!m_Verifier) CreateVerifier();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetPrivateKeyLen();
|
||||
return GetSignatureLen() / 2;
|
||||
}
|
||||
|
||||
size_t IdentityEx::GetSignatureLen () const
|
||||
{
|
||||
size_t IdentityEx::GetSignatureLen() const {
|
||||
if (!m_Verifier) CreateVerifier();
|
||||
if (m_Verifier)
|
||||
return m_Verifier->GetSignatureLen();
|
||||
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)
|
||||
return m_Verifier->Verify(buf, len, signature);
|
||||
return false;
|
||||
}
|
||||
|
||||
SigningKeyType IdentityEx::GetSigningKeyType () const
|
||||
{
|
||||
SigningKeyType IdentityEx::GetSigningKeyType() const {
|
||||
if (m_StandardIdentity.certificate[0] == CERTIFICATE_TYPE_KEY && m_ExtendedLen >= 2)
|
||||
return bufbe16toh(m_ExtendedBuffer); // signing key
|
||||
return SIGNING_KEY_TYPE_DSA_SHA1;
|
||||
}
|
||||
|
||||
bool IdentityEx::IsRSA () const
|
||||
{
|
||||
bool IdentityEx::IsRSA() const {
|
||||
auto sigType = GetSigningKeyType();
|
||||
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)
|
||||
return bufbe16toh(m_ExtendedBuffer + 2); // crypto key
|
||||
return CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
}
|
||||
|
||||
i2p::crypto::Verifier * IdentityEx::CreateVerifier (SigningKeyType keyType)
|
||||
{
|
||||
switch (keyType)
|
||||
{
|
||||
i2p::crypto::Verifier *IdentityEx::CreateVerifier(SigningKeyType keyType) {
|
||||
switch (keyType) {
|
||||
case SIGNING_KEY_TYPE_DSA_SHA1:
|
||||
return new i2p::crypto::DSAVerifier();
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
|
@ -363,22 +320,20 @@ namespace data
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void IdentityEx::CreateVerifier () const
|
||||
{
|
||||
void IdentityEx::CreateVerifier() const {
|
||||
if (m_Verifier) return; // don't create again
|
||||
auto verifier = CreateVerifier(GetSigningKeyType());
|
||||
if (verifier)
|
||||
{
|
||||
if (verifier) {
|
||||
auto keyLen = verifier->GetPublicKeyLen();
|
||||
if (keyLen <= 128)
|
||||
verifier->SetPublicKey(m_StandardIdentity.signingKey + 128 - keyLen);
|
||||
else
|
||||
{
|
||||
else {
|
||||
// for P521
|
||||
uint8_t *signingKey = new uint8_t[keyLen];
|
||||
memcpy(signingKey, m_StandardIdentity.signingKey, 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);
|
||||
delete[] signingKey;
|
||||
}
|
||||
|
@ -386,8 +341,7 @@ namespace data
|
|||
UpdateVerifier(verifier);
|
||||
}
|
||||
|
||||
void IdentityEx::UpdateVerifier (i2p::crypto::Verifier * verifier) const
|
||||
{
|
||||
void IdentityEx::UpdateVerifier(i2p::crypto::Verifier *verifier) const {
|
||||
bool del = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
|
@ -400,8 +354,7 @@ namespace data
|
|||
delete verifier;
|
||||
}
|
||||
|
||||
void IdentityEx::DropVerifier () const
|
||||
{
|
||||
void IdentityEx::DropVerifier() const {
|
||||
i2p::crypto::Verifier *verifier;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_VerifierMutex);
|
||||
|
@ -411,10 +364,9 @@ namespace data
|
|||
delete verifier;
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (CryptoKeyType keyType, const uint8_t * key)
|
||||
{
|
||||
switch (keyType)
|
||||
{
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>
|
||||
IdentityEx::CreateEncryptor(CryptoKeyType keyType, const uint8_t *key) {
|
||||
switch (keyType) {
|
||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
||||
break;
|
||||
|
@ -434,14 +386,12 @@ namespace data
|
|||
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
|
||||
return CreateEncryptor(GetCryptoKeyType(), key);
|
||||
}
|
||||
|
||||
PrivateKeys& PrivateKeys::operator=(const Keys& keys)
|
||||
{
|
||||
PrivateKeys &PrivateKeys::operator=(const Keys &keys) {
|
||||
m_Public = std::make_shared<IdentityEx>(Identity(keys));
|
||||
memcpy(m_PrivateKey, keys.privateKey, 256); // 256
|
||||
memcpy(m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen());
|
||||
|
@ -453,29 +403,28 @@ namespace data
|
|||
return *this;
|
||||
}
|
||||
|
||||
PrivateKeys& PrivateKeys::operator=(const PrivateKeys& other)
|
||||
{
|
||||
PrivateKeys &PrivateKeys::operator=(const PrivateKeys &other) {
|
||||
m_Public = std::make_shared<IdentityEx>(*other.m_Public);
|
||||
memcpy(m_PrivateKey, other.m_PrivateKey, 256); // 256
|
||||
m_OfflineSignature = other.m_OfflineSignature;
|
||||
m_TransientSignatureLen = other.m_TransientSignatureLen;
|
||||
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;
|
||||
CreateSigner();
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t PrivateKeys::GetFullLen () const
|
||||
{
|
||||
size_t PrivateKeys::GetFullLen() const {
|
||||
size_t ret = m_Public->GetFullLen() + GetPrivateKeyLen() + m_Public->GetSigningPrivateKeyLen();
|
||||
if (IsOfflineSignature())
|
||||
ret += m_OfflineSignature.size() + m_TransientSigningPrivateKeyLen;
|
||||
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>();
|
||||
size_t ret = m_Public->FromBuffer(buf, len);
|
||||
auto cryptoKeyLen = GetPrivateKeyLen();
|
||||
|
@ -490,25 +439,24 @@ namespace data
|
|||
// check if signing private key is all zeros
|
||||
bool allzeros = true;
|
||||
for (size_t i = 0; i < signingPrivateKeySize; i++)
|
||||
if (m_SigningPrivateKey[i])
|
||||
{
|
||||
if (m_SigningPrivateKey[i]) {
|
||||
allzeros = false;
|
||||
break;
|
||||
}
|
||||
if (allzeros)
|
||||
{
|
||||
if (allzeros) {
|
||||
// offline information
|
||||
const uint8_t *offlineInfo = buf + ret;
|
||||
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));
|
||||
if (!transientVerifier) return 0;
|
||||
auto keyLen = transientVerifier->GetPublicKeyLen();
|
||||
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->Verify (offlineInfo, keyLen + 6, buf + ret))
|
||||
{
|
||||
if (!m_Public->Verify(offlineInfo, keyLen + 6, buf + ret)) {
|
||||
LogPrint(eLogError, "Identity: Offline signature verification failed");
|
||||
return 0;
|
||||
}
|
||||
|
@ -524,14 +472,12 @@ namespace data
|
|||
memcpy(m_SigningPrivateKey, buf + ret, m_TransientSigningPrivateKeyLen);
|
||||
ret += m_TransientSigningPrivateKeyLen;
|
||||
CreateSigner(keyType);
|
||||
}
|
||||
else
|
||||
} else
|
||||
CreateSigner(m_Public->GetSigningKeyType());
|
||||
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);
|
||||
auto cryptoKeyLen = GetPrivateKeyLen();
|
||||
memcpy(buf + ret, m_PrivateKey, cryptoKeyLen);
|
||||
|
@ -543,8 +489,7 @@ namespace data
|
|||
else
|
||||
memcpy(buf + ret, m_SigningPrivateKey, signingPrivateKeySize);
|
||||
ret += signingPrivateKeySize;
|
||||
if (IsOfflineSignature ())
|
||||
{
|
||||
if (IsOfflineSignature()) {
|
||||
// offline signature
|
||||
auto offlineSignatureLen = m_OfflineSignature.size();
|
||||
if (ret + offlineSignatureLen > len) return 0;
|
||||
|
@ -558,8 +503,7 @@ namespace data
|
|||
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()];
|
||||
size_t l = i2p::data::Base64ToByteStream(s.c_str(), s.length(), buf, s.length());
|
||||
size_t ret = FromBuffer(buf, l);
|
||||
|
@ -567,8 +511,7 @@ namespace data
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::string PrivateKeys::ToBase64 () const
|
||||
{
|
||||
std::string PrivateKeys::ToBase64() const {
|
||||
uint8_t *buf = new uint8_t[GetFullLen()];
|
||||
char *str = new char[GetFullLen() * 2];
|
||||
size_t l = ToBuffer(buf, GetFullLen());
|
||||
|
@ -580,40 +523,37 @@ namespace data
|
|||
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)
|
||||
CreateSigner();
|
||||
m_Signer->Sign(buf, len, signature);
|
||||
}
|
||||
|
||||
void PrivateKeys::CreateSigner () const
|
||||
{
|
||||
void PrivateKeys::CreateSigner() const {
|
||||
if (IsOfflineSignature())
|
||||
CreateSigner(bufbe16toh(m_OfflineSignature.data() + 4)); // key type
|
||||
else
|
||||
CreateSigner(m_Public->GetSigningKeyType());
|
||||
}
|
||||
|
||||
void PrivateKeys::CreateSigner (SigningKeyType keyType) const
|
||||
{
|
||||
void PrivateKeys::CreateSigner(SigningKeyType keyType) const {
|
||||
if (m_Signer) return;
|
||||
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())
|
||||
m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey, m_Public->GetStandardIdentity ().certificate - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
|
||||
else
|
||||
{
|
||||
m_Signer.reset(new i2p::crypto::EDDSA25519Signer(m_SigningPrivateKey,
|
||||
m_Public->GetStandardIdentity().certificate -
|
||||
i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH)); // TODO: remove public key check
|
||||
else {
|
||||
// public key is not required
|
||||
auto signer = CreateSigner(keyType, m_SigningPrivateKey);
|
||||
if (signer) m_Signer.reset(signer);
|
||||
}
|
||||
}
|
||||
|
||||
i2p::crypto::Signer * PrivateKeys::CreateSigner (SigningKeyType keyType, const uint8_t * priv)
|
||||
{
|
||||
switch (keyType)
|
||||
{
|
||||
i2p::crypto::Signer *PrivateKeys::CreateSigner(SigningKeyType keyType, const uint8_t *priv) {
|
||||
switch (keyType) {
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
return new i2p::crypto::ECDSAP256Signer(priv);
|
||||
break;
|
||||
|
@ -646,36 +586,31 @@ namespace data
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
size_t PrivateKeys::GetSignatureLen () const
|
||||
{
|
||||
size_t PrivateKeys::GetSignatureLen() const {
|
||||
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
|
||||
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)
|
||||
return m_Public->GetEncryptionPublicKeyBuffer() + 256;
|
||||
else
|
||||
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
|
||||
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;
|
||||
switch (cryptoType)
|
||||
{
|
||||
switch (cryptoType) {
|
||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||
return std::make_shared<i2p::crypto::ElGamalDecryptor>(key);
|
||||
break;
|
||||
|
@ -695,10 +630,8 @@ namespace data
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType)
|
||||
{
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1)
|
||||
{
|
||||
PrivateKeys PrivateKeys::CreateRandomKeys(SigningKeyType type, CryptoKeyType cryptoType) {
|
||||
if (type != SIGNING_KEY_TYPE_DSA_SHA1) {
|
||||
PrivateKeys keys;
|
||||
// signature
|
||||
uint8_t signingPublicKey[512]; // signing public key is 512 bytes max
|
||||
|
@ -715,10 +648,8 @@ namespace data
|
|||
return PrivateKeys(i2p::data::CreateRandomKeys()); // DSA-SHA1
|
||||
}
|
||||
|
||||
void PrivateKeys::GenerateSigningKeyPair (SigningKeyType type, uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
void PrivateKeys::GenerateSigningKeyPair(SigningKeyType type, uint8_t *priv, uint8_t *pub) {
|
||||
switch (type) {
|
||||
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
|
||||
i2p::crypto::CreateECDSAP256RandomKeys(priv, pub);
|
||||
break;
|
||||
|
@ -749,15 +680,14 @@ namespace data
|
|||
i2p::crypto::CreateRedDSA25519RandomKeys(priv, pub);
|
||||
break;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
void PrivateKeys::GenerateCryptoKeyPair (CryptoKeyType type, uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
void PrivateKeys::GenerateCryptoKeyPair(CryptoKeyType type, uint8_t *priv, uint8_t *pub) {
|
||||
switch (type) {
|
||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||
i2p::crypto::GenerateElGamalKeyPair(priv, pub);
|
||||
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);
|
||||
std::unique_ptr<i2p::crypto::Verifier> verifier(IdentityEx::CreateVerifier(type));
|
||||
if (verifier)
|
||||
{
|
||||
if (verifier) {
|
||||
size_t pubKeyLen = verifier->GetPublicKeyLen();
|
||||
keys.m_TransientSigningPrivateKeyLen = verifier->GetPrivateKeyLen();
|
||||
keys.m_TransientSignatureLen = verifier->GetSignatureLen();
|
||||
keys.m_OfflineSignature.resize(pubKeyLen + m_Public->GetSignatureLen() + 6);
|
||||
htobe32buf(keys.m_OfflineSignature.data(), expires); // expires
|
||||
htobe16buf(keys.m_OfflineSignature.data() + 4, type); // type
|
||||
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
|
||||
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
|
||||
GenerateSigningKeyPair(type, keys.m_SigningPrivateKey,
|
||||
keys.m_OfflineSignature.data() + 6); // public key
|
||||
Sign(keys.m_OfflineSignature.data(), pubKeyLen + 6,
|
||||
keys.m_OfflineSignature.data() + 6 + pubKeyLen); // signature
|
||||
// recreate signer
|
||||
keys.m_Signer = nullptr;
|
||||
keys.CreateSigner(type);
|
||||
|
@ -797,8 +727,7 @@ namespace data
|
|||
return keys;
|
||||
}
|
||||
|
||||
Keys CreateRandomKeys ()
|
||||
{
|
||||
Keys CreateRandomKeys() {
|
||||
Keys keys;
|
||||
// encryption
|
||||
i2p::crypto::GenerateElGamalKeyPair(keys.privateKey, keys.publicKey);
|
||||
|
@ -807,8 +736,7 @@ namespace data
|
|||
return keys;
|
||||
}
|
||||
|
||||
IdentHash CreateRoutingKey (const IdentHash& ident)
|
||||
{
|
||||
IdentHash CreateRoutingKey(const IdentHash &ident) {
|
||||
uint8_t buf[41]; // ident + yyyymmdd
|
||||
memcpy(buf, (const uint8_t *) ident, 32);
|
||||
i2p::util::GetCurrentDate((char *) (buf + 32));
|
||||
|
@ -817,8 +745,7 @@ namespace data
|
|||
return key;
|
||||
}
|
||||
|
||||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
|
||||
{
|
||||
XORMetric operator^(const IdentHash &key1, const IdentHash &key2) {
|
||||
XORMetric m;
|
||||
#if (defined(__x86_64__) || defined(__i386__)) && defined(__AVX__) // not all X86 targets supports AVX (like old Pentium, see #1600)
|
||||
if(i2p::cpu::avx)
|
||||
|
|
|
@ -20,18 +20,15 @@
|
|||
#include "Signature.h"
|
||||
#include "CryptoKey.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
typedef Tag<32> IdentHash;
|
||||
inline std::string GetIdentHashAbbreviation (const IdentHash& ident)
|
||||
{
|
||||
|
||||
inline std::string GetIdentHashAbbreviation(const IdentHash &ident) {
|
||||
return ident.ToBase64().substr(0, 4);
|
||||
}
|
||||
|
||||
struct Keys
|
||||
{
|
||||
struct Keys {
|
||||
uint8_t privateKey[256];
|
||||
uint8_t signingPrivateKey[20];
|
||||
uint8_t publicKey[256];
|
||||
|
@ -45,16 +42,19 @@ namespace data
|
|||
const uint8_t CERTIFICATE_TYPE_MULTIPLE = 4;
|
||||
const uint8_t CERTIFICATE_TYPE_KEY = 5;
|
||||
|
||||
struct Identity
|
||||
{
|
||||
struct Identity {
|
||||
uint8_t publicKey[256];
|
||||
uint8_t signingKey[128];
|
||||
uint8_t certificate[3]; // byte 1 - type, bytes 2-3 - length
|
||||
|
||||
Identity() = default;
|
||||
|
||||
Identity(const Keys &keys) { *this = keys; };
|
||||
|
||||
Identity &operator=(const Keys &keys);
|
||||
|
||||
size_t FromBuffer(const uint8_t *buf, size_t len);
|
||||
|
||||
IdentHash Hash() const;
|
||||
};
|
||||
|
||||
|
@ -85,50 +85,76 @@ namespace data
|
|||
typedef uint16_t CryptoKeyType;
|
||||
|
||||
const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521
|
||||
class IdentityEx
|
||||
{
|
||||
class IdentityEx {
|
||||
public:
|
||||
|
||||
IdentityEx();
|
||||
|
||||
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 IdentityEx &other);
|
||||
|
||||
IdentityEx(const Identity &standard);
|
||||
|
||||
~IdentityEx();
|
||||
|
||||
IdentityEx &operator=(const IdentityEx &other);
|
||||
|
||||
IdentityEx &operator=(const Identity &standard);
|
||||
|
||||
size_t FromBuffer(const uint8_t *buf, size_t len);
|
||||
|
||||
size_t ToBuffer(uint8_t *buf, size_t len) const;
|
||||
|
||||
size_t FromBase64(const std::string &s);
|
||||
|
||||
std::string ToBase64() const;
|
||||
|
||||
const Identity &GetStandardIdentity() const { return m_StandardIdentity; };
|
||||
|
||||
const IdentHash &GetIdentHash() const { return m_IdentHash; };
|
||||
|
||||
const uint8_t *GetEncryptionPublicKey() const { return m_StandardIdentity.publicKey; };
|
||||
|
||||
uint8_t *GetEncryptionPublicKeyBuffer() { return m_StandardIdentity.publicKey; };
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor(const uint8_t *key) const;
|
||||
|
||||
size_t GetFullLen() const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
|
||||
|
||||
size_t GetSigningPublicKeyLen() const;
|
||||
|
||||
const uint8_t *GetSigningPublicKeyBuffer() const; // returns NULL for P521
|
||||
size_t GetSigningPrivateKeyLen() const;
|
||||
|
||||
size_t GetSignatureLen() const;
|
||||
|
||||
bool Verify(const uint8_t *buf, size_t len, const uint8_t *signature) const;
|
||||
|
||||
SigningKeyType GetSigningKeyType() const;
|
||||
|
||||
bool IsRSA() const; // signing key type
|
||||
CryptoKeyType GetCryptoKeyType() const;
|
||||
|
||||
void DropVerifier() const; // to save memory
|
||||
|
||||
bool operator==(const IdentityEx &other) const { return GetIdentHash() == other.GetIdentHash(); }
|
||||
|
||||
void RecalculateIdentHash(uint8_t *buff = nullptr);
|
||||
|
||||
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:
|
||||
|
||||
void CreateVerifier() const;
|
||||
|
||||
void UpdateVerifier(i2p::crypto::Verifier *verifier) const;
|
||||
|
||||
private:
|
||||
|
@ -146,44 +172,67 @@ namespace data
|
|||
public:
|
||||
|
||||
PrivateKeys() = default;
|
||||
|
||||
PrivateKeys(const PrivateKeys &other) { *this = other; };
|
||||
|
||||
PrivateKeys(const Keys &keys) { *this = keys; };
|
||||
|
||||
PrivateKeys &operator=(const Keys &keys);
|
||||
|
||||
PrivateKeys &operator=(const PrivateKeys &other);
|
||||
|
||||
~PrivateKeys() = default;
|
||||
|
||||
std::shared_ptr<const IdentityEx> GetPublic() const { return m_Public; };
|
||||
|
||||
const uint8_t *GetPrivateKey() const { return m_PrivateKey; };
|
||||
|
||||
const uint8_t *GetSigningPrivateKey() const { return m_SigningPrivateKey; };
|
||||
|
||||
size_t GetSignatureLen() const; // might not match identity
|
||||
bool IsOfflineSignature() const { return m_TransientSignatureLen > 0; };
|
||||
|
||||
uint8_t *GetPadding();
|
||||
|
||||
void RecalculateIdentHash(uint8_t *buf = nullptr) { m_Public->RecalculateIdentHash(buf); }
|
||||
|
||||
void Sign(const uint8_t *buf, int len, uint8_t *signature) const;
|
||||
|
||||
size_t GetFullLen() const;
|
||||
|
||||
size_t FromBuffer(const uint8_t *buf, size_t len);
|
||||
|
||||
size_t ToBuffer(uint8_t *buf, size_t len) const;
|
||||
|
||||
size_t FromBase64(const std::string &s);
|
||||
|
||||
std::string ToBase64() 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 PrivateKeys CreateRandomKeys (SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1, CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||
static std::shared_ptr<i2p::crypto::CryptoKeyDecryptor>
|
||||
CreateDecryptor(CryptoKeyType cryptoType, const uint8_t *key);
|
||||
|
||||
static PrivateKeys CreateRandomKeys(SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1,
|
||||
CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||
|
||||
static 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);
|
||||
|
||||
// offline keys
|
||||
PrivateKeys CreateOfflineKeys(SigningKeyType type, uint32_t expires) const;
|
||||
|
||||
const std::vector<uint8_t> &GetOfflineSignature() const { return m_OfflineSignature; };
|
||||
|
||||
private:
|
||||
|
||||
void CreateSigner() const;
|
||||
|
||||
void CreateSigner(SigningKeyType keyType) const;
|
||||
|
||||
size_t GetPrivateKeyLen() const;
|
||||
|
||||
private:
|
||||
|
@ -198,49 +247,59 @@ namespace data
|
|||
};
|
||||
|
||||
// kademlia
|
||||
struct XORMetric
|
||||
{
|
||||
union
|
||||
{
|
||||
struct XORMetric {
|
||||
union {
|
||||
uint8_t metric[32];
|
||||
uint64_t metric_ll[4];
|
||||
};
|
||||
|
||||
void SetMin() { memset(metric, 0, 32); };
|
||||
|
||||
void SetMax() { memset(metric, 0xFF, 32); };
|
||||
|
||||
bool operator<(const XORMetric &other) const { return memcmp(metric, other.metric, 32) < 0; };
|
||||
};
|
||||
|
||||
IdentHash CreateRoutingKey(const IdentHash &ident);
|
||||
|
||||
XORMetric operator^(const IdentHash &key1, const IdentHash &key2);
|
||||
|
||||
// destination for delivery instructions
|
||||
class RoutingDestination
|
||||
{
|
||||
class RoutingDestination {
|
||||
public:
|
||||
|
||||
RoutingDestination() {};
|
||||
|
||||
virtual ~RoutingDestination() {};
|
||||
|
||||
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 bool IsDestination() const = 0; // for garlic
|
||||
|
||||
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:
|
||||
|
||||
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;
|
||||
|
||||
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
|
@ -19,19 +19,15 @@
|
|||
#include "I2PEndian.h"
|
||||
#include "Blinding.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i2p {
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
namespace tunnel {
|
||||
class InboundTunnel;
|
||||
}
|
||||
|
||||
namespace data
|
||||
{
|
||||
namespace data {
|
||||
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
|
||||
struct Lease
|
||||
{
|
||||
struct Lease {
|
||||
IdentHash tunnelGateway;
|
||||
uint32_t tunnelID;
|
||||
uint64_t endDate; // 0 means invalid
|
||||
|
@ -45,10 +41,8 @@ namespace data
|
|||
}
|
||||
};
|
||||
|
||||
struct LeaseCmp
|
||||
{
|
||||
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
|
||||
{
|
||||
struct LeaseCmp {
|
||||
bool operator()(std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const {
|
||||
if (l1->tunnelID != l2->tunnelID)
|
||||
return l1->tunnelID < l2->tunnelID;
|
||||
else
|
||||
|
@ -64,57 +58,91 @@ namespace data
|
|||
const uint8_t MAX_NUM_LEASES = 16;
|
||||
|
||||
const uint8_t NETDB_STORE_TYPE_LEASESET = 1;
|
||||
class LeaseSet: public RoutingDestination
|
||||
{
|
||||
|
||||
class LeaseSet : public RoutingDestination {
|
||||
public:
|
||||
|
||||
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 bool IsNewer(const uint8_t *buf, size_t len) const;
|
||||
|
||||
void PopulateLeases(); // from buffer
|
||||
|
||||
const uint8_t *GetBuffer() const { return m_Buffer; };
|
||||
|
||||
size_t GetBufferLen() const { return m_BufferLen; };
|
||||
|
||||
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> > 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 IsExpired() const;
|
||||
|
||||
bool IsEmpty() const { return m_Leases.empty(); };
|
||||
|
||||
uint64_t GetExpirationTime() const { return m_ExpirationTime; };
|
||||
|
||||
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 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 bool IsPublishedEncrypted() const { return false; };
|
||||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; };
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
|
||||
|
||||
bool IsDestination() const { return true; };
|
||||
|
||||
protected:
|
||||
|
||||
void UpdateLeasesBegin();
|
||||
|
||||
void UpdateLeasesEnd();
|
||||
|
||||
void UpdateLease(const Lease &lease, uint64_t ts);
|
||||
|
||||
// called from LeaseSet2
|
||||
LeaseSet(bool storeLeases);
|
||||
|
||||
void SetBuffer(const uint8_t *buf, size_t len);
|
||||
|
||||
void SetBufferLen(size_t len);
|
||||
|
||||
void SetIdentity(std::shared_ptr<const IdentityEx> identity) { m_Identity = identity; };
|
||||
|
||||
void SetExpirationTime(uint64_t t) { m_ExpirationTime = t; };
|
||||
|
||||
void SetIsValid(bool isValid) { m_IsValid = isValid; };
|
||||
|
||||
bool IsStoreLeases() const { return m_StoreLeases; };
|
||||
|
||||
private:
|
||||
|
||||
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:
|
||||
|
||||
|
@ -141,37 +169,55 @@ namespace data
|
|||
const uint16_t LEASESET2_FLAG_UNPUBLISHED_LEASESET = 0x0002;
|
||||
const uint16_t LEASESET2_FLAG_PUBLISHED_ENCRYPTED = 0x0004;
|
||||
|
||||
class LeaseSet2: public LeaseSet
|
||||
{
|
||||
class LeaseSet2 : public LeaseSet {
|
||||
public:
|
||||
|
||||
LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases = true, 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
|
||||
LeaseSet2(uint8_t storeType, const uint8_t *buf, size_t len, bool storeLeases = true,
|
||||
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; };
|
||||
|
||||
uint32_t GetPublishedTimestamp() const { return m_PublishedTimestamp; };
|
||||
|
||||
bool IsPublic() const { return m_IsPublic; };
|
||||
|
||||
bool IsPublishedEncrypted() const { return m_IsPublishedEncrypted; };
|
||||
|
||||
std::shared_ptr<const i2p::crypto::Verifier> GetTransientVerifier() const { return m_TransientVerifier; };
|
||||
|
||||
void Update(const uint8_t *buf, size_t len, bool verifySignature);
|
||||
|
||||
bool IsNewer(const uint8_t *buf, size_t len) const;
|
||||
|
||||
// implements RoutingDestination
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
|
||||
|
||||
CryptoKeyType GetEncryptionType() const { return m_EncryptionType; };
|
||||
|
||||
private:
|
||||
|
||||
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 ReadMetaLS2TypeSpecificPart(const uint8_t *buf, size_t len);
|
||||
|
||||
template<typename Verifier>
|
||||
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 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:
|
||||
|
||||
|
@ -185,18 +231,21 @@ namespace data
|
|||
|
||||
// also called from Streaming.cpp
|
||||
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;
|
||||
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;
|
||||
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));
|
||||
if (!transientVerifier) return nullptr;
|
||||
auto keyLen = transientVerifier->GetPublicKeyLen();
|
||||
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 (!verifier->Verify(signedData, keyLen + 6, buf + offset)) return nullptr;
|
||||
offset += verifier->GetSignatureLen();
|
||||
|
@ -204,31 +253,47 @@ namespace data
|
|||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
class LocalLeaseSet
|
||||
{
|
||||
class LocalLeaseSet {
|
||||
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);
|
||||
|
||||
virtual ~LocalLeaseSet() { delete[] m_Buffer; };
|
||||
|
||||
virtual uint8_t *GetBuffer() const { return m_Buffer; };
|
||||
|
||||
uint8_t *GetSignature() { return GetBuffer() + GetBufferLen() - GetSignatureLen(); };
|
||||
|
||||
virtual size_t GetBufferLen() const { return m_BufferLen; };
|
||||
|
||||
size_t GetSignatureLen() const { return m_Identity->GetSignatureLen(); };
|
||||
|
||||
uint8_t *GetLeases() { return m_Leases; };
|
||||
|
||||
const IdentHash &GetIdentHash() const { return m_Identity->GetIdentHash(); };
|
||||
|
||||
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_Identity; };
|
||||
|
||||
bool IsExpired() const;
|
||||
|
||||
uint64_t GetExpirationTime() const { return m_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 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:
|
||||
|
||||
|
@ -238,12 +303,10 @@ namespace data
|
|||
size_t m_BufferLen;
|
||||
};
|
||||
|
||||
class LocalLeaseSet2: public LocalLeaseSet
|
||||
{
|
||||
class LocalLeaseSet2 : public LocalLeaseSet {
|
||||
public:
|
||||
|
||||
struct KeySection
|
||||
{
|
||||
struct KeySection {
|
||||
uint16_t keyType, keyLen;
|
||||
const uint8_t *encryptionPublicKey;
|
||||
};
|
||||
|
@ -254,18 +317,22 @@ namespace data
|
|||
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels,
|
||||
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; };
|
||||
|
||||
uint8_t *GetBuffer() const { return m_Buffer + 1; };
|
||||
|
||||
size_t GetBufferLen() const { return m_BufferLen; };
|
||||
|
||||
uint8_t GetStoreType() const { return m_Buffer[0]; };
|
||||
|
||||
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:
|
||||
|
||||
|
@ -280,20 +347,25 @@ namespace data
|
|||
|
||||
typedef i2p::data::Tag<32> AuthPublicKey;
|
||||
|
||||
class LocalEncryptedLeaseSet2: public LocalLeaseSet2
|
||||
{
|
||||
class LocalEncryptedLeaseSet2 : public LocalLeaseSet2 {
|
||||
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; };
|
||||
|
||||
std::shared_ptr<const LocalLeaseSet> GetInnerLeaseSet() const { return m_InnerLeaseSet; };
|
||||
|
||||
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:
|
||||
|
||||
|
|
|
@ -34,41 +34,35 @@ struct BigEndian;
|
|||
// Little-Endian template
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
template<typename T>
|
||||
struct LittleEndian
|
||||
{
|
||||
union
|
||||
{
|
||||
struct LittleEndian {
|
||||
union {
|
||||
unsigned char bytes[sizeof(T)];
|
||||
T raw_value;
|
||||
};
|
||||
|
||||
LittleEndian(T t = T())
|
||||
{
|
||||
LittleEndian(T t = T()) {
|
||||
operator=(t);
|
||||
}
|
||||
|
||||
LittleEndian(const LittleEndian<T> & t)
|
||||
{
|
||||
LittleEndian(const LittleEndian<T> &t) {
|
||||
raw_value = t.raw_value;
|
||||
}
|
||||
|
||||
LittleEndian(const BigEndian<T> & t)
|
||||
{
|
||||
LittleEndian(const BigEndian<T> &t) {
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
bytes[i] = t.bytes[sizeof(T) - 1 - i];
|
||||
}
|
||||
|
||||
operator const T() const
|
||||
{
|
||||
operator const T() const {
|
||||
T t = T();
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
t |= T(bytes[i]) << (i << 3);
|
||||
return t;
|
||||
}
|
||||
|
||||
const T operator = (const T t)
|
||||
{
|
||||
const T operator=(const T t) {
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
bytes[sizeof(T) - 1 - i] = static_cast<unsigned char>(t >> (i << 3));
|
||||
return t;
|
||||
|
@ -76,42 +70,34 @@ struct LittleEndian
|
|||
|
||||
// operators
|
||||
|
||||
const T operator += (const T t)
|
||||
{
|
||||
const T operator+=(const T t) {
|
||||
return (*this = *this + t);
|
||||
}
|
||||
|
||||
const T operator -= (const T t)
|
||||
{
|
||||
const T operator-=(const T t) {
|
||||
return (*this = *this - t);
|
||||
}
|
||||
|
||||
const T operator *= (const T t)
|
||||
{
|
||||
const T operator*=(const T t) {
|
||||
return (*this = *this * t);
|
||||
}
|
||||
|
||||
const T operator /= (const T t)
|
||||
{
|
||||
const T operator/=(const T t) {
|
||||
return (*this = *this / t);
|
||||
}
|
||||
|
||||
const T operator %= (const T t)
|
||||
{
|
||||
const T operator%=(const T t) {
|
||||
return (*this = *this % t);
|
||||
}
|
||||
|
||||
LittleEndian<T> operator ++ (int)
|
||||
{
|
||||
LittleEndian<T> operator++(int) {
|
||||
LittleEndian<T> tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
LittleEndian<T> & operator ++ ()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
LittleEndian<T> &operator++() {
|
||||
for (unsigned i = 0; i < sizeof(T); i++) {
|
||||
++bytes[i];
|
||||
if (bytes[i] != 0)
|
||||
break;
|
||||
|
@ -119,17 +105,14 @@ struct LittleEndian
|
|||
return (*this);
|
||||
}
|
||||
|
||||
LittleEndian<T> operator -- (int)
|
||||
{
|
||||
LittleEndian<T> operator--(int) {
|
||||
LittleEndian<T> tmp(*this);
|
||||
operator--();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
LittleEndian<T> & operator -- ()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
LittleEndian<T> &operator--() {
|
||||
for (unsigned i = 0; i < sizeof(T); i++) {
|
||||
--bytes[i];
|
||||
if (bytes[i] != (T) (-1))
|
||||
break;
|
||||
|
@ -137,46 +120,41 @@ struct LittleEndian
|
|||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
// Big-Endian template
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
template<typename T>
|
||||
struct BigEndian
|
||||
{
|
||||
union
|
||||
{
|
||||
struct BigEndian {
|
||||
union {
|
||||
unsigned char bytes[sizeof(T)];
|
||||
T raw_value;
|
||||
};
|
||||
|
||||
BigEndian(T t = T())
|
||||
{
|
||||
BigEndian(T t = T()) {
|
||||
operator=(t);
|
||||
}
|
||||
|
||||
BigEndian(const BigEndian<T> & t)
|
||||
{
|
||||
BigEndian(const BigEndian<T> &t) {
|
||||
raw_value = t.raw_value;
|
||||
}
|
||||
|
||||
BigEndian(const LittleEndian<T> & t)
|
||||
{
|
||||
BigEndian(const LittleEndian<T> &t) {
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
bytes[i] = t.bytes[sizeof(T) - 1 - i];
|
||||
}
|
||||
|
||||
operator const T() const
|
||||
{
|
||||
operator const T() const {
|
||||
T t = T();
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
t |= T(bytes[sizeof(T) - 1 - i]) << (i << 3);
|
||||
return t;
|
||||
}
|
||||
|
||||
const T operator = (const T t)
|
||||
{
|
||||
const T operator=(const T t) {
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
bytes[sizeof(T) - 1 - i] = t >> (i << 3);
|
||||
return t;
|
||||
|
@ -184,42 +162,34 @@ struct BigEndian
|
|||
|
||||
// operators
|
||||
|
||||
const T operator += (const T t)
|
||||
{
|
||||
const T operator+=(const T t) {
|
||||
return (*this = *this + t);
|
||||
}
|
||||
|
||||
const T operator -= (const T t)
|
||||
{
|
||||
const T operator-=(const T t) {
|
||||
return (*this = *this - t);
|
||||
}
|
||||
|
||||
const T operator *= (const T t)
|
||||
{
|
||||
const T operator*=(const T t) {
|
||||
return (*this = *this * t);
|
||||
}
|
||||
|
||||
const T operator /= (const T t)
|
||||
{
|
||||
const T operator/=(const T t) {
|
||||
return (*this = *this / t);
|
||||
}
|
||||
|
||||
const T operator %= (const T t)
|
||||
{
|
||||
const T operator%=(const T t) {
|
||||
return (*this = *this % t);
|
||||
}
|
||||
|
||||
BigEndian<T> operator ++ (int)
|
||||
{
|
||||
BigEndian<T> operator++(int) {
|
||||
BigEndian<T> tmp(*this);
|
||||
operator++();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
BigEndian<T> & operator ++ ()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
BigEndian<T> &operator++() {
|
||||
for (unsigned i = 0; i < sizeof(T); i++) {
|
||||
++bytes[sizeof(T) - 1 - i];
|
||||
if (bytes[sizeof(T) - 1 - i] != 0)
|
||||
break;
|
||||
|
@ -227,17 +197,14 @@ struct BigEndian
|
|||
return (*this);
|
||||
}
|
||||
|
||||
BigEndian<T> operator -- (int)
|
||||
{
|
||||
BigEndian<T> operator--(int) {
|
||||
BigEndian<T> tmp(*this);
|
||||
operator--();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
BigEndian<T> & operator -- ()
|
||||
{
|
||||
for (unsigned i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
BigEndian<T> &operator--() {
|
||||
for (unsigned i = 0; i < sizeof(T); i++) {
|
||||
--bytes[sizeof(T) - 1 - i];
|
||||
if (bytes[sizeof(T) - 1 - i] != (T) (-1))
|
||||
break;
|
||||
|
@ -245,6 +212,7 @@ struct BigEndian
|
|||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // LITTLEBIGENDIAN_H
|
|
@ -45,6 +45,7 @@ namespace log {
|
|||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/**
|
||||
* @brief Maps our log levels to syslog one
|
||||
* @return syslog priority LOG_*, as defined in syslog.h
|
||||
|
@ -52,42 +53,49 @@ namespace log {
|
|||
static inline int GetSyslogPrio(enum LogLevel l) {
|
||||
int priority = LOG_DEBUG;
|
||||
switch (l) {
|
||||
case eLogNone : priority = LOG_CRIT; break;
|
||||
case eLogError : priority = LOG_ERR; break;
|
||||
case eLogWarning : priority = LOG_WARNING; break;
|
||||
case eLogInfo : priority = LOG_INFO; break;
|
||||
case eLogDebug : priority = LOG_DEBUG; break;
|
||||
default : priority = LOG_DEBUG; break;
|
||||
case eLogNone :
|
||||
priority = LOG_CRIT;
|
||||
break;
|
||||
case eLogError :
|
||||
priority = LOG_ERR;
|
||||
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;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Log::Log() :
|
||||
m_Destination(eLogStdout), m_MinLevel(eLogInfo),
|
||||
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;
|
||||
}
|
||||
|
||||
void Log::Start ()
|
||||
{
|
||||
if (!m_IsRunning)
|
||||
{
|
||||
void Log::Start() {
|
||||
if (!m_IsRunning) {
|
||||
m_IsRunning = true;
|
||||
m_Thread = new std::thread(std::bind(&Log::Run, this));
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Stop ()
|
||||
{
|
||||
switch (m_Destination)
|
||||
{
|
||||
void Log::Stop() {
|
||||
switch (m_Destination) {
|
||||
#ifndef _WIN32
|
||||
case eLogSyslog :
|
||||
closelog();
|
||||
|
@ -103,8 +111,7 @@ namespace log {
|
|||
}
|
||||
m_IsRunning = false;
|
||||
m_Queue.WakeUp();
|
||||
if (m_Thread)
|
||||
{
|
||||
if (m_Thread) {
|
||||
m_Thread->join();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
|
@ -148,8 +155,7 @@ namespace log {
|
|||
* Unfortunately, with current startup process with late fork() this
|
||||
* 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;
|
||||
std::hash <std::thread::id> hasher;
|
||||
unsigned short short_tid;
|
||||
|
@ -172,19 +178,18 @@ namespace log {
|
|||
default:
|
||||
std::cout << TimeAsString(msg->timestamp)
|
||||
<< "@" << short_tid
|
||||
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels]
|
||||
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level]
|
||||
<< LogMsgColors[eNumLogLevels]
|
||||
<< " - " << msg->text << std::endl;
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
|
||||
void Log::Run ()
|
||||
{
|
||||
void Log::Run() {
|
||||
i2p::util::SetThreadName("Logging");
|
||||
|
||||
Reopen();
|
||||
while (m_IsRunning)
|
||||
{
|
||||
while (m_IsRunning) {
|
||||
std::shared_ptr <LogMsg> msg;
|
||||
while ((msg = m_Queue.Get()))
|
||||
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);
|
||||
}
|
||||
|
||||
void Log::SendTo (const std::string& path)
|
||||
{
|
||||
void Log::SendTo(const std::string &path) {
|
||||
if (m_LogStream) m_LogStream = nullptr; // close previous
|
||||
auto flags = std::ofstream::out | std::ofstream::app;
|
||||
auto os = std::make_shared<std::ofstream>(path, flags);
|
||||
if (os->is_open ())
|
||||
{
|
||||
if (os->is_open()) {
|
||||
m_HasColors = false;
|
||||
m_Logfile = path;
|
||||
m_Destination = eLogFile;
|
||||
|
@ -222,6 +224,7 @@ namespace log {
|
|||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
void Log::SendTo(const char *name, int facility) {
|
||||
if (m_MinLevel == eLogNone) return;
|
||||
m_HasColors = false;
|
||||
|
@ -229,6 +232,7 @@ namespace log {
|
|||
m_LogStream = nullptr;
|
||||
openlog(name, LOG_CONS | LOG_PID, facility);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Log::Reopen() {
|
||||
|
@ -241,7 +245,9 @@ namespace log {
|
|||
}
|
||||
|
||||
static ThrowFunction g_ThrowFunction;
|
||||
|
||||
ThrowFunction GetThrowFunction() { return g_ThrowFunction; }
|
||||
|
||||
void SetThrowFunction(ThrowFunction f) { g_ThrowFunction = f; }
|
||||
|
||||
} // log
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
#include "Queue.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#endif
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
enum LogLevel {
|
||||
eLogNone = 0,
|
||||
eLogError,
|
||||
eLogWarning,
|
||||
|
@ -48,8 +49,7 @@ namespace log {
|
|||
|
||||
struct LogMsg; /* forward declaration */
|
||||
|
||||
class Log
|
||||
{
|
||||
class Log {
|
||||
private:
|
||||
|
||||
enum LogType m_Destination;
|
||||
|
@ -58,7 +58,8 @@ namespace log {
|
|||
std::string m_Logfile;
|
||||
std::time_t m_LastTimestamp;
|
||||
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;
|
||||
std::string m_TimeFormat;
|
||||
volatile bool m_IsRunning;
|
||||
|
@ -68,9 +69,11 @@ namespace log {
|
|||
|
||||
/** prevent making copies */
|
||||
Log(const Log &);
|
||||
|
||||
const Log &operator=(const Log &);
|
||||
|
||||
void Run();
|
||||
|
||||
void Process(std::shared_ptr <LogMsg> msg);
|
||||
|
||||
/**
|
||||
|
@ -84,12 +87,15 @@ namespace log {
|
|||
public:
|
||||
|
||||
Log();
|
||||
|
||||
~Log();
|
||||
|
||||
LogType GetLogType() { return m_Destination; };
|
||||
|
||||
LogLevel GetLogLevel() { return m_MinLevel; };
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
/**
|
||||
|
@ -117,12 +123,14 @@ namespace log {
|
|||
void SetTimeFormat(std::string format) { m_TimeFormat = format; };
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/**
|
||||
* @brief Sets log destination to syslog
|
||||
* @param name Wanted program name
|
||||
* @param facility Wanted log category
|
||||
*/
|
||||
void SendTo(const char *name, int facility);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
@ -154,25 +162,35 @@ namespace log {
|
|||
Log &Logger();
|
||||
|
||||
typedef std::function<void(const std::string &)> ThrowFunction;
|
||||
|
||||
ThrowFunction GetThrowFunction();
|
||||
|
||||
void SetThrowFunction(ThrowFunction f);
|
||||
} // log
|
||||
} // i2p
|
||||
|
||||
/** internal usage only -- folding args array to single string */
|
||||
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
|
||||
|
||||
/** internal usage only -- folding args array to single string */
|
||||
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<TArgs>(args)...);
|
||||
LogPrint (s, std::forward<TValue>(arg)
|
||||
);
|
||||
LogPrint (s, std::forward<TArgs>(args)
|
||||
...);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -182,10 +200,16 @@ void LogPrint (std::stringstream& s, TValue&& arg, TArgs&&... args) noexcept
|
|||
* @param args Array of message parts
|
||||
*/
|
||||
template<typename... TArgs>
|
||||
void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
||||
void LogPrint(LogLevel level, TArgs &&... args)
|
||||
|
||||
noexcept
|
||||
{
|
||||
i2p::log::Log &log = i2p::log::Logger();
|
||||
if (level > log.GetLogLevel ())
|
||||
if (level > log.
|
||||
|
||||
GetLogLevel()
|
||||
|
||||
)
|
||||
return;
|
||||
|
||||
// fold message to single string
|
||||
|
@ -194,12 +218,15 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
|||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
#else
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
LogPrint (ss, std::forward<TArgs>(args)
|
||||
...);
|
||||
#endif
|
||||
|
||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), std::move(ss).str());
|
||||
msg->tid = std::this_thread::get_id();
|
||||
log.Append(msg);
|
||||
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
|
||||
*/
|
||||
template<typename... TArgs>
|
||||
void ThrowFatal (TArgs&&... args) noexcept
|
||||
void ThrowFatal(TArgs &&... args)
|
||||
|
||||
noexcept
|
||||
{
|
||||
auto f = i2p::log::GetThrowFunction();
|
||||
if (!f) return;
|
||||
|
@ -216,9 +245,15 @@ void ThrowFatal (TArgs&&... args) noexcept
|
|||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
#else
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
LogPrint (ss, std::forward<TArgs>(args)
|
||||
...);
|
||||
#endif
|
||||
f (ss.str ());
|
||||
f (ss
|
||||
.
|
||||
|
||||
str()
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
#endif // LOG_H__
|
||||
|
|
1014
libi2pd/NTCP2.cpp
1014
libi2pd/NTCP2.cpp
File diff suppressed because it is too large
Load diff
119
libi2pd/NTCP2.h
119
libi2pd/NTCP2.h
|
@ -22,10 +22,8 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
|
||||
const size_t NTCP2_UNENCRYPTED_FRAME_MAX_SIZE = 65519;
|
||||
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_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
|
||||
|
||||
enum NTCP2BlockType
|
||||
{
|
||||
enum NTCP2BlockType {
|
||||
eNTCP2BlkDateTime = 0,
|
||||
eNTCP2BlkOptions, // 1
|
||||
eNTCP2BlkRouterInfo, // 2
|
||||
|
@ -53,8 +50,7 @@ namespace transport
|
|||
eNTCP2BlkPadding = 254
|
||||
};
|
||||
|
||||
enum NTCP2TerminationReason
|
||||
{
|
||||
enum NTCP2TerminationReason {
|
||||
eNTCP2NormalClose = 0,
|
||||
eNTCP2TerminationReceived, // 1
|
||||
eNTCP2IdleTimeout, // 2
|
||||
|
@ -78,38 +74,53 @@ namespace transport
|
|||
// RouterInfo flags
|
||||
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||
|
||||
struct NTCP2Establisher: private i2p::crypto::NoiseSymmetricState
|
||||
{
|
||||
struct NTCP2Establisher : private i2p::crypto::NoiseSymmetricState {
|
||||
NTCP2Establisher();
|
||||
|
||||
~NTCP2Establisher();
|
||||
|
||||
const uint8_t *GetPub() const { return m_EphemeralKeys->GetPublicKey(); };
|
||||
|
||||
const uint8_t *GetRemotePub() const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob
|
||||
uint8_t *GetRemotePub() { return m_RemoteEphemeralPublicKey; }; // to set
|
||||
|
||||
const uint8_t *GetK() const { return m_CK + 32; };
|
||||
|
||||
const uint8_t *GetCK() const { return m_CK; };
|
||||
|
||||
const uint8_t *GetH() const { return m_H; };
|
||||
|
||||
void KDF1Alice();
|
||||
|
||||
void KDF1Bob();
|
||||
|
||||
void KDF2Alice();
|
||||
|
||||
void KDF2Bob();
|
||||
|
||||
void KDF3Alice(); // for SessionConfirmed part 2
|
||||
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 KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
||||
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 KeyDerivationFunction2(const uint8_t *sessionRequest, size_t sessionRequestLen,
|
||||
const uint8_t *epub); // for SessionCreate
|
||||
void CreateEphemeralKey();
|
||||
|
||||
void CreateSessionRequestMessage();
|
||||
|
||||
void CreateSessionCreatedMessage();
|
||||
|
||||
void CreateSessionConfirmedMessagePart1(const uint8_t *nonce);
|
||||
|
||||
void CreateSessionConfirmedMessagePart2(const uint8_t *nonce);
|
||||
|
||||
bool ProcessSessionRequestMessage(uint16_t &paddingLen, bool &clockSkew);
|
||||
|
||||
bool ProcessSessionCreatedMessage(uint16_t &paddingLen);
|
||||
|
||||
bool ProcessSessionConfirmedMessagePart1(const uint8_t *nonce);
|
||||
|
||||
bool ProcessSessionConfirmedMessagePart2(const uint8_t *nonce, uint8_t *m3p2Buf);
|
||||
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||
|
@ -125,24 +136,32 @@ namespace transport
|
|||
};
|
||||
|
||||
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:
|
||||
|
||||
NTCP2Session(NTCP2Server &server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
||||
|
||||
~NTCP2Session();
|
||||
|
||||
void Terminate();
|
||||
|
||||
void TerminateByTimeout();
|
||||
|
||||
void Done();
|
||||
|
||||
void Close() { m_Socket.close(); }; // for accept
|
||||
void DeleteNextReceiveBuffer(uint64_t ts);
|
||||
|
||||
boost::asio::ip::tcp::socket &GetSocket() { return m_Socket; };
|
||||
|
||||
const boost::asio::ip::tcp::endpoint &GetRemoteEndpoint() { return m_RemoteEndpoint; };
|
||||
|
||||
void SetRemoteEndpoint(const boost::asio::ip::tcp::endpoint &ep) { m_RemoteEndpoint = ep; };
|
||||
|
||||
bool IsEstablished() const { return m_IsEstablished; };
|
||||
|
||||
bool IsTerminated() const { return m_IsTerminated; };
|
||||
|
||||
void ClientLogin(); // Alice
|
||||
|
@ -156,41 +175,70 @@ namespace transport
|
|||
void Established();
|
||||
|
||||
void CreateNonce(uint64_t seqn, uint8_t *nonce);
|
||||
|
||||
void CreateNextReceivedBuffer(size_t size);
|
||||
|
||||
void KeyDerivationFunctionDataPhase();
|
||||
|
||||
void SetSipKeys(const uint8_t *sendSipKey, const uint8_t *receiveSipKey);
|
||||
|
||||
// establish
|
||||
void SendSessionRequest();
|
||||
|
||||
void SendSessionCreated();
|
||||
|
||||
void SendSessionConfirmed();
|
||||
|
||||
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 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 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 HandleSessionConfirmedReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
|
||||
|
||||
// data
|
||||
void ReceiveLength();
|
||||
|
||||
void HandleReceivedLength(const boost::system::error_code &ecode, std::size_t bytes_transferred);
|
||||
|
||||
void Receive();
|
||||
|
||||
void HandleReceived(const boost::system::error_code &ecode, std::size_t bytes_transferred);
|
||||
|
||||
void ProcessNextFrame(const uint8_t *frame, size_t len);
|
||||
|
||||
void SetNextSentFrameLength(size_t frameLen, uint8_t *lengthBuf);
|
||||
|
||||
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 HandleNextFrameSent(const boost::system::error_code &ecode, std::size_t bytes_transferred);
|
||||
|
||||
size_t CreatePaddingBlock(size_t msgLen, uint8_t *buf, size_t len);
|
||||
|
||||
void SendQueue();
|
||||
|
||||
void SendRouterInfo();
|
||||
|
||||
void SendTermination(NTCP2TerminationReason reason);
|
||||
|
||||
void SendTerminationAndTerminate(NTCP2TerminationReason reason);
|
||||
|
||||
void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
|
||||
private:
|
||||
|
@ -212,8 +260,7 @@ namespace transport
|
|||
uint16_t m_NextReceivedLen;
|
||||
uint8_t *m_NextReceivedBuffer, *m_NextSendBuffer;
|
||||
size_t m_NextReceivedBufferSize;
|
||||
union
|
||||
{
|
||||
union {
|
||||
uint8_t buf[8];
|
||||
uint16_t key;
|
||||
} m_ReceiveIV, m_SendIV;
|
||||
|
@ -229,47 +276,60 @@ namespace transport
|
|||
int m_NextPaddingSize;
|
||||
};
|
||||
|
||||
class NTCP2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
class NTCP2Server : private i2p::util::RunnableServiceWithWork {
|
||||
public:
|
||||
|
||||
enum ProxyType
|
||||
{
|
||||
enum ProxyType {
|
||||
eNoProxy,
|
||||
eSocksProxy,
|
||||
eHTTPProxy
|
||||
};
|
||||
|
||||
NTCP2Server();
|
||||
|
||||
~NTCP2Server();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
boost::asio::io_service &GetService() { return GetIOService(); };
|
||||
|
||||
bool AddNTCP2Session(std::shared_ptr<NTCP2Session> session, bool incoming = false);
|
||||
|
||||
void RemoveNTCP2Session(std::shared_ptr<NTCP2Session> session);
|
||||
|
||||
std::shared_ptr<NTCP2Session> FindNTCP2Session(const i2p::data::IdentHash &ident);
|
||||
|
||||
void ConnectWithProxy(std::shared_ptr<NTCP2Session> conn);
|
||||
|
||||
void Connect(std::shared_ptr<NTCP2Session> conn);
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
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 HandleConnect (const boost::system::error_code& ecode, 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);
|
||||
void HandleConnect(const boost::system::error_code &ecode, 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
|
||||
void ScheduleTermination();
|
||||
|
||||
void HandleTerminationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
@ -289,7 +349,10 @@ namespace transport
|
|||
public:
|
||||
|
||||
// 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
|
@ -32,10 +32,8 @@
|
|||
#include "version.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_MIN_FLOODFILLS = 5;
|
||||
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 */
|
||||
typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter;
|
||||
|
||||
class NetDb
|
||||
{
|
||||
class NetDb {
|
||||
public:
|
||||
|
||||
NetDb();
|
||||
|
||||
~NetDb();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
std::shared_ptr<const RouterInfo> AddRouterInfo(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 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<LeaseSet> FindLeaseSet(const IdentHash &destination) const;
|
||||
|
||||
std::shared_ptr<RouterProfile> FindRouterProfile(const IdentHash &ident) const;
|
||||
|
||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr, bool direct = true);
|
||||
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
void RequestDestination(const IdentHash &destination,
|
||||
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 HandleDatabaseSearchReplyMsg(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
void HandleDatabaseLookupMsg(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
void HandleNTCP2RouterInfoMsg(std::shared_ptr<const I2NPMessage> m);
|
||||
|
||||
void HandleDeliveryStatusMsg(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
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> 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>
|
||||
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>
|
||||
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> 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::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
|
||||
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
|
||||
std::set<IdentHash> &excluded,
|
||||
bool closeThanUsOnly = false) const;
|
||||
|
||||
std::shared_ptr<const RouterInfo>
|
||||
GetClosestNonFloodfill(const IdentHash &destination, const std::set<IdentHash> &excluded) const;
|
||||
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(FamilyID fam) const;
|
||||
|
||||
void SetUnreachable(const IdentHash &ident, bool unreachable);
|
||||
|
||||
void PostI2NPMsg(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
@ -107,25 +140,35 @@ namespace data
|
|||
void SetHidden(bool hide);
|
||||
|
||||
void Reseed();
|
||||
|
||||
Families &GetFamilies() { return m_Families; };
|
||||
|
||||
// for web interface
|
||||
int GetNumRouters() const { return m_RouterInfos.size(); };
|
||||
|
||||
int GetNumFloodfills() const { return m_Floodfills.size(); };
|
||||
|
||||
int GetNumLeaseSets() const { return m_LeaseSets.size(); };
|
||||
|
||||
/** visit all lease sets we currently store */
|
||||
void VisitLeaseSets(LeaseSetVisitor v);
|
||||
|
||||
/** visit all router infos we have currently on disk, usually insanely expensive, does not access in memory RI */
|
||||
void VisitStoredRouterInfos(RouterInfoVisitor v);
|
||||
|
||||
/** visit all router infos we have loaded in memory, cheaper than VisitLocalRouterInfos but locks access while visiting */
|
||||
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 */
|
||||
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
|
||||
|
||||
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);
|
||||
|
||||
std::shared_ptr<Lease> NewLease(const Lease &lease) { return m_LeasesPool.AcquireSharedMt(lease); };
|
||||
|
||||
uint32_t GetPublishReplyToken() const { return m_PublishReplyToken; };
|
||||
|
@ -133,19 +176,28 @@ namespace data
|
|||
private:
|
||||
|
||||
void Load();
|
||||
|
||||
bool LoadRouterInfo(const std::string &path, uint64_t ts);
|
||||
|
||||
void SaveUpdated();
|
||||
|
||||
void Run(); // exploratory thread
|
||||
void Explore(int numDestinations);
|
||||
|
||||
void Publish();
|
||||
|
||||
void Flood(const IdentHash &ident, std::shared_ptr<I2NPMessage> floodMsg);
|
||||
|
||||
void ManageLeaseSets();
|
||||
|
||||
void ManageRequests();
|
||||
|
||||
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 IdentHash& ident, const uint8_t * buf, int len, bool& updated);
|
||||
|
||||
std::shared_ptr<const RouterInfo>
|
||||
AddRouterInfo(const IdentHash &ident, const uint8_t *buf, int len, bool &updated);
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter(Filter filter) const;
|
||||
|
@ -169,6 +221,7 @@ namespace data
|
|||
i2p::fs::HashedStorage m_Storage;
|
||||
|
||||
friend class NetDbRequests;
|
||||
|
||||
NetDbRequests m_Requests;
|
||||
|
||||
bool m_PersistProfiles;
|
||||
|
|
|
@ -12,70 +12,64 @@
|
|||
#include "NetDb.hpp"
|
||||
#include "NetDbRequests.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (std::shared_ptr<const RouterInfo> router,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
std::shared_ptr<I2NPMessage>
|
||||
RequestedDestination::CreateRequestMessage(std::shared_ptr<const RouterInfo> router,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) {
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
if (replyTunnel)
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination,
|
||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
||||
replyTunnel->GetNextIdentHash(),
|
||||
replyTunnel->GetNextTunnelID(), m_IsExploratory,
|
||||
&m_ExcludedPeers);
|
||||
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)
|
||||
m_ExcludedPeers.insert(router->GetIdentHash());
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch();
|
||||
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,
|
||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||
i2p::context.GetRouterInfo().GetIdentHash(), 0, false,
|
||||
&m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert(floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch();
|
||||
return msg;
|
||||
}
|
||||
|
||||
void RequestedDestination::ClearExcludedPeers ()
|
||||
{
|
||||
void RequestedDestination::ClearExcludedPeers() {
|
||||
m_ExcludedPeers.clear();
|
||||
}
|
||||
|
||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
void RequestedDestination::Success(std::shared_ptr<RouterInfo> r) {
|
||||
if (m_RequestComplete) {
|
||||
m_RequestComplete(r);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestedDestination::Fail ()
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
void RequestedDestination::Fail() {
|
||||
if (m_RequestComplete) {
|
||||
m_RequestComplete(nullptr);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::Start ()
|
||||
{
|
||||
void NetDbRequests::Start() {
|
||||
}
|
||||
|
||||
void NetDbRequests::Stop ()
|
||||
{
|
||||
void NetDbRequests::Stop() {
|
||||
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
|
||||
auto dest = std::make_shared<RequestedDestination>(destination, isExploratory);
|
||||
dest->SetRequestComplete(requestComplete);
|
||||
|
@ -87,20 +81,17 @@ namespace data
|
|||
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::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
auto it = m_RequestedDestinations.find(ident);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
{
|
||||
if (it != m_RequestedDestinations.end()) {
|
||||
request = it->second;
|
||||
m_RequestedDestinations.erase(it);
|
||||
}
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
if (request) {
|
||||
if (r)
|
||||
request->Success(r);
|
||||
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);
|
||||
auto it = m_RequestedDestinations.find(ident);
|
||||
if (it != m_RequestedDestinations.end())
|
||||
|
@ -117,12 +107,10 @@ namespace data
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void NetDbRequests::ManageRequests ()
|
||||
{
|
||||
void NetDbRequests::ManageRequests() {
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch();
|
||||
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;
|
||||
bool done = false;
|
||||
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
|
||||
{
|
||||
auto count = dest->GetExcludedPeers().size();
|
||||
if (!dest->IsExploratory () && count < 7)
|
||||
{
|
||||
if (!dest->IsExploratory() && count < 7) {
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool();
|
||||
auto outbound = pool->GetNextOutboundTunnel();
|
||||
auto inbound = pool->GetNextInboundTunnel();
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill(dest->GetDestination(),
|
||||
dest->GetExcludedPeers());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsg(nextFloodfill->GetIdentHash(), 0,
|
||||
dest->CreateRequestMessage(nextFloodfill, inbound));
|
||||
else
|
||||
{
|
||||
else {
|
||||
done = true;
|
||||
if (!inbound) LogPrint(eLogWarning, "NetDbReq: No inbound tunnels");
|
||||
if (!outbound) LogPrint(eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
if (!nextFloodfill) LogPrint(eLogWarning, "NetDbReq: No more floodfills");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // delete obsolete request
|
||||
} else // delete obsolete request
|
||||
done = true;
|
||||
|
||||
if (done)
|
||||
|
|
|
@ -15,33 +15,43 @@
|
|||
#include "Identity.h"
|
||||
#include "RouterInfo.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
class RequestedDestination
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
class RequestedDestination {
|
||||
public:
|
||||
|
||||
typedef std::function<void(std::shared_ptr<RouterInfo>)> RequestComplete;
|
||||
|
||||
RequestedDestination(const IdentHash &destination, bool isExploratory = false) :
|
||||
m_Destination(destination), m_IsExploratory(isExploratory), m_CreationTime(0) {};
|
||||
|
||||
~RequestedDestination() { if (m_RequestComplete) m_RequestComplete(nullptr); };
|
||||
|
||||
const IdentHash &GetDestination() const { return m_Destination; };
|
||||
|
||||
int GetNumExcludedPeers() const { return m_ExcludedPeers.size(); };
|
||||
|
||||
const std::set<IdentHash> &GetExcludedPeers() { return m_ExcludedPeers; };
|
||||
|
||||
void ClearExcludedPeers();
|
||||
|
||||
bool IsExploratory() const { return m_IsExploratory; };
|
||||
|
||||
bool IsExcluded(const IdentHash &ident) const { return m_ExcludedPeers.count(ident); };
|
||||
|
||||
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);
|
||||
|
||||
void SetRequestComplete(const RequestComplete &requestComplete) { m_RequestComplete = requestComplete; };
|
||||
|
||||
bool IsRequestComplete() const { return m_RequestComplete != nullptr; };
|
||||
|
||||
void Success(std::shared_ptr<RouterInfo> r);
|
||||
|
||||
void Fail();
|
||||
|
||||
private:
|
||||
|
@ -53,16 +63,20 @@ namespace data
|
|||
RequestComplete m_RequestComplete;
|
||||
};
|
||||
|
||||
class NetDbRequests
|
||||
{
|
||||
class NetDbRequests {
|
||||
public:
|
||||
|
||||
void Start();
|
||||
|
||||
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);
|
||||
|
||||
std::shared_ptr<RequestedDestination> FindRequest(const IdentHash &ident) const;
|
||||
|
||||
void ManageRequests();
|
||||
|
||||
private:
|
||||
|
|
|
@ -9,12 +9,9 @@
|
|||
#include "Poly1305.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
void Poly1305HMAC(uint64_t *out, const uint64_t *key, const uint8_t *buf, std::size_t sz) {
|
||||
Poly1305 p(key);
|
||||
p.Update(buf, sz);
|
||||
p.Finish(out);
|
||||
|
|
|
@ -8,52 +8,44 @@
|
|||
|
||||
#ifndef LIBI2PD_POLY1305_H
|
||||
#define LIBI2PD_POLY1305_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "Crypto.h"
|
||||
|
||||
#if !OPENSSL_AEAD_CHACHA20_POLY1305
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
const std::size_t POLY1305_DIGEST_BYTES = 16;
|
||||
const std::size_t POLY1305_DIGEST_DWORDS = 4;
|
||||
const std::size_t POLY1305_KEY_BYTES = 32;
|
||||
const std::size_t POLY1305_KEY_DWORDS = 8;
|
||||
const std::size_t POLY1305_BLOCK_BYTES = 16;
|
||||
|
||||
namespace poly1305
|
||||
{
|
||||
struct LongBlock
|
||||
{
|
||||
namespace poly1305 {
|
||||
struct LongBlock {
|
||||
unsigned long data[17];
|
||||
operator unsigned long * ()
|
||||
{
|
||||
|
||||
operator unsigned long *() {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
struct Block
|
||||
{
|
||||
struct Block {
|
||||
unsigned char data[17];
|
||||
|
||||
void Zero()
|
||||
{
|
||||
void Zero() {
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
operator uint8_t * ()
|
||||
{
|
||||
operator uint8_t *() {
|
||||
return data;
|
||||
}
|
||||
|
||||
Block & operator += (const Block & other)
|
||||
{
|
||||
Block &operator+=(const Block &other) {
|
||||
unsigned short u;
|
||||
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];
|
||||
data[i] = (unsigned char) u & 0xff;
|
||||
u >>= 8;
|
||||
|
@ -61,8 +53,7 @@ namespace crypto
|
|||
return *this;
|
||||
}
|
||||
|
||||
Block & operator %=(const LongBlock & other)
|
||||
{
|
||||
Block &operator%=(const LongBlock &other) {
|
||||
unsigned long u;
|
||||
unsigned int i;
|
||||
u = 0;
|
||||
|
@ -84,14 +75,12 @@ namespace crypto
|
|||
return *this;
|
||||
}
|
||||
|
||||
Block & operator = (const Block & other)
|
||||
{
|
||||
Block &operator=(const Block &other) {
|
||||
memcpy(data, other.data, sizeof(data));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Block & operator ~ ()
|
||||
{
|
||||
Block &operator~() {
|
||||
static const Block minusp = {
|
||||
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -109,8 +98,7 @@ namespace crypto
|
|||
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;
|
||||
data[0] = key[0] & 0xff;
|
||||
data[1] = key[1] & 0xff;
|
||||
|
@ -132,28 +120,23 @@ namespace crypto
|
|||
}
|
||||
|
||||
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);
|
||||
data[16] = last;
|
||||
}
|
||||
};
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
struct Buffer {
|
||||
uint8_t data[POLY1305_BLOCK_BYTES];
|
||||
|
||||
operator uint8_t * ()
|
||||
{
|
||||
operator uint8_t *() {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct Poly1305
|
||||
{
|
||||
Poly1305(const uint64_t * key)
|
||||
{
|
||||
struct Poly1305 {
|
||||
Poly1305(const uint64_t *key) {
|
||||
m_Leftover = 0;
|
||||
m_H.Zero();
|
||||
m_Final = 0;
|
||||
|
@ -161,11 +144,9 @@ namespace crypto
|
|||
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
|
||||
if(m_Leftover)
|
||||
{
|
||||
if (m_Leftover) {
|
||||
size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
|
||||
if (want > sz) want = sz;
|
||||
memcpy(m_Buffer + m_Leftover, buf, want);
|
||||
|
@ -177,23 +158,20 @@ namespace crypto
|
|||
m_Leftover = 0;
|
||||
}
|
||||
// process blocks
|
||||
if(sz >= POLY1305_BLOCK_BYTES)
|
||||
{
|
||||
if (sz >= POLY1305_BLOCK_BYTES) {
|
||||
size_t want = (sz & ~(POLY1305_BLOCK_BYTES - 1));
|
||||
Blocks(buf, want);
|
||||
buf += want;
|
||||
sz -= want;
|
||||
}
|
||||
// leftover
|
||||
if(sz)
|
||||
{
|
||||
if (sz) {
|
||||
memcpy(m_Buffer + m_Leftover, buf, 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;
|
||||
while (sz >= POLY1305_BLOCK_BYTES) {
|
||||
unsigned long u;
|
||||
|
@ -222,11 +200,9 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
|
||||
void Finish(uint64_t * out)
|
||||
{
|
||||
void Finish(uint64_t *out) {
|
||||
// process leftovers
|
||||
if(m_Leftover)
|
||||
{
|
||||
if (m_Leftover) {
|
||||
size_t idx = m_Leftover;
|
||||
m_Buffer[idx++] = 1;
|
||||
for (; idx < POLY1305_BLOCK_BYTES; idx++)
|
||||
|
|
|
@ -14,31 +14,25 @@
|
|||
#include "Log.h"
|
||||
#include "Profiling.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
i2p::fs::HashedStorage m_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
|
||||
|
||||
RouterProfile::RouterProfile() :
|
||||
m_LastUpdateTime(boost::posix_time::second_clock::local_time()),
|
||||
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();
|
||||
}
|
||||
|
||||
void RouterProfile::UpdateTime ()
|
||||
{
|
||||
void RouterProfile::UpdateTime() {
|
||||
m_LastUpdateTime = GetTime();
|
||||
}
|
||||
|
||||
void RouterProfile::Save (const IdentHash& identHash)
|
||||
{
|
||||
void RouterProfile::Save(const IdentHash &identHash) {
|
||||
// fill sections
|
||||
boost::property_tree::ptree participation;
|
||||
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 path = m_ProfilesStorage.Path(ident);
|
||||
boost::property_tree::ptree pt;
|
||||
|
||||
if (!i2p::fs::Exists(path))
|
||||
{
|
||||
if (!i2p::fs::Exists(path)) {
|
||||
LogPrint(eLogWarning, "Profiling: No profile yet for ", ident);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
boost::property_tree::read_ini(path, pt);
|
||||
} catch (std::exception& ex)
|
||||
{
|
||||
} catch (std::exception &ex) {
|
||||
/* boost exception verbose enough */
|
||||
LogPrint(eLogError, "Profiling: ", ex.what());
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
auto t = pt.get(PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||
if (t.length() > 0)
|
||||
m_LastUpdateTime = boost::posix_time::time_from_string(t);
|
||||
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
try
|
||||
{
|
||||
if ((GetTime() - m_LastUpdateTime).hours() < PEER_PROFILE_EXPIRATION_TIMEOUT) {
|
||||
try {
|
||||
// read participations
|
||||
auto participations = pt.get_child(PEER_PROFILE_SECTION_PARTICIPATION);
|
||||
m_NumTunnelsAgreed = participations.get(PEER_PROFILE_PARTICIPATION_AGREED, 0);
|
||||
m_NumTunnelsDeclined = participations.get(PEER_PROFILE_PARTICIPATION_DECLINED, 0);
|
||||
m_NumTunnelsNonReplied = participations.get(PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
|
||||
catch (boost::property_tree::ptree_bad_path &ex) {
|
||||
LogPrint(eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION,
|
||||
" in profile for ", ident);
|
||||
}
|
||||
try
|
||||
{
|
||||
try {
|
||||
// read usage
|
||||
auto usage = pt.get_child(PEER_PROFILE_SECTION_USAGE);
|
||||
m_NumTimesTaken = usage.get(PEER_PROFILE_USAGE_TAKEN, 0);
|
||||
m_NumTimesRejected = usage.get(PEER_PROFILE_USAGE_REJECTED, 0);
|
||||
}
|
||||
catch (boost::property_tree::ptree_bad_path& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
|
||||
catch (boost::property_tree::ptree_bad_path &ex) {
|
||||
LogPrint(eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_USAGE,
|
||||
" in profile for ", ident);
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
*this = RouterProfile();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
catch (std::exception &ex) {
|
||||
LogPrint(eLogError, "Profiling: Can't read profile ", ident, " :", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelBuildResponse (uint8_t ret)
|
||||
{
|
||||
void RouterProfile::TunnelBuildResponse(uint8_t ret) {
|
||||
UpdateTime();
|
||||
if (ret > 0)
|
||||
m_NumTunnelsDeclined++;
|
||||
|
@ -136,28 +119,23 @@ namespace data
|
|||
m_NumTunnelsAgreed++;
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelNonReplied ()
|
||||
{
|
||||
void RouterProfile::TunnelNonReplied() {
|
||||
m_NumTunnelsNonReplied++;
|
||||
UpdateTime();
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowPartcipationRate () const
|
||||
{
|
||||
bool RouterProfile::IsLowPartcipationRate() const {
|
||||
return 4 * m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowReplyRate () const
|
||||
{
|
||||
bool RouterProfile::IsLowReplyRate() const {
|
||||
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
|
||||
return m_NumTunnelsNonReplied > 10 * (total + 1);
|
||||
}
|
||||
|
||||
bool RouterProfile::IsBad ()
|
||||
{
|
||||
bool RouterProfile::IsBad() {
|
||||
auto isBad = IsAlwaysDeclining() || IsLowPartcipationRate() /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
{
|
||||
if (isBad && m_NumTimesRejected > 10 * (m_NumTimesTaken + 1)) {
|
||||
// reset profile
|
||||
m_NumTunnelsAgreed = 0;
|
||||
m_NumTunnelsDeclined = 0;
|
||||
|
@ -168,21 +146,18 @@ namespace data
|
|||
return isBad;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||
{
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash) {
|
||||
auto profile = std::make_shared<RouterProfile>();
|
||||
profile->Load(identHash); // if possible
|
||||
return profile;
|
||||
}
|
||||
|
||||
void InitProfilesStorage ()
|
||||
{
|
||||
void InitProfilesStorage() {
|
||||
m_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
|
||||
m_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
|
||||
}
|
||||
|
||||
void DeleteObsoleteProfiles ()
|
||||
{
|
||||
void DeleteObsoleteProfiles() {
|
||||
struct stat st;
|
||||
std::time_t now = std::time(nullptr);
|
||||
|
||||
|
|
|
@ -13,10 +13,8 @@
|
|||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include "Identity.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
// sections
|
||||
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
||||
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_VARIANCE = 3 * 3600; // in seconds (3 hours)
|
||||
|
||||
class RouterProfile
|
||||
{
|
||||
class RouterProfile {
|
||||
public:
|
||||
|
||||
RouterProfile();
|
||||
|
||||
RouterProfile &operator=(const RouterProfile &) = default;
|
||||
|
||||
void Save(const IdentHash &identHash);
|
||||
|
||||
void Load(const IdentHash &identHash);
|
||||
|
||||
bool IsBad();
|
||||
|
||||
void TunnelBuildResponse(uint8_t ret);
|
||||
|
||||
void TunnelNonReplied();
|
||||
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime GetTime() const;
|
||||
|
||||
void UpdateTime();
|
||||
|
||||
bool IsAlwaysDeclining() const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
|
||||
bool IsLowPartcipationRate() const;
|
||||
|
||||
bool IsLowReplyRate() const;
|
||||
|
||||
private:
|
||||
|
@ -69,7 +72,9 @@ namespace data
|
|||
};
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash);
|
||||
|
||||
void InitProfilesStorage();
|
||||
|
||||
void DeleteObsoleteProfiles();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,27 +17,21 @@
|
|||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
template<typename Element>
|
||||
class Queue
|
||||
{
|
||||
class Queue {
|
||||
public:
|
||||
|
||||
void Put (Element e)
|
||||
{
|
||||
void Put(Element e) {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
m_Queue.push(std::move(e));
|
||||
m_NonEmpty.notify_one();
|
||||
}
|
||||
|
||||
template<template<typename, typename...> class Container, typename... R>
|
||||
void Put (const Container<Element, R...>& vec)
|
||||
{
|
||||
if (!vec.empty ())
|
||||
{
|
||||
void Put(const Container<Element, R...> &vec) {
|
||||
if (!vec.empty()) {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
for (const auto &it: vec)
|
||||
m_Queue.push(std::move(it));
|
||||
|
@ -45,74 +39,63 @@ namespace util
|
|||
}
|
||||
}
|
||||
|
||||
Element GetNext ()
|
||||
{
|
||||
Element GetNext() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe();
|
||||
if (!el)
|
||||
{
|
||||
if (!el) {
|
||||
m_NonEmpty.wait(l);
|
||||
el = GetNonThreadSafe();
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
Element GetNextWithTimeout (int usec)
|
||||
{
|
||||
Element GetNextWithTimeout(int usec) {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe();
|
||||
if (!el)
|
||||
{
|
||||
if (!el) {
|
||||
m_NonEmpty.wait_for(l, std::chrono::milliseconds(usec));
|
||||
el = GetNonThreadSafe();
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
void Wait ()
|
||||
{
|
||||
void Wait() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
m_NonEmpty.wait(l);
|
||||
}
|
||||
|
||||
bool Wait (int sec, int usec)
|
||||
{
|
||||
bool Wait(int sec, int usec) {
|
||||
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);
|
||||
return m_Queue.empty();
|
||||
}
|
||||
|
||||
int GetSize ()
|
||||
{
|
||||
int GetSize() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.size();
|
||||
}
|
||||
|
||||
void WakeUp() { m_NonEmpty.notify_all(); };
|
||||
|
||||
Element Get ()
|
||||
{
|
||||
Element Get() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe();
|
||||
}
|
||||
|
||||
Element Peek ()
|
||||
{
|
||||
Element Peek() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe(true);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Element GetNonThreadSafe (bool peek = false)
|
||||
{
|
||||
if (!m_Queue.empty ())
|
||||
{
|
||||
Element GetNonThreadSafe(bool peek = false) {
|
||||
if (!m_Queue.empty()) {
|
||||
auto el = m_Queue.front();
|
||||
if (!peek)
|
||||
m_Queue.pop();
|
||||
|
|
|
@ -27,48 +27,40 @@
|
|||
#include "util.h"
|
||||
#include "Config.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
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)
|
||||
*/
|
||||
void Reseeder::Bootstrap ()
|
||||
{
|
||||
std::string su3FileName; i2p::config::GetOption("reseed.file", su3FileName);
|
||||
std::string zipFileName; i2p::config::GetOption("reseed.zipfile", zipFileName);
|
||||
void Reseeder::Bootstrap() {
|
||||
std::string su3FileName;
|
||||
i2p::config::GetOption("reseed.file", su3FileName);
|
||||
std::string zipFileName;
|
||||
i2p::config::GetOption("reseed.zipfile", zipFileName);
|
||||
|
||||
if (su3FileName.length() > 0) // bootstrap from SU3 file or URL
|
||||
{
|
||||
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
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
num = ProcessSU3File(su3FileName.c_str());
|
||||
}
|
||||
if (num == 0)
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", su3FileName);
|
||||
}
|
||||
else if (zipFileName.length() > 0) // bootstrap from ZIP file
|
||||
} else if (zipFileName.length() > 0) // bootstrap from ZIP file
|
||||
{
|
||||
int num = ProcessZIPFile(zipFileName.c_str());
|
||||
if (num == 0)
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", zipFileName);
|
||||
}
|
||||
else // bootstrap from reseed servers
|
||||
} else // bootstrap from reseed servers
|
||||
{
|
||||
int num = ReseedFromServers();
|
||||
if (num == 0)
|
||||
|
@ -80,38 +72,38 @@ namespace data
|
|||
* @brief bootstrap from random server, retry 10 times
|
||||
* @return number of entries added to netDb
|
||||
*/
|
||||
int Reseeder::ReseedFromServers ()
|
||||
{
|
||||
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
|
||||
bool yggdrasil; i2p::config::GetOption("meshnets.yggdrasil", yggdrasil);
|
||||
int Reseeder::ReseedFromServers() {
|
||||
bool ipv6;
|
||||
i2p::config::GetOption("ipv6", ipv6);
|
||||
bool ipv4;
|
||||
i2p::config::GetOption("ipv4", ipv4);
|
||||
bool yggdrasil;
|
||||
i2p::config::GetOption("meshnets.yggdrasil", yggdrasil);
|
||||
|
||||
std::vector<std::string> httpsReseedHostList;
|
||||
if (ipv4 || ipv6)
|
||||
{
|
||||
std::string reseedURLs; i2p::config::GetOption("reseed.urls", reseedURLs);
|
||||
if (ipv4 || ipv6) {
|
||||
std::string reseedURLs;
|
||||
i2p::config::GetOption("reseed.urls", reseedURLs);
|
||||
if (!reseedURLs.empty())
|
||||
boost::split(httpsReseedHostList, reseedURLs, boost::is_any_of(","), boost::token_compress_on);
|
||||
}
|
||||
|
||||
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");
|
||||
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
|
||||
std::string yggReseedURLs;
|
||||
i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
|
||||
if (!yggReseedURLs.empty())
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reseedRetries = 0;
|
||||
while (reseedRetries < 10)
|
||||
{
|
||||
while (reseedRetries < 10) {
|
||||
auto ind = rand() % (httpsReseedHostList.size() + yggReseedHostList.size());
|
||||
bool isHttps = ind < httpsReseedHostList.size();
|
||||
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
|
||||
|
@ -130,58 +122,47 @@ namespace data
|
|||
* @param url
|
||||
* @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);
|
||||
std::string su3 = isHttps ? HttpsRequest(url) : YggdrasilRequest(url);
|
||||
if (su3.length () > 0)
|
||||
{
|
||||
if (su3.length() > 0) {
|
||||
std::stringstream s(su3);
|
||||
return ProcessSU3Stream(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogWarning, "Reseed: SU3 download failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Reseeder::ProcessSU3File (const char * filename)
|
||||
{
|
||||
int Reseeder::ProcessSU3File(const char *filename) {
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open())
|
||||
return ProcessSU3Stream(s);
|
||||
else
|
||||
{
|
||||
else {
|
||||
LogPrint(eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Reseeder::ProcessZIPFile (const char * filename)
|
||||
{
|
||||
int Reseeder::ProcessZIPFile(const char *filename) {
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
if (s.is_open()) {
|
||||
s.seekg(0, std::ios::end);
|
||||
auto len = s.tellg();
|
||||
s.seekg(0, std::ios::beg);
|
||||
return ProcessZIPStream(s, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char SU3_MAGIC_NUMBER[] = "I2Psu3";
|
||||
int Reseeder::ProcessSU3Stream (std::istream& s)
|
||||
{
|
||||
|
||||
int Reseeder::ProcessSU3Stream(std::istream &s) {
|
||||
char magicNumber[7];
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,16 +205,14 @@ namespace data
|
|||
s.read(signerID, signerIDLength); // signerID
|
||||
signerID[signerIDLength] = 0;
|
||||
|
||||
bool verify; i2p::config::GetOption("reseed.verify", verify);
|
||||
if (verify)
|
||||
{
|
||||
bool verify;
|
||||
i2p::config::GetOption("reseed.verify", verify);
|
||||
if (verify) {
|
||||
//try to verify signature
|
||||
auto it = m_SigningKeys.find(signerID);
|
||||
if (it != m_SigningKeys.end ())
|
||||
{
|
||||
if (it != m_SigningKeys.end()) {
|
||||
// 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 tbsLen = pos + contentLength;
|
||||
uint8_t *tbs = new uint8_t[tbsLen];
|
||||
|
@ -261,18 +240,17 @@ namespace data
|
|||
else
|
||||
verify = false; // verified
|
||||
delete[] enSigBuf;
|
||||
BN_free (s); BN_free (n);
|
||||
BN_free(s);
|
||||
BN_free(n);
|
||||
BN_CTX_free(bnctx);
|
||||
}
|
||||
|
||||
delete[] signature;
|
||||
delete[] tbs;
|
||||
s.seekg(pos, std::ios::beg);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
|
||||
}
|
||||
else
|
||||
} else
|
||||
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_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
|
||||
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;
|
||||
size_t contentPos = s.tellg();
|
||||
while (!s.eof ())
|
||||
{
|
||||
while (!s.eof()) {
|
||||
uint32_t signature;
|
||||
s.read((char *) &signature, 4);
|
||||
signature = le32toh (signature);
|
||||
if (signature == ZIP_HEADER_SIGNATURE)
|
||||
{
|
||||
if (signature == ZIP_HEADER_SIGNATURE) {
|
||||
// next local file
|
||||
s.seekg(2, std::ios::cur); // version
|
||||
uint16_t bitFlag;
|
||||
|
@ -332,18 +308,17 @@ namespace data
|
|||
localFileName[fileNameLength] = 0;
|
||||
s.seekg(extraFieldLength, std::ios::cur);
|
||||
// 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();
|
||||
if (!FindZipDataDescriptor (s))
|
||||
{
|
||||
if (!FindZipDataDescriptor(s)) {
|
||||
LogPrint(eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
return numFiles;
|
||||
}
|
||||
s.read((char *) &crc_32, 4);
|
||||
crc_32 = le32toh (crc_32);
|
||||
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);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
|
||||
|
@ -352,8 +327,7 @@ namespace data
|
|||
}
|
||||
|
||||
LogPrint(eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes");
|
||||
if (!compressedSize)
|
||||
{
|
||||
if (!compressedSize) {
|
||||
LogPrint(eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
continue;
|
||||
}
|
||||
|
@ -371,23 +345,18 @@ namespace data
|
|||
inflator.next_out = uncompressed;
|
||||
inflator.avail_out = uncompressedSize;
|
||||
int err;
|
||||
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
|
||||
{
|
||||
if ((err = inflate(&inflator, Z_SYNC_FLUSH)) >= 0) {
|
||||
uncompressedSize -= inflator.avail_out;
|
||||
if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
|
||||
{
|
||||
if (crc32(0, uncompressed, uncompressedSize) == crc_32) {
|
||||
i2p::data::netdb.AddRouterInfo(uncompressed, uncompressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: CRC32 verification failed");
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: SU3 decompression error ", err);
|
||||
delete[] uncompressed;
|
||||
inflateEnd(&inflator);
|
||||
}
|
||||
else // no compression
|
||||
} else // no compression
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo(compressed, compressedSize);
|
||||
numFiles++;
|
||||
|
@ -395,9 +364,7 @@ namespace data
|
|||
delete[] compressed;
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
|
||||
s.seekg(12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
|
||||
LogPrint(eLogWarning, "Reseed: Missing zip central directory header");
|
||||
break; // no more files
|
||||
|
@ -411,11 +378,12 @@ namespace data
|
|||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
int numOutdated = 0;
|
||||
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++;
|
||||
}
|
||||
});
|
||||
|
@ -438,42 +406,35 @@ namespace data
|
|||
}
|
||||
|
||||
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;
|
||||
while (!s.eof ())
|
||||
{
|
||||
while (!s.eof()) {
|
||||
uint8_t nextByte;
|
||||
s.read((char *) &nextByte, 1);
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
|
||||
{
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd]) {
|
||||
nextInd++;
|
||||
if (nextInd >= sizeof(ZIP_DATA_DESCRIPTOR_SIGNATURE))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
} else
|
||||
nextInd = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Reseeder::LoadCertificate (const std::string& filename)
|
||||
{
|
||||
void Reseeder::LoadCertificate(const std::string &filename) {
|
||||
SSL_CTX *ctx = SSL_CTX_new(TLS_method());
|
||||
int ret = SSL_CTX_use_certificate_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
|
||||
if (ret)
|
||||
{
|
||||
if (ret) {
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
X509 *cert = SSL_get_certificate(ssl);
|
||||
// verify
|
||||
if (cert)
|
||||
{
|
||||
if (cert) {
|
||||
// extract issuer name
|
||||
char name[100];
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
|
||||
char *cn = strstr(name, "CN=");
|
||||
if (cn)
|
||||
{
|
||||
if (cn) {
|
||||
cn += 3;
|
||||
char *terminator = strchr(cn, '/');
|
||||
if (terminator) terminator[0] = 0;
|
||||
|
@ -490,14 +451,12 @@ namespace data
|
|||
LogPrint(eLogError, "Reseed: Can't find CN field in ", filename);
|
||||
}
|
||||
SSL_free(ssl);
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void Reseeder::LoadCertificates ()
|
||||
{
|
||||
void Reseeder::LoadCertificates() {
|
||||
std::string certDir = i2p::fs::GetCertsDir() + i2p::fs::dirSep + "reseed";
|
||||
|
||||
std::vector<std::string> files;
|
||||
|
@ -519,10 +478,10 @@ namespace data
|
|||
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;
|
||||
std::string proxy; i2p::config::GetOption("reseed.proxy", proxy);
|
||||
std::string proxy;
|
||||
i2p::config::GetOption("reseed.proxy", proxy);
|
||||
// check for proxy url
|
||||
if (proxy.size()) {
|
||||
// parse
|
||||
|
@ -558,19 +517,15 @@ namespace data
|
|||
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
|
||||
boost::asio::ssl::stream <boost::asio::ip::tcp::socket> s(service, ctx);
|
||||
|
||||
if(proxyUrl.schema.size())
|
||||
{
|
||||
if (proxyUrl.schema.size()) {
|
||||
// proxy connection
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve(
|
||||
boost::asio::ip::tcp::resolver::query(proxyUrl.host, std::to_string(proxyUrl.port)), ecode);
|
||||
if(!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
s.lowest_layer().connect(*it, ecode);
|
||||
if(!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
auto &sock = s.next_layer();
|
||||
if(proxyUrl.schema == "http")
|
||||
{
|
||||
if (proxyUrl.schema == "http") {
|
||||
i2p::http::HTTPReq proxyReq;
|
||||
i2p::http::HTTPRes proxyRes;
|
||||
proxyReq.method = "CONNECT";
|
||||
|
@ -585,48 +540,42 @@ namespace data
|
|||
out << proxyReq.to_string();
|
||||
|
||||
boost::asio::write(sock, writebuf.data(), boost::asio::transfer_all(), ecode);
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT write error: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read_until(sock, readbuf, "\r\n\r\n", ecode);
|
||||
if (ecode)
|
||||
{
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT read error: ", ecode.message());
|
||||
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();
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT malformed reply");
|
||||
return "";
|
||||
}
|
||||
if(proxyRes.code != 200)
|
||||
{
|
||||
if (proxyRes.code != 200) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: HTTP CONNECT got bad status: ", proxyRes.code);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// assume socks if not http, is checked before this for other types
|
||||
// TODO: support username/password auth etc
|
||||
uint8_t hs_writebuf[3] = {0x05, 0x01, 0x00};
|
||||
uint8_t hs_readbuf[2];
|
||||
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
boost::asio::write(sock, boost::asio::buffer(hs_writebuf, 3), boost::asio::transfer_all(),
|
||||
ecode);
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake write failed: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(hs_readbuf, 2), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake read failed: ", ecode.message());
|
||||
return "";
|
||||
|
@ -640,8 +589,7 @@ namespace data
|
|||
buf[3] = 0x03;
|
||||
sz += 4;
|
||||
size_t hostsz = url.host.size();
|
||||
if(1 + 2 + hostsz + sz > sizeof(buf))
|
||||
{
|
||||
if (1 + 2 + hostsz + sz > sizeof(buf)) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed, hostname too big: ", url.host);
|
||||
return "";
|
||||
|
@ -652,21 +600,18 @@ namespace data
|
|||
htobe16buf(buf + sz, url.port);
|
||||
sz += 2;
|
||||
boost::asio::write(sock, boost::asio::buffer(buf, sz), boost::asio::transfer_all(), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed writing: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
boost::asio::read(sock, boost::asio::buffer(buf, 10), ecode);
|
||||
if(ecode)
|
||||
{
|
||||
if (ecode) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake failed reading: ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
if(buf[1] != 0x00)
|
||||
{
|
||||
if (buf[1] != 0x00) {
|
||||
sock.close();
|
||||
LogPrint(eLogError, "Reseed: SOCKS handshake bad reply code: ", std::to_string(buf[1]));
|
||||
return "";
|
||||
|
@ -674,58 +619,46 @@ namespace data
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// direct connection
|
||||
auto it = boost::asio::ip::tcp::resolver(service).resolve(
|
||||
boost::asio::ip::tcp::resolver::query(url.host, std::to_string(url.port)), ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
bool connected = false;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
while (it != end)
|
||||
{
|
||||
while (it != end) {
|
||||
boost::asio::ip::tcp::endpoint ep = *it;
|
||||
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);
|
||||
if (!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
if (!connected) {
|
||||
LogPrint(eLogError, "Reseed: Failed to connect to ", url.host);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
SSL_set_tlsext_host_name(s.native_handle(), url.host.c_str());
|
||||
s.handshake(boost::asio::ssl::stream_base::client, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
LogPrint(eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
|
||||
return ReseedRequest(s, url.to_string());
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: SSL handshake failed: ", ecode.message());
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message());
|
||||
return "";
|
||||
}
|
||||
|
||||
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;
|
||||
i2p::http::HTTPReq req;
|
||||
req.uri = uri;
|
||||
|
@ -734,7 +667,8 @@ namespace data
|
|||
s.write_some(boost::asio::buffer(req.to_string()));
|
||||
// read response
|
||||
std::stringstream rs;
|
||||
char recv_buf[1024]; size_t l = 0;
|
||||
char recv_buf[1024];
|
||||
size_t l = 0;
|
||||
do {
|
||||
l = s.read_some(boost::asio::buffer(recv_buf, sizeof(recv_buf)), ecode);
|
||||
if (l) rs.write(recv_buf, l);
|
||||
|
@ -765,11 +699,9 @@ namespace data
|
|||
return data;
|
||||
}
|
||||
|
||||
std::string Reseeder::YggdrasilRequest (const std::string& address)
|
||||
{
|
||||
std::string Reseeder::YggdrasilRequest(const std::string &address) {
|
||||
i2p::http::URL url;
|
||||
if (!url.parse(address))
|
||||
{
|
||||
if (!url.parse(address)) {
|
||||
LogPrint(eLogError, "Reseed: Failed to parse url: ", address);
|
||||
return "";
|
||||
}
|
||||
|
@ -784,12 +716,10 @@ namespace data
|
|||
auto host = url.host.substr(1, url.host.length() - 2);
|
||||
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);
|
||||
if (!ecode)
|
||||
{
|
||||
if (!ecode) {
|
||||
LogPrint(eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
|
||||
return ReseedRequest(s, url.to_string());
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message());
|
||||
|
||||
return "";
|
||||
|
|
|
@ -16,22 +16,24 @@
|
|||
#include "Identity.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
|
||||
class Reseeder
|
||||
{
|
||||
class Reseeder {
|
||||
typedef Tag<512> PublicKey;
|
||||
|
||||
public:
|
||||
|
||||
Reseeder();
|
||||
|
||||
~Reseeder();
|
||||
|
||||
void Bootstrap();
|
||||
|
||||
int ReseedFromServers();
|
||||
|
||||
int ProcessSU3File(const char *filename);
|
||||
|
||||
int ProcessZIPFile(const char *filename);
|
||||
|
||||
void LoadCertificates();
|
||||
|
@ -39,15 +41,19 @@ namespace data
|
|||
private:
|
||||
|
||||
int ReseedFromSU3Url(const std::string &url, bool isHttps = true);
|
||||
|
||||
void LoadCertificate(const std::string &filename);
|
||||
|
||||
int ProcessSU3Stream(std::istream &s);
|
||||
|
||||
int ProcessZIPStream(std::istream &s, uint64_t contentLength);
|
||||
|
||||
bool FindZipDataDescriptor(std::istream &s);
|
||||
|
||||
std::string HttpsRequest(const std::string &address);
|
||||
|
||||
std::string YggdrasilRequest(const std::string &address);
|
||||
|
||||
template<typename Stream>
|
||||
std::string ReseedRequest(Stream &s, const std::string &uri);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,10 +19,8 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "Garlic.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace garlic
|
||||
{
|
||||
namespace i2p {
|
||||
namespace garlic {
|
||||
class RouterIncomingRatchetSession;
|
||||
}
|
||||
|
||||
|
@ -32,8 +30,7 @@ namespace garlic
|
|||
const char SSU2_KEYS[] = "ssu2.keys";
|
||||
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
|
||||
|
||||
enum RouterStatus
|
||||
{
|
||||
enum RouterStatus {
|
||||
eRouterStatusOK = 0,
|
||||
eRouterStatusTesting = 1,
|
||||
eRouterStatusFirewalled = 2,
|
||||
|
@ -43,27 +40,23 @@ namespace garlic
|
|||
eRouterStatusMesh = 6
|
||||
};
|
||||
|
||||
enum RouterError
|
||||
{
|
||||
enum RouterError {
|
||||
eRouterErrorNone = 0,
|
||||
eRouterErrorClockSkew = 1,
|
||||
eRouterErrorOffline = 2,
|
||||
eRouterErrorSymmetricNAT = 3
|
||||
};
|
||||
|
||||
class RouterContext: public i2p::garlic::GarlicDestination
|
||||
{
|
||||
class RouterContext : public i2p::garlic::GarlicDestination {
|
||||
private:
|
||||
|
||||
struct NTCP2PrivateKeys
|
||||
{
|
||||
struct NTCP2PrivateKeys {
|
||||
uint8_t staticPublicKey[32];
|
||||
uint8_t staticPrivateKey[32];
|
||||
uint8_t iv[16];
|
||||
};
|
||||
|
||||
struct SSU2PrivateKeys
|
||||
{
|
||||
struct SSU2PrivateKeys {
|
||||
uint8_t staticPublicKey[32];
|
||||
uint8_t staticPrivateKey[32];
|
||||
uint8_t intro[32];
|
||||
|
@ -72,120 +65,192 @@ namespace garlic
|
|||
public:
|
||||
|
||||
RouterContext();
|
||||
|
||||
void Init();
|
||||
|
||||
const i2p::data::PrivateKeys &GetPrivateKeys() const { return m_Keys; };
|
||||
|
||||
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,
|
||||
[](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,
|
||||
[](i2p::garlic::GarlicDestination *) {});
|
||||
}
|
||||
|
||||
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; };
|
||||
|
||||
i2p::crypto::X25519Keys &GetNTCP2StaticKeys();
|
||||
|
||||
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 *GetSSU2IntroKey() const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; };
|
||||
|
||||
i2p::crypto::X25519Keys &GetSSU2StaticKeys();
|
||||
|
||||
uint32_t GetUptime() const; // in seconds
|
||||
uint64_t GetLastUpdateTime() const { return m_LastUpdateTime; };
|
||||
|
||||
uint64_t GetBandwidthLimit() const { return m_BandwidthLimit; };
|
||||
|
||||
uint64_t GetTransitBandwidthLimit() const { return (m_BandwidthLimit * m_ShareRatio) / 100LL; };
|
||||
|
||||
RouterStatus GetStatus() const { return m_Status; };
|
||||
|
||||
void SetStatus(RouterStatus status);
|
||||
|
||||
void SetStatusSSU2(RouterStatus status);
|
||||
|
||||
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; };
|
||||
|
||||
void SetStatusV6(RouterStatus status);
|
||||
|
||||
void SetStatusV6SSU2(RouterStatus status);
|
||||
|
||||
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; };
|
||||
|
||||
void SetNetID(int netID) { m_NetID = netID; };
|
||||
|
||||
bool DecryptTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data);
|
||||
|
||||
bool DecryptTunnelShortRequestRecord(const uint8_t *encrypted, uint8_t *data);
|
||||
|
||||
void UpdatePort(int port); // called from 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 UpdateNTCP2Address(bool enable);
|
||||
|
||||
void PublishSSU2Address(int port, bool publish, bool v4, bool v6);
|
||||
|
||||
void UpdateSSU2Address(bool enable);
|
||||
|
||||
void RemoveNTCPAddress(bool v4only = true); // delete NTCP address for older routers. TODO: remove later
|
||||
void RemoveSSUAddress(); // delete SSU address for older routers
|
||||
bool AddIntroducer(const i2p::data::RouterInfo::Introducer &introducer);
|
||||
|
||||
void RemoveIntroducer(const boost::asio::ip::udp::endpoint &e);
|
||||
|
||||
bool AddSSU2Introducer(const i2p::data::RouterInfo::Introducer &introducer, bool v4);
|
||||
|
||||
void RemoveSSU2Introducer(const i2p::data::IdentHash &h, bool v4);
|
||||
|
||||
void ClearSSU2Introducers(bool v4);
|
||||
|
||||
bool IsUnreachable() const;
|
||||
|
||||
void SetUnreachable(bool v4, bool v6);
|
||||
|
||||
void SetUnreachableSSU2(bool v4, bool v6);
|
||||
|
||||
void SetReachable(bool v4, bool v6);
|
||||
|
||||
bool IsFloodfill() const { return m_IsFloodfill; };
|
||||
|
||||
void SetFloodfill(bool floodfill);
|
||||
|
||||
void SetFamily(const std::string &family);
|
||||
|
||||
std::string GetFamily() const;
|
||||
|
||||
void SetBandwidth(int limit); /* in kilobytes */
|
||||
void SetBandwidth(char L); /* by letter */
|
||||
void SetShareRatio(int percents); // 0 - 100
|
||||
bool AcceptsTunnels() const { return m_AcceptsTunnels; };
|
||||
|
||||
void SetAcceptsTunnels(bool acceptsTunnels) { m_AcceptsTunnels = acceptsTunnels; };
|
||||
|
||||
bool SupportsV6() const { return m_RouterInfo.IsV6(); };
|
||||
|
||||
bool SupportsV4() const { return m_RouterInfo.IsV4(); };
|
||||
|
||||
bool SupportsMesh() const { return m_RouterInfo.IsMesh(); };
|
||||
|
||||
void SetSupportsV6(bool supportsV6);
|
||||
|
||||
void SetSupportsV4(bool supportsV4);
|
||||
|
||||
void SetSupportsMesh(bool supportsmesh, const boost::asio::ip::address_v6 &host);
|
||||
|
||||
void SetMTU(int mtu, bool v4);
|
||||
|
||||
i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; };
|
||||
|
||||
void UpdateNTCP2V6Address(const boost::asio::ip::address &host); // called from Daemon. TODO: remove
|
||||
void UpdateStats();
|
||||
|
||||
void UpdateTimestamp(uint64_t ts); // in seconds, called from NetDb before publishing
|
||||
void CleanupDestination(); // garlic destination
|
||||
|
||||
// implements LocalDestination
|
||||
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;
|
||||
|
||||
void Sign(const uint8_t *buf, int len, uint8_t *signature) const { m_Keys.Sign(buf, len, signature); };
|
||||
|
||||
void SetLeaseSetUpdated() {};
|
||||
|
||||
// implements GarlicDestination
|
||||
std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet() { return nullptr; };
|
||||
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const;
|
||||
|
||||
// override GarlicDestination
|
||||
void ProcessGarlicMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ProcessDeliveryStatusMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
protected:
|
||||
|
||||
// implements GarlicDestination
|
||||
void HandleI2NPMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
bool HandleCloveI2NPMessage(I2NPMessageType typeID, const uint8_t *payload, size_t len, uint32_t msgID);
|
||||
|
||||
private:
|
||||
|
||||
void CreateNewRouter();
|
||||
|
||||
void NewRouterInfo();
|
||||
|
||||
void UpdateRouterInfo();
|
||||
|
||||
void NewNTCP2Keys();
|
||||
|
||||
void NewSSU2Keys();
|
||||
|
||||
bool IsSSU2Only() const; // SSU2 and no SSU
|
||||
bool Load();
|
||||
|
||||
void SaveKeys();
|
||||
|
||||
uint16_t SelectRandomPort() const;
|
||||
|
||||
bool DecryptECIESTunnelBuildRecord(const uint8_t *encrypted, uint8_t *data, size_t clearTextSize);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,10 +21,8 @@
|
|||
#include "Profiling.h"
|
||||
#include "Family.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
|
||||
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
|
||||
const char ROUTER_INFO_PROPERTY_NETID[] = "netId";
|
||||
|
@ -58,12 +56,10 @@ namespace data
|
|||
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
|
||||
class RouterInfo: public RoutingDestination
|
||||
{
|
||||
class RouterInfo : public RoutingDestination {
|
||||
public:
|
||||
|
||||
enum SupportedTransports
|
||||
{
|
||||
enum SupportedTransports {
|
||||
eNTCP2V4 = 0x01,
|
||||
eNTCP2V6 = 0x02,
|
||||
eSSUV4 = 0x04,
|
||||
|
@ -75,8 +71,7 @@ namespace data
|
|||
};
|
||||
typedef uint8_t CompatibleTransports;
|
||||
|
||||
enum Caps
|
||||
{
|
||||
enum Caps {
|
||||
eFloodfill = 0x01,
|
||||
eHighBandwidth = 0x02,
|
||||
eExtraBandwidth = 0x04,
|
||||
|
@ -85,16 +80,14 @@ namespace data
|
|||
eUnreachable = 0x20
|
||||
};
|
||||
|
||||
enum AddressCaps
|
||||
{
|
||||
enum AddressCaps {
|
||||
eV4 = 0x01,
|
||||
eV6 = 0x02,
|
||||
eSSUTesting = 0x04,
|
||||
eSSUIntroducer = 0x08
|
||||
};
|
||||
|
||||
enum TransportStyle
|
||||
{
|
||||
enum TransportStyle {
|
||||
eTransportUnknown = 0,
|
||||
eTransportNTCP,
|
||||
eTransportSSU,
|
||||
|
@ -102,8 +95,7 @@ namespace data
|
|||
};
|
||||
|
||||
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
|
||||
struct Introducer
|
||||
{
|
||||
struct Introducer {
|
||||
Introducer() : iPort(0), iExp(0) {};
|
||||
boost::asio::ip::address iHost;
|
||||
int iPort;
|
||||
|
@ -112,14 +104,12 @@ namespace data
|
|||
uint32_t iExp;
|
||||
};
|
||||
|
||||
struct SSUExt
|
||||
{
|
||||
struct SSUExt {
|
||||
int mtu;
|
||||
std::vector<Introducer> introducers;
|
||||
};
|
||||
|
||||
struct Address
|
||||
{
|
||||
struct Address {
|
||||
TransportStyle transportStyle;
|
||||
boost::asio::ip::address host;
|
||||
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;
|
||||
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()) ||
|
||||
(IsV6() && other.is_v6());
|
||||
}
|
||||
|
||||
bool operator==(const Address& other) const
|
||||
{
|
||||
bool operator==(const Address &other) const {
|
||||
return transportStyle == other.transportStyle &&
|
||||
host == other.host && port == other.port;
|
||||
}
|
||||
|
||||
bool operator!=(const Address& other) const
|
||||
{
|
||||
bool operator!=(const Address &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool IsNTCP2() const { return transportStyle == eTransportNTCP; };
|
||||
|
||||
bool IsSSU2() const { return transportStyle == eTransportSSU2; };
|
||||
|
||||
bool IsPublishedNTCP2() const { return IsNTCP2() && published; };
|
||||
|
||||
bool IsReachableSSU() const { return (bool) ssu && (published || UsesIntroducer()); };
|
||||
|
||||
bool UsesIntroducer() const { return (bool) ssu && !ssu->introducers.empty(); };
|
||||
|
||||
bool IsIntroducer() const { return caps & eSSUIntroducer; };
|
||||
|
||||
bool IsPeerTesting() const { return caps & eSSUTesting; };
|
||||
|
||||
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()); };
|
||||
};
|
||||
|
||||
class Buffer: public std::array<uint8_t, MAX_RI_BUFFER_SIZE>
|
||||
{
|
||||
class Buffer : public std::array<uint8_t, MAX_RI_BUFFER_SIZE> {
|
||||
public:
|
||||
|
||||
Buffer() = default;
|
||||
|
||||
Buffer(const uint8_t *buf, size_t len);
|
||||
};
|
||||
|
||||
typedef std::vector<std::shared_ptr<Address> > Addresses;
|
||||
|
||||
RouterInfo(const std::string &fullPath);
|
||||
|
||||
RouterInfo(const RouterInfo &) = default;
|
||||
|
||||
RouterInfo &operator=(const RouterInfo &) = default;
|
||||
|
||||
RouterInfo(std::shared_ptr<Buffer> &&buf, size_t len);
|
||||
|
||||
RouterInfo(const uint8_t *buf, size_t len);
|
||||
|
||||
virtual ~RouterInfo();
|
||||
|
||||
std::shared_ptr<const IdentityEx> GetRouterIdentity() const { return m_RouterIdentity; };
|
||||
|
||||
void SetRouterIdentity(std::shared_ptr<const IdentityEx> identity);
|
||||
|
||||
std::string GetIdentHashBase64() const { return GetIdentHash().ToBase64(); };
|
||||
|
||||
uint64_t GetTimestamp() const { return m_Timestamp; };
|
||||
|
||||
int GetVersion() const { return m_Version; };
|
||||
|
||||
virtual void SetProperty(const std::string &key, const std::string &value) {};
|
||||
|
||||
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> GetSSU2AddressWithStaticKey(const uint8_t *key, bool isV6) const;
|
||||
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V4Address() const;
|
||||
|
||||
std::shared_ptr<const Address> GetPublishedNTCP2V6Address() const;
|
||||
|
||||
std::shared_ptr<const Address> GetSSUAddress(bool v4only = true) const;
|
||||
|
||||
std::shared_ptr<const Address> GetSSUV6Address() const;
|
||||
|
||||
std::shared_ptr<const Address> GetYggdrasilAddress() const;
|
||||
|
||||
std::shared_ptr<const Address> GetSSU2V4Address() const;
|
||||
|
||||
std::shared_ptr<const Address> GetSSU2V6Address() 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 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,
|
||||
const boost::asio::ip::address &host, int port); // published
|
||||
bool AddIntroducer(const Introducer &introducer);
|
||||
|
||||
bool RemoveIntroducer(const boost::asio::ip::udp::endpoint &e);
|
||||
|
||||
void SetUnreachableAddressesTransportCaps(uint8_t transports); // bitmask of AddressCaps
|
||||
void UpdateSupportedTransports();
|
||||
|
||||
bool IsFloodfill() const { return m_Caps & Caps::eFloodfill; };
|
||||
|
||||
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 IsSSUV6() const { return m_SupportedTransports & eSSUV6; };
|
||||
|
||||
bool IsNTCP2(bool v4only = true) const;
|
||||
|
||||
bool IsNTCP2V6() const { return m_SupportedTransports & eNTCP2V6; };
|
||||
|
||||
bool IsSSU2V4() const { return m_SupportedTransports & eSSU2V4; };
|
||||
|
||||
bool IsSSU2V6() const { return m_SupportedTransports & eSSU2V6; };
|
||||
|
||||
bool IsV6() const { return m_SupportedTransports & (eSSUV6 | eNTCP2V6 | eSSU2V6); };
|
||||
|
||||
bool IsV4() const { return m_SupportedTransports & (eSSUV4 | eNTCP2V4 | eSSU2V4); };
|
||||
|
||||
bool IsMesh() const { return m_SupportedTransports & eNTCP2V6Mesh; };
|
||||
|
||||
void EnableV6();
|
||||
|
||||
void DisableV6();
|
||||
|
||||
void EnableV4();
|
||||
|
||||
void DisableV4();
|
||||
|
||||
void EnableMesh();
|
||||
|
||||
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; };
|
||||
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 IsHidden() const { return m_Caps & eHidden; };
|
||||
|
||||
bool IsHighBandwidth() const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
|
||||
bool IsExtraBandwidth() const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
|
||||
bool IsEligibleFloodfill() const;
|
||||
|
||||
bool IsPeerTesting(bool v4) const;
|
||||
|
||||
bool IsSSU2PeerTesting(bool v4) const;
|
||||
|
||||
bool IsIntroducer(bool v4) const;
|
||||
|
||||
bool IsSSU2Introducer(bool v4) const;
|
||||
|
||||
uint8_t GetCaps() const { return m_Caps; };
|
||||
|
||||
void SetCaps(uint8_t caps) { m_Caps = caps; };
|
||||
|
||||
void SetUnreachable(bool unreachable) { m_IsUnreachable = unreachable; };
|
||||
|
||||
bool IsUnreachable() const { return m_IsUnreachable; };
|
||||
|
||||
const uint8_t *GetBuffer() const { return m_Buffer->data(); };
|
||||
|
||||
const uint8_t *LoadBuffer(const std::string &fullPath); // load if necessary
|
||||
size_t GetBufferLen() const { return m_BufferLen; };
|
||||
|
||||
bool IsUpdated() const { return m_IsUpdated; };
|
||||
|
||||
void SetUpdated(bool updated) { m_IsUpdated = updated; };
|
||||
|
||||
bool SaveToFile(const std::string &fullPath);
|
||||
|
||||
std::shared_ptr<RouterProfile> GetProfile() const;
|
||||
|
||||
void SaveProfile() { if (m_Profile) m_Profile->Save(GetIdentHash()); };
|
||||
|
||||
void Update(const uint8_t *buf, size_t len);
|
||||
|
||||
void DeleteBuffer() { m_Buffer = nullptr; };
|
||||
|
||||
bool IsNewer(const uint8_t *buf, size_t len) const;
|
||||
|
||||
/** return true if we are in a router family and the signature is valid */
|
||||
|
@ -263,6 +330,7 @@ namespace data
|
|||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_RouterIdentity; };
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
|
||||
|
||||
bool IsDestination() const { return false; };
|
||||
|
@ -270,25 +338,40 @@ namespace data
|
|||
protected:
|
||||
|
||||
RouterInfo();
|
||||
|
||||
uint8_t *GetBufferPointer(size_t offset = 0) { return m_Buffer->data() + offset; };
|
||||
|
||||
void UpdateBuffer(const uint8_t *buf, size_t len);
|
||||
|
||||
void SetBufferLen(size_t len) { m_BufferLen = len; };
|
||||
|
||||
void RefreshTimestamp();
|
||||
|
||||
const Addresses &GetAddresses() const { return *m_Addresses; };
|
||||
|
||||
CompatibleTransports GetReachableTransports() const { return m_ReachableTransports; };
|
||||
|
||||
void SetReachableTransports(CompatibleTransports transports) { m_ReachableTransports = transports; };
|
||||
|
||||
private:
|
||||
|
||||
bool LoadFile(const std::string &fullPath);
|
||||
|
||||
void ReadFromFile(const std::string &fullPath);
|
||||
|
||||
void ReadFromStream(std::istream &s);
|
||||
|
||||
void ReadFromBuffer(bool verifySignature);
|
||||
|
||||
size_t ReadString(char *str, size_t len, std::istream &s) const;
|
||||
|
||||
void ExtractCaps(const char *value);
|
||||
|
||||
uint8_t ExtractAddressCaps(const char *value) const;
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const Address> GetAddress(Filter filter) const;
|
||||
|
||||
virtual std::shared_ptr<Buffer> NewBuffer() const;
|
||||
|
||||
private:
|
||||
|
@ -306,27 +389,35 @@ namespace data
|
|||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||
};
|
||||
|
||||
class LocalRouterInfo: public RouterInfo
|
||||
{
|
||||
class LocalRouterInfo : public RouterInfo {
|
||||
public:
|
||||
|
||||
LocalRouterInfo() = default;
|
||||
|
||||
void CreateBuffer(const PrivateKeys &privateKeys);
|
||||
|
||||
void UpdateCaps(uint8_t caps);
|
||||
|
||||
void SetProperty(const std::string &key, const std::string &value) override;
|
||||
|
||||
void DeleteProperty(const std::string &key);
|
||||
|
||||
std::string GetProperty(const std::string &key) const;
|
||||
|
||||
void ClearProperties() override { m_Properties.clear(); };
|
||||
|
||||
bool AddSSU2Introducer(const Introducer &introducer, bool v4);
|
||||
|
||||
bool RemoveSSU2Introducer(const IdentHash &h, bool v4);
|
||||
|
||||
private:
|
||||
|
||||
void WriteToStream(std::ostream &s) const;
|
||||
|
||||
void UpdateCapsProperty();
|
||||
|
||||
void WriteString(const std::string &str, std::ostream &s) const;
|
||||
|
||||
std::shared_ptr<Buffer> NewBuffer() const override;
|
||||
|
||||
private:
|
||||
|
|
495
libi2pd/SSU.cpp
495
libi2pd/SSU.cpp
File diff suppressed because it is too large
Load diff
|
@ -25,10 +25,8 @@
|
|||
#include "I2NPProtocol.h"
|
||||
#include "SSUSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
||||
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
||||
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_SEND_BUFFER_SIZE = 0x1FFFF; // 128K
|
||||
|
||||
struct SSUPacket
|
||||
{
|
||||
struct SSUPacket {
|
||||
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
|
||||
boost::asio::ip::udp::endpoint from;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
class SSUServer
|
||||
{
|
||||
class SSUServer {
|
||||
public:
|
||||
|
||||
SSUServer(int port);
|
||||
|
||||
~SSUServer();
|
||||
|
||||
void Start();
|
||||
|
||||
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,
|
||||
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> GetRandomEstablishedV4Session(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 DeleteAllSessions();
|
||||
|
||||
boost::asio::io_service &GetService() { return m_Service; };
|
||||
|
||||
i2p::util::MemoryPool<Fragment> &GetFragmentsPool() { return m_FragmentsPool; };
|
||||
|
||||
i2p::util::MemoryPool<IncompleteMessage> &GetIncompleteMessagesPool() { return m_IncompleteMessagesPool; };
|
||||
|
||||
i2p::util::MemoryPool<SentMessage> &GetSentMessagesPool() { return m_SentMessagesPool; };
|
||||
|
||||
uint16_t GetPort() const { return m_Endpoint.port(); };
|
||||
|
||||
bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; };
|
||||
|
||||
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 AddRelay(uint32_t tag, std::shared_ptr<SSUSession> relay);
|
||||
|
||||
void RemoveRelay(uint32_t tag);
|
||||
|
||||
std::shared_ptr<SSUSession> FindRelaySession(uint32_t tag);
|
||||
|
||||
void RescheduleIntroducersUpdateTimer();
|
||||
|
||||
void RescheduleIntroducersUpdateTimerV6();
|
||||
|
||||
void NewPeerTest(uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session = nullptr);
|
||||
|
||||
PeerTestParticipant GetPeerTestParticipant(uint32_t nonce);
|
||||
|
||||
std::shared_ptr<SSUSession> GetPeerTestSession(uint32_t nonce);
|
||||
|
||||
void UpdatePeerTest(uint32_t nonce, PeerTestParticipant role);
|
||||
|
||||
void RemovePeerTest(uint32_t nonce);
|
||||
|
||||
private:
|
||||
|
||||
void OpenSocket();
|
||||
|
||||
void OpenSocketV6();
|
||||
|
||||
void Run();
|
||||
|
||||
void RunReceivers();
|
||||
|
||||
void RunReceiversV6();
|
||||
|
||||
void Receive();
|
||||
|
||||
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,
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > *sessions);
|
||||
|
||||
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>
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session(Filter filter);
|
||||
|
||||
template<typename 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 ScheduleIntroducersUpdateTimerV6();
|
||||
|
||||
void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4);
|
||||
|
||||
void SchedulePeerTestsCleanupTimer();
|
||||
|
||||
void HandlePeerTestsCleanupTimer(const boost::system::error_code &ecode);
|
||||
|
||||
// timer
|
||||
void ScheduleTermination();
|
||||
|
||||
void HandleTerminationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void ScheduleTerminationV6();
|
||||
|
||||
void HandleTerminationTimerV6(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
||||
struct PeerTest
|
||||
{
|
||||
struct PeerTest {
|
||||
uint64_t creationTime;
|
||||
PeerTestParticipant role;
|
||||
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
||||
|
@ -150,8 +194,14 @@ namespace transport
|
|||
|
||||
public:
|
||||
// for HTTP only
|
||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||
const decltype(m_SessionsV6)& GetSessionsV6 () const { return m_SessionsV6; };
|
||||
const decltype(m_Sessions)
|
||||
&
|
||||
|
||||
GetSessions() const { return m_Sessions; };
|
||||
const decltype(m_SessionsV6)
|
||||
&
|
||||
|
||||
GetSessionsV6() const { return m_SessionsV6; };
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
512
libi2pd/SSU2.cpp
512
libi2pd/SSU2.cpp
File diff suppressed because it is too large
Load diff
|
@ -13,10 +13,8 @@
|
|||
#include "util.h"
|
||||
#include "SSU2Session.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const int SSU2_TERMINATION_CHECK_TIMEOUT = 30; // in seconds
|
||||
const int SSU2_RESEND_CHECK_TIMEOUT = 500; // in milliseconds
|
||||
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_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
||||
|
||||
class SSU2Server: private i2p::util::RunnableServiceWithWork
|
||||
{
|
||||
struct Packet
|
||||
{
|
||||
class SSU2Server : private i2p::util::RunnableServiceWithWork {
|
||||
struct Packet {
|
||||
uint8_t buf[SSU2_MAX_PACKET_SIZE];
|
||||
size_t len;
|
||||
boost::asio::ip::udp::endpoint from;
|
||||
};
|
||||
|
||||
class ReceiveService: public i2p::util::RunnableService
|
||||
{
|
||||
class ReceiveService : public i2p::util::RunnableService {
|
||||
public:
|
||||
|
||||
ReceiveService(const std::string &name) : RunnableService(name) {};
|
||||
|
||||
boost::asio::io_service &GetService() { return GetIOService(); };
|
||||
|
||||
void Start() { StartIOService(); };
|
||||
|
||||
void Stop() { StopIOService(); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
SSU2Server();
|
||||
|
||||
~SSU2Server() {};
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
boost::asio::io_service &GetService() { return GetIOService(); };
|
||||
|
||||
void SetLocalAddress(const boost::asio::ip::address &localAddress);
|
||||
|
||||
bool IsSupported(const boost::asio::ip::address &addr) const;
|
||||
|
||||
uint16_t GetPort(bool v4) const;
|
||||
|
||||
bool IsSyncClockFromPeers() const { return m_IsSyncClockFromPeers; };
|
||||
|
||||
void AddSession(std::shared_ptr<SSU2Session> session);
|
||||
|
||||
void RemoveSession(uint64_t connID);
|
||||
|
||||
void AddSessionByRouterHash(std::shared_ptr<SSU2Session> session);
|
||||
|
||||
bool AddPendingOutgoingSession(std::shared_ptr<SSU2Session> session);
|
||||
|
||||
void RemovePendingOutgoingSession(const boost::asio::ip::udp::endpoint &ep);
|
||||
|
||||
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> GetRandomSession(i2p::data::RouterInfo::CompatibleTransports remoteTransports,
|
||||
const i2p::data::IdentHash &excluded) const;
|
||||
|
||||
void AddRelay(uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||
|
||||
void RemoveRelay(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,
|
||||
const boost::asio::ip::udp::endpoint &to);
|
||||
|
||||
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);
|
||||
|
||||
bool CreateSession(std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||
|
||||
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);
|
||||
|
||||
uint64_t FindOutgoingToken(const boost::asio::ip::udp::endpoint &ep) const;
|
||||
|
||||
uint64_t GetIncomingToken(const boost::asio::ip::udp::endpoint &ep);
|
||||
|
||||
std::pair<uint64_t, uint32_t> NewIncomingToken(const boost::asio::ip::udp::endpoint &ep);
|
||||
|
||||
void RescheduleIntroducersUpdateTimer();
|
||||
|
||||
void RescheduleIntroducersUpdateTimerV6();
|
||||
|
||||
i2p::util::MemoryPool<SSU2SentPacket> &GetSentPacketsPool() { return m_SentPacketsPool; };
|
||||
|
@ -94,25 +114,38 @@ namespace transport
|
|||
private:
|
||||
|
||||
boost::asio::ip::udp::socket &OpenSocket(const boost::asio::ip::udp::endpoint &localEndpoint);
|
||||
|
||||
void Receive(boost::asio::ip::udp::socket &socket);
|
||||
|
||||
void HandleReceivedFrom(const boost::system::error_code &ecode, size_t bytes_transferred,
|
||||
Packet *packet, boost::asio::ip::udp::socket &socket);
|
||||
|
||||
void HandleReceivedPacket(Packet *packet);
|
||||
|
||||
void HandleReceivedPackets(std::vector<Packet *> packets);
|
||||
|
||||
void ProcessNextPacket(uint8_t *buf, size_t len, const boost::asio::ip::udp::endpoint &senderEndpoint);
|
||||
|
||||
void ScheduleTermination();
|
||||
|
||||
void HandleTerminationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void ScheduleResend();
|
||||
|
||||
void HandleResendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void ConnectThroughIntroducer(std::shared_ptr<SSU2Session> session);
|
||||
|
||||
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 ScheduleIntroducersUpdateTimer();
|
||||
|
||||
void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4);
|
||||
|
||||
void ScheduleIntroducersUpdateTimerV6();
|
||||
|
||||
private:
|
||||
|
@ -137,7 +170,10 @@ namespace transport
|
|||
public:
|
||||
|
||||
// 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
|
@ -20,10 +20,8 @@
|
|||
#include "RouterContext.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
const int SSU2_TERMINATION_TIMEOUT = 330; // 5.5 minutes
|
||||
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 uint8_t SSU2_MAX_NUM_FRAGMENTS = 64;
|
||||
|
||||
enum SSU2MessageType
|
||||
{
|
||||
enum SSU2MessageType {
|
||||
eSSU2SessionRequest = 0,
|
||||
eSSU2SessionCreated = 1,
|
||||
eSSU2SessionConfirmed = 2,
|
||||
|
@ -60,8 +57,7 @@ namespace transport
|
|||
eSSU2HolePunch = 11
|
||||
};
|
||||
|
||||
enum SSU2BlockType
|
||||
{
|
||||
enum SSU2BlockType {
|
||||
eSSU2BlkDateTime = 0,
|
||||
eSSU2BlkOptions, // 1
|
||||
eSSU2BlkRouterInfo, // 2
|
||||
|
@ -86,8 +82,7 @@ namespace transport
|
|||
eSSU2BlkPadding = 254
|
||||
};
|
||||
|
||||
enum SSU2SessionState
|
||||
{
|
||||
enum SSU2SessionState {
|
||||
eSSU2SessionStateUnknown,
|
||||
eSSU2SessionStateTokenReceived,
|
||||
eSSU2SessionStateSessionRequestSent,
|
||||
|
@ -105,8 +100,7 @@ namespace transport
|
|||
eSSU2SessionStateTokenRequestReceived
|
||||
};
|
||||
|
||||
enum SSU2PeerTestCode
|
||||
{
|
||||
enum SSU2PeerTestCode {
|
||||
eSSU2PeerTestCodeAccept = 0,
|
||||
eSSU2PeerTestCodeBobReasonUnspecified = 1,
|
||||
eSSU2PeerTestCodeBobNoCharlieAvailable = 2,
|
||||
|
@ -122,8 +116,7 @@ namespace transport
|
|||
eSSU2PeerTestCodeUnspecified = 128
|
||||
};
|
||||
|
||||
enum SSU2RelayResponseCode
|
||||
{
|
||||
enum SSU2RelayResponseCode {
|
||||
eSSU2RelayResponseCodeAccept = 0,
|
||||
eSSU2RelayResponseCodeBobRelayTagNotFound = 5,
|
||||
eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65,
|
||||
|
@ -131,8 +124,7 @@ namespace transport
|
|||
eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70
|
||||
};
|
||||
|
||||
enum SSU2TerminationReason
|
||||
{
|
||||
enum SSU2TerminationReason {
|
||||
eSSU2TerminationReasonNormalClose = 0,
|
||||
eSSU2TerminationReasonTerminationReceived = 1,
|
||||
eSSU2TerminationReasonIdleTimeout = 2,
|
||||
|
@ -158,10 +150,8 @@ namespace transport
|
|||
eSSU2TerminationReasonReplacedByNewSession = 22
|
||||
};
|
||||
|
||||
struct SSU2IncompleteMessage
|
||||
{
|
||||
struct Fragment
|
||||
{
|
||||
struct SSU2IncompleteMessage {
|
||||
struct Fragment {
|
||||
uint8_t buf[SSU2_MAX_PACKET_SIZE];
|
||||
size_t len;
|
||||
bool isLast;
|
||||
|
@ -175,8 +165,7 @@ namespace transport
|
|||
void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize);
|
||||
};
|
||||
|
||||
struct SSU2SentPacket
|
||||
{
|
||||
struct SSU2SentPacket {
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
size_t payloadSize = 0;
|
||||
uint64_t sendTime; // in milliseconds
|
||||
|
@ -188,14 +177,12 @@ namespace transport
|
|||
const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02;
|
||||
|
||||
class SSU2Server;
|
||||
class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session>
|
||||
{
|
||||
union Header
|
||||
{
|
||||
|
||||
class SSU2Session : public TransportSession, public std::enable_shared_from_this<SSU2Session> {
|
||||
union Header {
|
||||
uint64_t ll[2];
|
||||
uint8_t buf[16];
|
||||
struct
|
||||
{
|
||||
struct {
|
||||
uint64_t connID;
|
||||
uint32_t packetNum;
|
||||
uint8_t type;
|
||||
|
@ -203,8 +190,7 @@ namespace transport
|
|||
} h;
|
||||
};
|
||||
|
||||
struct HandshakePacket
|
||||
{
|
||||
struct HandshakePacket {
|
||||
Header header;
|
||||
uint8_t headerX[48]; // part1 for SessionConfirmed
|
||||
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,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
||||
|
||||
~SSU2Session();
|
||||
|
||||
void SetRemoteEndpoint(const boost::asio::ip::udp::endpoint &ep) { m_RemoteEndpoint = ep; };
|
||||
|
||||
const boost::asio::ip::udp::endpoint &GetRemoteEndpoint() const { return m_RemoteEndpoint; };
|
||||
|
||||
i2p::data::RouterInfo::CompatibleTransports GetRemoteTransports() const { return m_RemoteTransports; };
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> GetAddress() const { return m_Address; };
|
||||
|
||||
void SetOnEstablished(OnEstablished e) { m_OnEstablished = e; };
|
||||
|
||||
OnEstablished GetOnEstablished() const { return m_OnEstablished; };
|
||||
|
||||
void Connect();
|
||||
|
||||
bool Introduce(std::shared_ptr<SSU2Session> session, uint32_t relayTag);
|
||||
|
||||
void WaitForIntroduction();
|
||||
|
||||
void SendPeerTest(); // Alice, Data message
|
||||
void SendKeepAlive();
|
||||
|
||||
void RequestTermination(SSU2TerminationReason reason);
|
||||
|
||||
void CleanUp(uint64_t ts);
|
||||
|
||||
void FlushData();
|
||||
|
||||
void Done() override;
|
||||
|
||||
void SendLocalRouterInfo(bool update) override;
|
||||
|
||||
void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) override;
|
||||
|
||||
uint32_t GetRelayTag() const override { return m_RelayTag; };
|
||||
|
||||
void Resend(uint64_t ts);
|
||||
|
||||
bool IsEstablished() const { return m_State == eSSU2SessionStateEstablished; };
|
||||
|
||||
uint64_t GetConnID() const { return m_SourceConnID; };
|
||||
|
||||
SSU2SessionState GetState() const { return m_State; };
|
||||
|
||||
void SetState(SSU2SessionState state) { m_State = state; };
|
||||
|
||||
bool ProcessFirstIncomingMessage(uint64_t connID, uint8_t *buf, size_t len);
|
||||
|
||||
bool ProcessSessionCreated(uint8_t *buf, size_t len);
|
||||
|
||||
bool ProcessSessionConfirmed(uint8_t *buf, size_t len);
|
||||
|
||||
bool ProcessRetry(uint8_t *buf, size_t len);
|
||||
|
||||
bool ProcessHolePunch(uint8_t *buf, size_t len);
|
||||
|
||||
bool ProcessPeerTest(uint8_t *buf, size_t len);
|
||||
|
||||
void ProcessData(uint8_t *buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
void Terminate();
|
||||
|
||||
void Established();
|
||||
|
||||
void ScheduleConnectTimer();
|
||||
|
||||
void HandleConnectTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void PostI2NPMessages(std::vector<std::shared_ptr<I2NPMessage> > msgs);
|
||||
|
||||
bool SendQueue(); // returns true if ack block was sent
|
||||
bool SendFragmentedMessage(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ResendHandshakePacket();
|
||||
|
||||
void ConnectAfterIntroduction();
|
||||
|
||||
void ProcessSessionRequest(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 SendSessionCreated(const uint8_t *X);
|
||||
|
||||
void SendSessionConfirmed(const uint8_t *Y);
|
||||
|
||||
void KDFDataPhase(uint8_t *keydata_ab, uint8_t *keydata_ba);
|
||||
|
||||
void SendTokenRequest();
|
||||
|
||||
void SendRetry();
|
||||
|
||||
uint32_t SendData(const uint8_t *buf, size_t len); // returns packet num
|
||||
void SendQuickAck();
|
||||
|
||||
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 HandlePayload(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 HandleAckRange(uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts);
|
||||
|
||||
void HandleAddress(const uint8_t *buf, size_t len);
|
||||
|
||||
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);
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress() const;
|
||||
|
||||
void AdjustMaxPayloadSize();
|
||||
|
||||
RouterStatus GetRouterStatus() const;
|
||||
|
||||
void SetRouterStatus(RouterStatus status) const;
|
||||
|
||||
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo(const uint8_t *buf, size_t size);
|
||||
|
||||
void CreateNonce(uint64_t seqn, uint8_t *nonce);
|
||||
|
||||
bool UpdateReceivePacketNum(uint32_t packetNum); // for Ack, returns false if duplicate
|
||||
void HandleFirstFragment(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
|
||||
void HandleRelayRequest(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 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 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 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 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 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 CreateTerminationBlock(uint8_t *buf, size_t len);
|
||||
|
||||
|
@ -347,8 +411,7 @@ namespace transport
|
|||
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;
|
||||
i2p::crypto::ChaCha20((uint8_t * ) & data, 8, kh, nonce, (uint8_t * ) & data);
|
||||
return data;
|
||||
|
|
|
@ -13,14 +13,10 @@
|
|||
#include "SSU.h"
|
||||
#include "SSUData.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
void IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
|
||||
{
|
||||
if (msg->len + fragmentSize > msg->maxLen)
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
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");
|
||||
auto newMsg = NewI2NPMessage();
|
||||
*newMsg = *msg;
|
||||
|
@ -34,74 +30,60 @@ namespace transport
|
|||
SSUData::SSUData(SSUSession &session) :
|
||||
m_Session(session), m_ResendTimer(session.GetService()),
|
||||
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_IncompleteMessages.clear();
|
||||
m_SentMessages.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;
|
||||
auto ssuAddress = remoteRouter->GetSSUAddress();
|
||||
if (ssuAddress && ssuAddress->ssu->mtu)
|
||||
{
|
||||
if (ssuAddress && ssuAddress->ssu->mtu) {
|
||||
if (m_Session.IsV6())
|
||||
m_PacketSize = ssuAddress->ssu->mtu - IPV6_HEADER_SIZE - UDP_HEADER_SIZE;
|
||||
else
|
||||
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
|
||||
m_PacketSize >>= 4;
|
||||
m_PacketSize <<= 4;
|
||||
if (m_PacketSize > m_MaxPacketSize) m_PacketSize = m_MaxPacketSize;
|
||||
LogPrint(eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LogPrint(eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
||||
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);
|
||||
if (routerInfo)
|
||||
AdjustPacketSize(routerInfo);
|
||||
}
|
||||
|
||||
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
||||
{
|
||||
void SSUData::ProcessSentMessageAck(uint32_t msgID) {
|
||||
auto it = m_SentMessages.find(msgID);
|
||||
if (it != m_SentMessages.end ())
|
||||
{
|
||||
if (it != m_SentMessages.end()) {
|
||||
m_SentMessages.erase(it);
|
||||
if (m_SentMessages.empty())
|
||||
m_ResendTimer.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
||||
{
|
||||
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED)
|
||||
{
|
||||
void SSUData::ProcessAcks(uint8_t *&buf, uint8_t flag) {
|
||||
if (flag & DATA_FLAG_EXPLICIT_ACKS_INCLUDED) {
|
||||
// explicit ACKs
|
||||
uint8_t numAcks = *buf;
|
||||
buf++;
|
||||
|
@ -109,33 +91,27 @@ namespace transport
|
|||
ProcessSentMessageAck(bufbe32toh(buf + i * 4));
|
||||
buf += numAcks * 4;
|
||||
}
|
||||
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
|
||||
{
|
||||
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED) {
|
||||
// explicit ACK bitfields
|
||||
uint8_t numBitfields = *buf;
|
||||
buf++;
|
||||
for (int i = 0; i < numBitfields; i++)
|
||||
{
|
||||
for (int i = 0; i < numBitfields; i++) {
|
||||
uint32_t msgID = bufbe32toh(buf);
|
||||
buf += 4; // msgID
|
||||
auto it = m_SentMessages.find(msgID);
|
||||
// process individual Ack bitfields
|
||||
bool isNonLast = false;
|
||||
int fragment = 0;
|
||||
do
|
||||
{
|
||||
do {
|
||||
uint8_t bitfield = *buf;
|
||||
isNonLast = bitfield & 0x80;
|
||||
bitfield &= 0x7F; // clear MSB
|
||||
if (bitfield && it != m_SentMessages.end ())
|
||||
{
|
||||
if (bitfield && it != m_SentMessages.end()) {
|
||||
int numSentFragments = it->second->fragments.size();
|
||||
// process bits
|
||||
uint8_t mask = 0x01;
|
||||
for (int j = 0; j < 7; j++)
|
||||
{
|
||||
if (bitfield & mask)
|
||||
{
|
||||
for (int j = 0; j < 7; j++) {
|
||||
if (bitfield & mask) {
|
||||
if (fragment < numSentFragments)
|
||||
it->second->fragments[fragment] = nullptr;
|
||||
}
|
||||
|
@ -144,18 +120,15 @@ namespace transport
|
|||
}
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
while (isNonLast);
|
||||
} while (isNonLast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ProcessFragments (uint8_t * buf)
|
||||
{
|
||||
void SSUData::ProcessFragments(uint8_t *buf) {
|
||||
uint8_t numFragments = *buf; // number of fragments
|
||||
buf++;
|
||||
for (int i = 0; i < numFragments; i++)
|
||||
{
|
||||
for (int i = 0; i < numFragments; i++) {
|
||||
uint32_t msgID = bufbe32toh(buf); // message ID
|
||||
buf += 4;
|
||||
uint8_t frag[4] = {0};
|
||||
|
@ -165,21 +138,20 @@ namespace transport
|
|||
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
|
||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||
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");
|
||||
return;
|
||||
}
|
||||
|
||||
// find message with msgID
|
||||
auto it = m_IncompleteMessages.find(msgID);
|
||||
if (it == m_IncompleteMessages.end ())
|
||||
{
|
||||
if (it == m_IncompleteMessages.end()) {
|
||||
// create new message
|
||||
auto msg = NewI2NPShortMessage();
|
||||
msg->len -= I2NP_SHORT_HEADER_SIZE;
|
||||
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;
|
||||
// mark fragment as received
|
||||
|
@ -189,49 +161,46 @@ namespace transport
|
|||
LogPrint(eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
|
||||
|
||||
// handle current fragment
|
||||
if (fragmentNum == incompleteMessage->nextFragmentNum)
|
||||
{
|
||||
if (fragmentNum == incompleteMessage->nextFragmentNum) {
|
||||
// expected fragment
|
||||
incompleteMessage->AttachNextFragment(buf, fragmentSize);
|
||||
if (!isLast && !incompleteMessage->savedFragments.empty ())
|
||||
{
|
||||
if (!isLast && !incompleteMessage->savedFragments.empty()) {
|
||||
// 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;
|
||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
||||
{
|
||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) {
|
||||
incompleteMessage->AttachNextFragment(savedFragment->buf, savedFragment->len);
|
||||
isLast = savedFragment->isLast;
|
||||
incompleteMessage->savedFragments.erase(it1++);
|
||||
}
|
||||
else
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (isLast)
|
||||
LogPrint(eLogDebug, "SSU: Message ", msgID, " complete");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
||||
// duplicate fragment
|
||||
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
|
||||
else
|
||||
{
|
||||
LogPrint(eLogWarning, "SSU: Duplicate fragment ", (int) fragmentNum, " of message ", msgID,
|
||||
", ignored");
|
||||
else {
|
||||
// missing fragment
|
||||
LogPrint (eLogWarning, "SSU: Missing fragments from ", (int)incompleteMessage->nextFragmentNum, " to ", fragmentNum - 1, " of message ", msgID);
|
||||
auto savedFragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared (fragmentNum, buf, fragmentSize, isLast);
|
||||
LogPrint(eLogWarning, "SSU: Missing fragments from ", (int) incompleteMessage->nextFragmentNum,
|
||||
" to ", fragmentNum - 1, " of message ", msgID);
|
||||
auto savedFragment = m_Session.GetServer().GetFragmentsPool().AcquireShared(fragmentNum, buf,
|
||||
fragmentSize,
|
||||
isLast);
|
||||
if (incompleteMessage->savedFragments.insert(savedFragment).second)
|
||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch();
|
||||
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;
|
||||
}
|
||||
|
||||
if (isLast)
|
||||
{
|
||||
if (isLast) {
|
||||
// delete incomplete message
|
||||
auto msg = incompleteMessage->msg;
|
||||
incompleteMessage->msg = nullptr;
|
||||
|
@ -239,47 +208,35 @@ namespace transport
|
|||
// process message
|
||||
SendMsgAck(msgID);
|
||||
msg->FromSSU(msgID);
|
||||
if (m_Session.GetState () == eSessionStateEstablished)
|
||||
{
|
||||
if (!m_ReceivedMessages.count (msgID))
|
||||
{
|
||||
if (m_Session.GetState() == eSessionStateEstablished) {
|
||||
if (!m_ReceivedMessages.count(msgID)) {
|
||||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch();
|
||||
m_ReceivedMessages.emplace(msgID, m_LastMessageReceivedTime);
|
||||
if (!msg->IsExpired ())
|
||||
{
|
||||
if (!msg->IsExpired()) {
|
||||
m_Handler.PutNextMessage(std::move(msg));
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogDebug, "SSU: message expired");
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "SSU: Message ", msgID, " already received");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// we expect DeliveryStatus
|
||||
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
||||
{
|
||||
if (msg->GetTypeID() == eI2NPDeliveryStatus) {
|
||||
LogPrint(eLogDebug, "SSU: session established");
|
||||
m_Session.Established();
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogError, "SSU: unexpected message ", (int) msg->GetTypeID());
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
SendFragmentAck(msgID, incompleteMessage->receivedFragmentsBits);
|
||||
buf += fragmentSize;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::FlushReceivedMessage ()
|
||||
{
|
||||
void SSUData::FlushReceivedMessage() {
|
||||
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 flag = *buf;
|
||||
buf++;
|
||||
|
@ -288,8 +245,7 @@ namespace transport
|
|||
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
||||
ProcessAcks(buf, flag);
|
||||
// extended data if presented
|
||||
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED)
|
||||
{
|
||||
if (flag & DATA_FLAG_EXTENDED_DATA_INCLUDED) {
|
||||
uint8_t extendedDataSize = *buf;
|
||||
buf++; // size
|
||||
LogPrint(eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
|
||||
|
@ -299,11 +255,9 @@ namespace transport
|
|||
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();
|
||||
if (m_SentMessages.find (msgID) != m_SentMessages.end())
|
||||
{
|
||||
if (m_SentMessages.find(msgID) != m_SentMessages.end()) {
|
||||
LogPrint(eLogWarning, "SSU: message ", msgID, " already sent");
|
||||
return;
|
||||
}
|
||||
|
@ -312,19 +266,18 @@ namespace transport
|
|||
|
||||
auto ret = m_SentMessages.emplace(msgID, m_Session.GetServer().GetSentMessagesPool().AcquireShared());
|
||||
auto &sentMessage = ret.first->second;
|
||||
if (ret.second)
|
||||
{
|
||||
if (ret.second) {
|
||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch() + RESEND_INTERVAL;
|
||||
sentMessage->numResends = 0;
|
||||
}
|
||||
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();
|
||||
uint8_t *msgBuf = msg->GetSSUHeader();
|
||||
|
||||
uint32_t fragmentNum = 0;
|
||||
while (len > 0 && fragmentNum <= 127)
|
||||
{
|
||||
while (len > 0 && fragmentNum <= 127) {
|
||||
auto fragment = m_Session.GetServer().GetFragmentsPool().AcquireShared();
|
||||
fragment->fragmentNum = fragmentNum;
|
||||
uint8_t *payload = fragment->buf + sizeof(SSUHeader);
|
||||
|
@ -360,27 +313,22 @@ namespace transport
|
|||
// encrypt message with session key
|
||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
||||
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
|
||||
try
|
||||
{
|
||||
try {
|
||||
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());
|
||||
}
|
||||
if (!isLast)
|
||||
{
|
||||
if (!isLast) {
|
||||
len -= payloadSize;
|
||||
msgBuf += payloadSize;
|
||||
}
|
||||
else
|
||||
} else
|
||||
len = 0;
|
||||
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 *payload = buf + sizeof(SSUHeader);
|
||||
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
||||
|
@ -396,8 +344,7 @@ namespace transport
|
|||
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;
|
||||
uint8_t buf[64 + 18] = {0};
|
||||
uint8_t *payload = buf + sizeof(SSUHeader);
|
||||
|
@ -409,12 +356,12 @@ namespace transport
|
|||
*(uint32_t * )(payload) = htobe32(msgID); // msgID
|
||||
payload += 4;
|
||||
size_t len = 0;
|
||||
while (bits)
|
||||
{
|
||||
while (bits) {
|
||||
*payload = (bits & 0x7F); // next 7 bits
|
||||
bits >>= 7;
|
||||
if (bits) *payload &= 0x80; // 0x80 means non-last
|
||||
payload++; len++;
|
||||
payload++;
|
||||
len++;
|
||||
}
|
||||
*payload = 0; // number of fragments
|
||||
len = (len <= 4) ? 48 : 64; // 48 = 37 + 7 + 4
|
||||
|
@ -423,88 +370,73 @@ namespace transport
|
|||
m_Session.Send(buf, len);
|
||||
}
|
||||
|
||||
void SSUData::ScheduleResend()
|
||||
{
|
||||
void SSUData::ScheduleResend() {
|
||||
m_ResendTimer.cancel();
|
||||
m_ResendTimer.expires_from_now(boost::posix_time::seconds(RESEND_INTERVAL));
|
||||
auto s = m_Session.shared_from_this();
|
||||
m_ResendTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||
{ s->m_Data.HandleResendTimer (ecode); });
|
||||
m_ResendTimer.async_wait(
|
||||
[s](const boost::system::error_code &ecode) { s->m_Data.HandleResendTimer(ecode); });
|
||||
}
|
||||
|
||||
void SSUData::HandleResendTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
void SSUData::HandleResendTimer(const boost::system::error_code &ecode) {
|
||||
if (ecode != boost::asio::error::operation_aborted) {
|
||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18];
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch();
|
||||
int numResent = 0;
|
||||
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
||||
{
|
||||
if (ts >= it->second->nextResendTime)
|
||||
{
|
||||
if (it->second->numResends < MAX_NUM_RESENDS)
|
||||
{
|
||||
for (auto it = m_SentMessages.begin(); it != m_SentMessages.end();) {
|
||||
if (ts >= it->second->nextResendTime) {
|
||||
if (it->second->numResends < MAX_NUM_RESENDS) {
|
||||
for (auto &f: it->second->fragments)
|
||||
if (f)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (f) {
|
||||
try {
|
||||
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
|
||||
m_Session.Send(buf, f->len); // resend
|
||||
numResent++;
|
||||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't resend message ", it->first, " data fragment: ", ec.what ());
|
||||
catch (boost::system::system_error &ec) {
|
||||
LogPrint(eLogWarning, "SSU: Can't resend message ", it->first,
|
||||
" data fragment: ", ec.what());
|
||||
}
|
||||
}
|
||||
|
||||
it->second->numResends++;
|
||||
it->second->nextResendTime += it->second->numResends * RESEND_INTERVAL;
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
} else {
|
||||
LogPrint(eLogInfo, "SSU: message ", it->first, " has not been ACKed after ",
|
||||
MAX_NUM_RESENDS, " attempts, deleted");
|
||||
it = m_SentMessages.erase(it);
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
if (m_SentMessages.empty()) return; // nothing to resend
|
||||
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
|
||||
ScheduleResend();
|
||||
else
|
||||
{
|
||||
else {
|
||||
LogPrint(eLogError, "SSU: resend window exceeds max size. Session terminated");
|
||||
m_Session.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::CleanUp (uint64_t ts)
|
||||
{
|
||||
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 ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
void SSUData::CleanUp(uint64_t ts) {
|
||||
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 ",
|
||||
INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
|
||||
it = m_IncompleteMessages.erase(it);
|
||||
}
|
||||
else
|
||||
} else
|
||||
++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
|
||||
m_ReceivedMessages.clear();
|
||||
else
|
||||
{
|
||||
else {
|
||||
// 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)
|
||||
it = m_ReceivedMessages.erase(it);
|
||||
else
|
||||
|
|
|
@ -21,10 +21,8 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "TransportSession.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const size_t SSU_MTU_V4 = 1484;
|
||||
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
|
||||
|
@ -44,28 +42,25 @@ namespace transport
|
|||
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
|
||||
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
|
||||
|
||||
struct Fragment
|
||||
{
|
||||
struct Fragment {
|
||||
int fragmentNum;
|
||||
size_t len;
|
||||
bool isLast;
|
||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
|
||||
|
||||
Fragment() = default;
|
||||
|
||||
Fragment(int n, const uint8_t *b, int l, bool last) :
|
||||
fragmentNum(n), len(l), isLast(last) { memcpy(buf, b, len); };
|
||||
};
|
||||
|
||||
struct FragmentCmp
|
||||
{
|
||||
bool operator() (const std::shared_ptr<Fragment>& f1, const std::shared_ptr<Fragment>& f2) const
|
||||
{
|
||||
struct FragmentCmp {
|
||||
bool operator()(const std::shared_ptr<Fragment> &f1, const std::shared_ptr<Fragment> &f2) const {
|
||||
return f1->fragmentNum < f2->fragmentNum;
|
||||
};
|
||||
};
|
||||
|
||||
struct IncompleteMessage
|
||||
{
|
||||
struct IncompleteMessage {
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
int nextFragmentNum;
|
||||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
|
@ -73,45 +68,57 @@ namespace transport
|
|||
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
struct SentMessage
|
||||
{
|
||||
struct SentMessage {
|
||||
std::vector<std::shared_ptr<Fragment> > fragments;
|
||||
uint32_t nextResendTime; // in seconds
|
||||
int numResends;
|
||||
};
|
||||
|
||||
class SSUSession;
|
||||
class SSUData
|
||||
{
|
||||
|
||||
class SSUData {
|
||||
public:
|
||||
|
||||
SSUData(SSUSession &session);
|
||||
|
||||
~SSUData();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
void CleanUp(uint64_t ts);
|
||||
|
||||
void ProcessMessage(uint8_t *buf, size_t len);
|
||||
|
||||
void FlushReceivedMessage();
|
||||
|
||||
void Send(std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
|
||||
void AdjustPacketSize(std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
|
||||
|
||||
void UpdatePacketSize(const i2p::data::IdentHash &remoteIdent);
|
||||
|
||||
private:
|
||||
|
||||
void SendMsgAck(uint32_t msgID);
|
||||
|
||||
void SendFragmentAck(uint32_t msgID, uint64_t bits);
|
||||
|
||||
void ProcessAcks(uint8_t *&buf, uint8_t flag);
|
||||
|
||||
void ProcessFragments(uint8_t *buf);
|
||||
|
||||
void ProcessSentMessageAck(uint32_t msgID);
|
||||
|
||||
void ScheduleResend();
|
||||
|
||||
void HandleResendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,19 +17,18 @@
|
|||
#include "TransportSession.h"
|
||||
#include "SSUData.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const uint8_t SSU_HEADER_EXTENDED_OPTIONS_INCLUDED = 0x04;
|
||||
struct SSUHeader
|
||||
{
|
||||
|
||||
struct SSUHeader {
|
||||
uint8_t mac[16];
|
||||
uint8_t iv[16];
|
||||
uint8_t flag;
|
||||
uint8_t time[4];
|
||||
|
||||
uint8_t GetPayloadType() const { return flag >> 4; };
|
||||
|
||||
bool IsExtendedOptions() const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
|
||||
};
|
||||
|
||||
|
@ -53,8 +52,7 @@ namespace transport
|
|||
// extended options
|
||||
const uint16_t EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG = 0x0001;
|
||||
|
||||
enum SessionState
|
||||
{
|
||||
enum SessionState {
|
||||
eSessionStateUnknown,
|
||||
eSessionStateIntroduced,
|
||||
eSessionStateEstablished,
|
||||
|
@ -62,8 +60,7 @@ namespace transport
|
|||
eSessionStateFailed
|
||||
};
|
||||
|
||||
enum PeerTestParticipant
|
||||
{
|
||||
enum PeerTestParticipant {
|
||||
ePeerTestParticipantUnknown = 0,
|
||||
ePeerTestParticipantAlice1,
|
||||
ePeerTestParticipantAlice2,
|
||||
|
@ -72,82 +69,127 @@ namespace transport
|
|||
};
|
||||
|
||||
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:
|
||||
|
||||
SSUSession(SSUServer &server, boost::asio::ip::udp::endpoint &remoteEndpoint,
|
||||
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);
|
||||
|
||||
~SSUSession();
|
||||
|
||||
void Connect();
|
||||
|
||||
void WaitForConnect();
|
||||
|
||||
void Introduce(const i2p::data::RouterInfo::Introducer &introducer,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
|
||||
void WaitForIntroduction();
|
||||
|
||||
void Close();
|
||||
|
||||
void Done();
|
||||
|
||||
void Failed();
|
||||
|
||||
const boost::asio::ip::udp::endpoint &GetRemoteEndpoint() { return m_RemoteEndpoint; };
|
||||
|
||||
SSUServer &GetServer() { return m_Server; };
|
||||
|
||||
bool IsV6() const { return m_RemoteEndpoint.address().is_v6(); };
|
||||
|
||||
void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs);
|
||||
|
||||
void SendPeerTest(); // Alice
|
||||
|
||||
SessionState GetState() const { return m_State; };
|
||||
|
||||
size_t GetNumSentBytes() const { return m_NumSentBytes; };
|
||||
|
||||
size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; };
|
||||
|
||||
void SendKeepAlive();
|
||||
|
||||
uint32_t GetRelayTag() const { return m_RelayTag; };
|
||||
|
||||
const i2p::data::RouterInfo::IntroKey &GetIntroKey() const { return m_IntroKey; };
|
||||
|
||||
void FlushData();
|
||||
|
||||
void CleanUp(uint64_t ts);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service &GetService();
|
||||
|
||||
void CreateAESandMacKey(const uint8_t *pubKey);
|
||||
|
||||
size_t GetSSUHeaderSize(const uint8_t *buf) const;
|
||||
|
||||
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 SendSessionRequest();
|
||||
|
||||
void SendRelayRequest(const i2p::data::RouterInfo::Introducer &introducer, uint32_t nonce);
|
||||
|
||||
void ProcessSessionCreated(uint8_t *buf, size_t len);
|
||||
|
||||
void SendSessionCreated(const uint8_t *x, bool sendRelayTag = true);
|
||||
|
||||
void ProcessSessionConfirmed(const uint8_t *buf, size_t len);
|
||||
|
||||
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 SendRelayResponse(uint32_t nonce, const boost::asio::ip::udp::endpoint &from,
|
||||
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 ProcessRelayResponse(const uint8_t *buf, size_t len);
|
||||
|
||||
void ProcessRelayIntro(const uint8_t *buf, size_t len);
|
||||
|
||||
void Established();
|
||||
|
||||
void ScheduleConnectTimer();
|
||||
|
||||
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 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 SendSessionDestroyed();
|
||||
|
||||
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 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);
|
||||
|
||||
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 Decrypt(uint8_t *buf, size_t len, const i2p::crypto::AESKey &aesKey);
|
||||
|
||||
void DecryptSessionKey(uint8_t *buf, size_t len);
|
||||
|
||||
bool Validate(uint8_t *buf, size_t len, const i2p::crypto::MACKey &macKey);
|
||||
|
||||
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:
|
||||
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
#include "Log.h"
|
||||
#include "Signature.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
#if OPENSSL_EDDSA
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||
{
|
||||
|
@ -38,24 +36,21 @@ namespace crypto
|
|||
}
|
||||
|
||||
#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);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
m_PublicKey = GetEd25519()->DecodePublicKey(m_PublicKeyEncoded, 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];
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init(&ctx);
|
||||
|
@ -66,10 +61,11 @@ namespace crypto
|
|||
|
||||
return GetEd25519()->Verify(m_PublicKey, digest, signature);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EDDSA25519SignerCompat::EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||
{
|
||||
EDDSA25519SignerCompat::EDDSA25519SignerCompat(const uint8_t *signingPrivateKey,
|
||||
const uint8_t *signingPublicKey) {
|
||||
// expand key
|
||||
Ed25519::ExpandPrivateKey(signingPrivateKey, m_ExpandedPrivateKey);
|
||||
// generate and encode public key
|
||||
|
@ -77,8 +73,7 @@ namespace crypto
|
|||
auto publicKey = GetEd25519()->GeneratePublicKey(m_ExpandedPrivateKey, 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
|
||||
LogPrint(eLogWarning, "Older EdDSA key detected");
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
|
||||
|
@ -88,12 +83,10 @@ namespace crypto
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,60 +19,59 @@
|
|||
#include "Ed25519.h"
|
||||
#include "Gost.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
class Verifier
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
class Verifier {
|
||||
public:
|
||||
|
||||
virtual ~Verifier() {};
|
||||
|
||||
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 GetSignatureLen() const = 0;
|
||||
|
||||
virtual size_t GetPrivateKeyLen() const { return GetSignatureLen() / 2; };
|
||||
|
||||
virtual void SetPublicKey(const uint8_t *signingKey) = 0;
|
||||
};
|
||||
|
||||
class Signer
|
||||
{
|
||||
class Signer {
|
||||
public:
|
||||
|
||||
virtual ~Signer() {};
|
||||
|
||||
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_SIGNATURE_LENGTH = 40;
|
||||
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH / 2;
|
||||
class DSAVerifier: public Verifier
|
||||
{
|
||||
|
||||
class DSAVerifier : public Verifier {
|
||||
public:
|
||||
|
||||
DSAVerifier ()
|
||||
{
|
||||
DSAVerifier() {
|
||||
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);
|
||||
}
|
||||
|
||||
~DSAVerifier ()
|
||||
{
|
||||
~DSAVerifier() {
|
||||
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
|
||||
uint8_t digest[20];
|
||||
SHA1(buf, len, digest);
|
||||
// signature
|
||||
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
|
||||
int ret = DSA_do_verify(digest, 20, sig, m_PublicKey);
|
||||
DSA_SIG_free(sig);
|
||||
|
@ -80,6 +79,7 @@ namespace crypto
|
|||
}
|
||||
|
||||
size_t GetPublicKeyLen() const { return DSA_PUBLIC_KEY_LENGTH; };
|
||||
|
||||
size_t GetSignatureLen() const { return DSA_SIGNATURE_LENGTH; };
|
||||
|
||||
private:
|
||||
|
@ -87,24 +87,22 @@ namespace crypto
|
|||
DSA *m_PublicKey;
|
||||
};
|
||||
|
||||
class DSASigner: public Signer
|
||||
{
|
||||
class DSASigner : public Signer {
|
||||
public:
|
||||
|
||||
DSASigner(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey)
|
||||
// openssl 1.1 always requires DSA public key even for signing
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
SHA1(buf, len, digest);
|
||||
DSA_SIG *sig = DSA_do_sign(digest, 20, m_PrivateKey);
|
||||
|
@ -120,8 +118,7 @@ namespace crypto
|
|||
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_generate_key(dsa);
|
||||
const BIGNUM *pub_key, *priv_key;
|
||||
|
@ -131,62 +128,58 @@ namespace crypto
|
|||
DSA_free(dsa);
|
||||
}
|
||||
|
||||
struct SHA256Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
struct SHA256Hash {
|
||||
static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
SHA256(buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 32 };
|
||||
enum {
|
||||
hashLen = 32
|
||||
};
|
||||
};
|
||||
|
||||
struct SHA384Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
struct SHA384Hash {
|
||||
static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
SHA384(buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 48 };
|
||||
enum {
|
||||
hashLen = 48
|
||||
};
|
||||
};
|
||||
|
||||
struct SHA512Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
struct SHA512Hash {
|
||||
static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
SHA512(buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 64 };
|
||||
enum {
|
||||
hashLen = 64
|
||||
};
|
||||
};
|
||||
|
||||
// EcDSA
|
||||
template<typename Hash, int curve, size_t keyLen>
|
||||
class ECDSAVerifier: public Verifier
|
||||
{
|
||||
class ECDSAVerifier : public Verifier {
|
||||
public:
|
||||
|
||||
ECDSAVerifier ()
|
||||
{
|
||||
ECDSAVerifier() {
|
||||
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 *y = BN_bin2bn(signingKey + keyLen / 2, keyLen / 2, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
|
@ -200,6 +193,7 @@ namespace crypto
|
|||
}
|
||||
|
||||
size_t GetPublicKeyLen() const { return keyLen; };
|
||||
|
||||
size_t GetSignatureLen() const { return keyLen; }; // signature length = key length
|
||||
|
||||
|
||||
|
@ -209,23 +203,19 @@ namespace crypto
|
|||
};
|
||||
|
||||
template<typename Hash, int curve, size_t keyLen>
|
||||
class ECDSASigner: public Signer
|
||||
{
|
||||
class ECDSASigner : public Signer {
|
||||
public:
|
||||
|
||||
ECDSASigner (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
ECDSASigner(const uint8_t *signingPrivateKey) {
|
||||
m_PrivateKey = EC_KEY_new_by_curve_name(curve);
|
||||
EC_KEY_set_private_key(m_PrivateKey, BN_bin2bn(signingPrivateKey, keyLen / 2, NULL));
|
||||
}
|
||||
|
||||
~ECDSASigner ()
|
||||
{
|
||||
~ECDSASigner() {
|
||||
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];
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
ECDSA_SIG *sig = ECDSA_do_sign(digest, Hash::hashLen, m_PrivateKey);
|
||||
|
@ -242,8 +232,8 @@ namespace crypto
|
|||
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_generate_key(signingKey);
|
||||
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);
|
||||
bn2buf(x, signingPublicKey, 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);
|
||||
}
|
||||
|
||||
|
@ -261,8 +252,7 @@ namespace crypto
|
|||
typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -271,8 +261,7 @@ namespace crypto
|
|||
typedef ECDSAVerifier<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Verifier;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -281,24 +270,25 @@ namespace crypto
|
|||
typedef ECDSAVerifier<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Verifier;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// EdDSA
|
||||
class EDDSA25519Verifier: public Verifier
|
||||
{
|
||||
class EDDSA25519Verifier : public Verifier {
|
||||
public:
|
||||
|
||||
EDDSA25519Verifier();
|
||||
|
||||
void SetPublicKey(const uint8_t *signingKey);
|
||||
|
||||
~EDDSA25519Verifier();
|
||||
|
||||
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 GetSignatureLen() const { return EDDSA25519_SIGNATURE_LENGTH; };
|
||||
|
||||
private:
|
||||
|
@ -311,15 +301,16 @@ namespace crypto
|
|||
#endif
|
||||
};
|
||||
|
||||
class EDDSA25519SignerCompat: public Signer
|
||||
{
|
||||
class EDDSA25519SignerCompat : public Signer {
|
||||
public:
|
||||
|
||||
EDDSA25519SignerCompat(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey = nullptr);
|
||||
|
||||
// we pass signingPublicKey to check if it matches private key
|
||||
~EDDSA25519SignerCompat();
|
||||
|
||||
void Sign(const uint8_t *buf, int len, uint8_t *signature) const;
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKeyEncoded; }; // for keys creation
|
||||
|
||||
private:
|
||||
|
@ -350,8 +341,7 @@ namespace crypto
|
|||
|
||||
#endif
|
||||
|
||||
inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
inline void CreateEDDSA25519RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
#if OPENSSL_EDDSA
|
||||
EVP_PKEY *pkey = NULL;
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL);
|
||||
|
@ -372,24 +362,24 @@ namespace crypto
|
|||
|
||||
|
||||
// ГОСТ Р 34.11
|
||||
struct GOSTR3411_256_Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
struct GOSTR3411_256_Hash {
|
||||
static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
GOSTR3411_2012_256(buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 32 };
|
||||
enum {
|
||||
hashLen = 32
|
||||
};
|
||||
};
|
||||
|
||||
struct GOSTR3411_512_Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
struct GOSTR3411_512_Hash {
|
||||
static void CalculateHash(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
GOSTR3411_2012_512(buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 64 };
|
||||
enum {
|
||||
hashLen = 64
|
||||
};
|
||||
};
|
||||
|
||||
// ГОСТ Р 34.10
|
||||
|
@ -397,42 +387,44 @@ namespace crypto
|
|||
const size_t GOSTR3410_512_PUBLIC_KEY_LENGTH = 128;
|
||||
|
||||
template<typename Hash>
|
||||
class GOSTR3410Verifier: public Verifier
|
||||
{
|
||||
class GOSTR3410Verifier : public Verifier {
|
||||
public:
|
||||
|
||||
enum { keyLen = Hash::hashLen };
|
||||
enum {
|
||||
keyLen = Hash::hashLen
|
||||
};
|
||||
|
||||
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 *y = BN_bin2bn(signingKey + GetPublicKeyLen() / 2, GetPublicKeyLen() / 2, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr);
|
||||
BIGNUM *r = BN_bin2bn(signature, GetSignatureLen() / 2, NULL);
|
||||
BIGNUM *s = BN_bin2bn(signature + GetSignatureLen() / 2, GetSignatureLen() / 2, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen() const { return keyLen * 2; }
|
||||
|
||||
size_t GetSignatureLen() const { return keyLen * 2; }
|
||||
|
||||
private:
|
||||
|
@ -442,21 +434,21 @@ namespace crypto
|
|||
};
|
||||
|
||||
template<typename Hash>
|
||||
class GOSTR3410Signer: public Signer
|
||||
{
|
||||
class GOSTR3410Signer : public Signer {
|
||||
public:
|
||||
|
||||
enum { keyLen = Hash::hashLen };
|
||||
enum {
|
||||
keyLen = Hash::hashLen
|
||||
};
|
||||
|
||||
GOSTR3410Signer(GOSTR3410ParamSet paramSet, const uint8_t *signingPrivateKey) :
|
||||
m_ParamSet (paramSet)
|
||||
{
|
||||
m_ParamSet(paramSet) {
|
||||
m_PrivateKey = BN_bin2bn(signingPrivateKey, keyLen, nullptr);
|
||||
}
|
||||
|
||||
~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];
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr);
|
||||
|
@ -464,7 +456,9 @@ namespace crypto
|
|||
GetGOSTR3410Curve(m_ParamSet)->Sign(m_PrivateKey, d, r, s);
|
||||
bn2buf(r, signature, 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:
|
||||
|
@ -473,8 +467,8 @@ namespace crypto
|
|||
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);
|
||||
auto keyLen = curve->GetKeyLen();
|
||||
RAND_bytes(signingPrivateKey, keyLen);
|
||||
|
@ -487,7 +481,8 @@ namespace crypto
|
|||
EC_POINT_free(pub);
|
||||
bn2buf(x, signingPublicKey, 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;
|
||||
|
@ -497,22 +492,21 @@ namespace crypto
|
|||
|
||||
// RedDSA
|
||||
typedef EDDSA25519Verifier RedDSA25519Verifier;
|
||||
class RedDSA25519Signer: public Signer
|
||||
{
|
||||
|
||||
class RedDSA25519Signer : public Signer {
|
||||
public:
|
||||
|
||||
RedDSA25519Signer (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
RedDSA25519Signer(const uint8_t *signingPrivateKey) {
|
||||
memcpy(m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
auto publicKey = GetEd25519()->GeneratePublicKey(m_PrivateKey, ctx);
|
||||
GetEd25519()->EncodePublicKey(publicKey, m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
~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);
|
||||
}
|
||||
|
||||
|
@ -524,8 +518,7 @@ namespace crypto
|
|||
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);
|
||||
RedDSA25519Signer signer(signingPrivateKey);
|
||||
memcpy(signingPublicKey, signer.GetPublicKey(), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
|
|
|
@ -12,32 +12,26 @@
|
|||
#include "Crypto.h"
|
||||
|
||||
#if !OPENSSL_SIPHASH
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace siphash
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
namespace siphash {
|
||||
constexpr int crounds = 2;
|
||||
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;
|
||||
ret |= x >> (64 - b);
|
||||
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[1] = (uint8_t)(v >> 8);
|
||||
p[2] = (uint8_t)(v >> 16);
|
||||
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[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 0xff;
|
||||
|
@ -48,20 +42,17 @@ namespace crypto
|
|||
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;
|
||||
int idx = 0;
|
||||
while(idx < 8)
|
||||
{
|
||||
while (idx < 8) {
|
||||
i |= ((uint64_t) p[idx]) << (idx * 8);
|
||||
++idx;
|
||||
}
|
||||
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;
|
||||
_v1 = rotl(_v1, 13);
|
||||
_v1 ^= _v0;
|
||||
|
@ -81,8 +72,7 @@ namespace crypto
|
|||
|
||||
/** hashsz must be 8 or 16 */
|
||||
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 v1 = 0x646f72616e646f6dULL;
|
||||
uint64_t v2 = 0x6c7967656e657261ULL;
|
||||
|
@ -101,8 +91,7 @@ namespace crypto
|
|||
|
||||
if (hashsz == 16) v1 ^= 0xee;
|
||||
|
||||
while(buf != end)
|
||||
{
|
||||
while (buf != end) {
|
||||
msg = siphash::u8to64le(buf);
|
||||
v3 ^= msg;
|
||||
for (i = 0; i < siphash::crounds; ++i)
|
||||
|
@ -112,8 +101,7 @@ namespace crypto
|
|||
buf += 8;
|
||||
}
|
||||
|
||||
while(left)
|
||||
{
|
||||
while (left) {
|
||||
--left;
|
||||
b |= ((uint64_t)(buf[left])) << (left * 8);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,14 +27,11 @@
|
|||
#include "Tunnel.h"
|
||||
#include "util.h" // MemoryPool
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
namespace i2p {
|
||||
namespace client {
|
||||
class ClientDestination;
|
||||
}
|
||||
namespace stream
|
||||
{
|
||||
namespace stream {
|
||||
const uint16_t PACKET_FLAG_SYNCHRONIZE = 0x0001;
|
||||
const uint16_t PACKET_FLAG_CLOSE = 0x0002;
|
||||
const uint16_t PACKET_FLAG_RESET = 0x0004;
|
||||
|
@ -64,81 +61,102 @@ namespace stream
|
|||
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
|
||||
const int MAX_RECEIVE_TIMEOUT = 20; // in seconds
|
||||
|
||||
struct Packet
|
||||
{
|
||||
struct Packet {
|
||||
size_t len, offset;
|
||||
uint8_t buf[MAX_PACKET_SIZE];
|
||||
uint64_t sendTime;
|
||||
|
||||
Packet() : len(0), offset(0), sendTime(0) {};
|
||||
|
||||
uint8_t *GetBuffer() { return buf + offset; };
|
||||
|
||||
size_t GetLength() const { return len - offset; };
|
||||
|
||||
uint32_t GetSendStreamID() const { return bufbe32toh(buf); };
|
||||
|
||||
uint32_t GetReceiveStreamID() const { return bufbe32toh(buf + 4); };
|
||||
|
||||
uint32_t GetSeqn() const { return bufbe32toh(buf + 8); };
|
||||
|
||||
uint32_t GetAckThrough() const { return bufbe32toh(buf + 12); };
|
||||
|
||||
uint8_t GetNACKCount() const { return buf[16]; };
|
||||
|
||||
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
|
||||
uint16_t GetFlags() const { return bufbe16toh(GetOption() - 2); };
|
||||
|
||||
uint16_t GetOptionSize() const { return bufbe16toh(GetOption()); };
|
||||
|
||||
const uint8_t *GetOptionData() const { return GetOption() + 2; };
|
||||
|
||||
const uint8_t *GetPayload() const { return GetOptionData() + GetOptionSize(); };
|
||||
|
||||
bool IsSYN() const { return GetFlags() & PACKET_FLAG_SYNCHRONIZE; };
|
||||
|
||||
bool IsNoAck() const { return GetFlags() & PACKET_FLAG_NO_ACK; };
|
||||
|
||||
bool IsEcho() const { return GetFlags() & PACKET_FLAG_ECHO; };
|
||||
};
|
||||
|
||||
struct PacketCmp
|
||||
{
|
||||
bool operator() (const Packet * p1, const Packet * p2) const
|
||||
{
|
||||
struct PacketCmp {
|
||||
bool operator()(const Packet *p1, const Packet *p2) const {
|
||||
return p1->GetSeqn() < p2->GetSeqn();
|
||||
};
|
||||
};
|
||||
|
||||
typedef std::function<void(const boost::system::error_code &ecode)> SendHandler;
|
||||
struct SendBuffer
|
||||
{
|
||||
|
||||
struct SendBuffer {
|
||||
uint8_t *buf;
|
||||
size_t len, offset;
|
||||
SendHandler handler;
|
||||
|
||||
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];
|
||||
memcpy(buf, b, len);
|
||||
}
|
||||
|
||||
SendBuffer(size_t l) : // create empty buffer
|
||||
len(l), offset (0)
|
||||
{
|
||||
len(l), offset(0) {
|
||||
buf = new uint8_t[len];
|
||||
}
|
||||
~SendBuffer ()
|
||||
{
|
||||
|
||||
~SendBuffer() {
|
||||
delete[] buf;
|
||||
if (handler) handler(boost::system::error_code());
|
||||
}
|
||||
|
||||
size_t GetRemainingSize() const { return len - 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:
|
||||
|
||||
SendBufferQueue() : m_Size(0) {};
|
||||
|
||||
~SendBufferQueue() { CleanUp(); };
|
||||
|
||||
void Add(const uint8_t *buf, size_t len, SendHandler handler);
|
||||
|
||||
void Add(std::shared_ptr<SendBuffer> buf);
|
||||
|
||||
size_t Get(uint8_t *buf, size_t len);
|
||||
|
||||
size_t GetSize() const { return m_Size; };
|
||||
|
||||
bool IsEmpty() const { return m_Buffers.empty(); };
|
||||
|
||||
void CleanUp();
|
||||
|
||||
private:
|
||||
|
@ -147,8 +165,7 @@ namespace stream
|
|||
size_t m_Size;
|
||||
};
|
||||
|
||||
enum StreamStatus
|
||||
{
|
||||
enum StreamStatus {
|
||||
eStreamStatusNew = 0,
|
||||
eStreamStatusOpen,
|
||||
eStreamStatusReset,
|
||||
|
@ -158,8 +175,8 @@ namespace stream
|
|||
};
|
||||
|
||||
class StreamingDestination;
|
||||
class Stream: public std::enable_shared_from_this<Stream>
|
||||
{
|
||||
|
||||
class Stream : public std::enable_shared_from_this<Stream> {
|
||||
public:
|
||||
|
||||
Stream(boost::asio::io_service &service, StreamingDestination &local,
|
||||
|
@ -167,37 +184,57 @@ namespace stream
|
|||
Stream(boost::asio::io_service &service, StreamingDestination &local); // incoming
|
||||
|
||||
~Stream();
|
||||
|
||||
uint32_t GetSendStreamID() const { return m_SendStreamID; };
|
||||
|
||||
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::IdentityEx> GetRemoteIdentity() const { return m_RemoteIdentity; };
|
||||
|
||||
bool IsOpen() const { return m_Status == eStreamStatusOpen; };
|
||||
|
||||
bool IsEstablished() const { return m_SendStreamID; };
|
||||
|
||||
StreamStatus GetStatus() const { return m_Status; };
|
||||
|
||||
StreamingDestination &GetLocalDestination() { return m_LocalDestination; };
|
||||
|
||||
void HandleNextPacket(Packet *packet);
|
||||
|
||||
void HandlePing(Packet *packet);
|
||||
|
||||
size_t Send(const uint8_t *buf, size_t len);
|
||||
|
||||
void AsyncSend(const uint8_t *buf, size_t len, SendHandler handler);
|
||||
|
||||
void SendPing();
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
void AsyncReceive(const Buffer &buffer, ReceiveHandler handler, int timeout = 0);
|
||||
|
||||
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())); };
|
||||
|
||||
/** only call close from destination thread, use Stream::AsyncClose for other threads */
|
||||
void Close();
|
||||
|
||||
void Cancel() { m_ReceiveTimer.cancel(); };
|
||||
|
||||
size_t GetNumSentBytes() const { return m_NumSentBytes; };
|
||||
|
||||
size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; };
|
||||
|
||||
size_t GetSendQueueSize() const { return m_SentPackets.size(); };
|
||||
|
||||
size_t GetReceiveQueueSize() const { return m_ReceiveQueue.size(); };
|
||||
|
||||
size_t GetSendBufferSize() const { return m_SendBuffer.GetSize(); };
|
||||
|
||||
int GetWindowSize() const { return m_WindowSize; };
|
||||
|
||||
int GetRTT() const { return m_RTT; };
|
||||
|
||||
void Terminate(bool deleteFromDestination = true);
|
||||
|
@ -207,25 +244,38 @@ namespace stream
|
|||
void CleanUp();
|
||||
|
||||
void SendBuffer();
|
||||
|
||||
void SendQuickAck();
|
||||
|
||||
void SendClose();
|
||||
|
||||
bool SendPacket(Packet *packet);
|
||||
|
||||
void SendPackets(const std::vector<Packet *> &packets);
|
||||
|
||||
void SendUpdatedLeaseSet();
|
||||
|
||||
void SavePacket(Packet *packet);
|
||||
|
||||
void ProcessPacket(Packet *packet);
|
||||
|
||||
bool ProcessOptions(uint16_t flags, Packet *packet);
|
||||
|
||||
void ProcessAck(Packet *packet);
|
||||
|
||||
size_t ConcatenatePackets(uint8_t *buf, size_t len);
|
||||
|
||||
void UpdateCurrentRemoteLease(bool expired = false);
|
||||
|
||||
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 HandleResendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void HandleAckSendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
@ -257,42 +307,60 @@ namespace stream
|
|||
size_t m_MTU;
|
||||
};
|
||||
|
||||
class StreamingDestination: public std::enable_shared_from_this<StreamingDestination>
|
||||
{
|
||||
class StreamingDestination : public std::enable_shared_from_this<StreamingDestination> {
|
||||
public:
|
||||
|
||||
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();
|
||||
|
||||
void Start();
|
||||
|
||||
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 DeleteStream(std::shared_ptr<Stream> stream);
|
||||
|
||||
bool DeleteStream(uint32_t recvStreamID);
|
||||
|
||||
void SetAcceptor(const Acceptor &acceptor);
|
||||
|
||||
void ResetAcceptor();
|
||||
|
||||
bool IsAcceptorSet() const { return m_Acceptor != nullptr; };
|
||||
|
||||
void AcceptOnce(const Acceptor &acceptor);
|
||||
|
||||
void AcceptOnceAcceptor(std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> GetOwner() const { return m_Owner; };
|
||||
|
||||
void SetOwner(std::shared_ptr<i2p::client::ClientDestination> owner) { m_Owner = owner; };
|
||||
|
||||
uint16_t GetLocalPort() const { return m_LocalPort; };
|
||||
|
||||
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(); }
|
||||
|
||||
void DeletePacket(Packet *p) { return m_PacketsPool.Release(p); }
|
||||
|
||||
private:
|
||||
|
||||
void HandleNextPacket(Packet *packet);
|
||||
|
||||
std::shared_ptr<Stream> CreateNewIncomingStream(uint32_t receiveStreamID);
|
||||
|
||||
void HandlePendingIncomingTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
@ -318,28 +386,28 @@ namespace stream
|
|||
std::unique_ptr<i2p::data::GzipDeflator> m_Deflator;
|
||||
|
||||
// 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>
|
||||
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();
|
||||
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)
|
||||
s->HandleReceiveTimer (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), buffer, handler, 0);
|
||||
else
|
||||
{
|
||||
s->HandleReceiveTimer(boost::asio::error::make_error_code(boost::asio::error::operation_aborted),
|
||||
buffer, handler, 0);
|
||||
else {
|
||||
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
|
||||
s->m_ReceiveTimer.expires_from_now(boost::posix_time::seconds(t));
|
||||
int left = timeout - t;
|
||||
auto self = s->shared_from_this();
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
@ -347,26 +415,24 @@ namespace stream
|
|||
}
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
void Stream::HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout)
|
||||
{
|
||||
size_t received = ConcatenatePackets (boost::asio::buffer_cast<uint8_t *>(buffer), boost::asio::buffer_size(buffer));
|
||||
void
|
||||
Stream::HandleReceiveTimer(const boost::system::error_code &ecode, const Buffer &buffer, ReceiveHandler handler,
|
||||
int remainingTimeout) {
|
||||
size_t received = ConcatenatePackets(boost::asio::buffer_cast<uint8_t *>(buffer),
|
||||
boost::asio::buffer_size(buffer));
|
||||
if (received > 0)
|
||||
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
|
||||
if (m_Status == eStreamStatusReset)
|
||||
handler(boost::asio::error::make_error_code(boost::asio::error::connection_reset), 0);
|
||||
else
|
||||
handler(boost::asio::error::make_error_code(boost::asio::error::operation_aborted), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// timeout expired
|
||||
if (remainingTimeout <= 0)
|
||||
handler(boost::asio::error::make_error_code(boost::asio::error::timed_out), received);
|
||||
else
|
||||
{
|
||||
else {
|
||||
// itermediate interrupt
|
||||
SendUpdatedLeaseSet(); // send our leaseset if applicable
|
||||
AsyncReceive(buffer, handler, remainingTimeout);
|
||||
|
|
|
@ -17,66 +17,65 @@
|
|||
namespace i2p {
|
||||
namespace data {
|
||||
template<size_t sz>
|
||||
class Tag
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sz % 8 == 0, "Tag size must be multiple of 8 bytes");
|
||||
class Tag {
|
||||
BOOST_STATIC_ASSERT_MSG(sz
|
||||
% 8 == 0, "Tag size must be multiple of 8 bytes");
|
||||
|
||||
public:
|
||||
|
||||
Tag() = default;
|
||||
|
||||
Tag(const uint8_t *buf) { memcpy(m_Buf, buf, sz); }
|
||||
|
||||
bool operator==(const Tag &other) const { return !memcmp(m_Buf, other.m_Buf, sz); }
|
||||
|
||||
bool operator!=(const Tag &other) const { return !(*this == other); }
|
||||
|
||||
bool operator<(const Tag &other) const { return memcmp(m_Buf, other.m_Buf, sz) < 0; }
|
||||
|
||||
uint8_t *operator()() { return m_Buf; }
|
||||
|
||||
const uint8_t *operator()() const { return m_Buf; }
|
||||
|
||||
operator uint8_t *() { return m_Buf; }
|
||||
|
||||
operator const uint8_t *() const { return m_Buf; }
|
||||
|
||||
const uint8_t *data() const { return m_Buf; }
|
||||
|
||||
const uint64_t *GetLL() const { return ll; }
|
||||
|
||||
bool IsZero () const
|
||||
{
|
||||
bool IsZero() const {
|
||||
for (size_t i = 0; i < sz / 8; ++i)
|
||||
if (ll[i]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Fill(uint8_t c)
|
||||
{
|
||||
void Fill(uint8_t c) {
|
||||
memset(m_Buf, c, sz);
|
||||
}
|
||||
|
||||
void Randomize()
|
||||
{
|
||||
void Randomize() {
|
||||
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];
|
||||
size_t l = i2p::data::ByteStreamToBase64(m_Buf, len, str, sz * 2);
|
||||
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];
|
||||
size_t l = i2p::data::ByteStreamToBase32(m_Buf, len, str, sz * 2);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -91,13 +90,11 @@ namespace data {
|
|||
} // data
|
||||
} // i2p
|
||||
|
||||
namespace std
|
||||
{
|
||||
namespace std {
|
||||
// hash for std::unordered_map
|
||||
template<size_t sz> struct hash<i2p::data::Tag<sz> >
|
||||
{
|
||||
size_t operator()(const i2p::data::Tag<sz>& s) const
|
||||
{
|
||||
template<size_t sz>
|
||||
struct hash<i2p::data::Tag<sz> > {
|
||||
size_t operator()(const i2p::data::Tag<sz> &s) const {
|
||||
return s.GetLL()[0];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,85 +27,67 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
static uint64_t GetLocalMillisecondsSinceEpoch ()
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
static uint64_t GetLocalMillisecondsSinceEpoch() {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
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>(
|
||||
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>(
|
||||
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>(
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
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);
|
||||
boost::asio::io_service service;
|
||||
boost::system::error_code ec;
|
||||
auto it = boost::asio::ip::udp::resolver(service).resolve(
|
||||
boost::asio::ip::udp::resolver::query(address, "ntp"), ec);
|
||||
if (!ec)
|
||||
{
|
||||
if (!ec) {
|
||||
bool found = false;
|
||||
boost::asio::ip::udp::resolver::iterator end;
|
||||
boost::asio::ip::udp::endpoint ep;
|
||||
while (it != end)
|
||||
{
|
||||
while (it != end) {
|
||||
ep = *it;
|
||||
if (!ep.address ().is_unspecified ())
|
||||
{
|
||||
if (ep.address ().is_v4 ())
|
||||
{
|
||||
if (!ep.address().is_unspecified()) {
|
||||
if (ep.address().is_v4()) {
|
||||
if (i2p::context.SupportsV4()) found = true;
|
||||
}
|
||||
else if (ep.address ().is_v6 ())
|
||||
{
|
||||
if (i2p::util::net::IsYggdrasilAddress (ep.address ()))
|
||||
{
|
||||
} else if (ep.address().is_v6()) {
|
||||
if (i2p::util::net::IsYggdrasilAddress(ep.address())) {
|
||||
if (i2p::context.SupportsMesh()) found = true;
|
||||
}
|
||||
else if (i2p::context.SupportsV6 ()) found = true;
|
||||
} else if (i2p::context.SupportsV6()) found = true;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
it++;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (!found) {
|
||||
LogPrint(eLogError, "Timestamp: can't find compatible address for ", address);
|
||||
return;
|
||||
}
|
||||
|
||||
boost::asio::ip::udp::socket socket(service);
|
||||
socket.open(ep.protocol(), ec);
|
||||
if (!ec)
|
||||
{
|
||||
if (!ec) {
|
||||
uint8_t buf[48];// 48 bytes NTP request/response
|
||||
memset(buf, 0, 48);
|
||||
htobe32buf(buf, (3 << 27) | (3 << 24)); // RFC 4330
|
||||
size_t len = 0;
|
||||
try
|
||||
{
|
||||
try {
|
||||
socket.send_to(boost::asio::buffer(buf, 48), ep);
|
||||
int i = 0;
|
||||
while (!socket.available() && i < 10) // 10 seconds max
|
||||
|
@ -116,129 +98,106 @@ namespace util
|
|||
if (socket.available())
|
||||
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());
|
||||
}
|
||||
if (len >= 8)
|
||||
{
|
||||
if (len >= 8) {
|
||||
auto ourTs = GetLocalSecondsSinceEpoch();
|
||||
uint32_t ts = bufbe32toh(buf + 32);
|
||||
if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900
|
||||
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");
|
||||
}
|
||||
else
|
||||
} else
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
NTPTimeSync::~NTPTimeSync ()
|
||||
{
|
||||
NTPTimeSync::~NTPTimeSync() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void NTPTimeSync::Start()
|
||||
{
|
||||
if (m_NTPServersList.size () > 0)
|
||||
{
|
||||
void NTPTimeSync::Start() {
|
||||
if (m_NTPServersList.size() > 0) {
|
||||
m_IsRunning = true;
|
||||
LogPrint(eLogInfo, "Timestamp: NTP time sync starting");
|
||||
m_Service.post(std::bind(&NTPTimeSync::Sync, this));
|
||||
m_Thread.reset(new std::thread(std::bind(&NTPTimeSync::Run, this)));
|
||||
}
|
||||
else
|
||||
} else
|
||||
LogPrint(eLogWarning, "Timestamp: No NTP server found");
|
||||
}
|
||||
|
||||
void NTPTimeSync::Stop ()
|
||||
{
|
||||
if (m_IsRunning)
|
||||
{
|
||||
void NTPTimeSync::Stop() {
|
||||
if (m_IsRunning) {
|
||||
LogPrint(eLogInfo, "Timestamp: NTP time sync stopping");
|
||||
m_IsRunning = false;
|
||||
m_Timer.cancel();
|
||||
m_Service.stop();
|
||||
if (m_Thread)
|
||||
{
|
||||
if (m_Thread) {
|
||||
m_Thread->join();
|
||||
m_Thread.reset(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTPTimeSync::Run ()
|
||||
{
|
||||
void NTPTimeSync::Run() {
|
||||
i2p::util::SetThreadName("Timesync");
|
||||
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (m_IsRunning) {
|
||||
try {
|
||||
m_Service.run();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
catch (std::exception &ex) {
|
||||
LogPrint(eLogError, "Timestamp: NTP time sync exception: ", ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTPTimeSync::Sync ()
|
||||
{
|
||||
void NTPTimeSync::Sync() {
|
||||
if (m_NTPServersList.size() > 0)
|
||||
SyncTimeWithNTP(m_NTPServersList[rand() % m_NTPServersList.size()]);
|
||||
else
|
||||
m_IsRunning = false;
|
||||
|
||||
if (m_IsRunning)
|
||||
{
|
||||
if (m_IsRunning) {
|
||||
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)
|
||||
Sync();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetMillisecondsSinceEpoch ()
|
||||
{
|
||||
uint64_t GetMillisecondsSinceEpoch() {
|
||||
return GetLocalMillisecondsSinceEpoch() + g_TimeOffset * 1000;
|
||||
}
|
||||
|
||||
uint64_t GetSecondsSinceEpoch ()
|
||||
{
|
||||
uint64_t GetSecondsSinceEpoch() {
|
||||
return GetLocalSecondsSinceEpoch() + g_TimeOffset;
|
||||
}
|
||||
|
||||
uint32_t GetMinutesSinceEpoch ()
|
||||
{
|
||||
uint32_t GetMinutesSinceEpoch() {
|
||||
return GetLocalMinutesSinceEpoch() + g_TimeOffset / 60;
|
||||
}
|
||||
|
||||
uint32_t GetHoursSinceEpoch ()
|
||||
{
|
||||
uint32_t GetHoursSinceEpoch() {
|
||||
return GetLocalHoursSinceEpoch() + g_TimeOffset / 3600;
|
||||
}
|
||||
|
||||
void GetCurrentDate (char * date)
|
||||
{
|
||||
void GetCurrentDate(char *date) {
|
||||
GetDateString(GetSecondsSinceEpoch(), date);
|
||||
}
|
||||
|
||||
void GetDateString (uint64_t timestamp, char * date)
|
||||
{
|
||||
void GetDateString(uint64_t timestamp, char *date) {
|
||||
using clock = std::chrono::system_clock;
|
||||
auto t = clock::to_time_t(clock::time_point(std::chrono::seconds(timestamp)));
|
||||
struct tm tm;
|
||||
|
@ -251,8 +210,7 @@ namespace util
|
|||
#endif
|
||||
}
|
||||
|
||||
void AdjustTimeOffset (int64_t offset)
|
||||
{
|
||||
void AdjustTimeOffset(int64_t offset) {
|
||||
g_TimeOffset += offset;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,32 +15,36 @@
|
|||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
uint64_t GetMillisecondsSinceEpoch();
|
||||
|
||||
uint64_t GetSecondsSinceEpoch();
|
||||
|
||||
uint32_t GetMinutesSinceEpoch();
|
||||
|
||||
uint32_t GetHoursSinceEpoch();
|
||||
|
||||
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
|
||||
|
||||
class NTPTimeSync
|
||||
{
|
||||
class NTPTimeSync {
|
||||
public:
|
||||
|
||||
NTPTimeSync();
|
||||
|
||||
~NTPTimeSync();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
|
||||
void Run();
|
||||
|
||||
void Sync();
|
||||
|
||||
private:
|
||||
|
|
|
@ -15,30 +15,24 @@
|
|||
#include "Transports.h"
|
||||
#include "TransitTunnel.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
namespace i2p {
|
||||
namespace tunnel {
|
||||
TransitTunnel::TransitTunnel(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey) :
|
||||
TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
|
||||
{
|
||||
TunnelBase(receiveTunnelID, nextTunnelID, nextIdent) {
|
||||
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);
|
||||
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);
|
||||
|
||||
m_NumTransmittedBytes += tunnelMsg->GetLength();
|
||||
|
@ -47,10 +41,8 @@ namespace tunnel
|
|||
m_TunnelDataMsgs.push_back(tunnelMsg);
|
||||
}
|
||||
|
||||
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
|
||||
{
|
||||
if (!m_TunnelDataMsgs.empty ())
|
||||
{
|
||||
void TransitTunnelParticipant::FlushTunnelDataMsgs() {
|
||||
if (!m_TunnelDataMsgs.empty()) {
|
||||
auto num = m_TunnelDataMsgs.size();
|
||||
if (num > 1)
|
||||
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());
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
void TransitTunnelGateway::SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg) {
|
||||
TunnelMessageBlock block;
|
||||
block.deliveryType = eDeliveryTypeLocal;
|
||||
block.data = msg;
|
||||
|
@ -78,14 +67,12 @@ namespace tunnel
|
|||
m_Gateway.PutTunnelDataMsg(block);
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::FlushTunnelDataMsgs ()
|
||||
{
|
||||
void TransitTunnelGateway::FlushTunnelDataMsgs() {
|
||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||
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);
|
||||
EncryptTunnelMsg(tunnelMsg, newMsg);
|
||||
|
||||
|
@ -96,22 +83,19 @@ namespace tunnel
|
|||
std::shared_ptr<TransitTunnel> CreateTransitTunnel(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey,
|
||||
bool isGateway, bool isEndpoint)
|
||||
{
|
||||
if (isEndpoint)
|
||||
{
|
||||
bool isGateway, bool isEndpoint) {
|
||||
if (isEndpoint) {
|
||||
LogPrint(eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
else if (isGateway)
|
||||
{
|
||||
return std::make_shared<TransitTunnelEndpoint>(receiveTunnelID, nextIdent, nextTunnelID, layerKey,
|
||||
ivKey);
|
||||
} else if (isGateway) {
|
||||
LogPrint(eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::make_shared<TransitTunnelGateway>(receiveTunnelID, nextIdent, nextTunnelID, layerKey,
|
||||
ivKey);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,9 @@
|
|||
#include "TunnelGateway.h"
|
||||
#include "TunnelBase.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
class TransitTunnel: public TunnelBase
|
||||
{
|
||||
namespace i2p {
|
||||
namespace tunnel {
|
||||
class TransitTunnel : public TunnelBase {
|
||||
public:
|
||||
|
||||
TransitTunnel(uint32_t receiveTunnelID,
|
||||
|
@ -35,15 +32,17 @@ namespace tunnel
|
|||
|
||||
// implements TunnelBase
|
||||
void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
|
||||
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
|
||||
|
||||
void EncryptTunnelMsg(std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
|
||||
|
||||
private:
|
||||
|
||||
i2p::crypto::TunnelEncryption m_Encryption;
|
||||
};
|
||||
|
||||
class TransitTunnelParticipant: public TransitTunnel
|
||||
{
|
||||
class TransitTunnelParticipant : public TransitTunnel {
|
||||
public:
|
||||
|
||||
TransitTunnelParticipant(uint32_t receiveTunnelID,
|
||||
|
@ -51,10 +50,13 @@ namespace tunnel
|
|||
const uint8_t *layerKey, const uint8_t *ivKey) :
|
||||
TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_NumTransmittedBytes(0) {};
|
||||
|
||||
~TransitTunnelParticipant();
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_NumTransmittedBytes; };
|
||||
|
||||
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
|
||||
|
||||
void FlushTunnelDataMsgs();
|
||||
|
||||
private:
|
||||
|
@ -63,8 +65,7 @@ namespace tunnel
|
|||
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
||||
};
|
||||
|
||||
class TransitTunnelGateway: public TransitTunnel
|
||||
{
|
||||
class TransitTunnelGateway : public TransitTunnel {
|
||||
public:
|
||||
|
||||
TransitTunnelGateway(uint32_t receiveTunnelID,
|
||||
|
@ -74,7 +75,9 @@ namespace tunnel
|
|||
layerKey, ivKey), m_Gateway(this) {};
|
||||
|
||||
void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
|
||||
void FlushTunnelDataMsgs();
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_Gateway.GetNumSentBytes(); };
|
||||
|
||||
private:
|
||||
|
@ -83,8 +86,7 @@ namespace tunnel
|
|||
TunnelGateway m_Gateway;
|
||||
};
|
||||
|
||||
class TransitTunnelEndpoint: public TransitTunnel
|
||||
{
|
||||
class TransitTunnelEndpoint : public TransitTunnel {
|
||||
public:
|
||||
|
||||
TransitTunnelEndpoint(uint32_t receiveTunnelID,
|
||||
|
@ -96,6 +98,7 @@ namespace tunnel
|
|||
void Cleanup() { m_Endpoint.Cleanup(); }
|
||||
|
||||
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_Endpoint.GetNumReceivedBytes(); }
|
||||
|
||||
private:
|
||||
|
|
|
@ -20,47 +20,39 @@
|
|||
#include "I2NPProtocol.h"
|
||||
#include "Timestamp.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
namespace i2p {
|
||||
namespace transport {
|
||||
const size_t IPV4_HEADER_SIZE = 20;
|
||||
const size_t IPV6_HEADER_SIZE = 40;
|
||||
const size_t UDP_HEADER_SIZE = 8;
|
||||
|
||||
class SignedData
|
||||
{
|
||||
class SignedData {
|
||||
public:
|
||||
|
||||
SignedData() {}
|
||||
SignedData (const SignedData& other)
|
||||
{
|
||||
|
||||
SignedData(const SignedData &other) {
|
||||
m_Stream << other.m_Stream.rdbuf();
|
||||
}
|
||||
|
||||
void Reset ()
|
||||
{
|
||||
void Reset() {
|
||||
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);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Insert (T t)
|
||||
{
|
||||
void Insert(T 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -69,49 +61,58 @@ namespace transport
|
|||
std::stringstream m_Stream;
|
||||
};
|
||||
|
||||
class TransportSession
|
||||
{
|
||||
class TransportSession {
|
||||
public:
|
||||
|
||||
TransportSession(std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout) :
|
||||
m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
|
||||
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ())
|
||||
{
|
||||
m_NumSentBytes(0), m_NumReceivedBytes(0), m_IsOutgoing(router),
|
||||
m_TerminationTimeout(terminationTimeout),
|
||||
m_LastActivityTimestamp(i2p::util::GetSecondsSinceEpoch()) {
|
||||
if (router)
|
||||
m_RemoteIdentity = router->GetRouterIdentity();
|
||||
m_CreationTime = m_LastActivityTimestamp;
|
||||
}
|
||||
|
||||
virtual ~TransportSession() {};
|
||||
|
||||
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);
|
||||
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);
|
||||
m_RemoteIdentity = ident;
|
||||
}
|
||||
|
||||
size_t GetNumSentBytes() const { return m_NumSentBytes; };
|
||||
|
||||
size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; };
|
||||
|
||||
bool IsOutgoing() const { return m_IsOutgoing; };
|
||||
|
||||
int GetTerminationTimeout() const { return m_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; };
|
||||
|
||||
void SetCreationTime(uint32_t ts) { m_CreationTime = ts; }; // for introducers
|
||||
|
||||
virtual uint32_t GetRelayTag() const { return 0; };
|
||||
|
||||
virtual void SendLocalRouterInfo(bool update = false) { SendI2NPMessages({CreateDatabaseStoreMsg()}); };
|
||||
|
||||
virtual void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs) = 0;
|
||||
|
||||
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
Loading…
Add table
Add a link
Reference in a new issue