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,22 +14,20 @@
|
|||
|
||||
// Afrikaans localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace afrikaans // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace afrikaans // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "afrikaans";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"failed", "Het misluk"},
|
||||
{"unknown", "onbekend"},
|
||||
|
@ -62,7 +60,7 @@ namespace afrikaans // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"dag", "dae"}},
|
||||
{"hours", {"uur", "ure"}},
|
||||
|
@ -71,11 +69,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,20 @@
|
|||
|
||||
// Armenian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace armenian // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace armenian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "armenian";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "ԿիԲ"},
|
||||
{"MiB", "ՄիԲ"},
|
||||
|
@ -196,7 +194,7 @@ namespace armenian // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"օր", "օր"}},
|
||||
{"hours", {"ժամ", "ժամ"}},
|
||||
|
@ -205,11 +203,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -15,22 +15,20 @@
|
|||
// Simplified Chinese localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace chinese // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace chinese // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "chinese";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
|
@ -198,7 +196,7 @@ namespace chinese // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"天"}},
|
||||
{"hours", {"时"}},
|
||||
|
@ -207,11 +205,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -15,36 +15,34 @@
|
|||
// English localization file
|
||||
// This is an example translation file without strings in it.
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace english // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace english // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "english";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"", {"", ""}},
|
||||
};
|
||||
|
||||
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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,20 @@
|
|||
|
||||
// French localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace french // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace french // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "french";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "Kio"},
|
||||
{"MiB", "Mio"},
|
||||
|
@ -192,7 +190,7 @@ namespace french // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"jour", "jours"}},
|
||||
{"hours", {"heure", "heures"}},
|
||||
|
@ -201,11 +199,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,20 @@
|
|||
|
||||
// German localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace german // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace german // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "german";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"Purple I2P Webconsole", "Purple-I2P-Webkonsole"},
|
||||
{"KiB", "KiB"},
|
||||
|
@ -197,7 +195,7 @@ namespace german // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"Tag", "Tage"}},
|
||||
{"hours", {"Stunde", "Stunden"}},
|
||||
|
@ -206,11 +204,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
28
i18n/I18N.h
28
i18n/I18N.h
|
@ -11,34 +11,28 @@
|
|||
|
||||
#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());
|
||||
i2p::client::context.SetLanguage(i2p::i18n::english::GetLocale());
|
||||
else
|
||||
i2p::client::context.SetLanguage (it->second.LocaleFunc());
|
||||
i2p::client::context.SetLanguage(it->second.LocaleFunc());
|
||||
}
|
||||
|
||||
inline std::string translate (const std::string& arg)
|
||||
{
|
||||
return i2p::client::context.GetLanguage ()->GetString (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)
|
||||
{
|
||||
return i2p::client::context.GetLanguage ()->GetPlural (arg, arg2, 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
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
||||
template<typename... TArgs>
|
||||
std::string tr (TArgs&&... args)
|
||||
{
|
||||
std::string tr(TArgs &&... args) {
|
||||
return i2p::i18n::translate(std::forward<TArgs>(args)...);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,48 +9,37 @@
|
|||
#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,
|
||||
const std::map<std::string, std::string>& strings,
|
||||
const std::map<std::string, std::vector<std::string>>& plurals,
|
||||
Locale(
|
||||
const std::string &language,
|
||||
const std::map <std::string, std::string> &strings,
|
||||
const std::map <std::string, std::vector<std::string>> &plurals,
|
||||
std::function<int(int)> formula
|
||||
): m_Language (language), m_Strings (strings), m_Plurals (plurals), m_Formula (formula) { };
|
||||
) : m_Language(language), m_Strings(strings), m_Plurals(plurals), m_Formula(formula) {};
|
||||
|
||||
// Get activated language name for webconsole
|
||||
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];
|
||||
}
|
||||
|
@ -58,48 +47,47 @@ namespace i18n
|
|||
|
||||
private:
|
||||
const std::string m_Language;
|
||||
const std::map<std::string, std::string> m_Strings;
|
||||
const std::map<std::string, std::vector<std::string>> m_Plurals;
|
||||
const std::map <std::string, std::string> m_Strings;
|
||||
const std::map <std::string, std::vector<std::string>> m_Plurals;
|
||||
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;
|
||||
std::function<std::shared_ptr<const i2p::i18n::Locale>(void)> LocaleFunc;
|
||||
};
|
||||
|
||||
// Add localization here with language name as namespace
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
|
||||
namespace afrikaans { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace armenian { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace chinese { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace english { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace french { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace german { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale(); }
|
||||
|
||||
/**
|
||||
* That map contains international language name lower-case, name in it's language and it's code
|
||||
*/
|
||||
static std::map<std::string, langData> languages
|
||||
static std::map <std::string, langData> languages
|
||||
{
|
||||
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
|
||||
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
|
||||
{ "chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale} },
|
||||
{ "english", {"English", "en", i2p::i18n::english::GetLocale} },
|
||||
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
|
||||
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
|
||||
{ "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} },
|
||||
{ "turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale} },
|
||||
{ "ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale} },
|
||||
{ "uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale} },
|
||||
{"afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale}},
|
||||
{"armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale}},
|
||||
{"chinese", {"简体字", "zh-CN", i2p::i18n::chinese::GetLocale}},
|
||||
{"english", {"English", "en", i2p::i18n::english::GetLocale}},
|
||||
{"french", {"Français", "fr", i2p::i18n::french::GetLocale}},
|
||||
{"german", {"Deutsch", "de", i2p::i18n::german::GetLocale}},
|
||||
{"russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale}},
|
||||
{"turkmen", {"türkmen dili", "tk", i2p::i18n::turkmen::GetLocale}},
|
||||
{"ukrainian", {"украї́нська мо́ва", "uk", i2p::i18n::ukrainian::GetLocale}},
|
||||
{"uzbek", {"Oʻzbek", "uz", i2p::i18n::uzbek::GetLocale}},
|
||||
};
|
||||
|
||||
} // i18n
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
||||
#endif // __I18N_LANGS_H__
|
||||
|
|
|
@ -14,22 +14,21 @@
|
|||
|
||||
// Russian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace russian // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace russian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "russian";
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "КиБ"},
|
||||
{"MiB", "МиБ"},
|
||||
|
@ -196,7 +195,7 @@ namespace russian // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"день", "дня", "дней"}},
|
||||
{"hours", {"час", "часа", "часов"}},
|
||||
|
@ -205,11 +204,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,20 @@
|
|||
|
||||
// Turkmen localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace turkmen // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace turkmen // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "turkmen";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n != 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
|
@ -196,7 +194,7 @@ namespace turkmen // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"gün", "gün"}},
|
||||
{"hours", {"sagat", "sagat"}},
|
||||
|
@ -205,11 +203,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,21 @@
|
|||
|
||||
// Ukrainian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace ukrainian // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace ukrainian // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "ukrainian";
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "КіБ"},
|
||||
{"MiB", "МіБ"},
|
||||
|
@ -196,7 +195,7 @@ namespace ukrainian // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"день", "дня", "днів"}},
|
||||
{"hours", {"годину", "години", "годин"}},
|
||||
|
@ -205,11 +204,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
|
@ -14,22 +14,20 @@
|
|||
|
||||
// Ukrainian localization file
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace i18n
|
||||
{
|
||||
namespace uzbek // language namespace
|
||||
{
|
||||
namespace i2p {
|
||||
namespace i18n {
|
||||
namespace uzbek // language namespace
|
||||
{
|
||||
// language name in lowercase
|
||||
static std::string language = "uzbek";
|
||||
|
||||
// See for language plural forms here:
|
||||
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
|
||||
static int plural (int n) {
|
||||
static int plural(int n) {
|
||||
return n > 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::string> strings
|
||||
static std::map <std::string, std::string> strings
|
||||
{
|
||||
{"KiB", "KiB"},
|
||||
{"MiB", "MiB"},
|
||||
|
@ -196,7 +194,7 @@ namespace uzbek // language namespace
|
|||
{"", ""},
|
||||
};
|
||||
|
||||
static std::map<std::string, std::vector<std::string>> plurals
|
||||
static std::map <std::string, std::vector<std::string>> plurals
|
||||
{
|
||||
{"days", {"kun", "kun"}},
|
||||
{"hours", {"soat", "soat"}},
|
||||
|
@ -205,11 +203,11 @@ 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
|
||||
} // i18n
|
||||
} // language
|
||||
} // i18n
|
||||
} // i2p
|
||||
|
|
110
libi2pd/Base.cpp
110
libi2pd/Base.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -77,15 +73,14 @@ namespace data
|
|||
*
|
||||
*/
|
||||
|
||||
size_t ByteStreamToBase64 ( /* Number of bytes in the encoded buffer */
|
||||
const uint8_t * InBuffer, /* Input buffer, binary data */
|
||||
size_t ByteStreamToBase64( /* Number of bytes in the encoded buffer */
|
||||
const uint8_t *InBuffer, /* Input buffer, binary data */
|
||||
size_t InCount, /* Number of bytes in the input buffer */
|
||||
char * OutBuffer, /* output buffer */
|
||||
char *OutBuffer, /* output buffer */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
{
|
||||
unsigned char * ps;
|
||||
unsigned char * pd;
|
||||
) {
|
||||
unsigned char *ps;
|
||||
unsigned char *pd;
|
||||
unsigned char acc_1;
|
||||
unsigned char acc_2;
|
||||
int i;
|
||||
|
@ -93,7 +88,7 @@ namespace data
|
|||
int m;
|
||||
size_t outCount;
|
||||
|
||||
ps = (unsigned char *)InBuffer;
|
||||
ps = (unsigned char *) InBuffer;
|
||||
n = InCount / 3;
|
||||
m = InCount % 3;
|
||||
if (!m)
|
||||
|
@ -103,9 +98,8 @@ namespace data
|
|||
|
||||
if (outCount > len) return 0;
|
||||
|
||||
pd = (unsigned char *)OutBuffer;
|
||||
for ( i = 0; i < n; i++ )
|
||||
{
|
||||
pd = (unsigned char *) OutBuffer;
|
||||
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 */
|
||||
|
@ -160,15 +151,14 @@ namespace data
|
|||
*
|
||||
*/
|
||||
|
||||
size_t Base64ToByteStream ( /* Number of output bytes */
|
||||
const char * InBuffer, /* BASE64 encoded buffer */
|
||||
size_t Base64ToByteStream( /* Number of output bytes */
|
||||
const char *InBuffer, /* BASE64 encoded buffer */
|
||||
size_t InCount, /* Number of input bytes */
|
||||
uint8_t * OutBuffer, /* output buffer length */
|
||||
uint8_t *OutBuffer, /* output buffer length */
|
||||
size_t len /* length of output buffer */
|
||||
)
|
||||
{
|
||||
unsigned char * ps;
|
||||
unsigned char * pd;
|
||||
) {
|
||||
unsigned char *ps;
|
||||
unsigned char *pd;
|
||||
unsigned char acc_1;
|
||||
unsigned char acc_2;
|
||||
int i;
|
||||
|
@ -187,18 +177,17 @@ namespace data
|
|||
else
|
||||
return 0;
|
||||
|
||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||
while ( *ps-- == P64 )
|
||||
ps = (unsigned char *) (InBuffer + InCount - 1);
|
||||
while (*ps-- == P64)
|
||||
outCount--;
|
||||
ps = (unsigned char *)InBuffer;
|
||||
ps = (unsigned char *) InBuffer;
|
||||
|
||||
if (outCount > len)
|
||||
return 0;
|
||||
|
||||
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,20 +211,18 @@ namespace data
|
|||
return outCount;
|
||||
}
|
||||
|
||||
size_t Base64EncodingBufferSize (const size_t input_size)
|
||||
{
|
||||
auto d = div (input_size, 3);
|
||||
size_t Base64EncodingBufferSize(const size_t input_size) {
|
||||
auto d = div(input_size, 3);
|
||||
if (d.rem)
|
||||
d.quot++;
|
||||
|
||||
return 4 * d.quot;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
str[l] = 0;
|
||||
// replace '-' by '+' and '~' by '/'
|
||||
for (size_t i = 0; i < l; i++)
|
||||
|
@ -258,21 +245,18 @@ namespace data
|
|||
*
|
||||
*/
|
||||
|
||||
static void iT64Build()
|
||||
{
|
||||
static void iT64Build() {
|
||||
int i;
|
||||
isFirstTime = 0;
|
||||
for ( i = 0; i < 256; i++ ) iT64[i] = -1;
|
||||
for ( i = 0; i < 64; i++ ) iT64[(int)T64[i]] = i;
|
||||
iT64[(int)P64] = 0;
|
||||
for (i = 0; i < 256; i++) iT64[i] = -1;
|
||||
for (i = 0; i < 64; i++) iT64[(int) T64[i]] = i;
|
||||
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;
|
||||
|
@ -324,5 +302,5 @@ namespace data
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,23 +14,27 @@
|
|||
#include <iostream>
|
||||
|
||||
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 ();
|
||||
namespace data {
|
||||
size_t ByteStreamToBase64(const uint8_t *InBuffer, size_t InCount, char *OutBuffer, size_t len);
|
||||
|
||||
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
|
||||
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||
size_t 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);
|
||||
|
||||
/**
|
||||
* Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
|
||||
*/
|
||||
size_t Base64EncodingBufferSize(const size_t input_size);
|
||||
|
||||
std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization
|
||||
std::string ToBase64Standard(const std::string &in); // using standard table, for Proxy-Authorization
|
||||
|
||||
} // data
|
||||
} // data
|
||||
} // i2p
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,114 +20,110 @@
|
|||
#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)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * q = BN_CTX_get (ctx);
|
||||
EC_GROUP_get_order (group, q, ctx);
|
||||
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);
|
||||
EC_GROUP_get_order(group, q, ctx);
|
||||
// calculate alpha = seed mod q
|
||||
BIGNUM * alpha = BN_CTX_get (ctx);
|
||||
BN_bin2bn (seed, 64, alpha); // seed is in BigEndian
|
||||
BN_mod (alpha, alpha, q, ctx); // % q
|
||||
BIGNUM *alpha = BN_CTX_get(ctx);
|
||||
BN_bin2bn(seed, 64, alpha); // seed is in BigEndian
|
||||
BN_mod(alpha, alpha, q, ctx); // % q
|
||||
// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
|
||||
auto p = EC_POINT_new (group);
|
||||
EC_POINT_mul (group, p, alpha, nullptr, nullptr, ctx); // B*alpha
|
||||
EC_POINT_add (group, p, pub, p, ctx); // pub + B*alpha
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
auto p = EC_POINT_new(group);
|
||||
EC_POINT_mul(group, p, alpha, nullptr, nullptr, ctx); // B*alpha
|
||||
EC_POINT_add(group, p, pub, p, ctx); // pub + B*alpha
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return p;
|
||||
}
|
||||
|
||||
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);
|
||||
EC_GROUP_get_order (group, q, ctx);
|
||||
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);
|
||||
EC_GROUP_get_order(group, q, ctx);
|
||||
// calculate alpha = seed mod q
|
||||
BIGNUM * alpha = BN_CTX_get (ctx);
|
||||
BN_bin2bn (seed, 64, alpha); // seed is in BigEndian
|
||||
BN_mod (alpha, alpha, q, ctx); // % q
|
||||
BN_add (alpha, alpha, priv); // alpha = alpha + priv
|
||||
BIGNUM *alpha = BN_CTX_get(ctx);
|
||||
BN_bin2bn(seed, 64, alpha); // seed is in BigEndian
|
||||
BN_mod(alpha, alpha, q, ctx); // % q
|
||||
BN_add(alpha, alpha, priv); // alpha = alpha + priv
|
||||
// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod q
|
||||
BN_mod (blindedPriv, alpha, q, ctx); // % q
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
BN_mod(blindedPriv, alpha, q, ctx); // % q
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
static void BlindEncodedPublicKeyECDSA (size_t publicKeyLen, const EC_GROUP * group, const uint8_t * pub, const uint8_t * seed, uint8_t * blindedPub)
|
||||
{
|
||||
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);
|
||||
EC_POINT_set_affine_coordinates_GFp (group, p, x, y, NULL);
|
||||
EC_POINT * p1 = BlindPublicKeyECDSA (group, p, seed);
|
||||
EC_POINT_free (p);
|
||||
EC_POINT_get_affine_coordinates_GFp (group, p1, x, y, NULL);
|
||||
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);
|
||||
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);
|
||||
EC_POINT_set_affine_coordinates_GFp(group, p, x, y, NULL);
|
||||
EC_POINT *p1 = BlindPublicKeyECDSA(group, p, seed);
|
||||
EC_POINT_free(p);
|
||||
EC_POINT_get_affine_coordinates_GFp(group, p1, x, y, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
BN_free (a);
|
||||
i2p::crypto::bn2buf (a1, blindedPriv, publicKeyLen/2);
|
||||
auto p = EC_POINT_new (group);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
EC_POINT_mul (group, p, a1, nullptr, nullptr, ctx); // B*a1
|
||||
BN_CTX_free (ctx);
|
||||
BN_free (a1);
|
||||
BIGNUM * x = BN_new(), * y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp (group, p, x, y, NULL);
|
||||
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);
|
||||
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);
|
||||
BN_free(a);
|
||||
i2p::crypto::bn2buf(a1, blindedPriv, publicKeyLen / 2);
|
||||
auto p = EC_POINT_new(group);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
EC_POINT_mul(group, p, a1, nullptr, nullptr, ctx); // B*a1
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(a1);
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp(group, p, x, y, NULL);
|
||||
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);
|
||||
}
|
||||
|
||||
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:
|
||||
{
|
||||
EC_GROUP *group = nullptr;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
group = EC_GROUP_new_by_curve_name(NID_secp521r1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: Signature type ", (int)sigType, " is not ECDSA");
|
||||
LogPrint(eLogError, "Blinding: Signature type ", (int) sigType, " is not ECDSA");
|
||||
}
|
||||
if (group)
|
||||
{
|
||||
blind (publicKeyLength, group, key, seed, std::forward<Args>(args)...);
|
||||
EC_GROUP_free (group);
|
||||
if (group) {
|
||||
blind(publicKeyLength, group, key, seed, std::forward<Args>(args)...);
|
||||
EC_GROUP_free(group);
|
||||
}
|
||||
return publicKeyLength;
|
||||
}
|
||||
|
@ -138,198 +134,196 @@ namespace data
|
|||
const uint8_t B33_PER_SECRET_FLAG = 0x02; // not used for now
|
||||
const uint8_t B33_PER_CLIENT_AUTH_FLAG = 0x04;
|
||||
|
||||
BlindedPublicKey::BlindedPublicKey (std::shared_ptr<const IdentityEx> identity, bool clientAuth):
|
||||
m_IsClientAuth (clientAuth)
|
||||
{
|
||||
BlindedPublicKey::BlindedPublicKey(std::shared_ptr<const IdentityEx> identity, bool clientAuth) :
|
||||
m_IsClientAuth(clientAuth) {
|
||||
if (!identity) return;
|
||||
auto len = identity->GetSigningPublicKeyLen ();
|
||||
m_PublicKey.resize (len);
|
||||
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
|
||||
m_SigType = identity->GetSigningKeyType ();
|
||||
auto len = identity->GetSigningPublicKeyLen();
|
||||
m_PublicKey.resize(len);
|
||||
memcpy(m_PublicKey.data(), identity->GetSigningPublicKeyBuffer(), len);
|
||||
m_SigType = identity->GetSigningKeyType();
|
||||
if (m_SigType == i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
||||
m_BlindedSigType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519; // 7 -> 11
|
||||
else
|
||||
m_BlindedSigType = m_SigType;
|
||||
}
|
||||
|
||||
BlindedPublicKey::BlindedPublicKey (const std::string& b33):
|
||||
m_SigType (0) // 0 means invalid, we can't blind DSA, set it later
|
||||
BlindedPublicKey::BlindedPublicKey(const std::string &b33) :
|
||||
m_SigType(0) // 0 means invalid, we can't blind DSA, set it later
|
||||
{
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogError, "Blinding: Malformed b33 ", b33);
|
||||
size_t l = i2p::data::Base32ToByteStream(b33.c_str(), b33.length(), addr, 40);
|
||||
if (l < 32) {
|
||||
LogPrint(eLogError, "Blinding: Malformed b33 ", b33);
|
||||
return;
|
||||
}
|
||||
uint32_t checksum = crc32 (0, addr + 3, l - 3);
|
||||
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)
|
||||
{
|
||||
auto len = blindedVerifier->GetPublicKeyLen ();
|
||||
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
|
||||
LogPrint (eLogError, "Blinding: Unknown signature type ", (int)m_SigType, " in b33");
|
||||
std::unique_ptr<i2p::crypto::Verifier> blindedVerifier(i2p::data::IdentityEx::CreateVerifier(m_SigType));
|
||||
if (blindedVerifier) {
|
||||
auto len = blindedVerifier->GetPublicKeyLen();
|
||||
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
|
||||
LogPrint(eLogError, "Blinding: Unknown signature type ", (int) m_SigType, " in b33");
|
||||
}
|
||||
|
||||
std::string BlindedPublicKey::ToB33 () const
|
||||
{
|
||||
if (m_PublicKey.size () > 32) return ""; // assume 25519
|
||||
uint8_t addr[35]; char str[60]; // TODO: define actual length
|
||||
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 flags = 0;
|
||||
if (m_IsClientAuth) flags |= B33_PER_CLIENT_AUTH_FLAG;
|
||||
addr[0] = flags; // flags
|
||||
addr[1] = m_SigType; // sig type
|
||||
addr[2] = m_BlindedSigType; // blinded sig type
|
||||
memcpy (addr + 3, m_PublicKey.data (), m_PublicKey.size ());
|
||||
uint32_t checksum = crc32 (0, addr + 3, m_PublicKey.size ());
|
||||
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);
|
||||
auto l = ByteStreamToBase32 (addr, m_PublicKey.size () + 3, str, 60);
|
||||
return std::string (str, str + l);
|
||||
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 ());
|
||||
uint16_t stA = htobe16(GetSigType());
|
||||
// stA1 = signature type of blinded A, 2 bytes big endian
|
||||
uint16_t stA1 = htobe16 (GetBlindedSigType ());
|
||||
uint16_t stA1 = htobe16(GetBlindedSigType());
|
||||
// credential = H("credential", A || stA || stA1)
|
||||
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);
|
||||
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
|
||||
{
|
||||
uint16_t stA = htobe16 (GetSigType ()), stA1 = htobe16 (GetBlindedSigType ());
|
||||
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);
|
||||
i2p::crypto::HKDF (salt, (const uint8_t *)date, 8, "i2pblinding1", seed);
|
||||
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);
|
||||
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:
|
||||
i2p::crypto::GetEd25519 ()->BlindPublicKey (GetPublicKey (), seed, blindedKey);
|
||||
i2p::crypto::GetEd25519()->BlindPublicKey(GetPublicKey(), seed, blindedKey);
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
|
||||
LogPrint(eLogError, "Blinding: Can't blind signature type ", (int) m_SigType);
|
||||
}
|
||||
return publicKeyLength;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
i2p::crypto::Ed25519::ExpandPrivateKey(priv, exp);
|
||||
i2p::crypto::GetEd25519()->BlindPrivateKey(exp, seed, blindedPriv, blindedPub);
|
||||
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
|
||||
LogPrint(eLogError, "Blinding: Can't blind signature type ", (int) m_SigType);
|
||||
}
|
||||
return publicKeyLength;
|
||||
}
|
||||
|
||||
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 ());
|
||||
for (const auto& it: bufs)
|
||||
SHA256_Update (&ctx, it.first, it.second);
|
||||
SHA256_Final (hash, &ctx);
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, p.c_str(), p.length());
|
||||
for (const auto &it: bufs)
|
||||
SHA256_Update(&ctx, it.first, it.second);
|
||||
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
|
||||
{
|
||||
publicKeyLength = GetBlindedKey(date, blinded);
|
||||
else {
|
||||
char currentDate[9];
|
||||
i2p::util::GetCurrentDate (currentDate);
|
||||
publicKeyLength = GetBlindedKey (currentDate, blinded);
|
||||
i2p::util::GetCurrentDate(currentDate);
|
||||
publicKeyLength = GetBlindedKey(currentDate, blinded);
|
||||
}
|
||||
if (publicKeyLength)
|
||||
{
|
||||
auto stA1 = htobe16 (m_BlindedSigType);
|
||||
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
|
||||
LogPrint (eLogError, "Blinding: Blinded key type ", (int)m_BlindedSigType, " is not supported");
|
||||
SHA256_Init(&ctx);
|
||||
SHA256_Update(&ctx, (const uint8_t *) &stA1, 2);
|
||||
SHA256_Update(&ctx, blinded, publicKeyLength);
|
||||
SHA256_Final((uint8_t *) hash, &ctx);
|
||||
} 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;
|
||||
BlindedPublicKey(std::shared_ptr<const IdentityEx> identity, bool clientAuth = false);
|
||||
|
||||
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
|
||||
BlindedPublicKey(const std::string &b33); // from b33 without .b32.i2p
|
||||
std::string ToB33() const;
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
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 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;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -49,7 +56,7 @@ namespace data
|
|||
i2p::data::SigningKeyType m_SigType, m_BlindedSigType;
|
||||
bool m_IsClientAuth = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,50 +11,42 @@
|
|||
#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()
|
||||
{
|
||||
delete [] m_Data;
|
||||
~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);
|
||||
if(m_Data[idx] & mask) return false; // filter hit
|
||||
if (m_Data[idx] & mask) return false; // filter hit
|
||||
m_Data[idx] |= mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @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
|
||||
|
@ -64,14 +56,13 @@ namespace util
|
|||
bm <<= (i % 8);
|
||||
}
|
||||
|
||||
uint8_t * m_Data;
|
||||
uint8_t *m_Data;
|
||||
std::size_t m_Size;
|
||||
};
|
||||
|
||||
|
||||
BloomFilterPtr BloomFilter(std::size_t capacity)
|
||||
{
|
||||
BloomFilterPtr BloomFilter(std::size_t capacity) {
|
||||
return std::make_shared<DecayingBloomFilter>(capacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,32 +8,32 @@
|
|||
|
||||
#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;
|
||||
virtual bool Add(const uint8_t *data, std::size_t len) = 0;
|
||||
|
||||
/** @brief optionally decay old entries */
|
||||
virtual void Decay() = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IBloomFilter> BloomFilterPtr;
|
||||
typedef std::shared_ptr <IBloomFilter> BloomFilterPtr;
|
||||
|
||||
/** @brief create bloom filter */
|
||||
BloomFilterPtr BloomFilter(std::size_t capacity = 1024 * 8);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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]);
|
||||
|
@ -54,5 +53,5 @@ namespace cpu
|
|||
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
|
||||
LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,13 @@
|
|||
#ifndef LIBI2PD_CPU_H
|
||||
#define LIBI2PD_CPU_H
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace cpu
|
||||
{
|
||||
namespace i2p {
|
||||
namespace cpu {
|
||||
extern bool aesni;
|
||||
extern bool avx;
|
||||
|
||||
void Detect(bool AesSwitch, bool AvxSwitch, bool force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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];
|
||||
|
@ -36,37 +31,36 @@ uint32_t u8t32le(const uint8_t * p)
|
|||
value = (value << 8) | p[0];
|
||||
|
||||
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);
|
||||
|
@ -78,10 +72,9 @@ void block (Chacha20State &input, int rounds)
|
|||
}
|
||||
x += input;
|
||||
input.block << x;
|
||||
}
|
||||
}
|
||||
|
||||
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
|
||||
{
|
||||
void Chacha20Init(Chacha20State &state, const uint8_t *nonce, const uint8_t *key, uint32_t counter) {
|
||||
state.data[0] = 0x61707865;
|
||||
state.data[1] = 0x3320646e;
|
||||
state.data[2] = 0x79622d32;
|
||||
|
@ -92,18 +85,15 @@ void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t *
|
|||
state.data[12] = htole32 (counter);
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
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,24 +104,21 @@ 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;
|
||||
}
|
||||
buf[j] ^= state.block.data[j - i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace chacha
|
||||
} // namespace crypto
|
||||
} // namespace chacha
|
||||
} // namespace crypto
|
||||
} // namespace i2p
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
*/
|
||||
#ifndef LIBI2PD_CHACHA20_H
|
||||
#define LIBI2PD_CHACHA20_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <inttypes.h>
|
||||
|
@ -17,55 +18,55 @@
|
|||
#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
|
||||
{
|
||||
Chacha20Block () {};
|
||||
Chacha20Block (Chacha20Block &&) = delete;
|
||||
|
||||
struct Chacha20Block {
|
||||
Chacha20Block() {};
|
||||
|
||||
Chacha20Block(Chacha20Block &&) = delete;
|
||||
|
||||
uint8_t data[blocksize];
|
||||
|
||||
void operator << (const Chacha20State & st);
|
||||
void operator<<(const Chacha20State &st);
|
||||
};
|
||||
|
||||
struct Chacha20State
|
||||
{
|
||||
Chacha20State (): offset (0) {};
|
||||
Chacha20State (Chacha20State &&) = delete;
|
||||
struct Chacha20State {
|
||||
Chacha20State() : offset(0) {};
|
||||
|
||||
Chacha20State & operator += (const Chacha20State & other)
|
||||
{
|
||||
for(int i = 0; i < 16; i++)
|
||||
Chacha20State(Chacha20State &&) = delete;
|
||||
|
||||
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
|
||||
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
|
||||
} // namespace i2p
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,45 +24,65 @@
|
|||
using namespace boost::program_options;
|
||||
|
||||
namespace i2p {
|
||||
namespace config {
|
||||
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;
|
||||
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)
|
||||
{
|
||||
ThrowFatal ("Error while parsing arguments: ", e.what());
|
||||
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())
|
||||
{
|
||||
ThrowFatal ("Missing or unreadable config file: ", path);
|
||||
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)
|
||||
{
|
||||
ThrowFatal ("Error while parsing config file: ", e.what());
|
||||
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,18 +479,16 @@ 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)
|
||||
{
|
||||
return GetOptionAsAny (name.c_str (), value);
|
||||
bool GetOptionAsAny(const std::string &name, boost::any &value) {
|
||||
return GetOptionAsAny(name.c_str(), value);
|
||||
}
|
||||
|
||||
} // namespace config
|
||||
} // namespace config
|
||||
} // namespace i2p
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
namespace i2p {
|
||||
namespace config {
|
||||
namespace config {
|
||||
extern boost::program_options::variables_map m_Options;
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ namespace config {
|
|||
*
|
||||
* Other exceptions will be passed to higher level.
|
||||
*/
|
||||
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false);
|
||||
void ParseCmdline(int argc, char *argv[], bool ignoreUnknown = false);
|
||||
|
||||
/**
|
||||
* @brief Load and parse given config file
|
||||
|
@ -64,7 +64,7 @@ namespace config {
|
|||
*
|
||||
* Other exceptions will be passed to higher level.
|
||||
*/
|
||||
void ParseConfig(const std::string& path);
|
||||
void ParseConfig(const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Used to combine options from cmdline, config and default values
|
||||
|
@ -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,13 +88,13 @@ namespace config {
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
bool GetOption(const std::string& name, T& value)
|
||||
{
|
||||
return GetOption (name.c_str (), 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);
|
||||
bool GetOptionAsAny(const char *name, boost::any &value);
|
||||
|
||||
bool GetOptionAsAny(const std::string &name, boost::any &value);
|
||||
|
||||
/**
|
||||
* @brief Set value of given parameter
|
||||
|
@ -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;
|
||||
|
@ -121,7 +119,7 @@ namespace config {
|
|||
* @return true if value set to default, false otherwise
|
||||
*/
|
||||
bool IsDefault(const char *name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
|
File diff suppressed because it is too large
Load diff
369
libi2pd/Crypto.h
369
libi2pd/Crypto.h
|
@ -50,53 +50,58 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
bool bn2buf(const BIGNUM *bn, uint8_t *buf, size_t len);
|
||||
|
||||
// DSA
|
||||
DSA * CreateDSA ();
|
||||
DSA *CreateDSA();
|
||||
|
||||
// RSA
|
||||
const BIGNUM * GetRSAE ();
|
||||
const BIGNUM *GetRSAE();
|
||||
|
||||
// DH
|
||||
class DHKeys
|
||||
{
|
||||
class DHKeys {
|
||||
public:
|
||||
|
||||
DHKeys ();
|
||||
~DHKeys ();
|
||||
DHKeys();
|
||||
|
||||
void GenerateKeys ();
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||
~DHKeys();
|
||||
|
||||
void GenerateKeys();
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKey; };
|
||||
|
||||
void Agree(const uint8_t *pub, uint8_t *shared);
|
||||
|
||||
private:
|
||||
|
||||
DH * m_DH;
|
||||
DH *m_DH;
|
||||
uint8_t m_PublicKey[256];
|
||||
};
|
||||
|
||||
// x25519
|
||||
class X25519Keys
|
||||
{
|
||||
class X25519Keys {
|
||||
public:
|
||||
|
||||
X25519Keys ();
|
||||
X25519Keys (const uint8_t * priv, const uint8_t * pub); // if pub is null, derive from priv
|
||||
~X25519Keys ();
|
||||
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);
|
||||
X25519Keys(const uint8_t *priv, const uint8_t *pub); // if pub is null, derive from priv
|
||||
~X25519Keys();
|
||||
|
||||
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
|
||||
void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
|
||||
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:
|
||||
|
||||
|
@ -105,40 +110,42 @@ namespace crypto
|
|||
EVP_PKEY_CTX * m_Ctx;
|
||||
EVP_PKEY * m_Pkey;
|
||||
#else
|
||||
BN_CTX * m_Ctx;
|
||||
BN_CTX *m_Ctx;
|
||||
uint8_t m_PrivateKey[32];
|
||||
#endif
|
||||
bool m_IsElligatorIneligible = false; // true if definitely ineligible
|
||||
};
|
||||
|
||||
// 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 GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
|
||||
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 GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
|
||||
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);
|
||||
|
||||
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
|
||||
void operator^=(const ChipherBlock &other) // XOR
|
||||
{
|
||||
if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
|
||||
if (!(((size_t) buf | (size_t) other.buf) & 0x03)) // multiple of 4 ?
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
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,23 +159,25 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
AESAlignedBuffer ()
|
||||
{
|
||||
AESAlignedBuffer() {
|
||||
m_Buf = m_UnalignedBuffer;
|
||||
uint8_t rem = ((size_t)m_Buf) & 0x0f;
|
||||
uint8_t rem = ((size_t) m_Buf) & 0x0f;
|
||||
if (rem)
|
||||
m_Buf += (16 - rem);
|
||||
}
|
||||
|
||||
operator uint8_t * () { return m_Buf; };
|
||||
operator const uint8_t * () const { return m_Buf; };
|
||||
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
|
||||
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
|
||||
operator uint8_t *() { return m_Buf; };
|
||||
|
||||
operator const uint8_t *() const { return m_Buf; };
|
||||
|
||||
ChipherBlock *GetChipherBlock() { return (ChipherBlock *) m_Buf; };
|
||||
|
||||
const ChipherBlock *GetChipherBlock() const { return (const ChipherBlock *) m_Buf; };
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
|
||||
uint8_t * m_Buf;
|
||||
uint8_t *m_Buf;
|
||||
};
|
||||
|
||||
|
||||
|
@ -192,14 +201,15 @@ namespace crypto
|
|||
#ifdef __AES__
|
||||
class ECBEncryption: public ECBCryptoAESNI
|
||||
#else
|
||||
|
||||
class ECBEncryption
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key);
|
||||
void SetKey(const AESKey &key);
|
||||
|
||||
void Encrypt(const ChipherBlock * in, ChipherBlock * out);
|
||||
void Encrypt(const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
private:
|
||||
AES_KEY m_Key;
|
||||
|
@ -208,32 +218,36 @@ 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);
|
||||
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); };
|
||||
CBCEncryption() { memset((uint8_t *) m_LastBlock, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
||||
void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes
|
||||
void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_LastBlock, 16); };
|
||||
void SetKey(const AESKey &key) { m_ECBEncryption.SetKey(key); }; // 32 bytes
|
||||
void SetIV(const uint8_t *iv) { memcpy((uint8_t *) m_LastBlock, iv, 16); }; // 16 bytes
|
||||
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
|
||||
void Encrypt(int numBlocks, const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
ECBEncryption & ECB() { return m_ECBEncryption; }
|
||||
void Encrypt(const uint8_t *in, std::size_t len, uint8_t *out);
|
||||
|
||||
void Encrypt(const uint8_t *in, uint8_t *out); // one block
|
||||
|
||||
ECBEncryption &ECB() { return m_ECBEncryption; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -242,21 +256,22 @@ namespace crypto
|
|||
ECBEncryption m_ECBEncryption;
|
||||
};
|
||||
|
||||
class CBCDecryption
|
||||
{
|
||||
class CBCDecryption {
|
||||
public:
|
||||
|
||||
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); };
|
||||
CBCDecryption() { memset((uint8_t *) m_IV, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
||||
void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes
|
||||
void GetIV (uint8_t * iv) const { memcpy (iv, (const uint8_t *)m_IV, 16); };
|
||||
void SetKey(const AESKey &key) { m_ECBDecryption.SetKey(key); }; // 32 bytes
|
||||
void SetIV(const uint8_t *iv) { memcpy((uint8_t *) m_IV, iv, 16); }; // 16 bytes
|
||||
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
|
||||
void Decrypt(int numBlocks, const ChipherBlock *in, ChipherBlock *out);
|
||||
|
||||
ECBDecryption & ECB() { return m_ECBDecryption; }
|
||||
void Decrypt(const uint8_t *in, std::size_t len, uint8_t *out);
|
||||
|
||||
void Decrypt(const uint8_t *in, uint8_t *out); // one block
|
||||
|
||||
ECBDecryption &ECB() { return m_ECBDecryption; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -268,13 +283,12 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
m_LayerEncryption.SetKey (layerKey);
|
||||
m_IVEncryption.SetKey (ivKey);
|
||||
void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
|
||||
m_LayerEncryption.SetKey(layerKey);
|
||||
m_IVEncryption.SetKey(ivKey);
|
||||
}
|
||||
|
||||
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||
void Encrypt(const uint8_t *in, uint8_t *out); // 1024 bytes (16 IV + 1008 data)
|
||||
|
||||
private:
|
||||
|
||||
|
@ -286,13 +300,12 @@ namespace crypto
|
|||
{
|
||||
public:
|
||||
|
||||
void SetKeys (const AESKey& layerKey, const AESKey& ivKey)
|
||||
{
|
||||
m_LayerDecryption.SetKey (layerKey);
|
||||
m_IVDecryption.SetKey (ivKey);
|
||||
void SetKeys(const AESKey &layerKey, const AESKey &ivKey) {
|
||||
m_LayerDecryption.SetKey(layerKey);
|
||||
m_IVDecryption.SetKey(ivKey);
|
||||
}
|
||||
|
||||
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
|
||||
void Decrypt(const uint8_t *in, uint8_t *out); // 1024 bytes (16 IV + 1008 data)
|
||||
|
||||
private:
|
||||
|
||||
|
@ -301,108 +314,142 @@ 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);
|
||||
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);
|
||||
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);
|
||||
};
|
||||
|
||||
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router)
|
||||
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
|
||||
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2)
|
||||
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
|
||||
void InitNoiseNState(NoiseSymmetricState &state, const uint8_t *pub); // Noise_N (tunnels, router)
|
||||
void InitNoiseXKState(NoiseSymmetricState &state, const uint8_t *pub); // Noise_XK (NTCP2)
|
||||
void InitNoiseXKState1(NoiseSymmetricState &state, const uint8_t *pub); // Noise_XK (SSU2)
|
||||
void InitNoiseIKState(NoiseSymmetricState &state, const uint8_t *pub); // Noise_IK (ratchets)
|
||||
|
||||
// init and terminate
|
||||
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{ *pr = sig->r; *ps = sig->s; }
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
|
||||
{ *pr = sig->r; *ps = sig->s; }
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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 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 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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 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;
|
||||
}
|
||||
|
||||
inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
|
||||
{ return pkey->pkey.rsa; }
|
||||
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {
|
||||
*pr = sig->r;
|
||||
*ps = sig->s;
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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,175 +11,154 @@
|
|||
#include "Gost.h"
|
||||
#include "CryptoKey.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
ElGamalEncryptor::ElGamalEncryptor (const uint8_t * pub)
|
||||
{
|
||||
memcpy (m_PublicKey, pub, 256);
|
||||
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)
|
||||
{
|
||||
ElGamalEncrypt (m_PublicKey, data, encrypted);
|
||||
void ElGamalEncryptor::Encrypt(const uint8_t *data, uint8_t *encrypted) {
|
||||
ElGamalEncrypt(m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ElGamalDecryptor::ElGamalDecryptor (const uint8_t * priv)
|
||||
{
|
||||
memcpy (m_PrivateKey, priv, 256);
|
||||
ElGamalDecryptor::ElGamalDecryptor(const uint8_t *priv) {
|
||||
memcpy(m_PrivateKey, priv, 256);
|
||||
}
|
||||
|
||||
bool ElGamalDecryptor::Decrypt (const uint8_t * encrypted, uint8_t * data)
|
||||
{
|
||||
return ElGamalDecrypt (m_PrivateKey, encrypted, data);
|
||||
bool ElGamalDecryptor::Decrypt(const uint8_t *encrypted, uint8_t *data) {
|
||||
return ElGamalDecrypt(m_PrivateKey, encrypted, data);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
ECIESP256Encryptor::~ECIESP256Encryptor ()
|
||||
{
|
||||
if (m_Curve) EC_GROUP_free (m_Curve);
|
||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||
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);
|
||||
ECIESEncrypt(m_Curve, m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
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(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 ()
|
||||
{
|
||||
if (m_Curve) EC_GROUP_free (m_Curve);
|
||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||
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 ECIESDecrypt(m_Curve, m_PrivateKey, encrypted, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
GenerateECIESKeyPair (curve, key, p);
|
||||
bn2buf (key, priv, 32);
|
||||
RAND_bytes (priv + 32, 224);
|
||||
BN_free (key);
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL);
|
||||
bn2buf (x, pub, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
RAND_bytes (pub + 64, 192);
|
||||
EC_POINT_free (p);
|
||||
BN_free (x); BN_free (y);
|
||||
EC_GROUP_free (curve);
|
||||
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;
|
||||
GenerateECIESKeyPair(curve, key, p);
|
||||
bn2buf(key, priv, 32);
|
||||
RAND_bytes(priv + 32, 224);
|
||||
BN_free(key);
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp(curve, p, x, y, NULL);
|
||||
bn2buf(x, pub, 32);
|
||||
bn2buf(y, pub + 32, 32);
|
||||
RAND_bytes(pub + 64, 192);
|
||||
EC_POINT_free(p);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
EC_GROUP_free(curve);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Encryptor::~ECIESGOSTR3410Encryptor ()
|
||||
{
|
||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||
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);
|
||||
ECIESEncrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PublicKey, data, encrypted);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor (const uint8_t * priv)
|
||||
{
|
||||
m_PrivateKey = BN_bin2bn (priv, 32, nullptr);
|
||||
ECIESGOSTR3410Decryptor::ECIESGOSTR3410Decryptor(const uint8_t *priv) {
|
||||
m_PrivateKey = BN_bin2bn(priv, 32, nullptr);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Decryptor::~ECIESGOSTR3410Decryptor ()
|
||||
{
|
||||
if (m_PrivateKey) BN_free (m_PrivateKey);
|
||||
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 ECIESDecrypt(GetGOSTR3410Curve(eGOSTR3410CryptoProA)->GetGroup(), m_PrivateKey, encrypted, data);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA);
|
||||
EC_POINT * p = nullptr;
|
||||
BIGNUM * key = nullptr;
|
||||
GenerateECIESKeyPair (curve->GetGroup (), key, p);
|
||||
bn2buf (key, priv, 32);
|
||||
RAND_bytes (priv + 32, 224);
|
||||
BN_free (key);
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL);
|
||||
bn2buf (x, pub, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
RAND_bytes (pub + 64, 192);
|
||||
EC_POINT_free (p);
|
||||
BN_free (x); BN_free (y);
|
||||
void CreateECIESGOSTR3410RandomKeys(uint8_t *priv, uint8_t *pub) {
|
||||
auto &curve = GetGOSTR3410Curve(eGOSTR3410CryptoProA);
|
||||
EC_POINT *p = nullptr;
|
||||
BIGNUM *key = nullptr;
|
||||
GenerateECIESKeyPair(curve->GetGroup(), key, p);
|
||||
bn2buf(key, priv, 32);
|
||||
RAND_bytes(priv + 32, 224);
|
||||
BN_free(key);
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp(curve->GetGroup(), p, x, y, NULL);
|
||||
bn2buf(x, pub, 32);
|
||||
bn2buf(y, pub + 32, 32);
|
||||
RAND_bytes(pub + 64, 192);
|
||||
EC_POINT_free(p);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
}
|
||||
|
||||
ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor (const uint8_t * pub)
|
||||
{
|
||||
memcpy (m_PublicKey, pub, 32);
|
||||
ECIESX25519AEADRatchetEncryptor::ECIESX25519AEADRatchetEncryptor(const uint8_t *pub) {
|
||||
memcpy(m_PublicKey, pub, 32);
|
||||
}
|
||||
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt (const uint8_t *, uint8_t * pub)
|
||||
{
|
||||
memcpy (pub, m_PublicKey, 32);
|
||||
void ECIESX25519AEADRatchetEncryptor::Encrypt(const uint8_t *, uint8_t *pub) {
|
||||
memcpy(pub, m_PublicKey, 32);
|
||||
}
|
||||
|
||||
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor (const uint8_t * priv, bool calculatePublic)
|
||||
{
|
||||
m_StaticKeys.SetPrivateKey (priv, calculatePublic);
|
||||
ECIESX25519AEADRatchetDecryptor::ECIESX25519AEADRatchetDecryptor(const uint8_t *priv, bool calculatePublic) {
|
||||
m_StaticKeys.SetPrivateKey(priv, calculatePublic);
|
||||
}
|
||||
|
||||
bool ECIESX25519AEADRatchetDecryptor::Decrypt (const uint8_t * epub, uint8_t * sharedSecret)
|
||||
{
|
||||
return m_StaticKeys.Agree (epub, 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);
|
||||
memcpy (pub, k.GetPublicKey (), 32);
|
||||
k.GenerateKeys();
|
||||
k.GetPrivateKey(priv);
|
||||
memcpy(pub, k.GetPublicKey(), 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,47 +12,48 @@
|
|||
#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;
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
// ElGamal
|
||||
class ElGamalEncryptor: public CryptoKeyEncryptor // for destination
|
||||
class ElGamalEncryptor : public CryptoKeyEncryptor // for destination
|
||||
{
|
||||
public:
|
||||
|
||||
ElGamalEncryptor (const uint8_t * pub);
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) override; // 222 bytes data, 514 bytes encrypted
|
||||
ElGamalEncryptor(const uint8_t *pub);
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override; // 222 bytes data, 514 bytes encrypted
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_PublicKey[256];
|
||||
};
|
||||
|
||||
class ElGamalDecryptor: public CryptoKeyDecryptor // for destination
|
||||
class ElGamalDecryptor : public CryptoKeyDecryptor // for destination
|
||||
{
|
||||
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; };
|
||||
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; };
|
||||
|
||||
private:
|
||||
|
||||
|
@ -61,79 +62,86 @@ 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;
|
||||
ECIESP256Encryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESP256Encryptor();
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
|
||||
|
||||
private:
|
||||
|
||||
EC_GROUP * m_Curve;
|
||||
EC_POINT * m_PublicKey;
|
||||
EC_GROUP *m_Curve;
|
||||
EC_POINT *m_PublicKey;
|
||||
};
|
||||
|
||||
|
||||
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; };
|
||||
ECIESP256Decryptor(const uint8_t *priv);
|
||||
|
||||
~ECIESP256Decryptor();
|
||||
|
||||
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
|
||||
|
||||
size_t GetPublicKeyLen() const override { return 64; };
|
||||
|
||||
private:
|
||||
|
||||
EC_GROUP * m_Curve;
|
||||
BIGNUM * m_PrivateKey;
|
||||
EC_GROUP *m_Curve;
|
||||
BIGNUM *m_PrivateKey;
|
||||
};
|
||||
|
||||
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||
void CreateECIESP256RandomKeys(uint8_t *priv, uint8_t *pub);
|
||||
|
||||
// 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;
|
||||
ECIESGOSTR3410Encryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESGOSTR3410Encryptor();
|
||||
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) override;
|
||||
|
||||
private:
|
||||
|
||||
EC_POINT * m_PublicKey;
|
||||
EC_POINT *m_PublicKey;
|
||||
};
|
||||
|
||||
|
||||
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; };
|
||||
ECIESGOSTR3410Decryptor(const uint8_t *priv);
|
||||
|
||||
~ECIESGOSTR3410Decryptor();
|
||||
|
||||
bool Decrypt(const uint8_t *encrypted, uint8_t *data) override;
|
||||
|
||||
size_t GetPublicKeyLen() const override { return 64; };
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * m_PrivateKey;
|
||||
BIGNUM *m_PrivateKey;
|
||||
};
|
||||
|
||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||
void CreateECIESGOSTR3410RandomKeys(uint8_t *priv, uint8_t *pub);
|
||||
|
||||
// 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;
|
||||
ECIESX25519AEADRatchetEncryptor(const uint8_t *pub);
|
||||
|
||||
~ECIESX25519AEADRatchetEncryptor() {};
|
||||
|
||||
void Encrypt(const uint8_t *, uint8_t *pub) override;
|
||||
// copies m_PublicKey to pub
|
||||
|
||||
private:
|
||||
|
@ -141,24 +149,27 @@ 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;
|
||||
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 (); };
|
||||
size_t GetPublicKeyLen() const override { return 32; };
|
||||
|
||||
const uint8_t *GetPubicKey() const { return m_StaticKeys.GetPublicKey(); };
|
||||
|
||||
private:
|
||||
|
||||
X25519Keys m_StaticKeys;
|
||||
};
|
||||
|
||||
void CreateECIESX25519AEADRatchetRandomKeys (uint8_t * priv, uint8_t * pub);
|
||||
}
|
||||
void CreateECIESX25519AEADRatchetRandomKeys(uint8_t *priv, uint8_t *pub);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,119 +14,110 @@
|
|||
#include "Destination.h"
|
||||
#include "Datagram.h"
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
if (m_Gzip)
|
||||
m_Deflator.reset (new i2p::data::GzipDeflator);
|
||||
m_Deflator.reset(new i2p::data::GzipDeflator);
|
||||
|
||||
auto identityLen = m_Owner->GetIdentity ()->GetFullLen ();
|
||||
m_From.resize (identityLen);
|
||||
m_Owner->GetIdentity ()->ToBuffer (m_From.data (), identityLen);
|
||||
m_Signature.resize (m_Owner->GetIdentity ()->GetSignatureLen ());
|
||||
auto identityLen = m_Owner->GetIdentity()->GetFullLen();
|
||||
m_From.resize(identityLen);
|
||||
m_Owner->GetIdentity()->ToBuffer(m_From.data(), identityLen);
|
||||
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);
|
||||
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);
|
||||
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
|
||||
m_Owner->Sign (payload, len, m_Signature.data ());
|
||||
m_Owner->Sign(hash, 32, m_Signature.data());
|
||||
} 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}},
|
||||
fromPort, toPort, false, !session->IsRatchets ()); // datagram
|
||||
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 ();
|
||||
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 ();
|
||||
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
|
||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||
verified = identity.Verify(hash, 32, signature);
|
||||
} else
|
||||
verified = identity.Verify(buf + headerLen, len - headerLen, signature);
|
||||
|
||||
if (verified)
|
||||
{
|
||||
if (verified) {
|
||||
auto h = identity.GetIdentHash();
|
||||
auto session = ObtainSession(h);
|
||||
session->Ack();
|
||||
auto r = FindReceiver(toPort);
|
||||
if(r)
|
||||
r(identity, fromPort, toPort, buf + headerLen, len -headerLen);
|
||||
if (r)
|
||||
r(identity, fromPort, toPort, buf + headerLen, len - headerLen);
|
||||
else
|
||||
LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||
LogPrint(eLogWarning, "DatagramDestination: no receiver for port ", toPort);
|
||||
} 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);
|
||||
m_RawReceiver(fromPort, toPort, buf, len);
|
||||
else
|
||||
LogPrint (eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||
LogPrint(eLogWarning, "DatagramDestination: no receiver for raw datagram");
|
||||
}
|
||||
|
||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
||||
{
|
||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) {
|
||||
std::lock_guard<std::mutex> lock(m_ReceiversMutex);
|
||||
Receiver r = m_Receiver;
|
||||
auto itr = m_ReceiversByPorts.find(port);
|
||||
|
@ -135,80 +126,71 @@ 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)
|
||||
{
|
||||
size_t uncompressedLen = m_Inflator.Inflate(buf, len, uncompressed, MAX_DATAGRAM_SIZE);
|
||||
if (uncompressedLen) {
|
||||
if (isRaw)
|
||||
HandleRawDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
HandleRawDatagram(fromPort, toPort, uncompressed, uncompressedLen);
|
||||
else
|
||||
HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram: decompression failed");
|
||||
HandleDatagram(fromPort, toPort, uncompressed, uncompressedLen);
|
||||
} 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)
|
||||
{
|
||||
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) {
|
||||
size_t size;
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared ();
|
||||
uint8_t * buf = msg->GetPayload ();
|
||||
auto msg = m_I2NPMsgsPool.AcquireShared();
|
||||
uint8_t *buf = msg->GetPayload();
|
||||
buf += 4; // reserve for length
|
||||
|
||||
if (m_Gzip && m_Deflator)
|
||||
size = m_Deflator->Deflate (payloads, buf, msg->maxLen - msg->len);
|
||||
size = m_Deflator->Deflate(payloads, buf, msg->maxLen - msg->len);
|
||||
else
|
||||
size = i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len);
|
||||
size = i2p::data::GzipNoCompression(payloads, buf, msg->maxLen - msg->len);
|
||||
|
||||
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
|
||||
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
|
||||
msg->len += size + 4;
|
||||
msg->FillI2NPMessageHeader (eI2NPData, 0, checksum);
|
||||
}
|
||||
else
|
||||
msg->FillI2NPMessageHeader(eI2NPData, 0, checksum);
|
||||
} else
|
||||
msg = nullptr;
|
||||
return msg;
|
||||
}
|
||||
|
||||
void DatagramDestination::CleanUp ()
|
||||
{
|
||||
if (m_Sessions.empty ()) return;
|
||||
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
|
||||
it->second->Stop();
|
||||
it = m_Sessions.erase(it); // we are expired
|
||||
} 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);
|
||||
if (itr == m_Sessions.end()) {
|
||||
// not found, create new session
|
||||
session = std::make_shared<DatagramSession>(m_Owner, identity);
|
||||
session->Start ();
|
||||
session->Start();
|
||||
m_Sessions[identity] = session;
|
||||
} else {
|
||||
session = itr->second;
|
||||
|
@ -216,47 +198,41 @@ 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)
|
||||
{
|
||||
if(item.first == remote) return std::make_shared<DatagramSession::Info>(item.second->GetSessionInfo());
|
||||
for (auto &item: m_Sessions) {
|
||||
if (item.first == remote) return std::make_shared<DatagramSession::Info>(item.second->GetSessionInfo());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DatagramSession::DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination,
|
||||
const i2p::data::IdentHash & remoteIdent) :
|
||||
const i2p::data::IdentHash &remoteIdent) :
|
||||
m_LocalDestination(localDestination),
|
||||
m_RemoteIdent(remoteIdent),
|
||||
m_RequestingLS(false)
|
||||
{
|
||||
m_RequestingLS(false) {
|
||||
}
|
||||
|
||||
void DatagramSession::Start ()
|
||||
{
|
||||
m_LastUse = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
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 ())
|
||||
if (msg || m_SendQueue.empty())
|
||||
m_SendQueue.push_back(msg);
|
||||
// flush queue right away if full
|
||||
if (!msg || m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE)
|
||||
FlushSendQueue();
|
||||
}
|
||||
|
||||
DatagramSession::Info DatagramSession::GetSessionInfo() const
|
||||
{
|
||||
if(!m_RoutingSession)
|
||||
DatagramSession::Info DatagramSession::GetSessionInfo() const {
|
||||
if (!m_RoutingSession)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
|
||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||
|
@ -264,134 +240,115 @@ namespace datagram
|
|||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
auto lease = routingPath->remoteLease;
|
||||
auto tunnel = routingPath->outboundTunnel;
|
||||
if(lease)
|
||||
{
|
||||
if(tunnel)
|
||||
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)
|
||||
path->updateTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (IsRatchets ())
|
||||
SendMsg (nullptr); // send empty message in case if we have some data to send
|
||||
if (path)
|
||||
path->updateTime = i2p::util::GetSecondsSinceEpoch();
|
||||
if (IsRatchets())
|
||||
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
|
||||
for (auto &it: m_PendingRoutingSessions)
|
||||
if (it->GetOwner() && m_RoutingSession->IsReadyToSend()) // found established session
|
||||
{
|
||||
m_RoutingSession = it;
|
||||
m_PendingRoutingSessions.clear ();
|
||||
m_PendingRoutingSessions.clear();
|
||||
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);
|
||||
if (!m_RoutingSession->GetOwner() || !m_RoutingSession->IsReadyToSend())
|
||||
m_PendingRoutingSessions.push_back(m_RoutingSession);
|
||||
}
|
||||
}
|
||||
|
||||
auto path = m_RoutingSession->GetSharedRoutingPath();
|
||||
if (path && m_RoutingSession->IsRatchets () &&
|
||||
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
|
||||
{
|
||||
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||
if (path && m_RoutingSession->IsRatchets() &&
|
||||
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);
|
||||
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
|
||||
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else
|
||||
m_RoutingSession->SetSharedRoutingPath(nullptr);
|
||||
} else {
|
||||
// no remote lease set?
|
||||
LogPrint(eLogWarning, "DatagramSession: no cached remote lease set for ", m_RemoteIdent.ToBase32());
|
||||
m_RoutingSession->SetSharedRoutingPath (nullptr);
|
||||
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);
|
||||
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,33 +358,31 @@ 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;
|
||||
if (!ls) return;
|
||||
// only update lease set if found and newer than previous lease set
|
||||
uint64_t oldExpire = 0;
|
||||
if(m_RemoteLeaseSet) oldExpire = m_RemoteLeaseSet->GetExpirationTime();
|
||||
if(ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
|
||||
if (m_RemoteLeaseSet) oldExpire = m_RemoteLeaseSet->GetExpirationTime();
|
||||
if (ls && ls->GetExpirationTime() > oldExpire) m_RemoteLeaseSet = ls;
|
||||
}
|
||||
|
||||
void DatagramSession::FlushSendQueue ()
|
||||
{
|
||||
if (m_SendQueue.empty ()) return;
|
||||
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);
|
||||
}
|
||||
m_SendQueue.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,15 +40,16 @@ 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 ();
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
|
||||
/** @brief ack the garlic routing path */
|
||||
|
@ -59,24 +57,26 @@ 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 (); }
|
||||
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) :
|
||||
|
||||
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);
|
||||
if (ibgw) IBGW = std::make_shared<i2p::data::IdentHash>(ibgw);
|
||||
else IBGW = nullptr;
|
||||
if(obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
|
||||
if (obep) OBEP = std::make_shared<i2p::data::IdentHash>(obep);
|
||||
else OBEP = nullptr;
|
||||
}
|
||||
};
|
||||
|
@ -104,50 +104,79 @@ 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 ();
|
||||
DatagramDestination(std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip);
|
||||
|
||||
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);
|
||||
~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);
|
||||
// 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 FlushSendQueue (std::shared_ptr<DatagramSession> session);
|
||||
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash &ident);
|
||||
|
||||
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
|
||||
void SendDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
|
||||
uint16_t fromPort, uint16_t toPort);
|
||||
|
||||
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };
|
||||
void ResetReceiver () { m_Receiver = nullptr; };
|
||||
void SendRawDatagram(std::shared_ptr<DatagramSession> session, const uint8_t *payload, size_t len,
|
||||
uint16_t fromPort, uint16_t toPort);
|
||||
|
||||
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 FlushSendQueue(std::shared_ptr<DatagramSession> session);
|
||||
|
||||
void SetRawReceiver (const RawReceiver& receiver) { m_RawReceiver = receiver; };
|
||||
void ResetRawReceiver () { m_RawReceiver = nullptr; };
|
||||
void HandleDataMessagePayload(uint16_t fromPort, uint16_t toPort, const uint8_t *buf, size_t len,
|
||||
bool isRaw = false);
|
||||
|
||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash & remote);
|
||||
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 SetRawReceiver(const RawReceiver &receiver) { m_RawReceiver = receiver; };
|
||||
|
||||
void ResetRawReceiver() { m_RawReceiver = nullptr; };
|
||||
|
||||
std::shared_ptr<DatagramSession::Info> GetInfoForRemote(const i2p::data::IdentHash &remote);
|
||||
|
||||
// clean up stale sessions
|
||||
void CleanUp ();
|
||||
void CleanUp();
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
|
||||
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash &ident);
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDataMessage (const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
|
||||
std::shared_ptr<I2NPMessage>
|
||||
CreateDataMessage(const std::vector<std::pair<const uint8_t *, size_t> > &payloads,
|
||||
uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true);
|
||||
|
||||
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
|
||||
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||
void 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 */
|
||||
Receiver FindReceiver(uint16_t port);
|
||||
|
@ -159,7 +188,7 @@ namespace datagram
|
|||
RawReceiver m_RawReceiver; // default
|
||||
bool m_Gzip; // gzip compression of data messages
|
||||
std::mutex m_SessionsMutex;
|
||||
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
|
||||
std::map<i2p::data::IdentHash, DatagramSession_ptr> m_Sessions;
|
||||
std::mutex m_ReceiversMutex;
|
||||
std::map<uint16_t, Receiver> m_ReceiversByPorts;
|
||||
|
||||
|
@ -168,7 +197,7 @@ namespace datagram
|
|||
std::vector<uint8_t> m_From, m_Signature;
|
||||
i2p::util::MemoryPool<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> > m_I2NPMsgsPool;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
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;
|
||||
|
@ -86,16 +84,15 @@ namespace client
|
|||
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
|
||||
const int DEFAULT_ANSWER_PINGS = true;
|
||||
|
||||
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
typedef std::function<void(std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
|
||||
|
||||
class LeaseSetDestination : public i2p::garlic::GarlicDestination,
|
||||
public std::enable_shared_from_this<LeaseSetDestination> {
|
||||
typedef std::function<void(std::shared_ptr<i2p::data::LeaseSet> leaseSet)> RequestComplete;
|
||||
|
||||
class LeaseSetDestination: public i2p::garlic::GarlicDestination,
|
||||
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
|
||||
{
|
||||
LeaseSetRequest (boost::asio::io_service& service): requestTime (0), requestTimeoutTimer (service) {};
|
||||
struct LeaseSetRequest {
|
||||
LeaseSetRequest(boost::asio::io_service &service) : requestTime(0), requestTimeoutTimer(service) {};
|
||||
std::set<i2p::data::IdentHash> excluded;
|
||||
uint64_t requestTime;
|
||||
boost::asio::deadline_timer requestTimeoutTimer;
|
||||
|
@ -104,85 +101,128 @@ 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)
|
||||
{
|
||||
for (auto& it: requestComplete) it (ls);
|
||||
requestComplete.clear ();
|
||||
void Complete(std::shared_ptr<i2p::data::LeaseSet> ls) {
|
||||
for (auto &it: requestComplete) it(ls);
|
||||
requestComplete.clear();
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
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; };
|
||||
LeaseSetDestination(boost::asio::io_service &service, bool isPublic,
|
||||
const std::map<std::string, std::string> *params = nullptr);
|
||||
|
||||
virtual void Start ();
|
||||
virtual void Stop ();
|
||||
~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; };
|
||||
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);
|
||||
void CancelDestinationRequest (const i2p::data::IdentHash& dest, bool notify = true);
|
||||
void CancelDestinationRequestWithEncryptedLeaseSet (std::shared_ptr<const i2p::data::BlindedPublicKey> dest, bool notify = true);
|
||||
std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() { return m_Pool; };
|
||||
|
||||
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);
|
||||
|
||||
void CancelDestinationRequest(const i2p::data::IdentHash &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; }
|
||||
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 SubmitSessionKey(const uint8_t *key, const uint8_t *tag);
|
||||
|
||||
bool IsPublic () const { return m_IsPublic; };
|
||||
void SetPublic (bool pub) { m_IsPublic = pub; };
|
||||
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 HandleI2NPMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
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
|
||||
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 HandleDataMessage(const uint8_t *buf, size_t len) = 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 UpdateLeaseSet();
|
||||
|
||||
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;
|
||||
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 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:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
boost::asio::io_service &m_Service;
|
||||
mutable std::mutex m_RemoteLeaseSetsMutex;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<i2p::data::LeaseSet> > m_RemoteLeaseSets;
|
||||
std::map<i2p::data::IdentHash, std::shared_ptr<LeaseSetRequest> > m_LeaseSetRequests;
|
||||
|
@ -204,83 +244,122 @@ namespace client
|
|||
public:
|
||||
|
||||
// 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; };
|
||||
bool IsPerClientAuth () const { return m_AuthType > 0; };
|
||||
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;
|
||||
};
|
||||
|
||||
class ClientDestination: public LeaseSetDestination
|
||||
{
|
||||
struct EncryptionKey
|
||||
{
|
||||
bool IsPerClientAuth() const { return m_AuthType > 0; };
|
||||
};
|
||||
|
||||
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); };
|
||||
void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv, pub); };
|
||||
void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv); };
|
||||
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); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
|
||||
bool isPublic, const std::map<std::string, std::string> * params = nullptr);
|
||||
~ClientDestination ();
|
||||
ClientDestination(boost::asio::io_service &service, const i2p::data::PrivateKeys &keys,
|
||||
bool isPublic, const std::map<std::string, std::string> *params = nullptr);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
~ClientDestination();
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
void 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; };
|
||||
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> GetStreamingDestination (int port = 0) const;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> RemoveStreamingDestination (int port);
|
||||
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 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; }
|
||||
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);
|
||||
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;
|
||||
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 ();
|
||||
void CleanupDestination();
|
||||
|
||||
// I2CP
|
||||
void HandleDataMessage (const uint8_t * buf, size_t len);
|
||||
void CreateNewLeaseSet (const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels);
|
||||
void HandleDataMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
void CreateNewLeaseSet(const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > &tunnels);
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<ClientDestination> GetSharedFromThis () {
|
||||
return std::static_pointer_cast<ClientDestination>(shared_from_this ());
|
||||
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);
|
||||
|
||||
void PersistTemporaryKeys(EncryptionKey *keys, bool isSingleKey);
|
||||
|
||||
void ReadAuthKey(const std::string &group, const std::map<std::string, std::string> *params);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -292,7 +371,7 @@ namespace client
|
|||
bool m_IsStreamingAnswerPings;
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
|
||||
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
|
||||
i2p::datagram::DatagramDestination * m_DatagramDestination;
|
||||
i2p::datagram::DatagramDestination *m_DatagramDestination;
|
||||
int m_RefCounter; // how many clients(tunnels) use this destination
|
||||
|
||||
boost::asio::deadline_timer m_ReadyChecker;
|
||||
|
@ -302,22 +381,25 @@ namespace client
|
|||
public:
|
||||
|
||||
// for HTTP only
|
||||
std::vector<std::shared_ptr<const i2p::stream::Stream> > GetAllStreams () const;
|
||||
bool DeleteStream (uint32_t recvStreamID);
|
||||
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 ();
|
||||
RunnableClientDestination(const i2p::data::PrivateKeys &keys, bool isPublic,
|
||||
const std::map<std::string, std::string> *params = nullptr);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
~RunnableClientDestination();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
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,23 +37,30 @@ 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 () {};
|
||||
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);
|
||||
virtual ~RatchetTagSet() {};
|
||||
|
||||
int GetTagSetID () const { return m_TagSetID; };
|
||||
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
|
||||
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,24 +73,29 @@ namespace garlic
|
|||
};
|
||||
|
||||
class ECIESX25519AEADRatchetSession;
|
||||
class ReceiveRatchetTagSet: public RatchetTagSet,
|
||||
public std::enable_shared_from_this<ReceiveRatchetTagSet>
|
||||
{
|
||||
|
||||
class ReceiveRatchetTagSet : public RatchetTagSet,
|
||||
public std::enable_shared_from_this<ReceiveRatchetTagSet> {
|
||||
public:
|
||||
|
||||
ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false):
|
||||
m_Session (session), m_IsNS (isNS) {};
|
||||
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; };
|
||||
bool IsNS() const { return m_IsNS; };
|
||||
|
||||
void Expire ();
|
||||
bool IsExpired (uint64_t ts) const;
|
||||
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession() { return m_Session; };
|
||||
|
||||
virtual bool IsIndexExpired (int index) const;
|
||||
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
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,23 +105,22 @@ namespace garlic
|
|||
uint64_t m_ExpirationTimestamp = 0;
|
||||
};
|
||||
|
||||
class SymmetricKeyTagSet: public ReceiveRatchetTagSet
|
||||
{
|
||||
class SymmetricKeyTagSet : public ReceiveRatchetTagSet {
|
||||
public:
|
||||
|
||||
SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key);
|
||||
SymmetricKeyTagSet(GarlicDestination *destination, const uint8_t *key);
|
||||
|
||||
bool IsIndexExpired (int index) const { return false; };
|
||||
bool HandleNextMessage (uint8_t * buf, size_t len, int index);
|
||||
bool IsIndexExpired(int index) const { return false; };
|
||||
|
||||
bool HandleNextMessage(uint8_t *buf, size_t len, int index);
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Destination;
|
||||
GarlicDestination *m_Destination;
|
||||
uint8_t m_Key[32];
|
||||
};
|
||||
|
||||
enum ECIESx25519BlockType
|
||||
{
|
||||
enum ECIESx25519BlockType {
|
||||
eECIESx25519BlkDateTime = 0,
|
||||
eECIESx25519BlkSessionID = 1,
|
||||
eECIESx25519BlkTermination = 4,
|
||||
|
@ -127,12 +136,10 @@ namespace garlic
|
|||
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
|
||||
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
|
||||
|
||||
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
|
||||
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
|
||||
|
@ -151,59 +157,92 @@ namespace garlic
|
|||
|
||||
public:
|
||||
|
||||
ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS);
|
||||
~ECIESX25519AEADRatchetSession ();
|
||||
ECIESX25519AEADRatchetSession(GarlicDestination *owner, bool attachLeaseSetNS);
|
||||
|
||||
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);
|
||||
~ECIESX25519AEADRatchetSession();
|
||||
|
||||
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
|
||||
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
||||
bool HandleNextMessage(uint8_t *buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset,
|
||||
int index = 0);
|
||||
|
||||
void Terminate () { m_IsTerminated = true; }
|
||||
void SetDestination (const i2p::data::IdentHash& dest) // TODO:
|
||||
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));
|
||||
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 CheckExpired(uint64_t ts); // true is expired
|
||||
bool CanBeRestarted(uint64_t ts) const {
|
||||
return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT;
|
||||
}
|
||||
|
||||
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; };
|
||||
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);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||
void InitNewSessionTagset (std::shared_ptr<RatchetTagSet> tagsetNsr) const;
|
||||
bool GenerateEphemeralKeysAndEncode(uint8_t *buf); // buf is 32 bytes
|
||||
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 HandleNewIncomingSession(const uint8_t *buf, size_t len);
|
||||
|
||||
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);
|
||||
bool HandleNewOutgoingSessionReply(uint8_t *buf, size_t len);
|
||||
|
||||
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);
|
||||
bool
|
||||
HandleExistingSessionMessage(uint8_t *buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset,
|
||||
int index);
|
||||
|
||||
void GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags);
|
||||
void NewNextSendRatchet ();
|
||||
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);
|
||||
|
||||
void GenerateMoreReceiveTags(std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags);
|
||||
|
||||
void NewNextSendRatchet();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -224,30 +263,34 @@ namespace garlic
|
|||
public:
|
||||
|
||||
// for HTTP only
|
||||
int GetState () const { return (int)m_State; }
|
||||
i2p::data::IdentHash GetDestination () const
|
||||
{
|
||||
return m_Destination ? *m_Destination : i2p::data::IdentHash ();
|
||||
int GetState() const { return (int) m_State; }
|
||||
|
||||
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; };
|
||||
RouterIncomingRatchetSession(const i2p::crypto::NoiseSymmetricState &initState);
|
||||
|
||||
bool HandleNextMessage(const uint8_t *buf, size_t len);
|
||||
|
||||
i2p::crypto::NoiseSymmetricState &GetCurrentNoiseState() { return m_CurrentNoiseState; };
|
||||
|
||||
private:
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,474 +11,461 @@
|
|||
#include "Crypto.h"
|
||||
#include "Ed25519.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
Ed25519::Ed25519 ()
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * tmp = BN_new ();
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
Ed25519::Ed25519() {
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BIGNUM *tmp = BN_new();
|
||||
|
||||
q = BN_new ();
|
||||
q = BN_new();
|
||||
// 2^255-19
|
||||
BN_set_bit (q, 255); // 2^255
|
||||
BN_sub_word (q, 19);
|
||||
BN_set_bit(q, 255); // 2^255
|
||||
BN_sub_word(q, 19);
|
||||
|
||||
l = BN_new ();
|
||||
l = BN_new();
|
||||
// 2^252 + 27742317777372353535851937790883648493
|
||||
BN_set_bit (l, 252);
|
||||
two_252_2 = BN_dup (l);
|
||||
BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
|
||||
BN_add (l, l, tmp);
|
||||
BN_sub_word (two_252_2, 2); // 2^252 - 2
|
||||
BN_set_bit(l, 252);
|
||||
two_252_2 = BN_dup(l);
|
||||
BN_dec2bn(&tmp, "27742317777372353535851937790883648493");
|
||||
BN_add(l, l, tmp);
|
||||
BN_sub_word(two_252_2, 2); // 2^252 - 2
|
||||
|
||||
// -121665*inv(121666)
|
||||
d = BN_new ();
|
||||
BN_set_word (tmp, 121666);
|
||||
BN_mod_inverse (tmp, tmp, q, ctx);
|
||||
BN_set_word (d, 121665);
|
||||
BN_set_negative (d, 1);
|
||||
BN_mod_mul (d, d, tmp, q, ctx);
|
||||
d = BN_new();
|
||||
BN_set_word(tmp, 121666);
|
||||
BN_mod_inverse(tmp, tmp, q, ctx);
|
||||
BN_set_word(d, 121665);
|
||||
BN_set_negative(d, 1);
|
||||
BN_mod_mul(d, d, tmp, q, ctx);
|
||||
|
||||
// 2^((q-1)/4)
|
||||
I = BN_new ();
|
||||
BN_free (tmp);
|
||||
tmp = BN_dup (q);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_div_word (tmp, 4);
|
||||
BN_set_word (I, 2);
|
||||
BN_mod_exp (I, I, tmp, q, ctx);
|
||||
BN_free (tmp);
|
||||
I = BN_new();
|
||||
BN_free(tmp);
|
||||
tmp = BN_dup(q);
|
||||
BN_sub_word(tmp, 1);
|
||||
BN_div_word(tmp, 4);
|
||||
BN_set_word(I, 2);
|
||||
BN_mod_exp(I, I, tmp, q, ctx);
|
||||
BN_free(tmp);
|
||||
|
||||
// 4*inv(5)
|
||||
BIGNUM * By = BN_new ();
|
||||
BN_set_word (By, 5);
|
||||
BN_mod_inverse (By, By, q, ctx);
|
||||
BN_mul_word (By, 4);
|
||||
BIGNUM * Bx = RecoverX (By, ctx);
|
||||
BN_mod (Bx, Bx, q, ctx); // % q
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
BIGNUM *By = BN_new();
|
||||
BN_set_word(By, 5);
|
||||
BN_mod_inverse(By, By, q, ctx);
|
||||
BN_mul_word(By, 4);
|
||||
BIGNUM *Bx = RecoverX(By, ctx);
|
||||
BN_mod(Bx, Bx, q, ctx); // % q
|
||||
BN_mod(By, By, q, ctx); // % q
|
||||
|
||||
// precalculate Bi256 table
|
||||
Bi256Carry = { Bx, By }; // B
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
Bi256Carry = {Bx, By}; // B
|
||||
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
|
||||
Bi256[i][j] = Sum(Bi256[i][j - 1], Bi256[i][0], ctx); // (256+j+1)^i*B
|
||||
Bi256Carry = Bi256[i][127];
|
||||
for (int j = 0; j < 128; j++) // add first point 128 more times
|
||||
Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx);
|
||||
Bi256Carry = Sum(Bi256Carry, Bi256[i][0], ctx);
|
||||
}
|
||||
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
for (int i = 0; i < 32; i++)
|
||||
for (int j = 0; j < 128; j++)
|
||||
Bi256[i][j] = other.Bi256[i][j];
|
||||
}
|
||||
|
||||
Ed25519::~Ed25519 ()
|
||||
{
|
||||
BN_free (q);
|
||||
BN_free (l);
|
||||
BN_free (d);
|
||||
BN_free (I);
|
||||
BN_free (two_252_2);
|
||||
Ed25519::~Ed25519() {
|
||||
BN_free(q);
|
||||
BN_free(l);
|
||||
BN_free(d);
|
||||
BN_free(I);
|
||||
BN_free(two_252_2);
|
||||
}
|
||||
|
||||
|
||||
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::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
|
||||
{
|
||||
return DecodePoint (buf, ctx);
|
||||
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
|
||||
{
|
||||
EncodePoint (Normalize (publicKey, ctx), buf);
|
||||
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
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
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
|
||||
// B*S = R + PK*h => R = B*S - PK*h
|
||||
// we don't decode R, but encode (B*S - PK*h)
|
||||
auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
|
||||
BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0
|
||||
auto PKh = Mul (publicKey, h, ctx); // PK*h
|
||||
auto Bs = MulB(signature + EDDSA25519_SIGNATURE_LENGTH / 2, ctx); // B*S;
|
||||
BN_mod(h, h, l, ctx); // public key is multiple of B, but B%l = 0
|
||||
auto PKh = Mul(publicKey, h, ctx); // PK*h
|
||||
uint8_t diff[32];
|
||||
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
|
||||
bool passed = !memcmp (signature, diff, 32); // R
|
||||
BN_free (h);
|
||||
BN_CTX_free (ctx);
|
||||
EncodePoint(Normalize(Sum(Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
|
||||
bool passed = !memcmp(signature, diff, 32); // R
|
||||
BN_free(h);
|
||||
BN_CTX_free(ctx);
|
||||
if (!passed)
|
||||
LogPrint (eLogError, "25519 signature verification failed");
|
||||
LogPrint(eLogError, "25519 signature verification failed");
|
||||
return passed;
|
||||
}
|
||||
|
||||
void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded,
|
||||
const uint8_t * buf, size_t len, uint8_t * signature) const
|
||||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
void Ed25519::Sign(const uint8_t *expandedPrivateKey, const uint8_t *publicKeyEncoded,
|
||||
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, buf, len); // data
|
||||
SHA512_Init(&ctx);
|
||||
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
|
||||
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
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, R, EDDSA25519_SIGNATURE_LENGTH / 2); // R
|
||||
SHA512_Update(&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update(&ctx, buf, len); // data
|
||||
SHA512_Final(digest, &ctx);
|
||||
BIGNUM *h = DecodeBN<64>(digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
|
||||
BN_mod_mul (h, h, a, l, bnCtx); // %l
|
||||
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_CTX_free (bnCtx);
|
||||
BIGNUM *a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH>(expandedPrivateKey); // left half of expanded key
|
||||
BN_mod_mul(h, h, a, l, bnCtx); // %l
|
||||
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_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
|
||||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
void Ed25519::SignRedDSA(const uint8_t *privateKey, const uint8_t *publicKeyEncoded,
|
||||
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];
|
||||
RAND_bytes (T, 80);
|
||||
RAND_bytes(T, 80);
|
||||
// calculate r = H*(T || publickey || data)
|
||||
SHA512_CTX ctx;
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, T, 80);
|
||||
SHA512_Update (&ctx, publicKeyEncoded, 32);
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, T, 80);
|
||||
SHA512_Update(&ctx, publicKeyEncoded, 32);
|
||||
SHA512_Update(&ctx, buf, len); // data
|
||||
uint8_t digest[64];
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * r = DecodeBN<64> (digest);
|
||||
BN_mod (r, r, l, bnCtx); // % l
|
||||
EncodeBN (r, digest, 32);
|
||||
SHA512_Final(digest, &ctx);
|
||||
BIGNUM *r = DecodeBN<64>(digest);
|
||||
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
|
||||
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), 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);
|
||||
// calculate S
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, R, EDDSA25519_SIGNATURE_LENGTH / 2); // R
|
||||
SHA512_Update(&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update(&ctx, buf, len); // data
|
||||
SHA512_Final(digest, &ctx);
|
||||
BIGNUM *h = DecodeBN<64>(digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);
|
||||
BN_mod_mul (h, h, a, l, bnCtx); // %l
|
||||
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_CTX_free (bnCtx);
|
||||
BIGNUM *a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH>(privateKey);
|
||||
BN_mod_mul(h, h, a, l, bnCtx); // %l
|
||||
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_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)
|
||||
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
|
||||
BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
|
||||
BIGNUM *x3 = BN_new(), *y3 = BN_new(), *z3 = BN_new(), *t3 = BN_new();
|
||||
|
||||
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
BN_mul(x3, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul(y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
|
||||
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); }
|
||||
BN_mul (t3, t1, t2, ctx);
|
||||
BN_mul (t3, t3, d, ctx); // C = d*t1*t2
|
||||
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);
|
||||
}
|
||||
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
|
||||
BN_mul(z3, p1.z, p2.z, ctx); // D = z1*z2
|
||||
else
|
||||
BN_copy (z3, p1.z); // D = z1
|
||||
}
|
||||
else
|
||||
{
|
||||
BN_copy(z3, p1.z); // D = z1
|
||||
} else {
|
||||
if (p2.z)
|
||||
BN_copy (z3, p2.z); // D = z2
|
||||
BN_copy(z3, p2.z); // D = z2
|
||||
else
|
||||
BN_one (z3); // D = 1
|
||||
BN_one(z3); // D = 1
|
||||
}
|
||||
|
||||
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
|
||||
BN_add (E, p1.x, p1.y);
|
||||
BN_add (F, p2.x, p2.y);
|
||||
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub (E, E, x3);
|
||||
BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
|
||||
BN_sub (F, z3, t3); // F = D - C
|
||||
BN_add (G, z3, t3); // G = D + C
|
||||
BN_add (H, y3, x3); // H = B + A
|
||||
BIGNUM *E = BN_CTX_get(ctx), *F = BN_CTX_get(ctx), *G = BN_CTX_get(ctx), *H = BN_CTX_get(ctx);
|
||||
BN_add(E, p1.x, p1.y);
|
||||
BN_add(F, p2.x, p2.y);
|
||||
BN_mul(E, E, F, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub(E, E, x3);
|
||||
BN_sub(E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
|
||||
BN_sub(F, z3, t3); // F = D - C
|
||||
BN_add(G, z3, t3); // G = D + C
|
||||
BN_add(H, y3, x3); // H = B + A
|
||||
|
||||
BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
|
||||
BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
|
||||
BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G
|
||||
BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H
|
||||
BN_mod_mul(x3, E, F, q, ctx); // x3 = E*F
|
||||
BN_mod_mul(y3, G, H, q, ctx); // y3 = G*H
|
||||
BN_mod_mul(z3, F, G, q, ctx); // z3 = F*G
|
||||
BN_mod_mul(t3, E, H, q, ctx); // t3 = E*H
|
||||
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_end(ctx);
|
||||
|
||||
return EDDSAPoint {x3, y3, z3, t3};
|
||||
return EDDSAPoint{x3, y3, z3, t3};
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
|
||||
BN_sqr(x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr(y2, p.y, ctx); // y2 = B = y^2
|
||||
if (p.t)
|
||||
BN_sqr (t2, p.t, ctx); // t2 = t^2
|
||||
else
|
||||
{
|
||||
BN_mul (t2, p.x, p.y, ctx); // t = x*y
|
||||
BN_sqr (t2, t2, ctx); // t2 = t^2
|
||||
BN_sqr(t2, p.t, ctx); // t2 = t^2
|
||||
else {
|
||||
BN_mul(t2, p.x, p.y, ctx); // t = x*y
|
||||
BN_sqr(t2, t2, ctx); // t2 = t^2
|
||||
}
|
||||
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
|
||||
BN_mul(t2, t2, d, ctx); // t2 = C = d*t^2
|
||||
if (p.z)
|
||||
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
|
||||
BN_sqr(z2, p.z, ctx); // z2 = D = z^2
|
||||
else
|
||||
BN_one (z2); // z2 = 1
|
||||
BN_one(z2); // z2 = 1
|
||||
|
||||
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
|
||||
BIGNUM *E = BN_CTX_get(ctx), *F = BN_CTX_get(ctx), *G = BN_CTX_get(ctx), *H = BN_CTX_get(ctx);
|
||||
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
|
||||
BN_mul (E, p.x, p.y, ctx);
|
||||
BN_lshift1 (E, E); // E =2*x*y
|
||||
BN_sub (F, z2, t2); // F = D - C
|
||||
BN_add (G, z2, t2); // G = D + C
|
||||
BN_add (H, y2, x2); // H = B + A
|
||||
BN_mul(E, p.x, p.y, ctx);
|
||||
BN_lshift1(E, E); // E =2*x*y
|
||||
BN_sub(F, z2, t2); // F = D - C
|
||||
BN_add(G, z2, t2); // G = D + C
|
||||
BN_add(H, y2, x2); // H = B + A
|
||||
|
||||
BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F
|
||||
BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H
|
||||
if (!p.z) p.z = BN_new ();
|
||||
BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G
|
||||
if (!p.t) p.t = BN_new ();
|
||||
BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H
|
||||
BN_mod_mul(p.x, E, F, q, ctx); // x2 = E*F
|
||||
BN_mod_mul(p.y, G, H, q, ctx); // y2 = G*H
|
||||
if (!p.z) p.z = BN_new();
|
||||
BN_mod_mul(p.z, F, G, q, ctx); // z2 = F*G
|
||||
if (!p.t) p.t = BN_new();
|
||||
BN_mod_mul(p.t, E, H, q, ctx); // t2 = E*H
|
||||
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_end(ctx);
|
||||
}
|
||||
|
||||
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);
|
||||
EDDSAPoint res {zero, one};
|
||||
if (!BN_is_zero (e))
|
||||
{
|
||||
int bitCount = BN_num_bits (e);
|
||||
for (int i = bitCount - 1; i >= 0; i--)
|
||||
{
|
||||
Double (res, ctx);
|
||||
if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
|
||||
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);
|
||||
EDDSAPoint res{zero, one};
|
||||
if (!BN_is_zero(e)) {
|
||||
int bitCount = BN_num_bits(e);
|
||||
for (int i = bitCount - 1; i >= 0; i--) {
|
||||
Double(res, ctx);
|
||||
if (BN_is_bit_set(e, i)) res = Sum(res, p, ctx);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
EDDSAPoint Ed25519::MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
|
||||
EDDSAPoint Ed25519::MulB(const uint8_t *e, BN_CTX *ctx) const // B*e, e is 32 bytes Little Endian
|
||||
{
|
||||
BIGNUM * zero = BN_new (), * one = BN_new ();
|
||||
BN_zero (zero); BN_one (one);
|
||||
EDDSAPoint res {zero, one};
|
||||
BIGNUM *zero = BN_new(), *one = BN_new();
|
||||
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
|
||||
{
|
||||
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
|
||||
res = Sum(res, Bi256[i][x - 1], ctx);
|
||||
else {
|
||||
res = Sum(res, -Bi256[i][255 - x], ctx); // -Bi[256-x]
|
||||
carry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (carry) res = Sum (res, Bi256Carry, ctx);
|
||||
if (carry) res = Sum(res, Bi256Carry, ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)};
|
||||
} else
|
||||
return EDDSAPoint{BN_dup(p.x), BN_dup(p.y)};
|
||||
}
|
||||
|
||||
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
|
||||
BN_sqr (y2, p.y, ctx); // y^2
|
||||
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
|
||||
BN_sqr(y2, p.y, ctx); // y^2
|
||||
// y^2 - x^2 - 1 - d*x^2*y^2
|
||||
BN_mul (tmp, d, x2, ctx);
|
||||
BN_mul (tmp, tmp, y2, ctx);
|
||||
BN_sub (tmp, y2, tmp);
|
||||
BN_sub (tmp, tmp, x2);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_mod (tmp, tmp, q, ctx); // % q
|
||||
bool ret = BN_is_zero (tmp);
|
||||
BN_CTX_end (ctx);
|
||||
BN_mul(tmp, d, x2, ctx);
|
||||
BN_mul(tmp, tmp, y2, ctx);
|
||||
BN_sub(tmp, y2, tmp);
|
||||
BN_sub(tmp, tmp, x2);
|
||||
BN_sub_word(tmp, 1);
|
||||
BN_mod(tmp, tmp, q, ctx); // % q
|
||||
bool ret = BN_is_zero(tmp);
|
||||
BN_CTX_end(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
// xx = (y^2 -1)*inv(d*y^2 +1)
|
||||
BN_mul (xx, d, y2, ctx);
|
||||
BN_add_word (xx, 1);
|
||||
BN_mod_inverse (xx, xx, q, ctx);
|
||||
BN_sub_word (y2, 1);
|
||||
BN_mul (xx, y2, xx, ctx);
|
||||
BN_mul(xx, d, y2, ctx);
|
||||
BN_add_word(xx, 1);
|
||||
BN_mod_inverse(xx, xx, q, ctx);
|
||||
BN_sub_word(y2, 1);
|
||||
BN_mul(xx, y2, xx, ctx);
|
||||
// x = srqt(xx) = xx^(2^252-2)
|
||||
BIGNUM * x = BN_new ();
|
||||
BN_mod_exp (x, xx, two_252_2, q, ctx);
|
||||
BIGNUM *x = BN_new();
|
||||
BN_mod_exp(x, xx, two_252_2, q, ctx);
|
||||
// check (x^2 -xx) % q
|
||||
BN_sqr (y2, x, ctx);
|
||||
BN_mod_sub (y2, y2, xx, q, ctx);
|
||||
if (!BN_is_zero (y2))
|
||||
BN_mod_mul (x, x, I, q, ctx);
|
||||
if (BN_is_odd (x))
|
||||
BN_sub (x, q, x);
|
||||
BN_CTX_end (ctx);
|
||||
BN_sqr(y2, x, ctx);
|
||||
BN_mod_sub(y2, y2, xx, q, ctx);
|
||||
if (!BN_is_zero(y2))
|
||||
BN_mod_mul(x, x, I, q, ctx);
|
||||
if (BN_is_odd(x))
|
||||
BN_sub(x, q, x);
|
||||
BN_CTX_end(ctx);
|
||||
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
|
||||
for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH / 2; i++) // invert bytes
|
||||
{
|
||||
buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i];
|
||||
buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i];
|
||||
buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1 - i];
|
||||
buf1[EDDSA25519_PUBLIC_KEY_LENGTH - 1 - i] = buf[i];
|
||||
}
|
||||
bool isHighestBitSet = buf1[0] & 0x80;
|
||||
if (isHighestBitSet)
|
||||
buf1[0] &= 0x7f; // clear highest bit
|
||||
BIGNUM * y = BN_new ();
|
||||
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
|
||||
BIGNUM * x = RecoverX (y, ctx);
|
||||
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
|
||||
EDDSAPoint p {x, y, z, t};
|
||||
if (!IsOnCurve (p, ctx))
|
||||
LogPrint (eLogError, "Decoded point is not on 25519");
|
||||
BIGNUM *y = BN_new();
|
||||
BN_bin2bn(buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
|
||||
BIGNUM *x = RecoverX(y, ctx);
|
||||
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
|
||||
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
|
||||
{
|
||||
EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
if (BN_is_bit_set (p.x, 0)) // highest bit
|
||||
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
|
||||
for (size_t i = 0; i < len / 2; i++) // invert bytes
|
||||
{
|
||||
buf1[i] = buf[len -1 - i];
|
||||
buf1[len -1 - i] = buf[i];
|
||||
buf1[i] = buf[len - 1 - i];
|
||||
buf1[len - 1 - i] = buf[i];
|
||||
}
|
||||
BIGNUM * res = BN_new ();
|
||||
BN_bin2bn (buf1, len, res);
|
||||
BIGNUM *res = BN_new();
|
||||
BN_bin2bn(buf1, len, res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Ed25519::EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const
|
||||
{
|
||||
bn2buf (bn, buf, len);
|
||||
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
|
||||
for (size_t i = 0; i < len / 2; i++) // invert bytes
|
||||
{
|
||||
uint8_t tmp = buf[i];
|
||||
buf[i] = buf[len -1 - i];
|
||||
buf[len -1 - i] = tmp;
|
||||
buf[i] = buf[len - 1 - i];
|
||||
buf[len - 1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#if !OPENSSL_X25519
|
||||
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);
|
||||
|
||||
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);
|
||||
unsigned int swap = 0;
|
||||
auto bits = BN_num_bits (k);
|
||||
while(bits)
|
||||
{
|
||||
auto bits = BN_num_bits(k);
|
||||
while (bits) {
|
||||
--bits;
|
||||
auto k_t = BN_is_bit_set(k, bits) ? 1 : 0;
|
||||
swap ^= k_t;
|
||||
if (swap)
|
||||
{
|
||||
std::swap (x2, x3);
|
||||
std::swap (z2, z3);
|
||||
if (swap) {
|
||||
std::swap(x2, x3);
|
||||
std::swap(z2, z3);
|
||||
}
|
||||
swap = k_t;
|
||||
BN_mod_sub(tmp0, x3, z3, q, ctx);
|
||||
|
@ -500,108 +487,112 @@ namespace crypto
|
|||
BN_mod_mul(z3, x1, z2, q, ctx);
|
||||
BN_mod_mul(z2, tmp1, tmp0, q, ctx);
|
||||
}
|
||||
if (swap)
|
||||
{
|
||||
std::swap (x2, x3);
|
||||
std::swap (z2, z3);
|
||||
if (swap) {
|
||||
std::swap(x2, x3);
|
||||
std::swap(z2, z3);
|
||||
}
|
||||
BN_mod_inverse (z2, z2, q, ctx);
|
||||
BIGNUM * res = BN_new (); // not from ctx
|
||||
BN_mod_inverse(z2, z2, q, ctx);
|
||||
BIGNUM *res = BN_new(); // not from ctx
|
||||
BN_mod_mul(res, x2, z2, q, ctx);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_end(ctx);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * p1 = DecodeBN<32> (p);
|
||||
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;
|
||||
BIGNUM * n = DecodeBN<32> (k);
|
||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
||||
EncodeBN (q1, buf, 32);
|
||||
BN_free (p1); BN_free (n); BN_free (q1);
|
||||
memcpy(k, e, 32);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
BIGNUM * n = DecodeBN<32> (k);
|
||||
BIGNUM * q1 = ScalarMul (p1, n, ctx);
|
||||
EncodeBN (q1, buf, 32);
|
||||
BN_free (p1); BN_free (n); BN_free (q1);
|
||||
memcpy(k, e, 32);
|
||||
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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
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
|
||||
BN_mod (alpha, alpha, l, ctx); // % l
|
||||
BIGNUM *alpha = DecodeBN<64>(seed); // seed is in Little Endian
|
||||
BN_mod(alpha, alpha, l, ctx); // % l
|
||||
uint8_t priv[32];
|
||||
EncodeBN (alpha, priv, 32); // back to Little Endian
|
||||
BN_free (alpha);
|
||||
EncodeBN(alpha, priv, 32); // back to Little Endian
|
||||
BN_free(alpha);
|
||||
// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
|
||||
auto A1 = Sum (DecodePublicKey (pub, ctx), MulB (priv, ctx), ctx); // pub + B*alpha
|
||||
EncodePublicKey (A1, blinded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
auto A1 = Sum(DecodePublicKey(pub, ctx), MulB(priv, ctx), ctx); // pub + B*alpha
|
||||
EncodePublicKey(A1, blinded, ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void Ed25519::BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
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
|
||||
BN_mod (alpha, alpha, l, ctx); // % l
|
||||
BIGNUM * p = DecodeBN<32> (priv); // priv is in Little Endian
|
||||
BN_add (alpha, alpha, p); // alpha = alpha + priv
|
||||
BIGNUM *alpha = DecodeBN<64>(seed); // seed is in Little Endian
|
||||
BN_mod(alpha, alpha, l, ctx); // % l
|
||||
BIGNUM *p = DecodeBN<32>(priv); // priv is in Little Endian
|
||||
BN_add(alpha, alpha, p); // alpha = alpha + priv
|
||||
// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
|
||||
BN_mod (alpha, alpha, l, ctx); // % l
|
||||
EncodeBN (alpha, blindedPriv, 32);
|
||||
BN_mod(alpha, alpha, l, ctx); // % l
|
||||
EncodeBN(alpha, blindedPriv, 32);
|
||||
// A' = DERIVE_PUBLIC(a')
|
||||
auto A1 = MulB (blindedPriv, ctx);
|
||||
EncodePublicKey (A1, blindedPub, ctx);
|
||||
BN_free (alpha); BN_free (p);
|
||||
BN_CTX_free (ctx);
|
||||
auto A1 = MulB(blindedPriv, ctx);
|
||||
EncodePublicKey(A1, blindedPub, ctx);
|
||||
BN_free(alpha);
|
||||
BN_free(p);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
|
||||
{
|
||||
SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, 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);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_mod (p, p, l, ctx); // % l
|
||||
EncodeBN (p, priv, 32);
|
||||
BN_CTX_free (ctx);
|
||||
BN_free (p);
|
||||
RAND_bytes(seed, 32);
|
||||
BIGNUM *p = DecodeBN<32>(seed);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_mod(p, p, l, ctx); // % l
|
||||
EncodeBN(p, priv, 32);
|
||||
BN_CTX_free(ctx);
|
||||
BN_free(p);
|
||||
}
|
||||
|
||||
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);
|
||||
g_Ed25519.reset(c);
|
||||
else
|
||||
delete c;
|
||||
}
|
||||
return g_Ed25519;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,127 +13,168 @@
|
|||
#include <openssl/bn.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
struct EDDSAPoint
|
||||
{
|
||||
BIGNUM * x {nullptr};
|
||||
BIGNUM * y {nullptr};
|
||||
BIGNUM * z {nullptr};
|
||||
BIGNUM * t {nullptr}; // projective coordinates
|
||||
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); }
|
||||
EDDSAPoint() {}
|
||||
|
||||
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(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);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
BIGNUM * x1 = NULL, * y1 = NULL, * z1 = NULL, * t1 = NULL;
|
||||
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)); };
|
||||
return EDDSAPoint {x1, y1, z1, t1};
|
||||
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 (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));
|
||||
};
|
||||
return EDDSAPoint{x1, y1, z1, t1};
|
||||
}
|
||||
};
|
||||
|
||||
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 ();
|
||||
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;
|
||||
|
||||
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 ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
|
||||
|
||||
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
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
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
|
||||
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 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;
|
||||
EDDSAPoint Sum(const EDDSAPoint &p1, const EDDSAPoint &p2, 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;
|
||||
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;
|
||||
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;
|
||||
BIGNUM *ScalarMul(const BIGNUM *p, const BIGNUM *e, BN_CTX *ctx) const;
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
BIGNUM *q, *l, *d, *I;
|
||||
// transient values
|
||||
BIGNUM * two_252_2; // 2^252-2
|
||||
BIGNUM *two_252_2; // 2^252-2
|
||||
EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes
|
||||
// if j > 128 we use 256 - j and carry 1 to next byte
|
||||
// Bi256[0][0] = B, base point
|
||||
EDDSAPoint Bi256Carry; // Bi256[32][0]
|
||||
};
|
||||
|
||||
std::unique_ptr<Ed25519>& GetEd25519 ();
|
||||
std::unique_ptr<Ed25519> &GetEd25519();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,49 +10,60 @@
|
|||
#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 ();
|
||||
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
|
||||
BN_set_bit(p, 255); // 2^255
|
||||
BN_sub_word(p, 19);
|
||||
p38 = BN_dup(p);
|
||||
BN_add_word(p38, 3);
|
||||
BN_div_word(p38, 8); // (p+3)/8
|
||||
p12 = BN_dup(p);
|
||||
BN_sub_word(p12, 1);
|
||||
BN_div_word(p12, 2); // (p-1)/2
|
||||
p14 = BN_dup(p);
|
||||
BN_sub_word(p14, 1);
|
||||
BN_div_word(p14, 4); // (p-1)/4
|
||||
|
||||
A = BN_new (); BN_set_word (A, 486662);
|
||||
nA = BN_new (); BN_sub (nA, p, A);
|
||||
A = BN_new();
|
||||
BN_set_word(A, 486662);
|
||||
nA = BN_new();
|
||||
BN_sub(nA, p, A);
|
||||
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
// calculate sqrt(-1)
|
||||
sqrtn1 = BN_new ();
|
||||
BN_set_word (sqrtn1, 2);
|
||||
BN_mod_exp (sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
|
||||
sqrtn1 = BN_new();
|
||||
BN_set_word(sqrtn1, 2);
|
||||
BN_mod_exp(sqrtn1, sqrtn1, p14, p, ctx); // 2^((p-1)/4
|
||||
|
||||
u = BN_new (); BN_set_word (u, 2);
|
||||
iu = BN_new (); BN_mod_inverse (iu, u, p, ctx);
|
||||
u = BN_new();
|
||||
BN_set_word(u, 2);
|
||||
iu = BN_new();
|
||||
BN_mod_inverse(iu, u, p, ctx);
|
||||
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
Elligator2::~Elligator2 ()
|
||||
{
|
||||
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);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
uint8_t key1[32];
|
||||
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||
|
@ -61,38 +72,35 @@ 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
|
||||
BN_sub (xA, p, xA); // p - (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);
|
||||
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)
|
||||
{
|
||||
RAND_bytes (&randByte, 1);
|
||||
if (random) {
|
||||
RAND_bytes(&randByte, 1);
|
||||
highY = randByte & 0x01;
|
||||
}
|
||||
|
||||
BIGNUM * r = BN_CTX_get (ctx);
|
||||
if (highY)
|
||||
{
|
||||
BN_mod_inverse (r, x, p, ctx);
|
||||
BN_mod_mul (r, r, xA, p, ctx);
|
||||
BIGNUM *r = BN_CTX_get(ctx);
|
||||
if (highY) {
|
||||
BN_mod_inverse(r, x, p, ctx);
|
||||
BN_mod_mul(r, r, xA, p, ctx);
|
||||
} else {
|
||||
BN_mod_inverse(r, xA, p, ctx);
|
||||
BN_mod_mul(r, r, x, p, ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
BN_mod_inverse (r, xA, p, ctx);
|
||||
BN_mod_mul (r, r, x, p, ctx);
|
||||
}
|
||||
BN_mod_mul (r, r, iu, p, ctx);
|
||||
BN_mod_mul(r, r, iu, p, ctx);
|
||||
|
||||
SquareRoot (r, r, ctx);
|
||||
bn2buf (r, encoded, 32);
|
||||
SquareRoot(r, r, ctx);
|
||||
bn2buf(r, encoded, 32);
|
||||
|
||||
if (random)
|
||||
encoded[0] |= (randByte & 0xC0); // copy two highest bits from randByte
|
||||
|
@ -102,20 +110,18 @@ namespace crypto
|
|||
encoded[i] = encoded[31 - i];
|
||||
encoded[31 - i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
ret = false;
|
||||
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
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);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
|
||||
uint8_t encoded1[32];
|
||||
for (size_t i = 0; i < 16; i++) // from Little Endian
|
||||
|
@ -125,71 +131,70 @@ 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
|
||||
if (BN_cmp(r, p12) <= 0) // r < (p-1)/2
|
||||
{
|
||||
// v = -A/(1+u*r^2)
|
||||
BIGNUM * v = BN_CTX_get (ctx); BN_mod_sqr (v, r, p, ctx);
|
||||
BN_mod_mul (v, v, u, p, ctx);
|
||||
BN_add_word (v, 1);
|
||||
BN_mod_inverse (v, v, p, ctx);
|
||||
BN_mod_mul (v, v, nA, p, ctx);
|
||||
BIGNUM *v = BN_CTX_get(ctx);
|
||||
BN_mod_sqr(v, r, p, ctx);
|
||||
BN_mod_mul(v, v, u, p, ctx);
|
||||
BN_add_word(v, 1);
|
||||
BN_mod_inverse(v, v, p, ctx);
|
||||
BN_mod_mul(v, v, nA, p, ctx);
|
||||
|
||||
BIGNUM * vpA = BN_CTX_get (ctx);
|
||||
BN_add (vpA, v, A); // v + A
|
||||
BIGNUM *vpA = BN_CTX_get(ctx);
|
||||
BN_add(vpA, v, A); // v + A
|
||||
// t = v^3+A*v^2+v = v^2*(v+A)+v
|
||||
BIGNUM * t = BN_CTX_get (ctx); BN_mod_sqr (t, v, p, ctx);
|
||||
BN_mod_mul (t, t, vpA, p, ctx);
|
||||
BN_mod_add (t, t, v, p, ctx);
|
||||
BIGNUM *t = BN_CTX_get(ctx);
|
||||
BN_mod_sqr(t, v, p, ctx);
|
||||
BN_mod_mul(t, t, vpA, p, ctx);
|
||||
BN_mod_add(t, t, v, p, ctx);
|
||||
|
||||
int legendre = Legendre (t, ctx);
|
||||
BIGNUM * x = BN_CTX_get (ctx);
|
||||
int legendre = Legendre(t, ctx);
|
||||
BIGNUM *x = BN_CTX_get(ctx);
|
||||
if (legendre == 1)
|
||||
BN_copy (x, v);
|
||||
else
|
||||
{
|
||||
BN_sub (x, p, v);
|
||||
BN_mod_sub (x, x, A, p, ctx);
|
||||
BN_copy(x, v);
|
||||
else {
|
||||
BN_sub(x, p, v);
|
||||
BN_mod_sub(x, x, A, p, ctx);
|
||||
}
|
||||
|
||||
bn2buf (x, key, 32);
|
||||
bn2buf(x, key, 32);
|
||||
for (size_t i = 0; i < 16; i++) // To Little Endian
|
||||
{
|
||||
uint8_t tmp = key[i];
|
||||
key[i] = key[31 - i];
|
||||
key[31 - i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
ret = false;
|
||||
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Elligator2::SquareRoot (const BIGNUM * x, BIGNUM * r, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * t = BN_CTX_get (ctx);
|
||||
BN_mod_exp (t, x, p14, p, ctx); // t = x^((p-1)/4)
|
||||
BN_mod_exp (r, x, p38, p, ctx); // r = x^((p+3)/8)
|
||||
BN_add_word (t, 1);
|
||||
void Elligator2::SquareRoot(const BIGNUM *x, BIGNUM *r, BN_CTX *ctx) const {
|
||||
BIGNUM *t = BN_CTX_get(ctx);
|
||||
BN_mod_exp(t, x, p14, p, ctx); // t = x^((p-1)/4)
|
||||
BN_mod_exp(r, x, p38, p, ctx); // r = x^((p+3)/8)
|
||||
BN_add_word(t, 1);
|
||||
|
||||
if (!BN_cmp (t, p))
|
||||
BN_mod_mul (r, r, sqrtn1, p, ctx);
|
||||
if (!BN_cmp(t, p))
|
||||
BN_mod_mul(r, r, sqrtn1, p, ctx);
|
||||
|
||||
if (BN_cmp (r, p12) > 0) // r > (p-1)/2
|
||||
BN_sub (r, p, r);
|
||||
if (BN_cmp(r, p12) > 0) // r > (p-1)/2
|
||||
BN_sub(r, p, r);
|
||||
}
|
||||
|
||||
int Elligator2::Legendre (const BIGNUM * a, BN_CTX * ctx) const
|
||||
{
|
||||
int Elligator2::Legendre(const BIGNUM *a, BN_CTX *ctx) const {
|
||||
// assume a < p, so don't check for a % p = 0, but a = 0 only
|
||||
if (BN_is_zero(a)) return 0;
|
||||
BIGNUM * r = BN_CTX_get (ctx);
|
||||
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
|
||||
BIGNUM *r = BN_CTX_get(ctx);
|
||||
BN_mod_exp(r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
|
||||
if (BN_is_word(r, 1))
|
||||
return 1;
|
||||
else if (BN_is_zero(r))
|
||||
|
@ -198,17 +203,16 @@ 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);
|
||||
g_Elligator.reset(el);
|
||||
else
|
||||
delete el;
|
||||
}
|
||||
return g_Elligator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,33 +13,33 @@
|
|||
#include <memory>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
|
||||
class Elligator2
|
||||
{
|
||||
class Elligator2 {
|
||||
public:
|
||||
|
||||
Elligator2 ();
|
||||
~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;
|
||||
~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
|
||||
void SquareRoot(const BIGNUM *x, BIGNUM *r, BN_CTX *ctx) const;
|
||||
|
||||
int Legendre(const BIGNUM *a, BN_CTX *ctx) const; // a/p
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * p, * p38, * p12, * p14, * sqrtn1, * A, * nA, * u, * iu;
|
||||
BIGNUM *p, *p38, *p12, *p14, *sqrtn1, *A, *nA, *u, *iu;
|
||||
};
|
||||
|
||||
std::unique_ptr<Elligator2>& GetElligator ();
|
||||
}
|
||||
std::unique_ptr <Elligator2> &GetElligator();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "Garlic.h"
|
||||
|
||||
namespace i2p {
|
||||
namespace fs {
|
||||
namespace fs {
|
||||
std::string appName = "i2pd";
|
||||
std::string dataDir = "";
|
||||
std::string certsDir = "";
|
||||
|
@ -31,23 +31,23 @@ namespace fs {
|
|||
std::string dirSep = "/";
|
||||
#endif
|
||||
|
||||
const std::string & GetAppName () {
|
||||
const std::string &GetAppName() {
|
||||
return appName;
|
||||
}
|
||||
|
||||
void SetAppName (const std::string& name) {
|
||||
void SetAppName(const std::string &name) {
|
||||
appName = name;
|
||||
}
|
||||
|
||||
const std::string & GetDataDir () {
|
||||
const std::string &GetDataDir() {
|
||||
return dataDir;
|
||||
}
|
||||
|
||||
const std::string & GetCertsDir () {
|
||||
const std::string &GetCertsDir() {
|
||||
return certsDir;
|
||||
}
|
||||
|
||||
const std::string GetUTF8DataDir () {
|
||||
const std::string GetUTF8DataDir() {
|
||||
#ifdef _WIN32
|
||||
boost::filesystem::wpath path (dataDir);
|
||||
auto loc = boost::filesystem::path::imbue(std::locale( std::locale(), new std::codecvt_utf8_utf16<wchar_t>() ) ); // convert path to UTF-8
|
||||
|
@ -59,7 +59,7 @@ namespace fs {
|
|||
#endif
|
||||
}
|
||||
|
||||
void DetectDataDir(const std::string & cmdline_param, bool isService) {
|
||||
void DetectDataDir(const std::string &cmdline_param, bool isService) {
|
||||
// with 'datadir' option
|
||||
if (cmdline_param != "") {
|
||||
dataDir = cmdline_param;
|
||||
|
@ -157,16 +157,13 @@ namespace fs {
|
|||
#endif
|
||||
}
|
||||
|
||||
void SetCertsDir(const std::string & cmdline_certsdir) {
|
||||
if (cmdline_certsdir != "")
|
||||
{
|
||||
if (cmdline_certsdir[cmdline_certsdir.length()-1] == '/')
|
||||
certsDir = cmdline_certsdir.substr(0, cmdline_certsdir.size()-1); // strip trailing slash
|
||||
void SetCertsDir(const std::string &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;
|
||||
|
@ -184,18 +181,18 @@ namespace fs {
|
|||
if (!boost::filesystem::exists(tags))
|
||||
boost::filesystem::create_directory(tags);
|
||||
else
|
||||
i2p::garlic::CleanUpTagsFiles ();
|
||||
i2p::garlic::CleanUpTagsFiles();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadDir(const std::string & path, std::vector<std::string> & files) {
|
||||
bool ReadDir(const std::string &path, std::vector<std::string> &files) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
return false;
|
||||
boost::filesystem::directory_iterator it(path);
|
||||
boost::filesystem::directory_iterator end;
|
||||
|
||||
for ( ; it != end; it++) {
|
||||
for (; it != end; it++) {
|
||||
if (!boost::filesystem::is_regular_file(it->status()))
|
||||
continue;
|
||||
files.push_back(it->path().string());
|
||||
|
@ -204,28 +201,26 @@ namespace fs {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Exists(const std::string & path) {
|
||||
bool Exists(const std::string &path) {
|
||||
return boost::filesystem::exists(path);
|
||||
}
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path)
|
||||
{
|
||||
uint32_t GetLastUpdateTime(const std::string &path) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
return 0;
|
||||
boost::system::error_code ec;
|
||||
auto t = boost::filesystem::last_write_time (path, ec);
|
||||
auto t = boost::filesystem::last_write_time(path, ec);
|
||||
return ec ? 0 : t;
|
||||
}
|
||||
|
||||
bool Remove(const std::string & path) {
|
||||
bool Remove(const std::string &path) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
return false;
|
||||
return boost::filesystem::remove(path);
|
||||
}
|
||||
|
||||
bool CreateDirectory (const std::string& path)
|
||||
{
|
||||
if (boost::filesystem::exists(path) && boost::filesystem::is_directory (boost::filesystem::status (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);
|
||||
}
|
||||
|
@ -234,7 +229,7 @@ namespace fs {
|
|||
root = path + i2p::fs::dirSep + name;
|
||||
}
|
||||
|
||||
bool HashedStorage::Init(const char * chars, size_t count) {
|
||||
bool HashedStorage::Init(const char *chars, size_t count) {
|
||||
if (!boost::filesystem::exists(root)) {
|
||||
boost::filesystem::create_directories(root);
|
||||
}
|
||||
|
@ -250,7 +245,7 @@ namespace fs {
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string HashedStorage::Path(const std::string & ident) const {
|
||||
std::string HashedStorage::Path(const std::string &ident) const {
|
||||
std::string safe_ident = ident;
|
||||
std::replace(safe_ident.begin(), safe_ident.end(), '/', '-');
|
||||
std::replace(safe_ident.begin(), safe_ident.end(), '\\', '-');
|
||||
|
@ -263,31 +258,30 @@ namespace fs {
|
|||
return t.str();
|
||||
}
|
||||
|
||||
void HashedStorage::Remove(const std::string & ident) {
|
||||
void HashedStorage::Remove(const std::string &ident) {
|
||||
std::string path = Path(ident);
|
||||
if (!boost::filesystem::exists(path))
|
||||
return;
|
||||
boost::filesystem::remove(path);
|
||||
}
|
||||
|
||||
void HashedStorage::Traverse(std::vector<std::string> & files) {
|
||||
Iterate([&files] (const std::string & fname) {
|
||||
void HashedStorage::Traverse(std::vector<std::string> &files) {
|
||||
Iterate([&files](const std::string &fname) {
|
||||
files.push_back(fname);
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for ( ; it != end; it++) {
|
||||
if (!boost::filesystem::is_regular_file( it->status() ))
|
||||
for (; it != end; it++) {
|
||||
if (!boost::filesystem::is_regular_file(it->status()))
|
||||
continue;
|
||||
const std::string & t = it->path().string();
|
||||
const std::string &t = it->path().string();
|
||||
v(t);
|
||||
}
|
||||
}
|
||||
} // fs
|
||||
} // fs
|
||||
} // i2p
|
||||
|
|
63
libi2pd/FS.h
63
libi2pd/FS.h
|
@ -16,7 +16,7 @@
|
|||
#include <functional>
|
||||
|
||||
namespace i2p {
|
||||
namespace fs {
|
||||
namespace fs {
|
||||
extern std::string dirSep;
|
||||
|
||||
/**
|
||||
|
@ -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,35 +47,44 @@ namespace fs {
|
|||
public:
|
||||
|
||||
typedef std::function<void(const std::string &)> FilenameVisitor;
|
||||
HashedStorage(const char *n, const char *p1, const char *p2, const char *s):
|
||||
|
||||
HashedStorage(const char *n, const char *p1, const char *p2, const char *s) :
|
||||
name(n), prefix1(p1), prefix2(p2), suffix(s) {};
|
||||
|
||||
/** 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; }
|
||||
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);
|
||||
void SetPlace(const std::string &path);
|
||||
|
||||
/** path to file with given ident */
|
||||
std::string Path(const std::string & ident) const;
|
||||
std::string Path(const std::string &ident) const;
|
||||
|
||||
/** remove file by ident */
|
||||
void Remove(const std::string & 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);
|
||||
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 ();
|
||||
const std::string &GetAppName();
|
||||
|
||||
/** @brief Set application name, affects autodetection of datadir */
|
||||
void SetAppName (const std::string& name);
|
||||
void SetAppName(const std::string &name);
|
||||
|
||||
/** @brief Returns datadir path */
|
||||
const std::string & GetDataDir();
|
||||
const std::string &GetDataDir();
|
||||
|
||||
/** @brief Returns certsdir path */
|
||||
const std::string & GetCertsDir();
|
||||
const std::string &GetCertsDir();
|
||||
|
||||
/** @brief Returns datadir path in UTF-8 encoding */
|
||||
const std::string GetUTF8DataDir();
|
||||
|
@ -93,7 +101,7 @@ namespace fs {
|
|||
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/
|
||||
* Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/
|
||||
*/
|
||||
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
|
||||
void DetectDataDir(const std::string &cmdline_datadir, bool isService = false);
|
||||
|
||||
/**
|
||||
* @brief Set certsdir either from cmdline option or using autodetection
|
||||
|
@ -106,7 +114,7 @@ namespace fs {
|
|||
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/certificates
|
||||
* Unix: /var/lib/i2pd/certificates (system=1) >> ~/.i2pd/ or /tmp/i2pd/certificates
|
||||
*/
|
||||
void SetCertsDir(const std::string & cmdline_certsdir);
|
||||
void SetCertsDir(const std::string &cmdline_certsdir);
|
||||
|
||||
/**
|
||||
* @brief Create subdirectories inside datadir
|
||||
|
@ -119,33 +127,33 @@ namespace fs {
|
|||
* @param files Vector to store found files
|
||||
* @return true on success and false if directory not exists
|
||||
*/
|
||||
bool ReadDir(const std::string & path, std::vector<std::string> & files);
|
||||
bool ReadDir(const std::string &path, std::vector <std::string> &files);
|
||||
|
||||
/**
|
||||
* @brief Remove file with given path
|
||||
* @param path Absolute path to file
|
||||
* @return true on success, false if file not exists, throws exception on error
|
||||
*/
|
||||
bool Remove(const std::string & path);
|
||||
bool Remove(const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Check existence of file
|
||||
* @param path Absolute path to file
|
||||
* @return true if file exists, false otherwise
|
||||
*/
|
||||
bool Exists(const std::string & path);
|
||||
bool Exists(const std::string &path);
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
|
||||
uint32_t GetLastUpdateTime(const std::string &path); // seconds since epoch
|
||||
|
||||
bool CreateDirectory (const std::string& path);
|
||||
bool CreateDirectory(const std::string &path);
|
||||
|
||||
template<typename T>
|
||||
void _ExpandPath(std::stringstream & path, T c) {
|
||||
void _ExpandPath(std::stringstream &path, T c) {
|
||||
path << i2p::fs::dirSep << c;
|
||||
}
|
||||
|
||||
template<typename T, typename ... Other>
|
||||
void _ExpandPath(std::stringstream & path, T c, Other ... other) {
|
||||
void _ExpandPath(std::stringstream &path, T c, Other ... other) {
|
||||
_ExpandPath(path, c);
|
||||
_ExpandPath(path, other ...);
|
||||
}
|
||||
|
@ -168,16 +176,15 @@ 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 ();
|
||||
s << storage.GetRoot();
|
||||
_ExpandPath(s, filenames...);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
} // fs
|
||||
} // fs
|
||||
} // i2p
|
||||
|
||||
#endif // /* FS_H__ */
|
||||
|
|
|
@ -15,90 +15,75 @@
|
|||
#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)
|
||||
{
|
||||
SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
|
||||
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
|
||||
if (ret)
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
X509 * cert = SSL_get_certificate (ssl);
|
||||
if (cert)
|
||||
{
|
||||
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) {
|
||||
SSL *ssl = SSL_new(ctx);
|
||||
X509 *cert = SSL_get_certificate(ssl);
|
||||
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)
|
||||
{
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
|
||||
char *cn = strstr(name, "CN=");
|
||||
if (cn) {
|
||||
cn += 3;
|
||||
char * family = strstr (cn, ".family");
|
||||
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)
|
||||
{
|
||||
auto pkey = X509_get_pubkey(cert);
|
||||
int keyType = EVP_PKEY_base_id(pkey);
|
||||
switch (keyType) {
|
||||
case EVP_PKEY_DSA:
|
||||
// TODO:
|
||||
break;
|
||||
case EVP_PKEY_EC:
|
||||
{
|
||||
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
|
||||
if (ecKey)
|
||||
{
|
||||
auto group = EC_KEY_get0_group (ecKey);
|
||||
if (group)
|
||||
{
|
||||
int curve = EC_GROUP_get_curve_name (group);
|
||||
if (curve == NID_X9_62_prime256v1)
|
||||
{
|
||||
case EVP_PKEY_EC: {
|
||||
EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(pkey);
|
||||
if (ecKey) {
|
||||
auto group = EC_KEY_get0_group(ecKey);
|
||||
if (group) {
|
||||
int curve = EC_GROUP_get_curve_name(group);
|
||||
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);
|
||||
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);
|
||||
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>();
|
||||
verifier->SetPublicKey (signingKey);
|
||||
verifier->SetPublicKey(signingKey);
|
||||
} else
|
||||
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
EC_KEY_free (ecKey);
|
||||
EC_KEY_free(ecKey);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Family: Certificate key type ", keyType, " is not supported");
|
||||
LogPrint(eLogWarning, "Family: Certificate key type ", keyType, " is not supported");
|
||||
}
|
||||
EVP_PKEY_free (pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
if (verifier && cn)
|
||||
m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
|
||||
m_SigningKeys.emplace(cn, std::make_pair(verifier, m_SigningKeys.size() + 1));
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Family: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_free(ssl);
|
||||
} 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;
|
||||
|
@ -109,91 +94,81 @@ namespace data
|
|||
return;
|
||||
}
|
||||
|
||||
for (const std::string & file : files) {
|
||||
for (const std::string &file: files) {
|
||||
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
|
||||
LogPrint(eLogWarning, "Family: ignoring file ", file);
|
||||
continue;
|
||||
}
|
||||
LoadCertificate (file);
|
||||
LoadCertificate(file);
|
||||
numCertificates++;
|
||||
}
|
||||
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
|
||||
LogPrint(eLogInfo, "Family: ", numCertificates, " certificates loaded");
|
||||
}
|
||||
|
||||
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
|
||||
const char * signature, const char * key) const
|
||||
{
|
||||
bool Families::VerifyFamily(const std::string &family, const IdentHash &ident,
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogError, "Family: ", family, " is too long");
|
||||
size_t len = family.length(), signatureLen = strlen(signature);
|
||||
if (len + 32 > 100) {
|
||||
LogPrint(eLogError, "Family: ", family, " is too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy (buf, family.c_str (), len);
|
||||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
memcpy(buf, family.c_str(), len);
|
||||
memcpy(buf + len, (const uint8_t *) ident, 32);
|
||||
len += 32;
|
||||
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
return it->second.first->Verify (buf, len, signatureBuf);
|
||||
Base64ToByteStream(signature, signatureLen, signatureBuf, 64);
|
||||
auto it = m_SigningKeys.find(family);
|
||||
if (it != m_SigningKeys.end())
|
||||
return it->second.first->Verify(buf, len, signatureBuf);
|
||||
// TODO: process key
|
||||
return true;
|
||||
}
|
||||
|
||||
FamilyID Families::GetFamilyID (const std::string& family) const
|
||||
{
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
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)
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
EVP_PKEY * pkey = SSL_get_privatekey (ssl);
|
||||
EC_KEY * ecKey = EVP_PKEY_get1_EC_KEY (pkey);
|
||||
if (ecKey)
|
||||
{
|
||||
auto group = EC_KEY_get0_group (ecKey);
|
||||
if (group)
|
||||
{
|
||||
int curve = EC_GROUP_get_curve_name (group);
|
||||
if (curve == NID_X9_62_prime256v1)
|
||||
{
|
||||
SSL_CTX *ctx = SSL_CTX_new(TLS_method());
|
||||
int ret = SSL_CTX_use_PrivateKey_file(ctx, filename.c_str(), SSL_FILETYPE_PEM);
|
||||
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) {
|
||||
auto group = EC_KEY_get0_group(ecKey);
|
||||
if (group) {
|
||||
int curve = EC_GROUP_get_curve_name(group);
|
||||
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);
|
||||
size_t len = family.length ();
|
||||
memcpy (buf, family.c_str (), len);
|
||||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
i2p::crypto::bn2buf(EC_KEY_get0_private_key(ecKey), signingPrivateKey, 32);
|
||||
i2p::crypto::ECDSAP256Signer signer(signingPrivateKey);
|
||||
size_t len = family.length();
|
||||
memcpy(buf, family.c_str(), len);
|
||||
memcpy(buf + len, (const uint8_t *) ident, 32);
|
||||
len += 32;
|
||||
signer.Sign (buf, len, signature);
|
||||
len = Base64EncodingBufferSize (64);
|
||||
char * b64 = new char[len+1];
|
||||
len = ByteStreamToBase64 (signature, 64, b64, len);
|
||||
signer.Sign(buf, len, signature);
|
||||
len = Base64EncodingBufferSize(64);
|
||||
char *b64 = new char[len + 1];
|
||||
len = ByteStreamToBase64(signature, 64, b64, len);
|
||||
b64[len] = 0;
|
||||
sig = b64;
|
||||
delete[] b64;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
} else
|
||||
LogPrint(eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Family: Can't open keys file: ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_free(ssl);
|
||||
} else
|
||||
LogPrint(eLogError, "Family: Can't open keys file: ", filename);
|
||||
SSL_CTX_free(ctx);
|
||||
return sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,34 +15,36 @@
|
|||
#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;
|
||||
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:
|
||||
|
||||
void LoadCertificate (const std::string& filename);
|
||||
void LoadCertificate(const std::string &filename);
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, std::pair<std::shared_ptr<i2p::crypto::Verifier>, FamilyID> > m_SigningKeys; // family -> (verifier, id)
|
||||
};
|
||||
|
||||
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
|
||||
std::string CreateFamilySignature(const std::string &family, const IdentHash &ident);
|
||||
// return base64 signature of empty string in case of failure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1127
libi2pd/Garlic.cpp
1127
libi2pd/Garlic.cpp
File diff suppressed because it is too large
Load diff
309
libi2pd/Garlic.h
309
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,37 +49,41 @@ 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>
|
||||
{
|
||||
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;
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
SetKey (key);
|
||||
AESDecryption(const uint8_t *key) : m_Key(key) {
|
||||
SetKey(key);
|
||||
}
|
||||
const i2p::crypto::AESKey& GetKey () const { return m_Key; };
|
||||
|
||||
const i2p::crypto::AESKey &GetKey() const { return m_Key; };
|
||||
|
||||
private:
|
||||
|
||||
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,
|
||||
|
@ -107,45 +105,62 @@ 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
|
||||
GarlicRoutingSession(GarlicDestination *owner, bool attachLeaseSet);
|
||||
|
||||
void SetLeaseSetUpdated ()
|
||||
{
|
||||
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() {
|
||||
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);
|
||||
bool IsLeaseSetNonConfirmed() const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
||||
|
||||
GarlicDestination * GetOwner () const { return m_Owner; }
|
||||
void SetOwner (GarlicDestination * owner) { m_Owner = owner; }
|
||||
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; }
|
||||
LeaseSetUpdateStatus GetLeaseSetUpdateStatus() const { return m_LeaseSetUpdateStatus; }
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEncryptedDeliveryStatusMsg (uint32_t msgID);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
GarlicDestination * m_Owner;
|
||||
GarlicDestination *m_Owner;
|
||||
|
||||
LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
|
||||
uint32_t m_LeaseSetUpdateMsgID;
|
||||
|
@ -156,45 +171,53 @@ namespace garlic
|
|||
public:
|
||||
|
||||
// for HTTP only
|
||||
virtual size_t GetNumOutgoingTags () const { return 0; };
|
||||
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
|
||||
{
|
||||
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
||||
~UnconfirmedTags () { delete[] sessionTags; };
|
||||
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;
|
||||
SessionTag * sessionTags;
|
||||
SessionTag *sessionTags;
|
||||
uint32_t tagsCreationTime;
|
||||
};
|
||||
|
||||
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);
|
||||
ElGamalAESSession(const uint8_t *sessionKey, const SessionTag &sessionTag); // one time encryption
|
||||
~ElGamalAESSession() {};
|
||||
|
||||
bool MessageConfirmed (uint32_t msgID);
|
||||
bool CleanupExpiredTags (); // returns true if something left
|
||||
bool CleanupUnconfirmedTags (); // returns true if something has been deleted
|
||||
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 CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination);
|
||||
size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID);
|
||||
size_t CreateAESBlock(uint8_t *buf, std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
void TagsConfirmed (uint32_t msgID);
|
||||
UnconfirmedTags * GenerateSessionTags ();
|
||||
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:
|
||||
|
||||
|
@ -210,73 +233,97 @@ namespace garlic
|
|||
public:
|
||||
|
||||
// for HTTP only
|
||||
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
|
||||
size_t GetNumOutgoingTags() const { return m_SessionTags.size(); };
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ElGamalAESSession> ElGamalAESSessionPtr;
|
||||
|
||||
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 ();
|
||||
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);
|
||||
void CleanupExpiredTags ();
|
||||
void RemoveDeliveryStatusSession (uint32_t msgID);
|
||||
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
~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);
|
||||
|
||||
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);
|
||||
|
||||
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
|
||||
void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
|
||||
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 ();
|
||||
void AddSessionKey(const uint8_t *key, const uint8_t *tag); // one tag
|
||||
void AddECIESx25519Key(const uint8_t *key, uint64_t tag); // one tag
|
||||
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);
|
||||
|
||||
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
virtual void SetLeaseSetUpdated ();
|
||||
uint64_t AddECIESx25519SessionNextTag(ReceiveRatchetTagSetPtr tagset);
|
||||
|
||||
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
|
||||
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
|
||||
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
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;
|
||||
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleDeliveryStatusMessage (uint32_t msgID);
|
||||
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;
|
||||
|
||||
void SaveTags ();
|
||||
void LoadTags ();
|
||||
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,
|
||||
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);
|
||||
|
||||
void HandleGarlicPayload(uint8_t *buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -285,7 +332,7 @@ namespace garlic
|
|||
std::mutex m_SessionsMutex;
|
||||
std::unordered_map<i2p::data::IdentHash, ElGamalAESSessionPtr> m_Sessions;
|
||||
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
|
||||
uint8_t * m_PayloadBuffer; // for ECIESX25519AEADRatchet
|
||||
uint8_t *m_PayloadBuffer; // for ECIESX25519AEADRatchet
|
||||
// incoming
|
||||
int m_NumRatchetInboundTags;
|
||||
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
|
||||
|
@ -298,15 +345,23 @@ namespace garlic
|
|||
public:
|
||||
|
||||
// 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; }
|
||||
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; }
|
||||
};
|
||||
|
||||
void CleanUpTagsFiles ();
|
||||
void CleanUpTagsFiles();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
400
libi2pd/Gost.cpp
400
libi2pd/Gost.cpp
|
@ -14,133 +14,122 @@
|
|||
#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)
|
||||
{
|
||||
m_KeyLen = BN_num_bytes (p);
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
m_Group = EC_GROUP_new_curve_GFp (p, a, b, ctx);
|
||||
EC_POINT * P = EC_POINT_new (m_Group);
|
||||
EC_POINT_set_affine_coordinates_GFp (m_Group, P, x, y, ctx);
|
||||
EC_GROUP_set_generator (m_Group, P, q, nullptr);
|
||||
EC_GROUP_set_curve_name (m_Group, NID_id_GostR3410_2001);
|
||||
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);
|
||||
EC_POINT *P = EC_POINT_new(m_Group);
|
||||
EC_POINT_set_affine_coordinates_GFp(m_Group, P, x, y, ctx);
|
||||
EC_GROUP_set_generator(m_Group, P, q, nullptr);
|
||||
EC_GROUP_set_curve_name(m_Group, NID_id_GostR3410_2001);
|
||||
EC_POINT_free(P);
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
GOSTR3410Curve::~GOSTR3410Curve ()
|
||||
{
|
||||
EC_GROUP_free (m_Group);
|
||||
GOSTR3410Curve::~GOSTR3410Curve() {
|
||||
EC_GROUP_free(m_Group);
|
||||
}
|
||||
|
||||
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);
|
||||
BN_CTX_free (ctx);
|
||||
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);
|
||||
BN_CTX_free(ctx);
|
||||
return p;
|
||||
}
|
||||
|
||||
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);
|
||||
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 * p = EC_POINT_new (m_Group);
|
||||
EC_POINT_set_affine_coordinates_GFp (m_Group, p, x, y, nullptr);
|
||||
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)
|
||||
{
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * q = BN_CTX_get (ctx);
|
||||
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);
|
||||
EC_GROUP_get_order(m_Group, q, ctx);
|
||||
BIGNUM * k = BN_CTX_get (ctx);
|
||||
BN_rand_range (k, q); // 0 < k < q
|
||||
EC_POINT * C = MulP (k); // C = k*P
|
||||
GetXY (C, r, nullptr); // r = Cx
|
||||
EC_POINT_free (C);
|
||||
BN_mod_mul (s, r, priv, q, ctx); // (r*priv)%q
|
||||
BIGNUM * tmp = BN_CTX_get (ctx);
|
||||
BN_mod_mul (tmp, k, digest, q, ctx); // (k*digest)%q
|
||||
BN_mod_add (s, s, tmp, q, ctx); // (r*priv+k*digest)%q
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
BIGNUM *k = BN_CTX_get(ctx);
|
||||
BN_rand_range(k, q); // 0 < k < q
|
||||
EC_POINT *C = MulP(k); // C = k*P
|
||||
GetXY(C, r, nullptr); // r = Cx
|
||||
EC_POINT_free(C);
|
||||
BN_mod_mul(s, r, priv, q, ctx); // (r*priv)%q
|
||||
BIGNUM *tmp = BN_CTX_get(ctx);
|
||||
BN_mod_mul(tmp, k, digest, q, ctx); // (k*digest)%q
|
||||
BN_mod_add(s, s, tmp, q, ctx); // (r*priv+k*digest)%q
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
EC_GROUP_get_order(m_Group, q, ctx);
|
||||
BIGNUM * h = BN_CTX_get (ctx);
|
||||
BN_mod (h, digest, q, ctx); // h = digest % q
|
||||
BN_mod_inverse (h, h, q, ctx); // 1/h mod q
|
||||
BIGNUM * z1 = BN_CTX_get (ctx);
|
||||
BN_mod_mul (z1, s, h, q, ctx); // z1 = s/h
|
||||
BIGNUM * z2 = BN_CTX_get (ctx);
|
||||
BN_sub (z2, q, r); // z2 = -r
|
||||
BN_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h
|
||||
EC_POINT * C = EC_POINT_new (m_Group);
|
||||
EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
|
||||
BIGNUM * x = BN_CTX_get (ctx);
|
||||
GetXY (C, x, nullptr); // Cx
|
||||
BN_mod (x, x, q, ctx); // Cx % q
|
||||
bool ret = !BN_cmp (x, r); // Cx = r ?
|
||||
EC_POINT_free (C);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
BIGNUM *h = BN_CTX_get(ctx);
|
||||
BN_mod(h, digest, q, ctx); // h = digest % q
|
||||
BN_mod_inverse(h, h, q, ctx); // 1/h mod q
|
||||
BIGNUM *z1 = BN_CTX_get(ctx);
|
||||
BN_mod_mul(z1, s, h, q, ctx); // z1 = s/h
|
||||
BIGNUM *z2 = BN_CTX_get(ctx);
|
||||
BN_sub(z2, q, r); // z2 = -r
|
||||
BN_mod_mul(z2, z2, h, q, ctx); // z2 = -r/h
|
||||
EC_POINT *C = EC_POINT_new(m_Group);
|
||||
EC_POINT_mul(m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
|
||||
BIGNUM *x = BN_CTX_get(ctx);
|
||||
GetXY(C, x, nullptr); // Cx
|
||||
BN_mod(x, x, q, ctx); // Cx % q
|
||||
bool ret = !BN_cmp(x, r); // Cx = r ?
|
||||
EC_POINT_free(C);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
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))
|
||||
{
|
||||
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);
|
||||
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)) {
|
||||
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);
|
||||
EC_GROUP_get_order(m_Group, q, ctx);
|
||||
BIGNUM * h = BN_CTX_get (ctx);
|
||||
BN_mod (h, digest, q, ctx); // h = digest % q
|
||||
BN_sub (h, q, h); // h = -h
|
||||
EC_POINT * H = EC_POINT_new (m_Group);
|
||||
EC_POINT_mul (m_Group, H, nullptr, C, h, ctx); // -h*C
|
||||
EC_POINT_add (m_Group, C, S, H, ctx); // s*P - h*C
|
||||
EC_POINT_free (H);
|
||||
EC_POINT_free (S);
|
||||
BIGNUM * r1 = BN_CTX_get (ctx);
|
||||
BN_mod_inverse (r1, r, q, ctx);
|
||||
Q = EC_POINT_new (m_Group);
|
||||
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
|
||||
BIGNUM *h = BN_CTX_get(ctx);
|
||||
BN_mod(h, digest, q, ctx); // h = digest % q
|
||||
BN_sub(h, q, h); // h = -h
|
||||
EC_POINT *H = EC_POINT_new(m_Group);
|
||||
EC_POINT_mul(m_Group, H, nullptr, C, h, ctx); // -h*C
|
||||
EC_POINT_add(m_Group, C, S, H, ctx); // s*P - h*C
|
||||
EC_POINT_free(H);
|
||||
EC_POINT_free(S);
|
||||
BIGNUM *r1 = BN_CTX_get(ctx);
|
||||
BN_mod_inverse(r1, r, q, ctx);
|
||||
Q = EC_POINT_new(m_Group);
|
||||
EC_POINT_mul(m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
|
||||
}
|
||||
EC_POINT_free (C);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
EC_POINT_free(C);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
return Q;
|
||||
}
|
||||
|
||||
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
static GOSTR3410Curve *CreateGOSTR3410Curve(GOSTR3410ParamSet paramSet) {
|
||||
// a, b, p, q, x, y
|
||||
static const char * params[eGOSTR3410NumParamSets][6] =
|
||||
static const char *params[eGOSTR3410NumParamSets][6] =
|
||||
{
|
||||
{
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
|
||||
|
@ -160,26 +149,30 @@ namespace crypto
|
|||
} // tc26-2012-paramSetA-512
|
||||
};
|
||||
|
||||
BIGNUM * a = nullptr, * b = nullptr, * p = nullptr, * q =nullptr, * x = nullptr, * y = nullptr;
|
||||
BIGNUM *a = nullptr, *b = nullptr, *p = nullptr, *q = nullptr, *x = nullptr, *y = nullptr;
|
||||
BN_hex2bn(&a, params[paramSet][0]);
|
||||
BN_hex2bn(&b, params[paramSet][1]);
|
||||
BN_hex2bn(&p, params[paramSet][2]);
|
||||
BN_hex2bn(&q, params[paramSet][3]);
|
||||
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);
|
||||
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);
|
||||
return curve;
|
||||
}
|
||||
|
||||
static std::array<std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
|
||||
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
if (!g_GOSTR3410Curves[paramSet])
|
||||
{
|
||||
auto c = CreateGOSTR3410Curve (paramSet);
|
||||
static std::array <std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
|
||||
|
||||
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);
|
||||
g_GOSTR3410Curves[paramSet].reset(c);
|
||||
else
|
||||
delete 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];
|
||||
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];
|
||||
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,189 +810,174 @@ 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]];
|
||||
r ^= T2[buf[b+40]];
|
||||
r ^= T3[buf[b+32]];
|
||||
r ^= T4[buf[b+24]];
|
||||
r ^= T5[buf[b+16]];
|
||||
r ^= T6[buf[b+8]];
|
||||
r = T0[buf[b + 56]];
|
||||
r ^= T1[buf[b + 48]];
|
||||
r ^= T2[buf[b + 40]];
|
||||
r ^= T3[buf[b + 32]];
|
||||
r ^= T4[buf[b + 24]];
|
||||
r ^= T5[buf[b + 16]];
|
||||
r ^= T6[buf[b + 8]];
|
||||
r ^= T7[buf[b]];
|
||||
res[b] = r;
|
||||
}
|
||||
memcpy (buf, res, 64);
|
||||
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++)
|
||||
{
|
||||
res.F ();
|
||||
k = k^C_[i];
|
||||
k.F ();
|
||||
res = k^res;
|
||||
GOST3411Block res = k ^ m;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
res.F();
|
||||
k = k ^ C_[i];
|
||||
k.F();
|
||||
res = k ^ res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
res = res^h;
|
||||
res = res^m;
|
||||
res.F();
|
||||
res = res.E(m);
|
||||
res = res ^ h;
|
||||
res = res ^ m;
|
||||
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);
|
||||
memset (N.buf, 0, 64);
|
||||
memset (s.buf, 0, 64);
|
||||
memcpy(h.buf, iv, 64);
|
||||
memset(N.buf, 0, 64);
|
||||
memset(s.buf, 0, 64);
|
||||
size_t l = len;
|
||||
// stage 2
|
||||
while (l >= 64)
|
||||
{
|
||||
memcpy (m.buf, buf + l - 64, 64); // TODO
|
||||
h= gN (N, h, m);
|
||||
N.Add (512);
|
||||
while (l >= 64) {
|
||||
memcpy(m.buf, buf + l - 64, 64); // TODO
|
||||
h = gN(N, h, m);
|
||||
N.Add(512);
|
||||
s = m + s;
|
||||
l -= 64;
|
||||
}
|
||||
// stage 3
|
||||
size_t padding = 64 - l;
|
||||
if (padding)
|
||||
{
|
||||
memset (m.buf, 0, padding - 1);
|
||||
if (padding) {
|
||||
memset(m.buf, 0, padding - 1);
|
||||
m.buf[padding - 1] = 1;
|
||||
}
|
||||
memcpy (m.buf + padding, buf, l);
|
||||
memcpy(m.buf + padding, buf, l);
|
||||
|
||||
h = gN (N, h, m);
|
||||
N.Add (l*8);
|
||||
h = gN(N, h, m);
|
||||
N.Add(l * 8);
|
||||
s = m + s;
|
||||
|
||||
GOST3411Block N0;
|
||||
memset (N0.buf, 0, 64);
|
||||
h = gN (N0, h, N);
|
||||
h = gN (N0, h, s);
|
||||
memset(N0.buf, 0, 64);
|
||||
h = gN(N0, h, N);
|
||||
h = gN(N0, h, s);
|
||||
|
||||
memcpy (digest, h.buf, 64);
|
||||
memcpy(digest, h.buf, 64);
|
||||
}
|
||||
|
||||
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
void GOSTR3411_2012_256(const uint8_t *buf, size_t len, uint8_t *digest) {
|
||||
uint8_t iv[64];
|
||||
memset (iv, 1, 64);
|
||||
memset(iv, 1, 64);
|
||||
uint8_t h[64];
|
||||
H (iv, buf, len, h);
|
||||
memcpy (digest, h, 32); // first half
|
||||
H(iv, buf, len, h);
|
||||
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);
|
||||
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);
|
||||
memset (ctx->N.buf, 0, 64);
|
||||
memset (ctx->s.buf, 0, 64);
|
||||
memset(iv, is512 ? 0 : 1, 64);
|
||||
memcpy(ctx->h.buf, iv, 64);
|
||||
memset(ctx->N.buf, 0, 64);
|
||||
memset(ctx->s.buf, 0, 64);
|
||||
ctx->len = 0;
|
||||
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
|
||||
{
|
||||
size_t l = 64 - ctx->len;
|
||||
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->m.buf[ctx->len + i] = buf[l - i - 1]; // invert
|
||||
ctx->len += l;
|
||||
len -= l;
|
||||
buf += l;
|
||||
|
||||
ctx->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add (512);
|
||||
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;
|
||||
ctx->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add (512);
|
||||
ctx->m.buf[i] = buf[63 - i]; // invert
|
||||
len -= 64;
|
||||
buf += 64;
|
||||
ctx->h = gN(ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add(512);
|
||||
ctx->s = ctx->m + ctx->s;
|
||||
}
|
||||
if (len > 0) // carry remaining
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
ctx->m.buf[i] = buf[len-i-1]; // invert
|
||||
ctx->m.buf[i] = buf[len - i - 1]; // invert
|
||||
}
|
||||
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)
|
||||
{
|
||||
memset (m.buf, 0, padding - 1);
|
||||
if (padding) {
|
||||
memset(m.buf, 0, padding - 1);
|
||||
m.buf[padding - 1] = 1;
|
||||
}
|
||||
memcpy (m.buf + padding, ctx->m.buf, ctx->len);
|
||||
memcpy(m.buf + padding, ctx->m.buf, ctx->len);
|
||||
|
||||
ctx->h = gN (ctx->N, ctx->h, m);
|
||||
ctx->N.Add (ctx->len*8);
|
||||
ctx->h = gN(ctx->N, ctx->h, m);
|
||||
ctx->N.Add(ctx->len * 8);
|
||||
ctx->s = m + ctx->s;
|
||||
|
||||
GOST3411Block N0;
|
||||
memset (N0.buf, 0, 64);
|
||||
ctx->h = gN (N0, ctx->h, ctx->N);
|
||||
ctx->h = gN (N0, ctx->h, ctx->s);
|
||||
memset(N0.buf, 0, 64);
|
||||
ctx->h = gN(N0, ctx->h, ctx->N);
|
||||
ctx->h = gN(N0, ctx->h, ctx->s);
|
||||
|
||||
size_t sz = ctx->is512 ? 64 : 32;
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
digest[i] = ctx->h.buf[sz - i - 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,42 +26,56 @@ namespace crypto
|
|||
eGOSTR3410NumParamSets
|
||||
};
|
||||
|
||||
class GOSTR3410Curve
|
||||
{
|
||||
class GOSTR3410Curve {
|
||||
public:
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
~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;
|
||||
|
||||
private:
|
||||
|
||||
EC_GROUP * m_Group;
|
||||
EC_GROUP *m_Group;
|
||||
size_t m_KeyLen; // in bytes
|
||||
};
|
||||
|
||||
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet);
|
||||
std::unique_ptr <GOSTR3410Curve> &GetGOSTR3410Curve(GOSTR3410ParamSet paramSet);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
165
libi2pd/Gzip.cpp
165
libi2pd/Gzip.cpp
|
@ -13,143 +13,122 @@
|
|||
#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)
|
||||
{
|
||||
memset (&m_Inflator, 0, sizeof (m_Inflator));
|
||||
inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip
|
||||
GzipInflator::GzipInflator() : m_IsDirty(false) {
|
||||
memset(&m_Inflator, 0, sizeof(m_Inflator));
|
||||
inflateInit2(&m_Inflator, MAX_WBITS + 16); // gzip
|
||||
}
|
||||
|
||||
GzipInflator::~GzipInflator ()
|
||||
{
|
||||
inflateEnd (&m_Inflator);
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogError, "Gzip: Incorrect length");
|
||||
size_t len = bufle16toh(in + 11);
|
||||
if (len + 23 < inLen) {
|
||||
LogPrint(eLogError, "Gzip: Incorrect length");
|
||||
return 0;
|
||||
}
|
||||
if (len > outLen) len = outLen;
|
||||
memcpy (out, in + 15, len);
|
||||
memcpy(out, in + 15, len);
|
||||
return len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsDirty) inflateReset (&m_Inflator);
|
||||
} else {
|
||||
if (m_IsDirty) inflateReset(&m_Inflator);
|
||||
m_IsDirty = true;
|
||||
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||
m_Inflator.avail_in = inLen;
|
||||
m_Inflator.next_out = out;
|
||||
m_Inflator.avail_out = outLen;
|
||||
int err;
|
||||
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
|
||||
if ((err = inflate(&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
|
||||
return outLen - m_Inflator.avail_out;
|
||||
// else
|
||||
LogPrint (eLogError, "Gzip: Inflate error ", err);
|
||||
LogPrint(eLogError, "Gzip: Inflate error ", err);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os)
|
||||
{
|
||||
void GzipInflator::Inflate(const uint8_t *in, size_t inLen, std::ostream &os) {
|
||||
m_IsDirty = true;
|
||||
uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
uint8_t *out = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||
m_Inflator.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)
|
||||
{
|
||||
inflateEnd (&m_Inflator);
|
||||
ret = inflate(&m_Inflator, Z_NO_FLUSH);
|
||||
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
|
||||
os.write((char *) out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
|
||||
} while (!m_Inflator.avail_out); // more data to read
|
||||
delete[] out;
|
||||
}
|
||||
|
||||
void GzipInflator::Inflate (std::istream& in, std::ostream& out)
|
||||
{
|
||||
uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
while (!in.eof ())
|
||||
{
|
||||
in.read ((char *) buf, GZIP_CHUNK_SIZE);
|
||||
Inflate (buf, in.gcount (), out);
|
||||
void GzipInflator::Inflate(std::istream &in, std::ostream &out) {
|
||||
uint8_t *buf = new uint8_t[GZIP_CHUNK_SIZE];
|
||||
while (!in.eof()) {
|
||||
in.read((char *) buf, GZIP_CHUNK_SIZE);
|
||||
Inflate(buf, in.gcount(), out);
|
||||
}
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
}
|
||||
|
||||
GzipDeflator::~GzipDeflator ()
|
||||
{
|
||||
deflateEnd (&m_Deflator);
|
||||
GzipDeflator::~GzipDeflator() {
|
||||
deflateEnd(&m_Deflator);
|
||||
}
|
||||
|
||||
void GzipDeflator::SetCompressionLevel (int level)
|
||||
{
|
||||
deflateParams (&m_Deflator, level, Z_DEFAULT_STRATEGY);
|
||||
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)
|
||||
{
|
||||
if (m_IsDirty) deflateReset (&m_Deflator);
|
||||
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);
|
||||
m_Deflator.avail_in = inLen;
|
||||
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;
|
||||
}
|
||||
// else
|
||||
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
||||
LogPrint(eLogError, "Gzip: Deflate error ", err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
auto flush = (it == bufs.back()) ? Z_FINISH : Z_NO_FLUSH;
|
||||
err = deflate(&m_Deflator, flush);
|
||||
if (err) {
|
||||
if (flush && err == Z_STREAM_END) {
|
||||
out[9] = 0xff; // OS is always unknown
|
||||
return outLen - m_Deflator.avail_out;
|
||||
}
|
||||
|
@ -158,44 +137,42 @@ namespace data
|
|||
offset = outLen - m_Deflator.avail_out;
|
||||
}
|
||||
// else
|
||||
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
||||
LogPrint(eLogError, "Gzip: Deflate error ", err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
htole16buf (out + 11, inLen);
|
||||
htole16buf (out + 13, 0xffff - inLen);
|
||||
memcpy (out + 15, in, inLen);
|
||||
htole32buf (out + inLen + 15, crc32 (0, in, inLen));
|
||||
htole32buf (out + inLen + 19, inLen);
|
||||
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);
|
||||
htole16buf(out + 11, inLen);
|
||||
htole16buf(out + 13, 0xffff - inLen);
|
||||
memcpy(out + 15, in, inLen);
|
||||
htole32buf(out + inLen + 15, crc32(0, in, inLen));
|
||||
htole32buf(out + inLen + 19, inLen);
|
||||
return inLen + 23;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
memcpy (out + 15 + len1, it.first, it.second);
|
||||
crc = crc32 (crc, it.first, it.second);
|
||||
memcpy(out + 15 + len1, it.first, it.second);
|
||||
crc = crc32(crc, it.first, it.second);
|
||||
}
|
||||
if (len > 0xffff) return 0;
|
||||
htole32buf (out + len + 15, crc);
|
||||
htole32buf (out + len + 19, len);
|
||||
htole16buf (out + 11, len);
|
||||
htole16buf (out + 13, 0xffff - len);
|
||||
htole32buf(out + len + 15, crc);
|
||||
htole32buf(out + len + 19, len);
|
||||
htole16buf(out + 11, len);
|
||||
htole16buf(out + 13, 0xffff - len);
|
||||
return len + 23;
|
||||
}
|
||||
|
||||
} // data
|
||||
} // data
|
||||
} // i2p
|
||||
|
|
|
@ -12,21 +12,21 @@
|
|||
#include <zlib.h>
|
||||
#include <vector>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
class GzipInflator
|
||||
{
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
class GzipInflator {
|
||||
public:
|
||||
|
||||
GzipInflator ();
|
||||
~GzipInflator ();
|
||||
GzipInflator();
|
||||
|
||||
~GzipInflator();
|
||||
|
||||
size_t Inflate(const uint8_t *in, size_t inLen, uint8_t *out, size_t outLen);
|
||||
|
||||
size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
|
||||
/** @note @a os failbit will be set in case of error */
|
||||
void Inflate (const uint8_t * in, size_t inLen, std::ostream& os);
|
||||
void Inflate (std::istream& in, std::ostream& out);
|
||||
void Inflate(const uint8_t *in, size_t inLen, std::ostream &os);
|
||||
|
||||
void Inflate(std::istream &in, std::ostream &out);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -34,16 +34,18 @@ namespace data
|
|||
bool m_IsDirty;
|
||||
};
|
||||
|
||||
class GzipDeflator
|
||||
{
|
||||
class GzipDeflator {
|
||||
public:
|
||||
|
||||
GzipDeflator ();
|
||||
~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);
|
||||
~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:
|
||||
|
||||
|
@ -51,9 +53,10 @@ namespace data
|
|||
bool m_IsDirty;
|
||||
};
|
||||
|
||||
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
|
||||
} // 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
|
||||
} // data
|
||||
} // i2p
|
||||
|
||||
#endif /* GZIP_H__ */
|
||||
|
|
233
libi2pd/HTTP.cpp
233
libi2pd/HTTP.cpp
|
@ -14,15 +14,14 @@
|
|||
#include "Base.h"
|
||||
#include "HTTP.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
{
|
||||
const std::vector<std::string> HTTP_METHODS = {
|
||||
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 = {
|
||||
const std::vector <std::string> HTTP_VERSIONS = {
|
||||
"HTTP/1.0", "HTTP/1.1"
|
||||
};
|
||||
const std::vector<const char *> weekdays = {
|
||||
|
@ -33,15 +32,15 @@ namespace http
|
|||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
inline bool is_http_version(const std::string & str) {
|
||||
inline bool is_http_version(const std::string &str) {
|
||||
return std::find(HTTP_VERSIONS.begin(), HTTP_VERSIONS.end(), str) != std::end(HTTP_VERSIONS);
|
||||
}
|
||||
|
||||
inline bool is_http_method(const std::string & str) {
|
||||
inline bool is_http_method(const std::string &str) {
|
||||
return std::find(HTTP_METHODS.begin(), HTTP_METHODS.end(), str) != std::end(HTTP_METHODS);
|
||||
}
|
||||
|
||||
void strsplit(const std::string & line, std::vector<std::string> &tokens, char delim, std::size_t limit = 0) {
|
||||
void strsplit(const std::string &line, std::vector <std::string> &tokens, char delim, std::size_t limit = 0) {
|
||||
std::size_t count = 0;
|
||||
std::stringstream ss(line);
|
||||
std::string token;
|
||||
|
@ -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();
|
||||
|
@ -72,7 +70,7 @@ namespace http
|
|||
return std::make_pair(line.substr(0, pos), line.substr(pos + len));
|
||||
}
|
||||
|
||||
void gen_rfc7231_date(std::string & out) {
|
||||
void gen_rfc7231_date(std::string &out) {
|
||||
std::time_t now = std::time(nullptr);
|
||||
char buf[128];
|
||||
std::tm *tm = std::gmtime(&now);
|
||||
|
@ -88,10 +86,10 @@ namespace http
|
|||
return parse(url);
|
||||
}
|
||||
|
||||
bool URL::parse(const std::string& url) {
|
||||
bool URL::parse(const std::string &url) {
|
||||
std::size_t pos_p = 0; /* < current parse position */
|
||||
std::size_t pos_c = 0; /* < work position */
|
||||
if(url.at(0) != '/' || pos_p > 0) {
|
||||
if (url.at(0) != '/' || pos_p > 0) {
|
||||
std::size_t pos_s = 0;
|
||||
/* schema */
|
||||
pos_c = url.find("://");
|
||||
|
@ -108,7 +106,7 @@ namespace http
|
|||
user = url.substr(pos_p, delim - pos_p);
|
||||
delim += 1;
|
||||
pass = url.substr(delim, pos_c - delim);
|
||||
} else if(delim) {
|
||||
} else if (delim) {
|
||||
user = url.substr(pos_p, pos_c - pos_p);
|
||||
}
|
||||
pos_p = pos_c + 1;
|
||||
|
@ -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 */
|
||||
|
@ -135,7 +132,7 @@ namespace http
|
|||
? url.substr(pos_p, std::string::npos)
|
||||
: url.substr(pos_p, pos_c - pos_p);
|
||||
/* stoi throws exception on failure, we don't need it */
|
||||
for (char c : port_str) {
|
||||
for (char c: port_str) {
|
||||
if (c < '0' || c > '9')
|
||||
return false;
|
||||
port *= 10;
|
||||
|
@ -181,15 +178,15 @@ namespace http
|
|||
return true;
|
||||
}
|
||||
|
||||
bool URL::parse_query(std::map<std::string, std::string> & params) {
|
||||
std::vector<std::string> tokens;
|
||||
bool URL::parse_query(std::map <std::string, std::string> ¶ms) {
|
||||
std::vector <std::string> tokens;
|
||||
strsplit(query, tokens, '&');
|
||||
|
||||
params.clear();
|
||||
for (const auto& it : tokens) {
|
||||
for (const auto &it: tokens) {
|
||||
if (!it.length()) // empty
|
||||
continue;
|
||||
std::size_t eq = it.find ('=');
|
||||
std::size_t eq = it.find('=');
|
||||
if (eq != std::string::npos) {
|
||||
auto e = std::pair<std::string, std::string>(it.substr(0, eq), it.substr(eq + 1));
|
||||
params.insert(e);
|
||||
|
@ -224,12 +221,11 @@ namespace http
|
|||
return out;
|
||||
}
|
||||
|
||||
bool URL::is_i2p() const
|
||||
{
|
||||
return host.rfind(".i2p") == ( host.size() - 4 );
|
||||
bool URL::is_i2p() const {
|
||||
return host.rfind(".i2p") == (host.size() - 4);
|
||||
}
|
||||
|
||||
void HTTPMsg::add_header(const char *name, std::string & value, bool replace) {
|
||||
void HTTPMsg::add_header(const char *name, std::string &value, bool replace) {
|
||||
add_header(name, value.c_str(), replace);
|
||||
}
|
||||
|
||||
|
@ -253,8 +249,10 @@ namespace http
|
|||
return parse(str);
|
||||
}
|
||||
|
||||
int HTTPReq::parse(const std::string& str) {
|
||||
enum { REQ_LINE, HEADER_LINE } expect = REQ_LINE;
|
||||
int HTTPReq::parse(const std::string &str) {
|
||||
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;
|
||||
|
@ -265,7 +263,7 @@ namespace http
|
|||
while ((eol = str.find(CRLF, pos)) != std::string::npos) {
|
||||
if (expect == REQ_LINE) {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
std::vector<std::string> tokens;
|
||||
std::vector <std::string> tokens;
|
||||
strsplit(line, tokens, ' ');
|
||||
if (tokens.size() != 3)
|
||||
return -1;
|
||||
|
@ -280,13 +278,11 @@ 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)
|
||||
headers.push_back (p);
|
||||
if (p.first.length() > 0)
|
||||
headers.push_back(p);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
@ -297,57 +293,48 @@ 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)
|
||||
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)
|
||||
{
|
||||
headers.push_back (std::make_pair(name, 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)
|
||||
{
|
||||
for (auto& it : headers)
|
||||
if (it.first == name)
|
||||
{
|
||||
void HTTPReq::UpdateHeader(const std::string &name, const std::string &value) {
|
||||
for (auto &it: headers)
|
||||
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 ();)
|
||||
{
|
||||
if (!it->first.compare(0, name.length (), name) && it->first != exempt)
|
||||
it = headers.erase (it);
|
||||
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
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
std::string HTTPReq::GetHeader (const std::string& name) const
|
||||
{
|
||||
for (auto& it : headers)
|
||||
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())
|
||||
|
@ -386,8 +371,10 @@ namespace http
|
|||
return parse(str);
|
||||
}
|
||||
|
||||
int HTTPRes::parse(const std::string& str) {
|
||||
enum { RES_LINE, HEADER_LINE } expect = RES_LINE;
|
||||
int HTTPRes::parse(const std::string &str) {
|
||||
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;
|
||||
|
||||
|
@ -397,7 +384,7 @@ namespace http
|
|||
while ((eol = str.find(CRLF, pos)) != std::string::npos) {
|
||||
if (expect == RES_LINE) {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
std::vector<std::string> tokens;
|
||||
std::vector <std::string> tokens;
|
||||
strsplit(line, tokens, ' ', 3);
|
||||
if (tokens.size() != 3)
|
||||
return -1;
|
||||
|
@ -413,8 +400,8 @@ namespace http
|
|||
} else {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length () > 0)
|
||||
headers.insert (p);
|
||||
if (p.first.length() > 0)
|
||||
headers.insert(p);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
@ -438,7 +425,7 @@ namespace http
|
|||
/* build response */
|
||||
std::stringstream ss;
|
||||
ss << version << " " << code << " " << status << CRLF;
|
||||
for (auto & h : headers) {
|
||||
for (auto &h: headers) {
|
||||
ss << h.first << ": " << h.second << CRLF;
|
||||
}
|
||||
ss << CRLF;
|
||||
|
@ -447,44 +434,77 @@ namespace http
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
const char * HTTPCodeToStatus(int code) {
|
||||
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,12 +514,10 @@ 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 ())
|
||||
{
|
||||
std::getline (in, hexLen);
|
||||
while (!in.eof()) {
|
||||
std::getline(in, hexLen);
|
||||
errno = 0;
|
||||
long int len = strtoul(hexLen.c_str(), (char **) NULL, 16);
|
||||
if (errno != 0)
|
||||
|
@ -508,20 +526,19 @@ namespace http
|
|||
return true; /* end of stream */
|
||||
if (len < 0 || len > 10 * 1024 * 1024) /* < 10Mb */
|
||||
return false; /* too large chunk */
|
||||
char * buf = new char[len];
|
||||
in.read (buf, len);
|
||||
out.write (buf, len);
|
||||
char *buf = new char[len];
|
||||
in.read(buf, len);
|
||||
out.write(buf, len);
|
||||
delete[] buf;
|
||||
std::getline (in, hexLen); // read \r\n after chunk
|
||||
std::getline(in, hexLen); // read \r\n after chunk
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass)
|
||||
{
|
||||
if (user.empty () && pass.empty ()) return "";
|
||||
return "Basic " + i2p::data::ToBase64Standard (user + ":" + 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);
|
||||
}
|
||||
|
||||
} // http
|
||||
} // http
|
||||
} // i2p
|
||||
|
|
|
@ -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 */
|
||||
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;
|
||||
|
@ -36,26 +33,27 @@ namespace http
|
|||
std::string query;
|
||||
std::string frag;
|
||||
|
||||
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
|
||||
URL() : schema(""), user(""), pass(""), host(""), port(0), path(""), query(""), frag("") {};
|
||||
|
||||
/**
|
||||
* @brief Tries to parse url from string
|
||||
* @return true on success, false on invalid url
|
||||
*/
|
||||
bool parse (const char *str, std::size_t len = 0);
|
||||
bool parse (const std::string& url);
|
||||
bool parse(const char *str, std::size_t len = 0);
|
||||
|
||||
bool parse(const std::string &url);
|
||||
|
||||
/**
|
||||
* @brief Parse query part of url to key/value map
|
||||
* @note Honestly, this should be implemented with std::multimap
|
||||
*/
|
||||
bool parse_query(std::map<std::string, std::string> & params);
|
||||
bool parse_query(std::map <std::string, std::string> ¶ms);
|
||||
|
||||
/**
|
||||
* @brief Serialize URL structure to url
|
||||
* @note Returns relative url if schema if empty, absolute url otherwise
|
||||
*/
|
||||
std::string to_string ();
|
||||
std::string to_string();
|
||||
|
||||
/**
|
||||
* @brief return true if the host is inside i2p
|
||||
|
@ -63,26 +61,26 @@ namespace http
|
|||
bool is_i2p() const;
|
||||
};
|
||||
|
||||
struct HTTPMsg
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
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, 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
|
||||
{
|
||||
std::list<std::pair<std::string, std::string> > headers;
|
||||
struct HTTPReq {
|
||||
std::list <std::pair<std::string, std::string>> headers;
|
||||
std::string version;
|
||||
std::string method;
|
||||
std::string uri;
|
||||
|
||||
HTTPReq (): version("HTTP/1.0"), method("GET"), uri("/") {};
|
||||
HTTPReq() : version("HTTP/1.0"), method("GET"), uri("/") {};
|
||||
|
||||
/**
|
||||
* @brief Tries to parse HTTP request from string
|
||||
|
@ -90,17 +88,23 @@ 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);
|
||||
|
||||
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) { RemoveHeader (name, ""); };
|
||||
std::string GetHeader (const std::string& name) const;
|
||||
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) { RemoveHeader(name, ""); };
|
||||
|
||||
std::string GetHeader(const std::string &name) const;
|
||||
};
|
||||
|
||||
struct HTTPRes : HTTPMsg {
|
||||
|
@ -116,7 +120,7 @@ namespace http
|
|||
*/
|
||||
std::string body;
|
||||
|
||||
HTTPRes (): version("HTTP/1.1"), status("OK"), code(200) {}
|
||||
HTTPRes() : version("HTTP/1.1"), status("OK"), code(200) {}
|
||||
|
||||
/**
|
||||
* @brief Tries to parse HTTP response from string
|
||||
|
@ -124,7 +128,8 @@ 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);
|
||||
|
||||
int parse(const std::string &buf);
|
||||
|
||||
/**
|
||||
* @brief Serialize HTTP response to string
|
||||
|
@ -135,10 +140,10 @@ namespace http
|
|||
*/
|
||||
std::string to_string();
|
||||
|
||||
void write(std::ostream & o);
|
||||
void write(std::ostream &o);
|
||||
|
||||
/** @brief Checks that response declared as chunked data */
|
||||
bool is_chunked() const ;
|
||||
bool is_chunked() const;
|
||||
|
||||
/** @brief Checks that response contains compressed data */
|
||||
bool is_gzipped(bool includingI2PGzip = true) const;
|
||||
|
@ -149,7 +154,7 @@ namespace http
|
|||
* @param code HTTP code [100, 599]
|
||||
* @return Immutable string with status
|
||||
*/
|
||||
const char * HTTPCodeToStatus(int code);
|
||||
const char *HTTPCodeToStatus(int code);
|
||||
|
||||
/**
|
||||
* @brief Replaces %-encoded characters in string with their values
|
||||
|
@ -157,7 +162,7 @@ namespace http
|
|||
* @param null If set to true - decode also %00 sequence, otherwise - skip
|
||||
* @return Decoded string
|
||||
*/
|
||||
std::string UrlDecode(const std::string& data, bool null = false);
|
||||
std::string UrlDecode(const std::string &data, bool null = false);
|
||||
|
||||
/**
|
||||
* @brief Merge HTTP response content with Transfer-Encoding: chunked
|
||||
|
@ -165,11 +170,11 @@ namespace http
|
|||
* @param out Output stream
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool MergeChunkedResponse (std::istream& in, std::ostream& out);
|
||||
bool MergeChunkedResponse(std::istream &in, std::ostream &out);
|
||||
|
||||
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass);
|
||||
std::string CreateBasicAuthorizationString(const std::string &user, const std::string &pass);
|
||||
|
||||
} // http
|
||||
} // http
|
||||
} // i2p
|
||||
|
||||
#endif /* HTTP_H__ */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,177 +132,226 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 62708;
|
||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
|
||||
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
|
||||
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60 * 1000; // 1 minute in milliseconds
|
||||
|
||||
struct I2NPMessage
|
||||
{
|
||||
uint8_t * buf;
|
||||
struct I2NPMessage {
|
||||
uint8_t *buf;
|
||||
size_t len, offset, maxLen;
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from;
|
||||
|
||||
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
|
||||
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
|
||||
I2NPMessage() : buf(nullptr), len(I2NP_HEADER_SIZE + 2),
|
||||
offset(2), maxLen(0), from(nullptr) {}; // reserve 2 bytes for NTCP header
|
||||
|
||||
// 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); };
|
||||
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 ()
|
||||
{
|
||||
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);
|
||||
};
|
||||
|
||||
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() {
|
||||
uint8_t hash[32];
|
||||
SHA256(GetPayload (), GetPayloadLength (), hash);
|
||||
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
||||
SHA256(GetPayload(), GetPayloadLength(), hash);
|
||||
GetHeader()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
||||
}
|
||||
|
||||
// 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; };
|
||||
uint8_t *GetPayload() { return GetBuffer() + I2NP_HEADER_SIZE; };
|
||||
|
||||
void Align (size_t alignment)
|
||||
{
|
||||
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) {
|
||||
if (len + alignment > maxLen) return;
|
||||
size_t rem = ((size_t)GetBuffer ()) % alignment;
|
||||
if (rem)
|
||||
{
|
||||
size_t rem = ((size_t) GetBuffer()) % alignment;
|
||||
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);
|
||||
memcpy(buf + len, buf1, len1);
|
||||
len += len1;
|
||||
return len1;
|
||||
}
|
||||
|
||||
I2NPMessage& operator=(const I2NPMessage& other)
|
||||
{
|
||||
memcpy (buf + offset, other.buf + other.offset, other.GetLength ());
|
||||
len = offset + other.GetLength ();
|
||||
I2NPMessage &operator=(const I2NPMessage &other) {
|
||||
memcpy(buf + offset, other.buf + other.offset, other.GetLength());
|
||||
len = offset + other.GetLength();
|
||||
from = other.from;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 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
|
||||
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 ();
|
||||
GetHeader ()[I2NP_HEADER_TYPEID_OFFSET] = ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET]; // typeid
|
||||
SetMsgID (msgID);
|
||||
SetExpiration (bufbe32toh (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET)*1000LL);
|
||||
SetSize (len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks (0);
|
||||
const uint8_t *ssu = GetSSUHeader();
|
||||
GetHeader()[I2NP_HEADER_TYPEID_OFFSET] = ssu[I2NP_SHORT_HEADER_TYPEID_OFFSET]; // typeid
|
||||
SetMsgID(msgID);
|
||||
SetExpiration(bufbe32toh(ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET) * 1000LL);
|
||||
SetSize(len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks(0);
|
||||
}
|
||||
uint32_t ToSSU () // return msgID
|
||||
|
||||
uint32_t ToSSU() // return msgID
|
||||
{
|
||||
uint8_t header[I2NP_HEADER_SIZE];
|
||||
memcpy (header, GetHeader (), I2NP_HEADER_SIZE);
|
||||
uint8_t * ssu = GetSSUHeader ();
|
||||
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);
|
||||
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
|
||||
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
|
||||
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 ()
|
||||
{
|
||||
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);
|
||||
SetSize (len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks (0);
|
||||
uint8_t *GetNTCP2Header() { return GetPayload() - I2NP_NTCP2_HEADER_SIZE; };
|
||||
|
||||
size_t GetNTCP2Length() const { return GetPayloadLength() + I2NP_NTCP2_HEADER_SIZE; };
|
||||
|
||||
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);
|
||||
SetSize(len - offset - I2NP_HEADER_SIZE);
|
||||
SetChks(0);
|
||||
}
|
||||
|
||||
void ToNTCP2 ()
|
||||
{
|
||||
uint8_t * ntcp2 = GetNTCP2Header ();
|
||||
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 ToNTCP2() {
|
||||
uint8_t *ntcp2 = GetNTCP2Header();
|
||||
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;
|
||||
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> NewI2NPMessage();
|
||||
|
||||
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> NewI2NPShortMessage();
|
||||
|
||||
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);
|
||||
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
|
||||
const std::set<i2p::data::IdentHash>& excludedFloodfills,
|
||||
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> 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);
|
||||
|
||||
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> 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>
|
||||
CreateDatabaseSearchReply(const i2p::data::IdentHash &ident, std::vector<i2p::data::IdentHash> routers);
|
||||
|
||||
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>
|
||||
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> 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);
|
||||
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);
|
||||
|
||||
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);
|
||||
bool IsRouterInfoMsg(std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
class I2NPMessagesHandler
|
||||
{
|
||||
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 {
|
||||
public:
|
||||
|
||||
~I2NPMessagesHandler ();
|
||||
void PutNextMessage (std::shared_ptr<I2NPMessage>&& msg);
|
||||
void Flush ();
|
||||
~I2NPMessagesHandler();
|
||||
|
||||
void PutNextMessage(std::shared_ptr<I2NPMessage> &&msg);
|
||||
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -310,8 +359,10 @@ namespace tunnel
|
|||
};
|
||||
|
||||
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
|
||||
uint16_t GetMaxNumTransitTunnels ();
|
||||
|
||||
void SetMaxNumTransitTunnels(uint16_t maxNumTransitTunnels);
|
||||
|
||||
uint16_t GetMaxNumTransitTunnels();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||
{
|
||||
return ident.ToBase64 ().substr (0, 4);
|
||||
|
||||
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,22 +42,25 @@ 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;
|
||||
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;
|
||||
};
|
||||
|
||||
Keys CreateRandomKeys ();
|
||||
Keys CreateRandomKeys();
|
||||
|
||||
const size_t DEFAULT_IDENTITY_SIZE = sizeof (Identity); // 387 bytes
|
||||
const size_t DEFAULT_IDENTITY_SIZE = sizeof(Identity); // 387 bytes
|
||||
|
||||
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
||||
|
@ -85,57 +85,83 @@ 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);
|
||||
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);
|
||||
IdentityEx();
|
||||
|
||||
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; };
|
||||
IdentityEx(const uint8_t *publicKey, const uint8_t *signingKey,
|
||||
SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1,
|
||||
CryptoKeyType cryptoType = CRYPTO_KEY_TYPE_ELGAMAL);
|
||||
|
||||
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
|
||||
IdentityEx(const uint8_t *buf, size_t len);
|
||||
|
||||
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
|
||||
void RecalculateIdentHash(uint8_t * buff=nullptr);
|
||||
IdentityEx(const IdentityEx &other);
|
||||
|
||||
static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType);
|
||||
static std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (CryptoKeyType keyType, const uint8_t * key);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
void CreateVerifier () const;
|
||||
void UpdateVerifier (i2p::crypto::Verifier * verifier) const;
|
||||
void CreateVerifier() const;
|
||||
|
||||
void UpdateVerifier(i2p::crypto::Verifier *verifier) const;
|
||||
|
||||
private:
|
||||
|
||||
Identity m_StandardIdentity;
|
||||
IdentHash m_IdentHash;
|
||||
mutable i2p::crypto::Verifier * m_Verifier = nullptr;
|
||||
mutable i2p::crypto::Verifier *m_Verifier = nullptr;
|
||||
mutable std::mutex m_VerifierMutex;
|
||||
size_t m_ExtendedLen;
|
||||
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
|
||||
|
@ -145,46 +171,69 @@ 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;
|
||||
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;
|
||||
PrivateKeys(const PrivateKeys &other) { *this = other; };
|
||||
|
||||
size_t GetFullLen () const;
|
||||
size_t FromBuffer (const uint8_t * buf, size_t len);
|
||||
size_t ToBuffer (uint8_t * buf, size_t len) const;
|
||||
PrivateKeys(const Keys &keys) { *this = keys; };
|
||||
|
||||
size_t FromBase64(const std::string& s);
|
||||
std::string ToBase64 () const;
|
||||
PrivateKeys &operator=(const Keys &keys);
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> CreateDecryptor (const uint8_t * key) const;
|
||||
PrivateKeys &operator=(const PrivateKeys &other);
|
||||
|
||||
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 i2p::crypto::Signer * CreateSigner (SigningKeyType keyType, const uint8_t * priv);
|
||||
~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 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 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; };
|
||||
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;
|
||||
void CreateSigner() const;
|
||||
|
||||
void CreateSigner(SigningKeyType keyType) const;
|
||||
|
||||
size_t GetPrivateKeyLen() const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -198,51 +247,61 @@ 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; };
|
||||
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);
|
||||
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 () {};
|
||||
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
|
||||
virtual ~RoutingDestination() {};
|
||||
|
||||
const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); };
|
||||
virtual CryptoKeyType GetEncryptionType () const { return GetIdentity ()->GetCryptoKeyType (); }; // override in LeaseSet2
|
||||
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
|
||||
};
|
||||
|
||||
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 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 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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1069
libi2pd/LeaseSet.cpp
1069
libi2pd/LeaseSet.cpp
File diff suppressed because it is too large
Load diff
|
@ -19,36 +19,30 @@
|
|||
#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
|
||||
bool isUpdated; // transient
|
||||
/* return true if this lease expires within t millisecond + fudge factor */
|
||||
bool ExpiresWithin( const uint64_t t, const uint64_t fudge = 1000 ) const {
|
||||
auto expire = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
if(fudge) expire += rand() % fudge;
|
||||
bool ExpiresWithin(const uint64_t t, const uint64_t fudge = 1000) const {
|
||||
auto expire = i2p::util::GetMillisecondsSinceEpoch();
|
||||
if (fudge) expire += rand() % fudge;
|
||||
if (endDate < expire) return true;
|
||||
return (endDate - expire) < t;
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -56,7 +50,7 @@ namespace data
|
|||
};
|
||||
};
|
||||
|
||||
typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
|
||||
typedef std::function<bool(const Lease &l)> LeaseInspectFunc;
|
||||
|
||||
const size_t MAX_LS_BUFFER_SIZE = 3072;
|
||||
const size_t LEASE_SIZE = 44; // 32 + 4 + 8
|
||||
|
@ -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 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
|
||||
LeaseSet(const uint8_t *buf, size_t len, bool storeLeases = true);
|
||||
|
||||
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;
|
||||
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); };
|
||||
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; };
|
||||
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;
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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; };
|
||||
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);
|
||||
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; };
|
||||
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
|
||||
void ReadFromBuffer(bool readIdentity = true, bool verifySignature = true);
|
||||
|
||||
virtual uint64_t
|
||||
ExtractExpirationTimestamp(const uint8_t *buf, size_t len) const; // returns max expiration time
|
||||
|
||||
private:
|
||||
|
||||
|
@ -122,8 +150,8 @@ namespace data
|
|||
std::set<std::shared_ptr<Lease>, LeaseCmp> m_Leases;
|
||||
uint64_t m_ExpirationTime; // in milliseconds
|
||||
std::shared_ptr<const IdentityEx> m_Identity;
|
||||
uint8_t * m_EncryptionKey;
|
||||
uint8_t * m_Buffer;
|
||||
uint8_t *m_EncryptionKey;
|
||||
uint8_t *m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
};
|
||||
|
||||
|
@ -131,7 +159,7 @@ namespace data
|
|||
* validate lease set buffer signature and extract expiration timestamp
|
||||
* @returns true if the leaseset is well formed and signature is valid
|
||||
*/
|
||||
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);
|
||||
bool LeaseSetBufferValidate(const uint8_t *ptr, size_t sz, uint64_t &expires);
|
||||
|
||||
const uint8_t NETDB_STORE_TYPE_STANDARD_LEASESET2 = 3;
|
||||
const uint8_t NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 = 5;
|
||||
|
@ -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
|
||||
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;
|
||||
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; };
|
||||
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);
|
||||
size_t ReadStandardLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
||||
size_t ReadMetaLS2TypeSpecificPart (const uint8_t * buf, size_t len);
|
||||
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);
|
||||
|
||||
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);
|
||||
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
|
||||
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
|
||||
|
||||
private:
|
||||
|
||||
|
@ -185,91 +231,112 @@ 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
|
||||
if (expiresTimestamp < i2p::util::GetSecondsSinceEpoch ()) return nullptr;
|
||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2;
|
||||
std::shared_ptr<i2p::crypto::Verifier> transientVerifier (i2p::data::IdentityEx::CreateVerifier (keyType));
|
||||
const uint8_t *signedData = buf + offset;
|
||||
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;
|
||||
std::shared_ptr<i2p::crypto::Verifier> transientVerifier(i2p::data::IdentityEx::CreateVerifier(keyType));
|
||||
if (!transientVerifier) return nullptr;
|
||||
auto keyLen = transientVerifier->GetPublicKeyLen ();
|
||||
auto keyLen = transientVerifier->GetPublicKeyLen();
|
||||
if (offset + keyLen >= len) return nullptr;
|
||||
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 ();
|
||||
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();
|
||||
return transientVerifier;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
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 * buf, size_t len);
|
||||
virtual ~LocalLeaseSet () { delete[] m_Buffer; };
|
||||
LocalLeaseSet(std::shared_ptr<const IdentityEx> identity, const uint8_t *encryptionPublicKey,
|
||||
std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels);
|
||||
|
||||
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; };
|
||||
LocalLeaseSet(std::shared_ptr<const IdentityEx> identity, const uint8_t *buf, size_t len);
|
||||
|
||||
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 ()); };
|
||||
virtual ~LocalLeaseSet() { delete[] m_Buffer; };
|
||||
|
||||
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 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());
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
private:
|
||||
|
||||
uint64_t m_ExpirationTime; // in milliseconds
|
||||
std::shared_ptr<const IdentityEx> m_Identity;
|
||||
uint8_t * m_Buffer, * m_Leases;
|
||||
uint8_t *m_Buffer, *m_Leases;
|
||||
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;
|
||||
const uint8_t *encryptionPublicKey;
|
||||
};
|
||||
typedef std::vector<KeySection> KeySections;
|
||||
|
||||
LocalLeaseSet2 (uint8_t storeType, const i2p::data::PrivateKeys& keys,
|
||||
const KeySections& encryptionKeys,
|
||||
const std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> >& tunnels,
|
||||
LocalLeaseSet2(uint8_t storeType, const i2p::data::PrivateKeys &keys,
|
||||
const KeySections &encryptionKeys,
|
||||
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; };
|
||||
virtual ~LocalLeaseSet2() { delete[] m_Buffer; };
|
||||
|
||||
uint8_t * GetBuffer () const { return m_Buffer + 1; };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
uint8_t *GetBuffer() const { return m_Buffer + 1; };
|
||||
|
||||
uint8_t GetStoreType () const { return m_Buffer[0]; };
|
||||
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:
|
||||
|
||||
uint8_t * m_Buffer; // 1 byte store type + actual buffer
|
||||
uint8_t *m_Buffer; // 1 byte store type + actual buffer
|
||||
size_t m_BufferLen;
|
||||
};
|
||||
|
||||
|
@ -280,27 +347,32 @@ 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; };
|
||||
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:
|
||||
|
||||
IdentHash m_StoreHash;
|
||||
std::shared_ptr<const LocalLeaseSet2> m_InnerLeaseSet;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,85 +33,71 @@ struct BigEndian;
|
|||
|
||||
// Little-Endian template
|
||||
|
||||
#pragma pack(push,1)
|
||||
#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())
|
||||
{
|
||||
operator =(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];
|
||||
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));
|
||||
bytes[sizeof(T) - 1 - i] = static_cast<unsigned char>(t >> (i << 3));
|
||||
return t;
|
||||
}
|
||||
|
||||
// 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 ++ ();
|
||||
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,64 +105,56 @@ struct LittleEndian
|
|||
return (*this);
|
||||
}
|
||||
|
||||
LittleEndian<T> operator -- (int)
|
||||
{
|
||||
LittleEndian<T> operator--(int) {
|
||||
LittleEndian<T> tmp(*this);
|
||||
operator -- ();
|
||||
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))
|
||||
if (bytes[i] != (T) (-1))
|
||||
break;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
// Big-Endian template
|
||||
|
||||
#pragma pack(push,1)
|
||||
#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())
|
||||
{
|
||||
operator =(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];
|
||||
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 ++ ();
|
||||
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,24 +197,22 @@ struct BigEndian
|
|||
return (*this);
|
||||
}
|
||||
|
||||
BigEndian<T> operator -- (int)
|
||||
{
|
||||
BigEndian<T> operator--(int) {
|
||||
BigEndian<T> tmp(*this);
|
||||
operator -- ();
|
||||
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))
|
||||
if (bytes[sizeof(T) - 1 - i] != (T) (-1))
|
||||
break;
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // LITTLEBIGENDIAN_H
|
120
libi2pd/Log.cpp
120
libi2pd/Log.cpp
|
@ -13,12 +13,12 @@
|
|||
#include <algorithm>
|
||||
|
||||
namespace i2p {
|
||||
namespace log {
|
||||
namespace log {
|
||||
static Log logger;
|
||||
/**
|
||||
* @brief Maps our loglevel to their symbolic name
|
||||
*/
|
||||
static const char * g_LogLevelStr[eNumLogLevels] =
|
||||
static const char *g_LogLevelStr[eNumLogLevels] =
|
||||
{
|
||||
"none", // eLogNone
|
||||
"error", // eLogError
|
||||
|
@ -45,49 +45,57 @@ namespace log {
|
|||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/**
|
||||
* @brief Maps our log levels to syslog one
|
||||
* @return syslog priority LOG_*, as defined in syslog.h
|
||||
*/
|
||||
static inline int GetSyslogPrio (enum LogLevel l) {
|
||||
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():
|
||||
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_LogStream(nullptr), m_Logfile(""), m_HasColors(true), m_TimeFormat("%H:%M:%S"),
|
||||
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));
|
||||
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();
|
||||
|
@ -102,10 +110,9 @@ namespace log {
|
|||
break;
|
||||
}
|
||||
m_IsRunning = false;
|
||||
m_Queue.WakeUp ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
m_Queue.WakeUp();
|
||||
if (m_Thread) {
|
||||
m_Thread->join();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
|
@ -116,13 +123,13 @@ namespace log {
|
|||
// static_cast<int(*)(int)>(std::tolower) // wrong
|
||||
// [](int c){ return std::tolower(c); } // wrong
|
||||
// [](char c){ return std::tolower(c); } // wrong
|
||||
[](unsigned char c){ return std::tolower(c); } // correct
|
||||
[](unsigned char c) { return std::tolower(c); } // correct
|
||||
);
|
||||
return s;
|
||||
}
|
||||
|
||||
void Log::SetLogLevel (const std::string& level_) {
|
||||
std::string level=str_tolower(level_);
|
||||
void Log::SetLogLevel(const std::string &level_) {
|
||||
std::string level = str_tolower(level_);
|
||||
if (level == "none") { m_MinLevel = eLogNone; }
|
||||
else if (level == "error") { m_MinLevel = eLogError; }
|
||||
else if (level == "warn") { m_MinLevel = eLogWarning; }
|
||||
|
@ -135,7 +142,7 @@ namespace log {
|
|||
LogPrint(eLogInfo, "Log: Logging level set to ", level);
|
||||
}
|
||||
|
||||
const char * Log::TimeAsString(std::time_t t) {
|
||||
const char *Log::TimeAsString(std::time_t t) {
|
||||
if (t != m_LastTimestamp) {
|
||||
strftime(m_LastDateTime, sizeof(m_LastDateTime), m_TimeFormat.c_str(), localtime(&t));
|
||||
m_LastTimestamp = t;
|
||||
|
@ -148,10 +155,9 @@ 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;
|
||||
std::hash <std::thread::id> hasher;
|
||||
unsigned short short_tid;
|
||||
short_tid = (short) (hasher(msg->tid) % 1000);
|
||||
switch (m_Destination) {
|
||||
|
@ -172,40 +178,36 @@ 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)
|
||||
{
|
||||
std::shared_ptr<LogMsg> msg;
|
||||
while ((msg = m_Queue.Get ()))
|
||||
Process (msg);
|
||||
Reopen();
|
||||
while (m_IsRunning) {
|
||||
std::shared_ptr <LogMsg> msg;
|
||||
while ((msg = m_Queue.Get()))
|
||||
Process(msg);
|
||||
if (m_LogStream) m_LogStream->flush();
|
||||
if (m_IsRunning)
|
||||
m_Queue.Wait ();
|
||||
m_Queue.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
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 ())
|
||||
{
|
||||
auto os = std::make_shared<std::ofstream>(path, flags);
|
||||
if (os->is_open()) {
|
||||
m_HasColors = false;
|
||||
m_Logfile = path;
|
||||
m_Destination = eLogFile;
|
||||
|
@ -215,13 +217,14 @@ namespace log {
|
|||
LogPrint(eLogError, "Log: Can't open file ", path);
|
||||
}
|
||||
|
||||
void Log::SendTo (std::shared_ptr<std::ostream> os) {
|
||||
void Log::SendTo(std::shared_ptr <std::ostream> os) {
|
||||
m_HasColors = false;
|
||||
m_Destination = eLogStream;
|
||||
m_LogStream = os;
|
||||
}
|
||||
|
||||
#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() {
|
||||
|
@ -236,14 +240,16 @@ namespace log {
|
|||
SendTo(m_Logfile);
|
||||
}
|
||||
|
||||
Log & Logger() {
|
||||
Log &Logger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
static ThrowFunction g_ThrowFunction;
|
||||
ThrowFunction GetThrowFunction () { return g_ThrowFunction; }
|
||||
void SetThrowFunction (ThrowFunction f) { g_ThrowFunction = f; }
|
||||
|
||||
} // log
|
||||
ThrowFunction GetThrowFunction() { return g_ThrowFunction; }
|
||||
|
||||
void SetThrowFunction(ThrowFunction f) { g_ThrowFunction = f; }
|
||||
|
||||
} // log
|
||||
} // i2p
|
||||
|
||||
|
|
151
libi2pd/Log.h
151
libi2pd/Log.h
|
@ -21,11 +21,12 @@
|
|||
#include "Queue.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#endif
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
enum LogLevel {
|
||||
eLogNone = 0,
|
||||
eLogError,
|
||||
eLogWarning,
|
||||
|
@ -44,34 +45,36 @@ enum LogType {
|
|||
};
|
||||
|
||||
namespace i2p {
|
||||
namespace log {
|
||||
namespace log {
|
||||
|
||||
struct LogMsg; /* forward declaration */
|
||||
|
||||
class Log
|
||||
{
|
||||
class Log {
|
||||
private:
|
||||
|
||||
enum LogType m_Destination;
|
||||
enum LogLevel m_MinLevel;
|
||||
std::shared_ptr<std::ostream> m_LogStream;
|
||||
std::shared_ptr <std::ostream> m_LogStream;
|
||||
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;
|
||||
std::thread * m_Thread;
|
||||
std::thread *m_Thread;
|
||||
|
||||
private:
|
||||
|
||||
/** prevent making copies */
|
||||
Log (const Log &);
|
||||
const Log& operator=(const Log&);
|
||||
Log(const Log &);
|
||||
|
||||
void Run ();
|
||||
void Process (std::shared_ptr<LogMsg> msg);
|
||||
const Log &operator=(const Log &);
|
||||
|
||||
void Run();
|
||||
|
||||
void Process(std::shared_ptr <LogMsg> msg);
|
||||
|
||||
/**
|
||||
* @brief Makes formatted string from unix timestamp
|
||||
|
@ -79,57 +82,62 @@ namespace log {
|
|||
*
|
||||
* This function internally caches the result for last provided value
|
||||
*/
|
||||
const char * TimeAsString(std::time_t ts);
|
||||
const char *TimeAsString(std::time_t ts);
|
||||
|
||||
public:
|
||||
|
||||
Log ();
|
||||
~Log ();
|
||||
Log();
|
||||
|
||||
LogType GetLogType () { return m_Destination; };
|
||||
LogLevel GetLogLevel () { return m_MinLevel; };
|
||||
~Log();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
LogType GetLogType() { return m_Destination; };
|
||||
|
||||
LogLevel GetLogLevel() { return m_MinLevel; };
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
/**
|
||||
* @brief Sets minimal allowed level for log messages
|
||||
* @param level String with wanted minimal msg level
|
||||
*/
|
||||
void SetLogLevel (const std::string& level);
|
||||
void SetLogLevel(const std::string &level);
|
||||
|
||||
/**
|
||||
* @brief Sets log destination to logfile
|
||||
* @param path Path to logfile
|
||||
*/
|
||||
void SendTo (const std::string &path);
|
||||
void SendTo(const std::string &path);
|
||||
|
||||
/**
|
||||
* @brief Sets log destination to given output stream
|
||||
* @param os Output stream
|
||||
*/
|
||||
void SendTo (std::shared_ptr<std::ostream> os);
|
||||
void SendTo(std::shared_ptr <std::ostream> os);
|
||||
|
||||
/**
|
||||
* @brief Sets format for timestamps in log
|
||||
* @param format String with timestamp format
|
||||
*/
|
||||
void SetTimeFormat (std::string format) { m_TimeFormat = format; };
|
||||
void SetTimeFormat(std::string format) { m_TimeFormat = format; };
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef _WIN32
|
||||
/**
|
||||
* @brief Sets log destination to syslog
|
||||
* @param name Wanted program name
|
||||
* @param facility Wanted log category
|
||||
*/
|
||||
void SendTo (const char *name, int facility);
|
||||
#endif
|
||||
void SendTo(const char *name, int facility);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Format log message and write to output stream/syslog
|
||||
* @param msg Pointer to processed message
|
||||
*/
|
||||
void Append(std::shared_ptr<i2p::log::LogMsg> &);
|
||||
void Append(std::shared_ptr <i2p::log::LogMsg> &);
|
||||
|
||||
/** @brief Reopen log file */
|
||||
void Reopen();
|
||||
|
@ -148,31 +156,41 @@ namespace log {
|
|||
LogLevel level; /**< message level */
|
||||
std::thread::id tid; /**< id of thread that generated message */
|
||||
|
||||
LogMsg (LogLevel lvl, std::time_t ts, std::string&& txt): timestamp(ts), text(std::move(txt)), level(lvl) {}
|
||||
LogMsg(LogLevel lvl, std::time_t ts, std::string &&txt) : timestamp(ts), text(std::move(txt)), level(lvl) {}
|
||||
};
|
||||
|
||||
Log & Logger();
|
||||
Log &Logger();
|
||||
|
||||
typedef std::function<void (const std::string&)> ThrowFunction;
|
||||
ThrowFunction GetThrowFunction ();
|
||||
void SetThrowFunction (ThrowFunction f);
|
||||
} // log
|
||||
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,24 +200,33 @@ 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
|
||||
{
|
||||
i2p::log::Log &log = i2p::log::Logger();
|
||||
if (level > log.GetLogLevel ())
|
||||
return;
|
||||
void LogPrint(LogLevel level, TArgs &&... args)
|
||||
|
||||
// fold message to single string
|
||||
std::stringstream ss;
|
||||
noexcept
|
||||
{
|
||||
i2p::log::Log &log = i2p::log::Logger();
|
||||
if (level > log.
|
||||
|
||||
GetLogLevel()
|
||||
|
||||
)
|
||||
return;
|
||||
|
||||
// fold message to single string
|
||||
std::stringstream ss;
|
||||
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
(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);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,18 +234,26 @@ 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;
|
||||
// fold message to single string
|
||||
std::stringstream ss("");
|
||||
auto f = i2p::log::GetThrowFunction();
|
||||
if (!f) return;
|
||||
// fold message to single string
|
||||
std::stringstream ss("");
|
||||
#if (__cplusplus >= 201703L) // C++ 17 or higher
|
||||
(LogPrint (ss, std::forward<TArgs>(args)), ...);
|
||||
(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__
|
||||
|
|
1812
libi2pd/NTCP2.cpp
1812
libi2pd/NTCP2.cpp
File diff suppressed because it is too large
Load diff
299
libi2pd/NTCP2.h
299
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;
|
||||
|
@ -37,14 +35,13 @@ namespace transport
|
|||
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
|
||||
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
const int NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT = 3; // 3 seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25*60; // 25 minuntes in seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25*60; // 25 minuntes
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL = 25 * 60; // 25 minuntes in seconds
|
||||
const int NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD = 25 * 60; // 25 minuntes
|
||||
|
||||
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,39 +74,54 @@ namespace transport
|
|||
// RouterInfo flags
|
||||
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||
|
||||
struct NTCP2Establisher: private i2p::crypto::NoiseSymmetricState
|
||||
{
|
||||
NTCP2Establisher ();
|
||||
~NTCP2Establisher ();
|
||||
struct NTCP2Establisher : private i2p::crypto::NoiseSymmetricState {
|
||||
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
|
||||
~NTCP2Establisher();
|
||||
|
||||
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; };
|
||||
const uint8_t *GetPub() const { return m_EphemeralKeys->GetPublicKey(); };
|
||||
|
||||
void KDF1Alice ();
|
||||
void KDF1Bob ();
|
||||
void KDF2Alice ();
|
||||
void KDF2Bob ();
|
||||
void KDF3Alice (); // for SessionConfirmed part 2
|
||||
void KDF3Bob ();
|
||||
const uint8_t *GetRemotePub() const { return m_RemoteEphemeralPublicKey; }; // Y for Alice and X for Bob
|
||||
uint8_t *GetRemotePub() { return m_RemoteEphemeralPublicKey; }; // to set
|
||||
|
||||
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 ();
|
||||
const uint8_t *GetK() const { return m_CK + 32; };
|
||||
|
||||
void CreateSessionRequestMessage ();
|
||||
void CreateSessionCreatedMessage ();
|
||||
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
|
||||
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
|
||||
const uint8_t *GetCK() const { return m_CK; };
|
||||
|
||||
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);
|
||||
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 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;
|
||||
uint8_t m_RemoteEphemeralPublicKey[32]; // x25519
|
||||
|
@ -119,83 +130,120 @@ namespace transport
|
|||
uint16_t m3p2Len;
|
||||
|
||||
uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE],
|
||||
m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer;
|
||||
m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], *m_SessionConfirmedBuffer;
|
||||
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
|
||||
|
||||
};
|
||||
|
||||
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,
|
||||
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; };
|
||||
~NTCP2Session();
|
||||
|
||||
bool IsEstablished () const { return m_IsEstablished; };
|
||||
bool IsTerminated () const { return m_IsTerminated; };
|
||||
void Terminate();
|
||||
|
||||
void ClientLogin (); // Alice
|
||||
void ServerLogin (); // Bob
|
||||
void TerminateByTimeout();
|
||||
|
||||
void SendLocalRouterInfo (bool update); // after handshake or by update
|
||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||
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
|
||||
void ServerLogin(); // Bob
|
||||
|
||||
void SendLocalRouterInfo(bool update); // after handshake or by update
|
||||
void SendI2NPMessages(const std::vector<std::shared_ptr<I2NPMessage> > &msgs);
|
||||
|
||||
private:
|
||||
|
||||
void Established ();
|
||||
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);
|
||||
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 SendSessionRequest();
|
||||
|
||||
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 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 HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||
void 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 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 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 ReceiveLength();
|
||||
|
||||
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 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);
|
||||
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 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:
|
||||
|
||||
NTCP2Server& m_Server;
|
||||
NTCP2Server &m_Server;
|
||||
boost::asio::ip::tcp::socket m_Socket;
|
||||
boost::asio::ip::tcp::endpoint m_RemoteEndpoint;
|
||||
bool m_IsEstablished, m_IsTerminated;
|
||||
|
@ -203,17 +251,16 @@ namespace transport
|
|||
std::unique_ptr<NTCP2Establisher> m_Establisher;
|
||||
// data phase
|
||||
uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32];
|
||||
const uint8_t * m_SendKey, * m_ReceiveKey;
|
||||
const uint8_t *m_SendKey, *m_ReceiveKey;
|
||||
#if OPENSSL_SIPHASH
|
||||
EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx;
|
||||
#else
|
||||
const uint8_t * m_SendSipKey, * m_ReceiveSipKey;
|
||||
const uint8_t *m_SendSipKey, *m_ReceiveSipKey;
|
||||
#endif
|
||||
uint16_t m_NextReceivedLen;
|
||||
uint8_t * m_NextReceivedBuffer, * m_NextSendBuffer;
|
||||
uint8_t *m_NextReceivedBuffer, *m_NextSendBuffer;
|
||||
size_t m_NextReceivedBufferSize;
|
||||
union
|
||||
{
|
||||
union {
|
||||
uint8_t buf[8];
|
||||
uint16_t key;
|
||||
} m_ReceiveIV, m_SendIV;
|
||||
|
@ -229,48 +276,61 @@ 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 ();
|
||||
NTCP2Server();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
boost::asio::io_service& GetService () { return GetIOService (); };
|
||||
~NTCP2Server();
|
||||
|
||||
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 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 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 SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
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 HandleAccept(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 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);
|
||||
|
||||
// timer
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
void ScheduleTermination();
|
||||
|
||||
void HandleTerminationTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -289,9 +349,12 @@ namespace transport
|
|||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
const decltype(m_NTCP2Sessions)& GetNTCP2Sessions () const { return m_NTCP2Sessions; };
|
||||
const decltype(m_NTCP2Sessions)
|
||||
&
|
||||
|
||||
GetNTCP2Sessions() const { return m_NTCP2Sessions; };
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1421
libi2pd/NetDb.cpp
1421
libi2pd/NetDb.cpp
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,96 +57,150 @@ 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 ();
|
||||
NetDb();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
~NetDb();
|
||||
|
||||
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 Start();
|
||||
|
||||
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 Stop();
|
||||
|
||||
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> AddRouterInfo(const uint8_t *buf, int len);
|
||||
|
||||
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> 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::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::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
|
||||
void SetUnreachable (const IdentHash& ident, bool unreachable);
|
||||
bool AddRouterInfo(const IdentHash &ident, const uint8_t *buf, int len);
|
||||
|
||||
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||
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 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> 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::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::shared_ptr<const RouterInfo> GetRandomRouterInFamily(FamilyID fam) const;
|
||||
|
||||
void SetUnreachable(const IdentHash &ident, bool unreachable);
|
||||
|
||||
void PostI2NPMsg(std::shared_ptr<const I2NPMessage> msg);
|
||||
|
||||
/** set hidden mode, aka don't publish our RI to netdb and don't explore */
|
||||
void SetHidden(bool hide);
|
||||
|
||||
void Reseed ();
|
||||
Families& GetFamilies () { return m_Families; };
|
||||
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 (); };
|
||||
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 (); };
|
||||
void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
|
||||
std::shared_ptr<Lease> NewLease (const Lease& lease) { return m_LeasesPool.AcquireSharedMt (lease); };
|
||||
void ClearRouterInfos() { m_RouterInfos.clear(); };
|
||||
|
||||
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||
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; };
|
||||
|
||||
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 Load();
|
||||
|
||||
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters = 40, int numFloodfills = 20);
|
||||
bool LoadRouterInfo(const std::string &path, uint64_t ts);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter(Filter filter) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -160,15 +212,16 @@ namespace data
|
|||
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||
|
||||
bool m_IsRunning;
|
||||
std::thread * m_Thread;
|
||||
std::thread *m_Thread;
|
||||
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
|
||||
|
||||
GzipInflator m_Inflator;
|
||||
Reseeder * m_Reseeder;
|
||||
Reseeder *m_Reseeder;
|
||||
Families m_Families;
|
||||
i2p::fs::HashedStorage m_Storage;
|
||||
|
||||
friend class NetDbRequests;
|
||||
|
||||
NetDbRequests m_Requests;
|
||||
|
||||
bool m_PersistProfiles;
|
||||
|
@ -187,7 +240,7 @@ namespace data
|
|||
};
|
||||
|
||||
extern NetDb netdb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,157 +12,142 @@
|
|||
#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,
|
||||
if (replyTunnel)
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination,
|
||||
replyTunnel->GetNextIdentHash(),
|
||||
replyTunnel->GetNextTunnelID(), m_IsExploratory,
|
||||
&m_ExcludedPeers);
|
||||
else
|
||||
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 ();
|
||||
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)
|
||||
{
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert (floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage(const IdentHash &floodfill) {
|
||||
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination,
|
||||
i2p::context.GetRouterInfo().GetIdentHash(), 0, false,
|
||||
&m_ExcludedPeers);
|
||||
m_ExcludedPeers.insert(floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch();
|
||||
return msg;
|
||||
}
|
||||
|
||||
void RequestedDestination::ClearExcludedPeers ()
|
||||
{
|
||||
m_ExcludedPeers.clear ();
|
||||
void RequestedDestination::ClearExcludedPeers() {
|
||||
m_ExcludedPeers.clear();
|
||||
}
|
||||
|
||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
m_RequestComplete (r);
|
||||
void RequestedDestination::Success(std::shared_ptr<RouterInfo> r) {
|
||||
if (m_RequestComplete) {
|
||||
m_RequestComplete(r);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestedDestination::Fail ()
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
{
|
||||
m_RequestComplete (nullptr);
|
||||
void RequestedDestination::Fail() {
|
||||
if (m_RequestComplete) {
|
||||
m_RequestComplete(nullptr);
|
||||
m_RequestComplete = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::Start ()
|
||||
{
|
||||
void NetDbRequests::Start() {
|
||||
}
|
||||
|
||||
void NetDbRequests::Stop ()
|
||||
{
|
||||
m_RequestedDestinations.clear ();
|
||||
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);
|
||||
auto dest = std::make_shared<RequestedDestination>(destination, isExploratory);
|
||||
dest->SetRequestComplete(requestComplete);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
|
||||
if (!m_RequestedDestinations.insert(std::make_pair(destination, dest)).second) // not inserted
|
||||
return nullptr;
|
||||
}
|
||||
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 ())
|
||||
{
|
||||
auto it = m_RequestedDestinations.find(ident);
|
||||
if (it != m_RequestedDestinations.end()) {
|
||||
request = it->second;
|
||||
m_RequestedDestinations.erase (it);
|
||||
m_RequestedDestinations.erase(it);
|
||||
}
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
if (request) {
|
||||
if (r)
|
||||
request->Success (r);
|
||||
request->Success(r);
|
||||
else
|
||||
request->Fail ();
|
||||
request->Fail();
|
||||
}
|
||||
}
|
||||
|
||||
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 ())
|
||||
auto it = m_RequestedDestinations.find(ident);
|
||||
if (it != m_RequestedDestinations.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NetDbRequests::ManageRequests ()
|
||||
{
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
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 ();)
|
||||
{
|
||||
auto& dest = it->second;
|
||||
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
|
||||
if (ts < dest->GetCreationTime() + 60) // request is worthless after 1 minute
|
||||
{
|
||||
if (ts > dest->GetCreationTime () + 5) // no response for 5 seconds
|
||||
if (ts > dest->GetCreationTime() + 5) // no response for 5 seconds
|
||||
{
|
||||
auto count = dest->GetExcludedPeers ().size ();
|
||||
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 count = dest->GetExcludedPeers().size();
|
||||
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());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
||||
dest->CreateRequestMessage (nextFloodfill, inbound));
|
||||
else
|
||||
{
|
||||
outbound->SendTunnelDataMsg(nextFloodfill->GetIdentHash(), 0,
|
||||
dest->CreateRequestMessage(nextFloodfill, inbound));
|
||||
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");
|
||||
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
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||
} else {
|
||||
if (!dest->IsExploratory())
|
||||
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)
|
||||
it = m_RequestedDestinations.erase (it);
|
||||
it = m_RequestedDestinations.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,34 +15,44 @@
|
|||
#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;
|
||||
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); };
|
||||
RequestedDestination(const IdentHash &destination, bool isExploratory = false) :
|
||||
m_Destination(destination), m_IsExploratory(isExploratory), m_CreationTime(0) {};
|
||||
|
||||
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 (const IdentHash& floodfill);
|
||||
~RequestedDestination() { if (m_RequestComplete) m_RequestComplete(nullptr); };
|
||||
|
||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
||||
void Success (std::shared_ptr<RouterInfo> r);
|
||||
void Fail ();
|
||||
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(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,24 +63,28 @@ namespace data
|
|||
RequestComplete m_RequestComplete;
|
||||
};
|
||||
|
||||
class NetDbRequests
|
||||
{
|
||||
class NetDbRequests {
|
||||
public:
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
void Start();
|
||||
|
||||
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 ();
|
||||
void Stop();
|
||||
|
||||
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:
|
||||
|
||||
mutable std::mutex m_RequestedDestinationsMutex;
|
||||
std::map<IdentHash, std::shared_ptr<RequestedDestination> > m_RequestedDestinations;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,17 +9,14 @@
|
|||
#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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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,40 +53,37 @@ namespace crypto
|
|||
return *this;
|
||||
}
|
||||
|
||||
Block & operator %=(const LongBlock & other)
|
||||
{
|
||||
Block &operator%=(const LongBlock &other) {
|
||||
unsigned long u;
|
||||
unsigned int i;
|
||||
u = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
u += other.data[i];
|
||||
data[i] = (unsigned char)u & 0xff;
|
||||
data[i] = (unsigned char) u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
u += other.data[16];
|
||||
data[16] = (unsigned char)u & 0x03;
|
||||
data[16] = (unsigned char) u & 0x03;
|
||||
u >>= 2;
|
||||
u += (u << 2);
|
||||
for (i = 0; i < 16; i++) {
|
||||
u += data[i];
|
||||
data[i] = (unsigned char)u & 0xff;
|
||||
data[i] = (unsigned char) u & 0xff;
|
||||
u >>= 8;
|
||||
}
|
||||
data[16] += (unsigned char)u;
|
||||
data[16] += (unsigned char) u;
|
||||
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,
|
||||
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xfc
|
||||
};
|
||||
Block orig;
|
||||
|
@ -103,15 +92,14 @@ namespace crypto
|
|||
orig = *this;
|
||||
*this += minusp;
|
||||
neg = -(data[16] >> 7);
|
||||
for(i = 0; i < 17; i++)
|
||||
for (i = 0; i < 17; i++)
|
||||
data[i] ^= neg & (orig.data[i] ^ data[i]);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void PutKey(const uint64_t * key_l)
|
||||
{
|
||||
const uint8_t * key = (const uint8_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;
|
||||
data[2] = key[2] & 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,39 +144,34 @@ 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;
|
||||
if (want > sz) want = sz;
|
||||
memcpy(m_Buffer + m_Leftover, buf, want);
|
||||
sz -= want;
|
||||
buf += want;
|
||||
m_Leftover += want;
|
||||
if(m_Leftover < POLY1305_BLOCK_BYTES) return;
|
||||
if (m_Leftover < POLY1305_BLOCK_BYTES) return;
|
||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
||||
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)
|
||||
{
|
||||
memcpy(m_Buffer+m_Leftover, buf, 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;
|
||||
|
@ -205,11 +183,11 @@ namespace crypto
|
|||
/* h *= r */
|
||||
for (i = 0; i < 17; i++) {
|
||||
u = 0;
|
||||
for (j = 0; j <= i ; j++) {
|
||||
u += (unsigned short)m_H.data[j] * m_R.data[i - j];
|
||||
for (j = 0; j <= i; j++) {
|
||||
u += (unsigned short) m_H.data[j] * m_R.data[i - j];
|
||||
}
|
||||
for (j = i + 1; j < 17; j++) {
|
||||
unsigned long v = (unsigned short)m_H.data[j] * m_R.data[i + 17 - j];
|
||||
unsigned long v = (unsigned short) m_H.data[j] * m_R.data[i + 17 - j];
|
||||
v = ((v << 8) + (v << 6)); /* v *= (5 << 6); */
|
||||
u += v;
|
||||
}
|
||||
|
@ -222,14 +200,12 @@ 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++)
|
||||
for (; idx < POLY1305_BLOCK_BYTES; idx++)
|
||||
m_Buffer[idx] = 0;
|
||||
m_Final = 1;
|
||||
Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
|
||||
|
@ -253,8 +229,8 @@ namespace crypto
|
|||
uint8_t m_Final;
|
||||
};
|
||||
|
||||
void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
|
||||
}
|
||||
void Poly1305HMAC(uint64_t *out, const uint64_t *key, const uint8_t *buf, std::size_t sz);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -14,150 +14,128 @@
|
|||
#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)
|
||||
{
|
||||
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) {
|
||||
}
|
||||
|
||||
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 ()
|
||||
{
|
||||
m_LastUpdateTime = GetTime ();
|
||||
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);
|
||||
participation.put (PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
|
||||
participation.put (PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
|
||||
participation.put(PEER_PROFILE_PARTICIPATION_AGREED, m_NumTunnelsAgreed);
|
||||
participation.put(PEER_PROFILE_PARTICIPATION_DECLINED, m_NumTunnelsDeclined);
|
||||
participation.put(PEER_PROFILE_PARTICIPATION_NON_REPLIED, m_NumTunnelsNonReplied);
|
||||
boost::property_tree::ptree usage;
|
||||
usage.put (PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||
usage.put (PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||
usage.put(PEER_PROFILE_USAGE_TAKEN, m_NumTimesTaken);
|
||||
usage.put(PEER_PROFILE_USAGE_REJECTED, m_NumTimesRejected);
|
||||
// fill property tree
|
||||
boost::property_tree::ptree pt;
|
||||
pt.put (PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string (m_LastUpdateTime));
|
||||
pt.put_child (PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
||||
pt.put_child (PEER_PROFILE_SECTION_USAGE, usage);
|
||||
pt.put(PEER_PROFILE_LAST_UPDATE_TIME, boost::posix_time::to_simple_string(m_LastUpdateTime));
|
||||
pt.put_child(PEER_PROFILE_SECTION_PARTICIPATION, participation);
|
||||
pt.put_child(PEER_PROFILE_SECTION_USAGE, usage);
|
||||
|
||||
// save to file
|
||||
std::string ident = identHash.ToBase64 ();
|
||||
std::string ident = identHash.ToBase64();
|
||||
std::string path = m_ProfilesStorage.Path(ident);
|
||||
|
||||
try {
|
||||
boost::property_tree::write_ini (path, pt);
|
||||
} catch (std::exception& ex) {
|
||||
boost::property_tree::write_ini(path, pt);
|
||||
} catch (std::exception &ex) {
|
||||
/* boost exception verbose enough */
|
||||
LogPrint (eLogError, "Profiling: ", ex.what ());
|
||||
LogPrint(eLogError, "Profiling: ", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::Load (const IdentHash& identHash)
|
||||
{
|
||||
std::string ident = identHash.ToBase64 ();
|
||||
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
|
||||
{
|
||||
boost::property_tree::read_ini (path, pt);
|
||||
} catch (std::exception& ex)
|
||||
{
|
||||
try {
|
||||
boost::property_tree::read_ini(path, pt);
|
||||
} catch (std::exception &ex) {
|
||||
/* boost exception verbose enough */
|
||||
LogPrint (eLogError, "Profiling: ", ex.what ());
|
||||
LogPrint(eLogError, "Profiling: ", ex.what());
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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 {
|
||||
// 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);
|
||||
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);
|
||||
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
|
||||
*this = RouterProfile();
|
||||
}
|
||||
else
|
||||
*this = RouterProfile ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
|
||||
catch (std::exception &ex) {
|
||||
LogPrint(eLogError, "Profiling: Can't read profile ", ident, " :", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelBuildResponse (uint8_t ret)
|
||||
{
|
||||
UpdateTime ();
|
||||
void RouterProfile::TunnelBuildResponse(uint8_t ret) {
|
||||
UpdateTime();
|
||||
if (ret > 0)
|
||||
m_NumTunnelsDeclined++;
|
||||
else
|
||||
m_NumTunnelsAgreed++;
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelNonReplied ()
|
||||
{
|
||||
void RouterProfile::TunnelNonReplied() {
|
||||
m_NumTunnelsNonReplied++;
|
||||
UpdateTime ();
|
||||
UpdateTime();
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowPartcipationRate () const
|
||||
{
|
||||
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||
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);
|
||||
return m_NumTunnelsNonReplied > 10 * (total + 1);
|
||||
}
|
||||
|
||||
bool RouterProfile::IsBad ()
|
||||
{
|
||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
{
|
||||
bool RouterProfile::IsBad() {
|
||||
auto isBad = IsAlwaysDeclining() || IsLowPartcipationRate() /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10 * (m_NumTimesTaken + 1)) {
|
||||
// reset profile
|
||||
m_NumTunnelsAgreed = 0;
|
||||
m_NumTunnelsDeclined = 0;
|
||||
|
@ -168,27 +146,24 @@ namespace data
|
|||
return isBad;
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||
{
|
||||
auto profile = std::make_shared<RouterProfile> ();
|
||||
profile->Load (identHash); // if possible
|
||||
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);
|
||||
|
||||
std::vector<std::string> files;
|
||||
m_ProfilesStorage.Traverse(files);
|
||||
for (const auto& path: files) {
|
||||
for (const auto &path: files) {
|
||||
if (stat(path.c_str(), &st) != 0) {
|
||||
LogPrint(eLogWarning, "Profiling: Can't stat(): ", path);
|
||||
continue;
|
||||
|
@ -199,5 +174,5 @@ namespace data
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,29 +30,34 @@ 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;
|
||||
RouterProfile();
|
||||
|
||||
void Save (const IdentHash& identHash);
|
||||
void Load (const IdentHash& identHash);
|
||||
RouterProfile &operator=(const RouterProfile &) = default;
|
||||
|
||||
bool IsBad ();
|
||||
void Save(const IdentHash &identHash);
|
||||
|
||||
void TunnelBuildResponse (uint8_t ret);
|
||||
void TunnelNonReplied ();
|
||||
void Load(const IdentHash &identHash);
|
||||
|
||||
bool IsBad();
|
||||
|
||||
void TunnelBuildResponse(uint8_t ret);
|
||||
|
||||
void TunnelNonReplied();
|
||||
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime GetTime () const;
|
||||
void UpdateTime ();
|
||||
boost::posix_time::ptime GetTime() const;
|
||||
|
||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
bool IsLowPartcipationRate () const;
|
||||
bool IsLowReplyRate () const;
|
||||
void UpdateTime();
|
||||
|
||||
bool IsAlwaysDeclining() const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
|
||||
bool IsLowPartcipationRate() const;
|
||||
|
||||
bool IsLowReplyRate() const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -68,10 +71,12 @@ namespace data
|
|||
uint32_t m_NumTimesRejected;
|
||||
};
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
|
||||
void InitProfilesStorage ();
|
||||
void DeleteObsoleteProfiles ();
|
||||
}
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile(const IdentHash &identHash);
|
||||
|
||||
void InitProfilesStorage();
|
||||
|
||||
void DeleteObsoleteProfiles();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
121
libi2pd/Queue.h
121
libi2pd/Queue.h
|
@ -17,105 +17,88 @@
|
|||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
template<typename Element>
|
||||
class Queue
|
||||
{
|
||||
class Queue {
|
||||
public:
|
||||
|
||||
void Put (Element e)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
m_Queue.push (std::move(e));
|
||||
m_NonEmpty.notify_one ();
|
||||
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 ())
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
for (const auto& it: vec)
|
||||
m_Queue.push (std::move(it));
|
||||
m_NonEmpty.notify_one ();
|
||||
template<template<typename, typename...> class Container, typename... R>
|
||||
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));
|
||||
m_NonEmpty.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
Element GetNext ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe ();
|
||||
if (!el)
|
||||
{
|
||||
m_NonEmpty.wait (l);
|
||||
el = GetNonThreadSafe ();
|
||||
Element GetNext() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe();
|
||||
if (!el) {
|
||||
m_NonEmpty.wait(l);
|
||||
el = GetNonThreadSafe();
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
Element GetNextWithTimeout (int usec)
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe ();
|
||||
if (!el)
|
||||
{
|
||||
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
|
||||
el = GetNonThreadSafe ();
|
||||
Element GetNextWithTimeout(int usec) {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
auto el = GetNonThreadSafe();
|
||||
if (!el) {
|
||||
m_NonEmpty.wait_for(l, std::chrono::milliseconds(usec));
|
||||
el = GetNonThreadSafe();
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
void Wait ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
m_NonEmpty.wait (l);
|
||||
void Wait() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
m_NonEmpty.wait(l);
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
bool IsEmpty ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.empty ();
|
||||
bool IsEmpty() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.empty();
|
||||
}
|
||||
|
||||
int GetSize ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.size ();
|
||||
int GetSize() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.size();
|
||||
}
|
||||
|
||||
void WakeUp () { m_NonEmpty.notify_all (); };
|
||||
void WakeUp() { m_NonEmpty.notify_all(); };
|
||||
|
||||
Element Get ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe ();
|
||||
Element Get() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe();
|
||||
}
|
||||
|
||||
Element Peek ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe (true);
|
||||
Element Peek() {
|
||||
std::unique_lock <std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe(true);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Element GetNonThreadSafe (bool peek = false)
|
||||
{
|
||||
if (!m_Queue.empty ())
|
||||
{
|
||||
auto el = m_Queue.front ();
|
||||
Element GetNonThreadSafe(bool peek = false) {
|
||||
if (!m_Queue.empty()) {
|
||||
auto el = m_Queue.front();
|
||||
if (!peek)
|
||||
m_Queue.pop ();
|
||||
m_Queue.pop();
|
||||
return el;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -123,11 +106,11 @@ namespace util
|
|||
|
||||
private:
|
||||
|
||||
std::queue<Element> m_Queue;
|
||||
std::queue <Element> m_Queue;
|
||||
std::mutex m_QueueMutex;
|
||||
std::condition_variable m_NonEmpty;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,52 +27,44 @@
|
|||
#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://")
|
||||
{
|
||||
num = ReseedFromSU3Url (su3FileName); // from https URL
|
||||
}
|
||||
else
|
||||
{
|
||||
num = ProcessSU3File (su3FileName.c_str ());
|
||||
if (su3FileName.length() > 8 && su3FileName.substr(0, 8) == "https://") {
|
||||
num = ReseedFromSU3Url(su3FileName); // from https URL
|
||||
} 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
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", su3FileName);
|
||||
} else if (zipFileName.length() > 0) // bootstrap from ZIP file
|
||||
{
|
||||
int num = ProcessZIPFile (zipFileName.c_str ());
|
||||
int num = ProcessZIPFile(zipFileName.c_str());
|
||||
if (num == 0)
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from ", zipFileName);
|
||||
}
|
||||
else // bootstrap from reseed servers
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from ", zipFileName);
|
||||
} else // bootstrap from reseed servers
|
||||
{
|
||||
int num = ReseedFromServers ();
|
||||
int num = ReseedFromServers();
|
||||
if (num == 0)
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from servers");
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from servers");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,48 +72,48 @@ 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 (!reseedURLs.empty ())
|
||||
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 ())
|
||||
{
|
||||
LogPrint (eLogInfo, "Reseed: Yggdrasil is supported");
|
||||
std::string yggReseedURLs; i2p::config::GetOption("reseed.yggurls", yggReseedURLs);
|
||||
if (!yggReseedURLs.empty ())
|
||||
if (yggdrasil && !i2p::util::net::GetYggdrasilAddress().is_unspecified()) {
|
||||
LogPrint(eLogInfo, "Reseed: Yggdrasil is supported");
|
||||
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())
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: No reseed servers specified");
|
||||
if (httpsReseedHostList.empty() && yggReseedHostList.empty()) {
|
||||
LogPrint(eLogWarning, "Reseed: No reseed servers specified");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reseedRetries = 0;
|
||||
while (reseedRetries < 10)
|
||||
{
|
||||
auto ind = rand () % (httpsReseedHostList.size () + yggReseedHostList.size ());
|
||||
bool isHttps = ind < httpsReseedHostList.size ();
|
||||
while (reseedRetries < 10) {
|
||||
auto ind = rand() % (httpsReseedHostList.size() + yggReseedHostList.size());
|
||||
bool isHttps = ind < httpsReseedHostList.size();
|
||||
std::string reseedUrl = isHttps ? httpsReseedHostList[ind] :
|
||||
yggReseedHostList[ind - httpsReseedHostList.size ()];
|
||||
yggReseedHostList[ind - httpsReseedHostList.size()];
|
||||
reseedUrl += "i2pseeds.su3";
|
||||
auto num = ReseedFromSU3Url (reseedUrl, isHttps);
|
||||
auto num = ReseedFromSU3Url(reseedUrl, isHttps);
|
||||
if (num > 0) return num; // success
|
||||
reseedRetries++;
|
||||
}
|
||||
LogPrint (eLogWarning, "Reseed: Failed to reseed from servers after 10 attempts");
|
||||
LogPrint(eLogWarning, "Reseed: Failed to reseed from servers after 10 attempts");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -130,298 +122,274 @@ namespace data
|
|||
* @param url
|
||||
* @return number of entries added to netDb
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
std::stringstream s(su3);
|
||||
return ProcessSU3Stream (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: SU3 download failed");
|
||||
return ProcessSU3Stream(s);
|
||||
} 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
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
if (s.is_open())
|
||||
return ProcessSU3Stream(s);
|
||||
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 ())
|
||||
{
|
||||
s.seekg (0, std::ios::end);
|
||||
auto len = s.tellg ();
|
||||
s.seekg (0, std::ios::beg);
|
||||
return ProcessZIPStream (s, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
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 {
|
||||
LogPrint(eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char SU3_MAGIC_NUMBER[]="I2Psu3";
|
||||
int Reseeder::ProcessSU3Stream (std::istream& s)
|
||||
{
|
||||
const char SU3_MAGIC_NUMBER[] = "I2Psu3";
|
||||
|
||||
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))
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
|
||||
s.read(magicNumber, 7); // magic number and zero byte 6
|
||||
if (strcmp(magicNumber, SU3_MAGIC_NUMBER)) {
|
||||
LogPrint(eLogError, "Reseed: Unexpected SU3 magic number");
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // su3 file format version
|
||||
s.seekg(1, std::ios::cur); // su3 file format version
|
||||
SigningKeyType signatureType;
|
||||
s.read ((char *)&signatureType, 2); // signature type
|
||||
signatureType = be16toh (signatureType);
|
||||
s.read((char *) &signatureType, 2); // signature type
|
||||
signatureType = be16toh(signatureType);
|
||||
uint16_t signatureLength;
|
||||
s.read ((char *)&signatureLength, 2); // signature length
|
||||
signatureLength = be16toh (signatureLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
s.read((char *) &signatureLength, 2); // signature length
|
||||
signatureLength = be16toh(signatureLength);
|
||||
s.seekg(1, std::ios::cur); // unused
|
||||
uint8_t versionLength;
|
||||
s.read ((char *)&versionLength, 1); // version length
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
s.read((char *) &versionLength, 1); // version length
|
||||
s.seekg(1, std::ios::cur); // unused
|
||||
uint8_t signerIDLength;
|
||||
s.read ((char *)&signerIDLength, 1); // signer ID length
|
||||
s.read((char *) &signerIDLength, 1); // signer ID length
|
||||
uint64_t contentLength;
|
||||
s.read ((char *)&contentLength, 8); // content length
|
||||
contentLength = be64toh (contentLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
s.read((char *) &contentLength, 8); // content length
|
||||
contentLength = be64toh(contentLength);
|
||||
s.seekg(1, std::ios::cur); // unused
|
||||
uint8_t fileType;
|
||||
s.read ((char *)&fileType, 1); // file type
|
||||
s.read((char *) &fileType, 1); // file type
|
||||
if (fileType != 0x00) // zip file
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
|
||||
LogPrint(eLogError, "Reseed: Can't handle file type ", (int) fileType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
s.seekg(1, std::ios::cur); // unused
|
||||
uint8_t contentType;
|
||||
s.read ((char *)&contentType, 1); // content type
|
||||
s.read((char *) &contentType, 1); // content type
|
||||
if (contentType != 0x03) // reseed data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
|
||||
LogPrint(eLogError, "Reseed: Unexpected content type ", (int) contentType);
|
||||
return 0;
|
||||
}
|
||||
s.seekg (12, std::ios::cur); // unused
|
||||
s.seekg(12, std::ios::cur); // unused
|
||||
|
||||
s.seekg (versionLength, std::ios::cur); // skip version
|
||||
s.seekg(versionLength, std::ios::cur); // skip version
|
||||
char signerID[256];
|
||||
s.read (signerID, signerIDLength); // signerID
|
||||
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 ())
|
||||
{
|
||||
auto it = m_SigningKeys.find(signerID);
|
||||
if (it != m_SigningKeys.end()) {
|
||||
// TODO: implement all signature types
|
||||
if (signatureType == SIGNING_KEY_TYPE_RSA_SHA512_4096)
|
||||
{
|
||||
size_t pos = s.tellg ();
|
||||
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];
|
||||
s.seekg (0, std::ios::beg);
|
||||
s.read ((char *)tbs, tbsLen);
|
||||
uint8_t * signature = new uint8_t[signatureLength];
|
||||
s.read ((char *)signature, signatureLength);
|
||||
uint8_t *tbs = new uint8_t[tbsLen];
|
||||
s.seekg(0, std::ios::beg);
|
||||
s.read((char *) tbs, tbsLen);
|
||||
uint8_t *signature = new uint8_t[signatureLength];
|
||||
s.read((char *) signature, signatureLength);
|
||||
// RSA-raw
|
||||
{
|
||||
// calculate digest
|
||||
uint8_t digest[64];
|
||||
SHA512 (tbs, tbsLen, digest);
|
||||
SHA512(tbs, tbsLen, digest);
|
||||
// encrypt signature
|
||||
BN_CTX * bnctx = BN_CTX_new ();
|
||||
BIGNUM * s = BN_new (), * n = BN_new ();
|
||||
BN_bin2bn (signature, signatureLength, s);
|
||||
BN_bin2bn (it->second, 512, n); // RSA 4096 assumed
|
||||
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
|
||||
uint8_t * enSigBuf = new uint8_t[signatureLength];
|
||||
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
|
||||
BN_CTX *bnctx = BN_CTX_new();
|
||||
BIGNUM *s = BN_new(), *n = BN_new();
|
||||
BN_bin2bn(signature, signatureLength, s);
|
||||
BN_bin2bn(it->second, 512, n); // RSA 4096 assumed
|
||||
BN_mod_exp(s, s, i2p::crypto::GetRSAE(), n, bnctx); // s = s^e mod n
|
||||
uint8_t *enSigBuf = new uint8_t[signatureLength];
|
||||
i2p::crypto::bn2buf(s, enSigBuf, signatureLength);
|
||||
// digest is right aligned
|
||||
// we can't use RSA_verify due wrong padding in SU3
|
||||
if (memcmp (enSigBuf + (signatureLength - 64), digest, 64))
|
||||
LogPrint (eLogWarning, "Reseed: SU3 signature verification failed");
|
||||
if (memcmp(enSigBuf + (signatureLength - 64), digest, 64))
|
||||
LogPrint(eLogWarning, "Reseed: SU3 signature verification failed");
|
||||
else
|
||||
verify = false; // verified
|
||||
delete[] enSigBuf;
|
||||
BN_free (s); BN_free (n);
|
||||
BN_CTX_free (bnctx);
|
||||
BN_free(s);
|
||||
BN_free(n);
|
||||
BN_CTX_free(bnctx);
|
||||
}
|
||||
|
||||
delete[] signature;
|
||||
delete[] tbs;
|
||||
s.seekg (pos, std::ios::beg);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
|
||||
s.seekg(pos, std::ios::beg);
|
||||
} else
|
||||
LogPrint(eLogWarning, "Reseed: Signature type ", signatureType, " is not supported");
|
||||
} else
|
||||
LogPrint(eLogWarning, "Reseed: Certificate for ", signerID, " not loaded");
|
||||
}
|
||||
|
||||
if (verify) // not verified
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: SU3 verification failed");
|
||||
LogPrint(eLogError, "Reseed: SU3 verification failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// handle content
|
||||
return ProcessZIPStream (s, contentLength);
|
||||
return ProcessZIPStream(s, contentLength);
|
||||
}
|
||||
|
||||
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 ())
|
||||
{
|
||||
size_t contentPos = s.tellg();
|
||||
while (!s.eof()) {
|
||||
uint32_t signature;
|
||||
s.read ((char *)&signature, 4);
|
||||
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
|
||||
s.seekg(2, std::ios::cur); // version
|
||||
uint16_t bitFlag;
|
||||
s.read ((char *)&bitFlag, 2);
|
||||
s.read((char *) &bitFlag, 2);
|
||||
bitFlag = le16toh (bitFlag);
|
||||
uint16_t compressionMethod;
|
||||
s.read ((char *)&compressionMethod, 2);
|
||||
s.read((char *) &compressionMethod, 2);
|
||||
compressionMethod = le16toh (compressionMethod);
|
||||
s.seekg (4, std::ios::cur); // skip fields we don't care about
|
||||
s.seekg(4, std::ios::cur); // skip fields we don't care about
|
||||
uint32_t compressedSize, uncompressedSize;
|
||||
uint32_t crc_32;
|
||||
s.read ((char *)&crc_32, 4);
|
||||
s.read((char *) &crc_32, 4);
|
||||
crc_32 = le32toh (crc_32);
|
||||
s.read ((char *)&compressedSize, 4);
|
||||
s.read((char *) &compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize);
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
s.read((char *) &uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
uint16_t fileNameLength, extraFieldLength;
|
||||
s.read ((char *)&fileNameLength, 2);
|
||||
s.read((char *) &fileNameLength, 2);
|
||||
fileNameLength = le16toh (fileNameLength);
|
||||
if ( fileNameLength > 255 ) {
|
||||
if (fileNameLength > 255) {
|
||||
// too big
|
||||
LogPrint(eLogError, "Reseed: SU3 fileNameLength too large: ", fileNameLength);
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&extraFieldLength, 2);
|
||||
s.read((char *) &extraFieldLength, 2);
|
||||
extraFieldLength = le16toh (extraFieldLength);
|
||||
char localFileName[255];
|
||||
s.read (localFileName, fileNameLength);
|
||||
s.read(localFileName, fileNameLength);
|
||||
localFileName[fileNameLength] = 0;
|
||||
s.seekg (extraFieldLength, std::ios::cur);
|
||||
s.seekg(extraFieldLength, std::ios::cur);
|
||||
// take care about data descriptor if presented
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
|
||||
{
|
||||
size_t pos = s.tellg ();
|
||||
if (!FindZipDataDescriptor (s))
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) {
|
||||
size_t pos = s.tellg();
|
||||
if (!FindZipDataDescriptor(s)) {
|
||||
LogPrint(eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&crc_32, 4);
|
||||
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
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
s.read((char *) &compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize) +
|
||||
4; // ??? we must consider signature as part of compressed data
|
||||
s.read((char *) &uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
|
||||
// now we know compressed and uncompressed size
|
||||
s.seekg (pos, std::ios::beg); // back to compressed data
|
||||
s.seekg(pos, std::ios::beg); // back to compressed data
|
||||
}
|
||||
|
||||
LogPrint (eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes");
|
||||
if (!compressedSize)
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
LogPrint(eLogDebug, "Reseed: Processing file ", localFileName, " ", compressedSize, " bytes");
|
||||
if (!compressedSize) {
|
||||
LogPrint(eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t * compressed = new uint8_t[compressedSize];
|
||||
s.read ((char *)compressed, compressedSize);
|
||||
uint8_t *compressed = new uint8_t[compressedSize];
|
||||
s.read((char *) compressed, compressedSize);
|
||||
if (compressionMethod) // we assume Deflate
|
||||
{
|
||||
z_stream inflator;
|
||||
memset (&inflator, 0, sizeof (inflator));
|
||||
inflateInit2 (&inflator, -MAX_WBITS); // no zlib header
|
||||
uint8_t * uncompressed = new uint8_t[uncompressedSize];
|
||||
memset(&inflator, 0, sizeof(inflator));
|
||||
inflateInit2(&inflator, -MAX_WBITS); // no zlib header
|
||||
uint8_t *uncompressed = new uint8_t[uncompressedSize];
|
||||
inflator.next_in = compressed;
|
||||
inflator.avail_in = compressedSize;
|
||||
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)
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
|
||||
if (crc32(0, uncompressed, uncompressedSize) == crc_32) {
|
||||
i2p::data::netdb.AddRouterInfo(uncompressed, uncompressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: CRC32 verification failed");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: CRC32 verification failed");
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: SU3 decompression error ", err);
|
||||
delete[] uncompressed;
|
||||
inflateEnd (&inflator);
|
||||
}
|
||||
else // no compression
|
||||
inflateEnd(&inflator);
|
||||
} else // no compression
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
|
||||
i2p::data::netdb.AddRouterInfo(compressed, compressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
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
|
||||
{
|
||||
s.seekg(12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
|
||||
} else {
|
||||
if (signature != ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE)
|
||||
LogPrint (eLogWarning, "Reseed: Missing zip central directory header");
|
||||
LogPrint(eLogWarning, "Reseed: Missing zip central directory header");
|
||||
break; // no more files
|
||||
}
|
||||
size_t end = s.tellg ();
|
||||
size_t end = s.tellg();
|
||||
if (end - contentPos >= contentLength)
|
||||
break; // we are beyond contentLength
|
||||
}
|
||||
if (numFiles) // check if routers are not outdated
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch();
|
||||
int numOutdated = 0;
|
||||
i2p::data::netdb.VisitRouterInfos (
|
||||
[&numOutdated, ts](std::shared_ptr<const RouterInfo> r)
|
||||
i2p::data::netdb.VisitRouterInfos(
|
||||
[&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++;
|
||||
}
|
||||
});
|
||||
if (numOutdated > numFiles/2) // more than half
|
||||
if (numOutdated > numFiles / 2) // more than half
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Mammoth's shit\n"
|
||||
LogPrint(eLogError, "Reseed: Mammoth's shit\n"
|
||||
" *_____*\n"
|
||||
" *_*****_*\n"
|
||||
" *_(O)_(O)_*\n"
|
||||
|
@ -430,74 +398,65 @@ namespace data
|
|||
" **_________**\n"
|
||||
" *_________*\n"
|
||||
" ***___***");
|
||||
i2p::data::netdb.ClearRouterInfos ();
|
||||
i2p::data::netdb.ClearRouterInfos();
|
||||
numFiles = 0;
|
||||
}
|
||||
}
|
||||
return numFiles;
|
||||
}
|
||||
|
||||
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
|
||||
bool Reseeder::FindZipDataDescriptor (std::istream& s)
|
||||
{
|
||||
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = {0x50, 0x4B, 0x07, 0x08};
|
||||
|
||||
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])
|
||||
{
|
||||
s.read((char *) &nextByte, 1);
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd]) {
|
||||
nextInd++;
|
||||
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
|
||||
if (nextInd >= sizeof(ZIP_DATA_DESCRIPTOR_SIGNATURE))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
} else
|
||||
nextInd = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
X509 * cert = SSL_get_certificate (ssl);
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
X509_NAME_oneline(X509_get_issuer_name(cert), name, 100);
|
||||
char *cn = strstr(name, "CN=");
|
||||
if (cn) {
|
||||
cn += 3;
|
||||
char * terminator = strchr (cn, '/');
|
||||
char *terminator = strchr(cn, '/');
|
||||
if (terminator) terminator[0] = 0;
|
||||
}
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
const RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const BIGNUM * n, * e, * d;
|
||||
const RSA *key = EVP_PKEY_get0_RSA(X509_get_pubkey(cert));
|
||||
const BIGNUM *n, *e, *d;
|
||||
RSA_get0_key(key, &n, &e, &d);
|
||||
PublicKey value;
|
||||
i2p::crypto::bn2buf (n, value, 512);
|
||||
i2p::crypto::bn2buf(n, value, 512);
|
||||
if (cn)
|
||||
m_SigningKeys[cn] = value;
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
|
||||
LogPrint(eLogError, "Reseed: Can't find CN field in ", filename);
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_free(ssl);
|
||||
} 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;
|
||||
|
@ -508,25 +467,25 @@ namespace data
|
|||
return;
|
||||
}
|
||||
|
||||
for (const std::string & file : files) {
|
||||
for (const std::string &file: files) {
|
||||
if (file.compare(file.size() - 4, 4, ".crt") != 0) {
|
||||
LogPrint(eLogWarning, "Reseed: Ignoring file ", file);
|
||||
continue;
|
||||
}
|
||||
LoadCertificate (file);
|
||||
LoadCertificate(file);
|
||||
numCertificates++;
|
||||
}
|
||||
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
|
||||
LogPrint(eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
|
||||
}
|
||||
|
||||
std::string Reseeder::HttpsRequest (const std::string& address)
|
||||
{
|
||||
std::string Reseeder::HttpsRequest(const std::string &address) {
|
||||
i2p::http::URL proxyUrl;
|
||||
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()) {
|
||||
if (proxy.size()) {
|
||||
// parse
|
||||
if(proxyUrl.parse(proxy)) {
|
||||
if (proxyUrl.parse(proxy)) {
|
||||
if (proxyUrl.schema == "http" && !proxyUrl.port) {
|
||||
proxyUrl.port = 80;
|
||||
} else if (proxyUrl.schema == "socks" && !proxyUrl.port) {
|
||||
|
@ -556,28 +515,24 @@ namespace data
|
|||
|
||||
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23);
|
||||
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> s(service, ctx);
|
||||
boost::asio::ssl::stream <boost::asio::ip::tcp::socket> s(service, ctx);
|
||||
|
||||
if(proxyUrl.schema.size())
|
||||
{
|
||||
if (proxyUrl.schema.size()) {
|
||||
// proxy connection
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
s.lowest_layer().connect(*it, ecode);
|
||||
if(!ecode)
|
||||
{
|
||||
auto & sock = s.next_layer();
|
||||
if(proxyUrl.schema == "http")
|
||||
{
|
||||
if (!ecode) {
|
||||
auto &sock = s.next_layer();
|
||||
if (proxyUrl.schema == "http") {
|
||||
i2p::http::HTTPReq proxyReq;
|
||||
i2p::http::HTTPRes proxyRes;
|
||||
proxyReq.method = "CONNECT";
|
||||
proxyReq.version = "HTTP/1.1";
|
||||
proxyReq.uri = url.host + ":" + std::to_string(url.port);
|
||||
auto auth = i2p::http::CreateBasicAuthorizationString (proxyUrl.user, proxyUrl.pass);
|
||||
if (!auth.empty ())
|
||||
auto auth = i2p::http::CreateBasicAuthorizationString(proxyUrl.user, proxyUrl.pass);
|
||||
if (!auth.empty())
|
||||
proxyReq.AddHeader("Proxy-Authorization", auth);
|
||||
|
||||
boost::asio::streambuf writebuf, readbuf;
|
||||
|
@ -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,33 +589,29 @@ 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 "";
|
||||
}
|
||||
buf[4] = (uint8_t) hostsz;
|
||||
memcpy(buf+5, url.host.c_str(), hostsz);
|
||||
memcpy(buf + 5, url.host.c_str(), hostsz);
|
||||
sz += hostsz + 1;
|
||||
htobe16buf(buf+sz, url.port);
|
||||
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,70 +619,59 @@ 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)
|
||||
{
|
||||
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) {
|
||||
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 ()))
|
||||
{
|
||||
s.lowest_layer().connect (ep, ecode);
|
||||
if (!ecode)
|
||||
{
|
||||
if ((ep.address().is_v4() && i2p::context.SupportsV4()) ||
|
||||
(ep.address().is_v6() && i2p::context.SupportsV6())) {
|
||||
s.lowest_layer().connect(ep, ecode);
|
||||
if (!ecode) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
}
|
||||
if (!connected)
|
||||
{
|
||||
if (!connected) {
|
||||
LogPrint(eLogError, "Reseed: Failed to connect to ", url.host);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
|
||||
return ReseedRequest (s, url.to_string());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SSL handshake failed: ", ecode.message ());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to ", url.host, ": ", ecode.message ());
|
||||
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) {
|
||||
LogPrint(eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
|
||||
return ReseedRequest(s, url.to_string());
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: SSL handshake failed: ", ecode.message());
|
||||
} 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;
|
||||
req.AddHeader("User-Agent", "Wget/1.11.4");
|
||||
req.AddHeader("Connection", "close");
|
||||
s.write_some (boost::asio::buffer (req.to_string()));
|
||||
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);
|
||||
l = s.read_some(boost::asio::buffer(recv_buf, sizeof(recv_buf)), ecode);
|
||||
if (l) rs.write(recv_buf, l);
|
||||
} while (!ecode && l);
|
||||
// process response
|
||||
std::string data = rs.str();
|
||||
|
@ -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 "";
|
||||
}
|
||||
|
@ -780,19 +712,17 @@ namespace data
|
|||
boost::asio::io_service service;
|
||||
boost::asio::ip::tcp::socket s(service, boost::asio::ip::tcp::v6());
|
||||
|
||||
if (url.host.length () < 2) return ""; // assume []
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
|
||||
return ReseedRequest (s, url.to_string());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message ());
|
||||
if (url.host.length() < 2) return ""; // assume []
|
||||
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) {
|
||||
LogPrint(eLogDebug, "Reseed: Connected to Yggdrasil ", url.host, ":", url.port);
|
||||
return ReseedRequest(s, url.to_string());
|
||||
} else
|
||||
LogPrint(eLogError, "Reseed: Couldn't connect to Yggdrasil ", url.host, ": ", ecode.message());
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,46 +16,52 @@
|
|||
#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 ();
|
||||
~Reseeder();
|
||||
|
||||
void Bootstrap();
|
||||
|
||||
int ReseedFromServers();
|
||||
|
||||
int ProcessSU3File(const char *filename);
|
||||
|
||||
int ProcessZIPFile(const char *filename);
|
||||
|
||||
void LoadCertificates();
|
||||
|
||||
private:
|
||||
|
||||
int ReseedFromSU3Url (const std::string& url, bool isHttps = true);
|
||||
void LoadCertificate (const std::string& filename);
|
||||
int ReseedFromSU3Url(const std::string &url, bool isHttps = true);
|
||||
|
||||
int ProcessSU3Stream (std::istream& s);
|
||||
int ProcessZIPStream (std::istream& s, uint64_t contentLength);
|
||||
void LoadCertificate(const std::string &filename);
|
||||
|
||||
bool FindZipDataDescriptor (std::istream& s);
|
||||
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);
|
||||
|
||||
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);
|
||||
std::string ReseedRequest(Stream &s, const std::string &uri);
|
||||
|
||||
private:
|
||||
|
||||
std::map<std::string, PublicKey> m_SigningKeys;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,12 +19,10 @@
|
|||
#include "RouterInfo.h"
|
||||
#include "Garlic.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace garlic
|
||||
{
|
||||
namespace i2p {
|
||||
namespace garlic {
|
||||
class RouterIncomingRatchetSession;
|
||||
}
|
||||
}
|
||||
|
||||
const char ROUTER_INFO[] = "router.info";
|
||||
const char ROUTER_KEYS[] = "router.keys";
|
||||
|
@ -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];
|
||||
|
@ -71,124 +64,196 @@ namespace garlic
|
|||
|
||||
public:
|
||||
|
||||
RouterContext ();
|
||||
void Init ();
|
||||
RouterContext();
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
i2p::data::LocalRouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
std::shared_ptr<i2p::data::RouterInfo> GetSharedRouterInfo ()
|
||||
{
|
||||
return std::shared_ptr<i2p::data::RouterInfo> (&m_RouterInfo,
|
||||
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() {
|
||||
return std::shared_ptr<i2p::data::RouterInfo>(&m_RouterInfo,
|
||||
[](i2p::data::RouterInfo *) {});
|
||||
}
|
||||
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
|
||||
{
|
||||
return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
|
||||
|
||||
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 * GetNTCP2IV () const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
||||
i2p::crypto::X25519Keys& GetNTCP2StaticKeys ();
|
||||
const uint8_t *GetNTCP2StaticPublicKey() const { return m_NTCP2Keys ? m_NTCP2Keys->staticPublicKey : nullptr; };
|
||||
|
||||
const uint8_t * GetSSU2StaticPublicKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPublicKey : nullptr; };
|
||||
const uint8_t * GetSSU2StaticPrivateKey () const { return m_SSU2Keys ? m_SSU2Keys->staticPrivateKey : nullptr; };
|
||||
const uint8_t * GetSSU2IntroKey () const { return m_SSU2Keys ? m_SSU2Keys->intro : nullptr; };
|
||||
i2p::crypto::X25519Keys& GetSSU2StaticKeys ();
|
||||
const uint8_t *GetNTCP2StaticPrivateKey() const {
|
||||
return m_NTCP2Keys ? m_NTCP2Keys->staticPrivateKey : nullptr;
|
||||
};
|
||||
|
||||
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; };
|
||||
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; };
|
||||
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);
|
||||
const uint8_t *GetNTCP2IV() const { return m_NTCP2Keys ? m_NTCP2Keys->iv : nullptr; };
|
||||
|
||||
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; };
|
||||
i2p::crypto::X25519Keys &GetNTCP2StaticKeys();
|
||||
|
||||
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
|
||||
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;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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 () {};
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
void CreateNewRouter();
|
||||
|
||||
bool DecryptECIESTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, size_t clearTextSize);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
|
|
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,9 +95,8 @@ namespace data
|
|||
};
|
||||
|
||||
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
|
||||
struct Introducer
|
||||
{
|
||||
Introducer (): iPort (0), iExp (0) {};
|
||||
struct Introducer {
|
||||
Introducer() : iPort(0), iExp(0) {};
|
||||
boost::asio::ip::address iHost;
|
||||
int iPort;
|
||||
IntroKey iKey; // or ih for SSU2
|
||||
|
@ -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,167 +119,260 @@ namespace data
|
|||
bool published = false;
|
||||
std::unique_ptr<SSUExt> ssu; // not null for SSU
|
||||
|
||||
bool IsCompatible (const boost::asio::ip::address& other) const
|
||||
{
|
||||
return (IsV4 () && other.is_v4 ()) ||
|
||||
(IsV6 () && other.is_v6 ());
|
||||
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 IsNTCP2() const { return transportStyle == eTransportNTCP; };
|
||||
|
||||
bool IsIntroducer () const { return caps & eSSUIntroducer; };
|
||||
bool IsPeerTesting () const { return caps & eSSUTesting; };
|
||||
bool IsSSU2() const { return transportStyle == eTransportSSU2; };
|
||||
|
||||
bool IsV4 () const { return (caps & AddressCaps::eV4) || (host.is_v4 () && !host.is_unspecified ()); };
|
||||
bool IsV6 () const { return (caps & AddressCaps::eV6) || (host.is_v6 () && !host.is_unspecified ()); };
|
||||
bool 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);
|
||||
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 ();
|
||||
RouterInfo(const std::string &fullPath);
|
||||
|
||||
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
|
||||
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;
|
||||
RouterInfo(const RouterInfo &) = default;
|
||||
|
||||
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);
|
||||
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 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 IsReachableBy (CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
||||
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;
|
||||
RouterInfo &operator=(const RouterInfo &) = default;
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t caps) { m_Caps = caps; };
|
||||
RouterInfo(std::shared_ptr<Buffer> &&buf, size_t len);
|
||||
|
||||
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
|
||||
bool IsUnreachable () const { return m_IsUnreachable; };
|
||||
RouterInfo(const uint8_t *buf, size_t len);
|
||||
|
||||
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; };
|
||||
virtual ~RouterInfo();
|
||||
|
||||
bool IsUpdated () const { return m_IsUpdated; };
|
||||
void SetUpdated (bool updated) { m_IsUpdated = updated; };
|
||||
bool SaveToFile (const std::string& fullPath);
|
||||
std::shared_ptr<const IdentityEx> GetRouterIdentity() const { return m_RouterIdentity; };
|
||||
|
||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
|
||||
void SetRouterIdentity(std::shared_ptr<const IdentityEx> identity);
|
||||
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
void DeleteBuffer () { m_Buffer = nullptr; };
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
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
|
||||
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);
|
||||
|
||||
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 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 IsReachableBy(CompatibleTransports transports) const { return m_ReachableTransports & transports; };
|
||||
|
||||
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 */
|
||||
bool IsFamily (FamilyID famid) const;
|
||||
bool IsFamily(FamilyID famid) const;
|
||||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };
|
||||
void Encrypt (const uint8_t * data, uint8_t * encrypted) const;
|
||||
std::shared_ptr<const IdentityEx> GetIdentity() const { return m_RouterIdentity; };
|
||||
|
||||
bool IsDestination () const { return false; };
|
||||
void Encrypt(const uint8_t *data, uint8_t *encrypted) const;
|
||||
|
||||
bool IsDestination() const { return false; };
|
||||
|
||||
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; };
|
||||
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;
|
||||
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;
|
||||
std::shared_ptr<const Address> GetAddress(Filter filter) const;
|
||||
|
||||
virtual std::shared_ptr<Buffer> NewBuffer() const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -298,7 +381,7 @@ namespace data
|
|||
std::shared_ptr<Buffer> m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
uint64_t m_Timestamp;
|
||||
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
boost::shared_ptr <Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
CompatibleTransports m_SupportedTransports, m_ReachableTransports;
|
||||
uint8_t m_Caps;
|
||||
|
@ -306,34 +389,42 @@ 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);
|
||||
LocalRouterInfo() = default;
|
||||
|
||||
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 (); };
|
||||
void CreateBuffer(const PrivateKeys &privateKeys);
|
||||
|
||||
bool AddSSU2Introducer (const Introducer& introducer, bool v4);
|
||||
bool RemoveSSU2Introducer (const IdentHash& h, bool v4);
|
||||
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;
|
||||
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:
|
||||
|
||||
std::map<std::string, std::string> m_Properties;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1067
libi2pd/SSU.cpp
1067
libi2pd/SSU.cpp
File diff suppressed because it is too large
Load diff
188
libi2pd/SSU.h
188
libi2pd/SSU.h
|
@ -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,99 +36,145 @@ 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,
|
||||
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,
|
||||
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);
|
||||
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; };
|
||||
void CreateDirectSession(std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
|
||||
|
||||
uint16_t GetPort () const { return m_Endpoint.port (); };
|
||||
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
|
||||
void SetLocalAddress (const boost::asio::ip::address& localAddress);
|
||||
std::shared_ptr<SSUSession> FindSession(const boost::asio::ip::udp::endpoint &e) const;
|
||||
|
||||
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 ();
|
||||
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session(std::shared_ptr<const SSUSession> excluded);
|
||||
|
||||
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);
|
||||
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 HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
|
||||
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 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);
|
||||
|
||||
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> address, bool peerTest = false);
|
||||
template<typename Filter>
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session(Filter filter);
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
|
||||
std::shared_ptr<SSUSession> GetRandomV6Session(Filter filter);
|
||||
|
||||
std::list<std::shared_ptr<SSUSession> > FindIntroducers (int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash>& excluded);
|
||||
void ScheduleIntroducersUpdateTimer ();
|
||||
void ScheduleIntroducersUpdateTimerV6 ();
|
||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
||||
std::list<std::shared_ptr<SSUSession> >
|
||||
FindIntroducers(int maxNumIntroducers, bool v4, std::set<i2p::data::IdentHash> &excluded);
|
||||
|
||||
void SchedulePeerTestsCleanupTimer ();
|
||||
void HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode);
|
||||
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);
|
||||
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
|
||||
};
|
||||
|
||||
volatile bool m_IsRunning;
|
||||
std::thread * m_Thread, * m_ReceiversThread, * m_ReceiversThreadV6;
|
||||
std::thread *m_Thread, *m_ReceiversThread, *m_ReceiversThreadV6;
|
||||
boost::asio::io_service m_Service, m_ReceiversService, m_ReceiversServiceV6;
|
||||
boost::asio::io_service::work m_Work, m_ReceiversWork, m_ReceiversWorkV6;
|
||||
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
|
||||
|
@ -150,10 +194,16 @@ 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; };
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
1130
libi2pd/SSU2.cpp
1130
libi2pd/SSU2.cpp
File diff suppressed because it is too large
Load diff
172
libi2pd/SSU2.h
172
libi2pd/SSU2.h
|
@ -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,94 +24,129 @@ 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 (); };
|
||||
ReceiveService(const std::string &name) : RunnableService(name) {};
|
||||
|
||||
boost::asio::io_service &GetService() { return GetIOService(); };
|
||||
|
||||
void Start() { StartIOService(); };
|
||||
|
||||
void Stop() { StopIOService(); };
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
SSU2Server ();
|
||||
~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; };
|
||||
~SSU2Server() {};
|
||||
|
||||
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 Start();
|
||||
|
||||
void AddRelay (uint32_t tag, std::shared_ptr<SSU2Session> relay);
|
||||
void RemoveRelay (uint32_t tag);
|
||||
std::shared_ptr<SSU2Session> FindRelaySession (uint32_t tag);
|
||||
void Stop();
|
||||
|
||||
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);
|
||||
boost::asio::io_service &GetService() { return GetIOService(); };
|
||||
|
||||
bool CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
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);
|
||||
bool StartPeerTest(std::shared_ptr<const i2p::data::RouterInfo> router, bool v4);
|
||||
|
||||
void RescheduleIntroducersUpdateTimer ();
|
||||
void RescheduleIntroducersUpdateTimerV6 ();
|
||||
void UpdateOutgoingToken(const boost::asio::ip::udp::endpoint &ep, uint64_t token, uint32_t exp);
|
||||
|
||||
i2p::util::MemoryPool<SSU2SentPacket>& GetSentPacketsPool () { return m_SentPacketsPool; };
|
||||
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; };
|
||||
|
||||
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);
|
||||
boost::asio::ip::udp::socket &OpenSocket(const boost::asio::ip::udp::endpoint &localEndpoint);
|
||||
|
||||
void ScheduleTermination ();
|
||||
void HandleTerminationTimer (const boost::system::error_code& ecode);
|
||||
void Receive(boost::asio::ip::udp::socket &socket);
|
||||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
void HandleReceivedFrom(const boost::system::error_code &ecode, size_t bytes_transferred,
|
||||
Packet *packet, boost::asio::ip::udp::socket &socket);
|
||||
|
||||
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;
|
||||
void UpdateIntroducers (bool v4);
|
||||
void ScheduleIntroducersUpdateTimer ();
|
||||
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode, bool v4);
|
||||
void ScheduleIntroducersUpdateTimerV6 ();
|
||||
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;
|
||||
|
||||
void UpdateIntroducers(bool v4);
|
||||
|
||||
void ScheduleIntroducersUpdateTimer();
|
||||
|
||||
void HandleIntroducersUpdateTimer(const boost::system::error_code &ecode, bool v4);
|
||||
|
||||
void ScheduleIntroducersUpdateTimerV6();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -137,9 +170,12 @@ namespace transport
|
|||
public:
|
||||
|
||||
// for HTTP/I2PControl
|
||||
const decltype(m_Sessions)& GetSSU2Sessions () const { return m_Sessions; };
|
||||
const decltype(m_Sessions)
|
||||
&
|
||||
|
||||
GetSSU2Sessions() const { return m_Sessions; };
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -20,16 +20,14 @@
|
|||
#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
|
||||
const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust
|
||||
const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds
|
||||
const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds
|
||||
const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52 * 60; // for next token block, in seconds
|
||||
const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds
|
||||
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
|
||||
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 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,13 +124,12 @@ namespace transport
|
|||
eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70
|
||||
};
|
||||
|
||||
enum SSU2TerminationReason
|
||||
{
|
||||
enum SSU2TerminationReason {
|
||||
eSSU2TerminationReasonNormalClose = 0,
|
||||
eSSU2TerminationReasonTerminationReceived = 1,
|
||||
eSSU2TerminationReasonIdleTimeout = 2,
|
||||
eSSU2TerminationReasonRouterShutdown = 3,
|
||||
eSSU2TerminationReasonDataPhaseAEADFailure= 4,
|
||||
eSSU2TerminationReasonDataPhaseAEADFailure = 4,
|
||||
eSSU2TerminationReasonIncompatibleOptions = 5,
|
||||
eSSU2TerminationReasonTncompatibleSignatureType = 6,
|
||||
eSSU2TerminationReasonClockSkew = 7,
|
||||
|
@ -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;
|
||||
|
@ -172,11 +162,10 @@ namespace transport
|
|||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
std::map<int, std::shared_ptr<Fragment> > outOfSequenceFragments;
|
||||
|
||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
||||
void AttachNextFragment(const uint8_t *fragment, size_t fragmentSize);
|
||||
};
|
||||
|
||||
struct SSU2SentPacket
|
||||
{
|
||||
struct SSU2SentPacket {
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE];
|
||||
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,123 +190,200 @@ namespace transport
|
|||
} h;
|
||||
};
|
||||
|
||||
struct HandshakePacket
|
||||
{
|
||||
struct HandshakePacket {
|
||||
Header header;
|
||||
uint8_t headerX[48]; // part1 for SessionConfirmed
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE*2];
|
||||
uint8_t payload[SSU2_MAX_PACKET_SIZE * 2];
|
||||
size_t payloadSize = 0;
|
||||
uint64_t sendTime = 0; // in milliseconds
|
||||
bool isSecondFragment = false; // for SessionConfirmed
|
||||
};
|
||||
|
||||
typedef std::function<void ()> OnEstablished;
|
||||
typedef std::function<void()> OnEstablished;
|
||||
|
||||
public:
|
||||
|
||||
SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
||||
SSU2Session(SSU2Server &server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr,
|
||||
std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr);
|
||||
~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; };
|
||||
~SSU2Session();
|
||||
|
||||
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; };
|
||||
void SetRemoteEndpoint(const boost::asio::ip::udp::endpoint &ep) { m_RemoteEndpoint = ep; };
|
||||
|
||||
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);
|
||||
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 Terminate();
|
||||
|
||||
void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len);
|
||||
void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len);
|
||||
void Established();
|
||||
|
||||
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 SendPathResponse (const uint8_t * data, size_t len);
|
||||
void ScheduleConnectTimer();
|
||||
|
||||
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);
|
||||
void HandleConnectTimer(const boost::system::error_code &ecode);
|
||||
|
||||
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 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 CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice
|
||||
size_t CreateTerminationBlock (uint8_t * buf, size_t len);
|
||||
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 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 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 CreatePeerTestBlock(uint8_t *buf, size_t len, uint32_t nonce); // Alice
|
||||
size_t CreateTerminationBlock(uint8_t *buf, size_t len);
|
||||
|
||||
private:
|
||||
|
||||
SSU2Server& m_Server;
|
||||
SSU2Server &m_Server;
|
||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
|
||||
std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment; // for Bob if applicable or second fragment for Alice
|
||||
|
@ -334,8 +398,8 @@ namespace transport
|
|||
std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num
|
||||
std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet
|
||||
std::map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // I2NP
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_PeerTests; // same as for relay sessions
|
||||
std::map<uint32_t, std::pair<std::shared_ptr<SSU2Session>, uint64_t> > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice
|
||||
std::map<uint32_t, std::pair<std::shared_ptr<SSU2Session>, uint64_t> > m_PeerTests; // same as for relay sessions
|
||||
std::list<std::shared_ptr<I2NPMessage> > m_SendQueue;
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
bool m_IsDataReceived;
|
||||
|
@ -347,13 +411,12 @@ 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);
|
||||
i2p::crypto::ChaCha20((uint8_t * ) & data, 8, kh, nonce, (uint8_t * ) & data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -13,129 +13,105 @@
|
|||
#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)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: I2NP message size ", msg->maxLen, " is not enough");
|
||||
auto newMsg = NewI2NPMessage ();
|
||||
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;
|
||||
msg = newMsg;
|
||||
}
|
||||
if (msg->Concat (fragment, fragmentSize) < fragmentSize)
|
||||
LogPrint (eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
|
||||
if (msg->Concat(fragment, fragmentSize) < fragmentSize)
|
||||
LogPrint(eLogError, "SSU: I2NP buffer overflow ", msg->maxLen);
|
||||
nextFragmentNum++;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
}
|
||||
|
||||
SSUData::~SSUData ()
|
||||
{
|
||||
SSUData::~SSUData() {
|
||||
}
|
||||
|
||||
void SSUData::Start ()
|
||||
{
|
||||
void SSUData::Start() {
|
||||
}
|
||||
|
||||
void SSUData::Stop ()
|
||||
{
|
||||
m_ResendTimer.cancel ();
|
||||
m_IncompleteMessages.clear ();
|
||||
m_SentMessages.clear ();
|
||||
m_ReceivedMessages.clear ();
|
||||
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 (m_Session.IsV6 ())
|
||||
auto ssuAddress = remoteRouter->GetSSUAddress();
|
||||
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
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
||||
LogPrint(eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
|
||||
} else {
|
||||
LogPrint(eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
||||
m_PacketSize = m_MaxPacketSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
|
||||
{
|
||||
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
|
||||
void SSUData::UpdatePacketSize(const i2p::data::IdentHash &remoteIdent) {
|
||||
auto routerInfo = i2p::data::netdb.FindRouter(remoteIdent);
|
||||
if (routerInfo)
|
||||
AdjustPacketSize (routerInfo);
|
||||
AdjustPacketSize(routerInfo);
|
||||
}
|
||||
|
||||
void SSUData::ProcessSentMessageAck (uint32_t msgID)
|
||||
{
|
||||
auto it = m_SentMessages.find (msgID);
|
||||
if (it != m_SentMessages.end ())
|
||||
{
|
||||
m_SentMessages.erase (it);
|
||||
if (m_SentMessages.empty ())
|
||||
m_ResendTimer.cancel ();
|
||||
void SSUData::ProcessSentMessageAck(uint32_t msgID) {
|
||||
auto it = m_SentMessages.find(msgID);
|
||||
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;
|
||||
uint8_t numAcks = *buf;
|
||||
buf++;
|
||||
for (int i = 0; i < numAcks; i++)
|
||||
ProcessSentMessageAck (bufbe32toh (buf+i*4));
|
||||
buf += numAcks*4;
|
||||
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;
|
||||
uint8_t numBitfields = *buf;
|
||||
buf++;
|
||||
for (int i = 0; i < numBitfields; i++)
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (buf);
|
||||
for (int i = 0; i < numBitfields; i++) {
|
||||
uint32_t msgID = bufbe32toh(buf);
|
||||
buf += 4; // msgID
|
||||
auto it = m_SentMessages.find (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 ())
|
||||
{
|
||||
int numSentFragments = it->second->fragments.size ();
|
||||
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,195 +120,172 @@ 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++)
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (buf); // message ID
|
||||
for (int i = 0; i < numFragments; i++) {
|
||||
uint32_t msgID = bufbe32toh(buf); // message ID
|
||||
buf += 4;
|
||||
uint8_t frag[4] = {0};
|
||||
memcpy (frag + 1, buf, 3);
|
||||
memcpy(frag + 1, buf, 3);
|
||||
buf += 3;
|
||||
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
|
||||
uint32_t fragmentInfo = bufbe32toh(frag); // fragment info
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU 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 ())
|
||||
{
|
||||
auto it = m_IncompleteMessages.find(msgID);
|
||||
if (it == m_IncompleteMessages.end()) {
|
||||
// create new message
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
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;
|
||||
it = m_IncompleteMessages.insert(std::make_pair(msgID,
|
||||
m_Session.GetServer().GetIncompleteMessagesPool().AcquireShared(
|
||||
std::move(msg)))).first;
|
||||
}
|
||||
auto& incompleteMessage = it->second;
|
||||
auto &incompleteMessage = it->second;
|
||||
// mark fragment as received
|
||||
if (fragmentNum < 64)
|
||||
incompleteMessage->receivedFragmentsBits |= (uint64_t(0x01) << fragmentNum);
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Fragment number ", fragmentNum, " exceeds 64");
|
||||
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 ())
|
||||
{
|
||||
incompleteMessage->AttachNextFragment(buf, fragmentSize);
|
||||
if (!isLast && !incompleteMessage->savedFragments.empty()) {
|
||||
// try saved fragments
|
||||
for (auto it1 = incompleteMessage->savedFragments.begin (); it1 != incompleteMessage->savedFragments.end ();)
|
||||
{
|
||||
auto& savedFragment = *it1;
|
||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum)
|
||||
{
|
||||
incompleteMessage->AttachNextFragment (savedFragment->buf, savedFragment->len);
|
||||
for (auto it1 = incompleteMessage->savedFragments.begin();
|
||||
it1 != incompleteMessage->savedFragments.end();) {
|
||||
auto &savedFragment = *it1;
|
||||
if (savedFragment->fragmentNum == incompleteMessage->nextFragmentNum) {
|
||||
incompleteMessage->AttachNextFragment(savedFragment->buf, savedFragment->len);
|
||||
isLast = savedFragment->isLast;
|
||||
incompleteMessage->savedFragments.erase (it1++);
|
||||
}
|
||||
else
|
||||
incompleteMessage->savedFragments.erase(it1++);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (isLast)
|
||||
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
|
||||
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);
|
||||
if (incompleteMessage->savedFragments.insert (savedFragment).second)
|
||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
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;
|
||||
m_IncompleteMessages.erase (msgID);
|
||||
m_IncompleteMessages.erase(msgID);
|
||||
// process message
|
||||
SendMsgAck (msgID);
|
||||
msg->FromSSU (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 ())
|
||||
{
|
||||
m_Handler.PutNextMessage (std::move (msg));
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU: message expired");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMsgAck(msgID);
|
||||
msg->FromSSU(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()) {
|
||||
m_Handler.PutNextMessage(std::move(msg));
|
||||
} else
|
||||
LogPrint(eLogDebug, "SSU: message expired");
|
||||
} else
|
||||
LogPrint(eLogWarning, "SSU: Message ", msgID, " already received");
|
||||
} else {
|
||||
// we expect DeliveryStatus
|
||||
if (msg->GetTypeID () == eI2NPDeliveryStatus)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: session established");
|
||||
m_Session.Established ();
|
||||
if (msg->GetTypeID() == eI2NPDeliveryStatus) {
|
||||
LogPrint(eLogDebug, "SSU: session established");
|
||||
m_Session.Established();
|
||||
} else
|
||||
LogPrint(eLogError, "SSU: unexpected message ", (int) msg->GetTypeID());
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
|
||||
}
|
||||
}
|
||||
else
|
||||
SendFragmentAck (msgID, incompleteMessage->receivedFragmentsBits);
|
||||
} else
|
||||
SendFragmentAck(msgID, incompleteMessage->receivedFragmentsBits);
|
||||
buf += fragmentSize;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::FlushReceivedMessage ()
|
||||
{
|
||||
m_Handler.Flush ();
|
||||
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++;
|
||||
LogPrint (eLogDebug, "SSU: Process data, flags=", (int)flag, ", len=", len);
|
||||
LogPrint(eLogDebug, "SSU: Process data, flags=", (int) flag, ", len=", len);
|
||||
// process acks if presented
|
||||
if (flag & (DATA_FLAG_ACK_BITFIELDS_INCLUDED | DATA_FLAG_EXPLICIT_ACKS_INCLUDED))
|
||||
ProcessAcks (buf, flag);
|
||||
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");
|
||||
LogPrint(eLogDebug, "SSU: extended data of ", extendedDataSize, " bytes present");
|
||||
buf += extendedDataSize;
|
||||
}
|
||||
// process data
|
||||
ProcessFragments (buf);
|
||||
ProcessFragments(buf);
|
||||
}
|
||||
|
||||
void SSUData::Send (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
uint32_t msgID = msg->ToSSU ();
|
||||
if (m_SentMessages.find (msgID) != m_SentMessages.end())
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
||||
void SSUData::Send(std::shared_ptr<i2p::I2NPMessage> msg) {
|
||||
uint32_t msgID = msg->ToSSU();
|
||||
if (m_SentMessages.find(msgID) != m_SentMessages.end()) {
|
||||
LogPrint(eLogWarning, "SSU: message ", msgID, " already sent");
|
||||
return;
|
||||
}
|
||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||
ScheduleResend ();
|
||||
if (m_SentMessages.empty()) // schedule resend at first message only
|
||||
ScheduleResend();
|
||||
|
||||
auto ret = m_SentMessages.emplace (msgID, m_Session.GetServer ().GetSentMessagesPool ().AcquireShared ());
|
||||
auto& sentMessage = ret.first->second;
|
||||
if (ret.second)
|
||||
{
|
||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
||||
auto ret = m_SentMessages.emplace(msgID, m_Session.GetServer().GetSentMessagesPool().AcquireShared());
|
||||
auto &sentMessage = ret.first->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 len = msg->GetLength ();
|
||||
uint8_t * msgBuf = msg->GetSSUHeader ();
|
||||
auto &fragments = sentMessage->fragments;
|
||||
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)
|
||||
{
|
||||
auto fragment = m_Session.GetServer ().GetFragmentsPool ().AcquireShared ();
|
||||
while (len > 0 && fragmentNum <= 127) {
|
||||
auto fragment = m_Session.GetServer().GetFragmentsPool().AcquireShared();
|
||||
fragment->fragmentNum = fragmentNum;
|
||||
uint8_t * payload = fragment->buf + sizeof (SSUHeader);
|
||||
uint8_t *payload = fragment->buf + sizeof(SSUHeader);
|
||||
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
|
||||
payload++;
|
||||
*payload = 1; // always 1 message fragment per message
|
||||
payload++;
|
||||
htobe32buf (payload, msgID);
|
||||
htobe32buf(payload, msgID);
|
||||
payload += 4;
|
||||
bool isLast = (len <= payloadSize) || fragmentNum == 127; // 127 fragments max
|
||||
size_t size = isLast ? len : payloadSize;
|
||||
|
@ -341,176 +294,155 @@ namespace transport
|
|||
fragmentInfo |= 0x010000;
|
||||
|
||||
fragmentInfo |= size;
|
||||
fragmentInfo = htobe32 (fragmentInfo);
|
||||
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
||||
fragmentInfo = htobe32(fragmentInfo);
|
||||
memcpy(payload, (uint8_t * )(&fragmentInfo) + 1, 3);
|
||||
payload += 3;
|
||||
memcpy (payload, msgBuf, size);
|
||||
memcpy(payload, msgBuf, size);
|
||||
|
||||
size += payload - fragment->buf;
|
||||
uint8_t rem = size & 0x0F;
|
||||
if (rem) // make sure 16 bytes boundary
|
||||
{
|
||||
auto padding = 16 - rem;
|
||||
memset (fragment->buf + size, 0, padding);
|
||||
memset(fragment->buf + size, 0, padding);
|
||||
size += padding;
|
||||
}
|
||||
fragment->len = size;
|
||||
fragments.push_back (fragment);
|
||||
fragments.push_back(fragment);
|
||||
|
||||
// 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
|
||||
{
|
||||
m_Session.Send (buf, size);
|
||||
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, fragment->buf, size, buf);
|
||||
try {
|
||||
m_Session.Send(buf, size);
|
||||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
|
||||
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);
|
||||
uint8_t *payload = buf + sizeof(SSUHeader);
|
||||
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
|
||||
payload++;
|
||||
*payload = 1; // number of ACKs
|
||||
payload++;
|
||||
htobe32buf (payload, msgID); // msgID
|
||||
htobe32buf(payload, msgID); // msgID
|
||||
payload += 4;
|
||||
*payload = 0; // number of fragments
|
||||
|
||||
// encrypt message with session key
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
||||
m_Session.Send (buf, 48);
|
||||
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, buf, 48);
|
||||
m_Session.Send(buf, 48);
|
||||
}
|
||||
|
||||
void SSUData::SendFragmentAck (uint32_t msgID, uint64_t bits)
|
||||
{
|
||||
void SSUData::SendFragmentAck(uint32_t msgID, uint64_t bits) {
|
||||
if (!bits) return;
|
||||
uint8_t buf[64 + 18] = {0};
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
uint8_t *payload = buf + sizeof(SSUHeader);
|
||||
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
||||
payload++;
|
||||
*payload = 1; // number of ACK bitfields
|
||||
payload++;
|
||||
// one ack
|
||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||
*(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
|
||||
// encrypt message with session key
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
||||
m_Session.Send (buf, len);
|
||||
m_Session.FillHeaderAndEncrypt(PAYLOAD_TYPE_DATA, buf, len);
|
||||
m_Session.Send(buf, len);
|
||||
}
|
||||
|
||||
void SSUData::ScheduleResend()
|
||||
{
|
||||
m_ResendTimer.cancel ();
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
|
||||
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 ();
|
||||
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& f: it->second->fragments)
|
||||
if (f)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, f->buf, f->len, buf);
|
||||
m_Session.Send (buf, f->len); // resend
|
||||
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 {
|
||||
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->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");
|
||||
it = m_SentMessages.erase(it);
|
||||
}
|
||||
} else
|
||||
++it;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU: message ", it->first, " has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
it = m_SentMessages.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
if (m_SentMessages.empty ()) return; // nothing to resend
|
||||
if (m_SentMessages.empty()) return; // nothing to resend
|
||||
if (numResent < MAX_OUTGOING_WINDOW_SIZE)
|
||||
ScheduleResend ();
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
|
||||
m_Session.Close ();
|
||||
ScheduleResend();
|
||||
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");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
else
|
||||
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
|
||||
++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
|
||||
{
|
||||
m_ReceivedMessages.clear();
|
||||
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);
|
||||
it = m_ReceivedMessages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,79 +42,88 @@ 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); };
|
||||
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
|
||||
uint64_t receivedFragmentsBits;
|
||||
std::set<std::shared_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||
|
||||
IncompleteMessage (std::shared_ptr<I2NPMessage>&& m): msg (m), nextFragmentNum (0),
|
||||
lastFragmentInsertTime (0), receivedFragmentsBits (0) {};
|
||||
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
|
||||
IncompleteMessage(std::shared_ptr<I2NPMessage> &&m) : msg(m), nextFragmentNum(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 ();
|
||||
SSUData(SSUSession &session);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
void CleanUp (uint64_t ts);
|
||||
~SSUData();
|
||||
|
||||
void ProcessMessage (uint8_t * buf, size_t len);
|
||||
void FlushReceivedMessage ();
|
||||
void Send (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void Start();
|
||||
|
||||
void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
|
||||
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
|
||||
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 SendMsgAck(uint32_t msgID);
|
||||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
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:
|
||||
|
||||
SSUSession& m_Session;
|
||||
SSUSession &m_Session;
|
||||
std::map<uint32_t, std::shared_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||
std::map<uint32_t, std::shared_ptr<SentMessage> > m_SentMessages;
|
||||
std::unordered_map<uint32_t, uint64_t> m_ReceivedMessages; // msgID -> timestamp in seconds
|
||||
|
@ -125,7 +132,7 @@ namespace transport
|
|||
i2p::I2NPMessagesHandler m_Handler;
|
||||
uint32_t m_LastMessageReceivedTime; // in second
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,20 +17,19 @@
|
|||
#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; };
|
||||
uint8_t GetPayloadType() const { return flag >> 4; };
|
||||
|
||||
bool IsExtendedOptions() const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
|
||||
};
|
||||
|
||||
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
|
||||
|
@ -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,87 +69,132 @@ 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,
|
||||
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,
|
||||
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; };
|
||||
void WaitForIntroduction();
|
||||
|
||||
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||
void SendPeerTest (); // Alice
|
||||
void Close();
|
||||
|
||||
SessionState GetState () const { return m_State; };
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
void Done();
|
||||
|
||||
void SendKeepAlive ();
|
||||
uint32_t GetRelayTag () const { return m_RelayTag; };
|
||||
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
|
||||
void Failed();
|
||||
|
||||
void FlushData ();
|
||||
void CleanUp (uint64_t ts);
|
||||
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 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 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);
|
||||
boost::asio::io_service &GetService();
|
||||
|
||||
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 CreateAESandMacKey(const uint8_t *pubKey);
|
||||
|
||||
void Reset ();
|
||||
size_t GetSSUHeaderSize(const uint8_t *buf) const;
|
||||
|
||||
static size_t ExtractIPAddressAndPort (const uint8_t * buf, size_t len, boost::asio::ip::address& ip, uint16_t& port); // returns actual buf size
|
||||
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 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 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
|
||||
|
||||
private:
|
||||
|
||||
friend class SSUData; // TODO: change in later
|
||||
SSUServer& m_Server;
|
||||
SSUServer &m_Server;
|
||||
const boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||
boost::asio::deadline_timer m_ConnectTimer;
|
||||
bool m_IsPeerTest;
|
||||
|
@ -168,10 +210,10 @@ namespace transport
|
|||
SSUData m_Data;
|
||||
bool m_IsDataReceived;
|
||||
std::unique_ptr<SignedData> m_SignedData; // we need it for SessionConfirmed only
|
||||
std::map<uint32_t, std::pair <std::shared_ptr<const i2p::data::RouterInfo>, uint64_t > > m_RelayRequests; // nonce->(Charlie, timestamp)
|
||||
std::map<uint32_t, std::pair<std::shared_ptr<const i2p::data::RouterInfo>, uint64_t> > m_RelayRequests; // nonce->(Charlie, timestamp)
|
||||
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
#include "Log.h"
|
||||
#include "Signature.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
namespace i2p {
|
||||
namespace crypto {
|
||||
#if OPENSSL_EDDSA
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||
{
|
||||
|
@ -38,63 +36,58 @@ namespace crypto
|
|||
}
|
||||
|
||||
#else
|
||||
EDDSA25519Verifier::EDDSA25519Verifier ()
|
||||
{
|
||||
|
||||
EDDSA25519Verifier::EDDSA25519Verifier() {
|
||||
}
|
||||
|
||||
EDDSA25519Verifier::~EDDSA25519Verifier ()
|
||||
{
|
||||
EDDSA25519Verifier::~EDDSA25519Verifier() {
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
SHA512_Init(&ctx);
|
||||
SHA512_Update(&ctx, signature, EDDSA25519_SIGNATURE_LENGTH / 2); // R
|
||||
SHA512_Update(&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update(&ctx, buf, len); // data
|
||||
SHA512_Final(digest, &ctx);
|
||||
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
|
||||
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);
|
||||
Ed25519::ExpandPrivateKey(signingPrivateKey, m_ExpandedPrivateKey);
|
||||
// generate and encode public key
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
BN_CTX *ctx = BN_CTX_new();
|
||||
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");
|
||||
LogPrint(eLogWarning, "Older EdDSA key detected");
|
||||
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
|
||||
publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
publicKey = GetEd25519()->GeneratePublicKey(m_ExpandedPrivateKey, ctx);
|
||||
GetEd25519()->EncodePublicKey(publicKey, m_PublicKeyEncoded, ctx);
|
||||
}
|
||||
BN_CTX_free (ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
EDDSA25519SignerCompat::~EDDSA25519SignerCompat ()
|
||||
{
|
||||
EDDSA25519SignerCompat::~EDDSA25519SignerCompat() {
|
||||
}
|
||||
|
||||
void EDDSA25519SignerCompat::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
void EDDSA25519SignerCompat::Sign(const uint8_t *buf, int len, uint8_t *signature) const {
|
||||
GetEd25519()->Sign(m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
|
||||
#if OPENSSL_EDDSA
|
||||
|
@ -136,5 +129,5 @@ namespace crypto
|
|||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,241 +19,232 @@
|
|||
#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;
|
||||
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;
|
||||
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
|
||||
{
|
||||
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH / 2;
|
||||
|
||||
class DSAVerifier : public Verifier {
|
||||
public:
|
||||
|
||||
DSAVerifier ()
|
||||
{
|
||||
m_PublicKey = CreateDSA ();
|
||||
DSAVerifier() {
|
||||
m_PublicKey = CreateDSA();
|
||||
}
|
||||
|
||||
void SetPublicKey (const uint8_t * signingKey)
|
||||
{
|
||||
DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
||||
void SetPublicKey(const uint8_t *signingKey) {
|
||||
DSA_set0_key(m_PublicKey, BN_bin2bn(signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL);
|
||||
}
|
||||
|
||||
~DSAVerifier ()
|
||||
{
|
||||
DSA_free (m_PublicKey);
|
||||
~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);
|
||||
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 *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 verification
|
||||
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
|
||||
int ret = DSA_do_verify(digest, 20, sig, m_PublicKey);
|
||||
DSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
|
||||
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
|
||||
size_t GetPublicKeyLen() const { return DSA_PUBLIC_KEY_LENGTH; };
|
||||
|
||||
size_t GetSignatureLen() const { return DSA_SIGNATURE_LENGTH; };
|
||||
|
||||
private:
|
||||
|
||||
DSA * m_PublicKey;
|
||||
DSA *m_PublicKey;
|
||||
};
|
||||
|
||||
class DSASigner: public Signer
|
||||
{
|
||||
class DSASigner : public Signer {
|
||||
public:
|
||||
|
||||
DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||
DSASigner(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey)
|
||||
// openssl 1.1 always requires DSA public key even for signing
|
||||
{
|
||||
m_PrivateKey = CreateDSA ();
|
||||
DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
||||
m_PrivateKey = CreateDSA();
|
||||
DSA_set0_key(m_PrivateKey, BN_bin2bn(signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL),
|
||||
BN_bin2bn(signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL));
|
||||
}
|
||||
|
||||
~DSASigner ()
|
||||
{
|
||||
DSA_free (m_PrivateKey);
|
||||
~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);
|
||||
const BIGNUM * r, * s;
|
||||
DSA_SIG_get0 (sig, &r, &s);
|
||||
bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2);
|
||||
bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2);
|
||||
SHA1(buf, len, digest);
|
||||
DSA_SIG *sig = DSA_do_sign(digest, 20, m_PrivateKey);
|
||||
const BIGNUM *r, *s;
|
||||
DSA_SIG_get0(sig, &r, &s);
|
||||
bn2buf(r, signature, DSA_SIGNATURE_LENGTH / 2);
|
||||
bn2buf(s, signature + DSA_SIGNATURE_LENGTH / 2, DSA_SIGNATURE_LENGTH / 2);
|
||||
DSA_SIG_free(sig);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
DSA * m_PrivateKey;
|
||||
DSA *m_PrivateKey;
|
||||
};
|
||||
|
||||
inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
DSA * dsa = CreateDSA ();
|
||||
DSA_generate_key (dsa);
|
||||
const BIGNUM * pub_key, * priv_key;
|
||||
inline void CreateDSARandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
DSA *dsa = CreateDSA();
|
||||
DSA_generate_key(dsa);
|
||||
const BIGNUM *pub_key, *priv_key;
|
||||
DSA_get0_key(dsa, &pub_key, &priv_key);
|
||||
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||
DSA_free (dsa);
|
||||
bn2buf(priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||
bn2buf(pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||
DSA_free(dsa);
|
||||
}
|
||||
|
||||
struct SHA256Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
SHA256 (buf, len, 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)
|
||||
{
|
||||
SHA384 (buf, len, 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)
|
||||
{
|
||||
SHA512 (buf, len, 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 ()
|
||||
{
|
||||
m_PublicKey = EC_KEY_new_by_curve_name (curve);
|
||||
ECDSAVerifier() {
|
||||
m_PublicKey = EC_KEY_new_by_curve_name(curve);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
~ECDSAVerifier ()
|
||||
{
|
||||
EC_KEY_free (m_PublicKey);
|
||||
~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();
|
||||
auto r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
|
||||
auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
ECDSA_SIG *sig = ECDSA_SIG_new();
|
||||
auto r = BN_bin2bn(signature, GetSignatureLen() / 2, NULL);
|
||||
auto s = BN_bin2bn(signature + GetSignatureLen() / 2, GetSignatureLen() / 2, NULL);
|
||||
ECDSA_SIG_set0(sig, r, s);
|
||||
// ECDSA verification
|
||||
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
|
||||
int ret = ECDSA_do_verify(digest, Hash::hashLen, sig, m_PublicKey);
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen () const { return keyLen; };
|
||||
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
|
||||
size_t GetPublicKeyLen() const { return keyLen; };
|
||||
|
||||
size_t GetSignatureLen() const { return keyLen; }; // signature length = key length
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EC_KEY * m_PublicKey;
|
||||
EC_KEY *m_PublicKey;
|
||||
};
|
||||
|
||||
template<typename Hash, int curve, size_t keyLen>
|
||||
class ECDSASigner: public Signer
|
||||
{
|
||||
class ECDSASigner : public Signer {
|
||||
public:
|
||||
|
||||
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(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 ()
|
||||
{
|
||||
EC_KEY_free (m_PrivateKey);
|
||||
~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);
|
||||
const BIGNUM * r, * s;
|
||||
ECDSA_SIG_get0 (sig, &r, &s);
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
ECDSA_SIG *sig = ECDSA_do_sign(digest, Hash::hashLen, m_PrivateKey);
|
||||
const BIGNUM *r, *s;
|
||||
ECDSA_SIG_get0(sig, &r, &s);
|
||||
// signatureLen = keyLen
|
||||
bn2buf (r, signature, keyLen/2);
|
||||
bn2buf (s, signature + keyLen/2, keyLen/2);
|
||||
bn2buf(r, signature, keyLen / 2);
|
||||
bn2buf(s, signature + keyLen / 2, keyLen / 2);
|
||||
ECDSA_SIG_free(sig);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
EC_KEY * m_PrivateKey;
|
||||
EC_KEY *m_PrivateKey;
|
||||
};
|
||||
|
||||
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);
|
||||
BIGNUM * x = BN_new(), * y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp (EC_KEY_get0_group(signingKey),
|
||||
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);
|
||||
EC_KEY_free (signingKey);
|
||||
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);
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(signingKey),
|
||||
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);
|
||||
EC_KEY_free(signingKey);
|
||||
}
|
||||
|
||||
// ECDSA_SHA256_P256
|
||||
|
@ -261,9 +252,8 @@ 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)
|
||||
{
|
||||
CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
inline void CreateECDSAP256RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
CreateECDSARandomKeys(NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
}
|
||||
|
||||
// ECDSA_SHA384_P384
|
||||
|
@ -271,9 +261,8 @@ 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)
|
||||
{
|
||||
CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
inline void CreateECDSAP384RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
CreateECDSARandomKeys(NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
}
|
||||
|
||||
// ECDSA_SHA512_P521
|
||||
|
@ -281,25 +270,26 @@ 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)
|
||||
{
|
||||
CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, 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 ();
|
||||
EDDSA25519Verifier();
|
||||
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const;
|
||||
void SetPublicKey(const uint8_t *signingKey);
|
||||
|
||||
size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; };
|
||||
size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; };
|
||||
~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,16 +301,17 @@ 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 ();
|
||||
EDDSA25519SignerCompat(const uint8_t *signingPrivateKey, const uint8_t *signingPublicKey = nullptr);
|
||||
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
|
||||
// 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);
|
||||
|
@ -364,32 +354,32 @@ namespace crypto
|
|||
EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len);
|
||||
EVP_PKEY_free (pkey);
|
||||
#else
|
||||
RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
|
||||
EDDSA25519Signer signer (signingPrivateKey);
|
||||
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
RAND_bytes(signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH);
|
||||
EDDSA25519Signer signer(signingPrivateKey);
|
||||
memcpy(signingPublicKey, signer.GetPublicKey(), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ГОСТ Р 34.11
|
||||
struct GOSTR3411_256_Hash
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
GOSTR3411_2012_256 (buf, len, 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)
|
||||
{
|
||||
GOSTR3411_2012_512 (buf, len, 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,97 +387,102 @@ 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)
|
||||
{
|
||||
GOSTR3410Verifier(GOSTR3410ParamSet paramSet) :
|
||||
m_ParamSet(paramSet), m_PublicKey(nullptr) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
~GOSTR3410Verifier ()
|
||||
{
|
||||
if (m_PublicKey) EC_POINT_free (m_PublicKey);
|
||||
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);
|
||||
}
|
||||
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
~GOSTR3410Verifier() {
|
||||
if (m_PublicKey) EC_POINT_free(m_PublicKey);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen () const { return keyLen*2; }
|
||||
size_t GetSignatureLen () const { return keyLen*2; }
|
||||
size_t GetPublicKeyLen() const { return keyLen * 2; }
|
||||
|
||||
size_t GetSignatureLen() const { return keyLen * 2; }
|
||||
|
||||
private:
|
||||
|
||||
GOSTR3410ParamSet m_ParamSet;
|
||||
EC_POINT * m_PublicKey;
|
||||
EC_POINT *m_PublicKey;
|
||||
};
|
||||
|
||||
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_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
|
||||
GOSTR3410Signer(GOSTR3410ParamSet paramSet, const uint8_t *signingPrivateKey) :
|
||||
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
|
||||
{
|
||||
~GOSTR3410Signer() { BN_free(m_PrivateKey); }
|
||||
|
||||
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);
|
||||
BIGNUM * r = BN_new (), * s = BN_new ();
|
||||
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);
|
||||
Hash::CalculateHash(buf, len, digest);
|
||||
BIGNUM *d = BN_bin2bn(digest, Hash::hashLen, nullptr);
|
||||
BIGNUM *r = BN_new(), *s = BN_new();
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
GOSTR3410ParamSet m_ParamSet;
|
||||
BIGNUM * m_PrivateKey;
|
||||
BIGNUM *m_PrivateKey;
|
||||
};
|
||||
|
||||
inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
const auto& curve = GetGOSTR3410Curve (paramSet);
|
||||
auto keyLen = curve->GetKeyLen ();
|
||||
RAND_bytes (signingPrivateKey, keyLen);
|
||||
BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
|
||||
inline void
|
||||
CreateGOSTR3410RandomKeys(GOSTR3410ParamSet paramSet, uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
const auto &curve = GetGOSTR3410Curve(paramSet);
|
||||
auto keyLen = curve->GetKeyLen();
|
||||
RAND_bytes(signingPrivateKey, keyLen);
|
||||
BIGNUM *priv = BN_bin2bn(signingPrivateKey, keyLen, nullptr);
|
||||
|
||||
auto pub = curve->MulP (priv);
|
||||
BN_free (priv);
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
curve->GetXY (pub, x, y);
|
||||
EC_POINT_free (pub);
|
||||
bn2buf (x, signingPublicKey, keyLen);
|
||||
bn2buf (y, signingPublicKey + keyLen, keyLen);
|
||||
BN_free (x); BN_free (y);
|
||||
auto pub = curve->MulP(priv);
|
||||
BN_free(priv);
|
||||
BIGNUM *x = BN_new(), *y = BN_new();
|
||||
curve->GetXY(pub, x, y);
|
||||
EC_POINT_free(pub);
|
||||
bn2buf(x, signingPublicKey, keyLen);
|
||||
bn2buf(y, signingPublicKey + keyLen, keyLen);
|
||||
BN_free(x);
|
||||
BN_free(y);
|
||||
}
|
||||
|
||||
typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier;
|
||||
|
@ -497,26 +492,25 @@ namespace crypto
|
|||
|
||||
// RedDSA
|
||||
typedef EDDSA25519Verifier RedDSA25519Verifier;
|
||||
class RedDSA25519Signer: public Signer
|
||||
{
|
||||
|
||||
class RedDSA25519Signer : public Signer {
|
||||
public:
|
||||
|
||||
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
|
||||
{
|
||||
GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
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);
|
||||
}
|
||||
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation
|
||||
~RedDSA25519Signer() {};
|
||||
|
||||
void Sign(const uint8_t *buf, int len, uint8_t *signature) const {
|
||||
GetEd25519()->SignRedDSA(m_PrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
|
||||
const uint8_t *GetPublicKey() const { return m_PublicKeyEncoded; }; // for keys creation
|
||||
|
||||
private:
|
||||
|
||||
|
@ -524,13 +518,12 @@ namespace crypto
|
|||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
|
||||
inline void CreateRedDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey);
|
||||
RedDSA25519Signer signer (signingPrivateKey);
|
||||
memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
inline void CreateRedDSA25519RandomKeys(uint8_t *signingPrivateKey, uint8_t *signingPublicKey) {
|
||||
GetEd25519()->CreateRedDSAPrivateKey(signingPrivateKey);
|
||||
RedDSA25519Signer signer(signingPrivateKey);
|
||||
memcpy(signingPublicKey, signer.GetPublicKey(), EDDSA25519_PUBLIC_KEY_LENGTH);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
|
@ -91,54 +81,52 @@ namespace crypto
|
|||
const uint64_t k1 = siphash::u8to64le(key + 8);
|
||||
uint64_t msg;
|
||||
int i;
|
||||
const uint8_t * end = buf + bufsz - (bufsz % sizeof(uint64_t));
|
||||
const uint8_t *end = buf + bufsz - (bufsz % sizeof(uint64_t));
|
||||
auto left = bufsz & 7;
|
||||
uint64_t b = ((uint64_t)bufsz) << 56;
|
||||
uint64_t b = ((uint64_t) bufsz) << 56;
|
||||
v3 ^= k1;
|
||||
v2 ^= k0;
|
||||
v1 ^= k1;
|
||||
v0 ^= k0;
|
||||
|
||||
if(hashsz == 16) v1 ^= 0xee;
|
||||
if (hashsz == 16) v1 ^= 0xee;
|
||||
|
||||
while(buf != end)
|
||||
{
|
||||
while (buf != end) {
|
||||
msg = siphash::u8to64le(buf);
|
||||
v3 ^= msg;
|
||||
for(i = 0; i < siphash::crounds; ++i)
|
||||
for (i = 0; i < siphash::crounds; ++i)
|
||||
siphash::round(v0, v1, v2, v3);
|
||||
|
||||
v0 ^= msg;
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
while(left)
|
||||
{
|
||||
while (left) {
|
||||
--left;
|
||||
b |= ((uint64_t)(buf[left])) << (left * 8);
|
||||
}
|
||||
|
||||
v3 ^= b;
|
||||
|
||||
for(i = 0; i < siphash::crounds; ++i)
|
||||
for (i = 0; i < siphash::crounds; ++i)
|
||||
siphash::round(v0, v1, v2, v3);
|
||||
|
||||
v0 ^= b;
|
||||
|
||||
|
||||
if(hashsz == 16)
|
||||
if (hashsz == 16)
|
||||
v2 ^= 0xee;
|
||||
else
|
||||
v2 ^= 0xff;
|
||||
|
||||
for(i = 0; i < siphash::drounds; ++i)
|
||||
for (i = 0; i < siphash::drounds; ++i)
|
||||
siphash::round(v0, v1, v2, v3);
|
||||
|
||||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
|
||||
siphash::u64to8le(b, h);
|
||||
|
||||
if(hashsz == 8) return;
|
||||
if (hashsz == 8) return;
|
||||
|
||||
v1 ^= 0xdd;
|
||||
|
||||
|
@ -148,7 +136,7 @@ namespace crypto
|
|||
b = v0 ^ v1 ^ v2 ^ v3;
|
||||
siphash::u64to8le(b, h + 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
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,82 +61,103 @@ 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; };
|
||||
Packet() : len(0), offset(0), sendTime(0) {};
|
||||
|
||||
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 (); };
|
||||
uint8_t *GetBuffer() { return buf + offset; };
|
||||
|
||||
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; };
|
||||
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
|
||||
{
|
||||
return p1->GetSeqn () < p2->GetSeqn ();
|
||||
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
|
||||
{
|
||||
uint8_t * buf;
|
||||
typedef std::function<void(const boost::system::error_code &ecode)> SendHandler;
|
||||
|
||||
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)
|
||||
{
|
||||
SendBuffer(const uint8_t *b, size_t l, SendHandler h) :
|
||||
len(l), offset(0), handler(h) {
|
||||
buf = new uint8_t[len];
|
||||
memcpy (buf, b, len);
|
||||
memcpy(buf, b, len);
|
||||
}
|
||||
SendBuffer (size_t l): // create empty buffer
|
||||
len(l), offset (0)
|
||||
{
|
||||
|
||||
SendBuffer(size_t l) : // create empty buffer
|
||||
len(l), offset(0) {
|
||||
buf = new uint8_t[len];
|
||||
}
|
||||
~SendBuffer ()
|
||||
{
|
||||
|
||||
~SendBuffer() {
|
||||
delete[] buf;
|
||||
if (handler) handler(boost::system::error_code ());
|
||||
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; };
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
class SendBufferQueue
|
||||
{
|
||||
class SendBufferQueue {
|
||||
public:
|
||||
|
||||
SendBufferQueue (): m_Size (0) {};
|
||||
~SendBufferQueue () { CleanUp (); };
|
||||
SendBufferQueue() : m_Size(0) {};
|
||||
|
||||
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 ();
|
||||
~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,84 +175,117 @@ 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,
|
||||
Stream(boost::asio::io_service &service, StreamingDestination &local,
|
||||
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
||||
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; };
|
||||
~Stream();
|
||||
|
||||
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 ();
|
||||
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 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 (); };
|
||||
void Close();
|
||||
|
||||
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 Cancel() { m_ReceiveTimer.cancel(); };
|
||||
|
||||
void Terminate (bool deleteFromDestination = true);
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
void CleanUp ();
|
||||
void CleanUp();
|
||||
|
||||
void SendBuffer ();
|
||||
void SendQuickAck ();
|
||||
void SendClose ();
|
||||
bool SendPacket (Packet * packet);
|
||||
void SendPackets (const std::vector<Packet *>& packets);
|
||||
void SendUpdatedLeaseSet ();
|
||||
void SendBuffer();
|
||||
|
||||
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 SendQuickAck();
|
||||
|
||||
void UpdateCurrentRemoteLease (bool expired = false);
|
||||
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);
|
||||
void ScheduleResend();
|
||||
|
||||
void HandleResendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
void HandleAckSendTimer(const boost::system::error_code &ecode);
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
boost::asio::io_service &m_Service;
|
||||
uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber;
|
||||
int32_t m_LastReceivedSequenceNumber;
|
||||
StreamStatus m_Status;
|
||||
bool m_IsAckSendScheduled;
|
||||
StreamingDestination& m_LocalDestination;
|
||||
StreamingDestination &m_LocalDestination;
|
||||
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
|
||||
std::shared_ptr<const i2p::crypto::Verifier> m_TransientVerifier; // in case of offline key
|
||||
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
|
||||
|
@ -257,43 +307,61 @@ 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;
|
||||
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 ();
|
||||
StreamingDestination(std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0,
|
||||
bool gzip = false);
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
~StreamingDestination();
|
||||
|
||||
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);
|
||||
void Start();
|
||||
|
||||
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 Stop();
|
||||
|
||||
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<Stream>
|
||||
CreateNewOutgoingStream(std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
|
||||
|
||||
Packet * NewPacket () { return m_PacketsPool.Acquire(); }
|
||||
void DeletePacket (Packet * p) { return m_PacketsPool.Release(p); }
|
||||
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);
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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 {
|
||||
int t = (timeout > MAX_RECEIVE_TIMEOUT) ? MAX_RECEIVE_TIMEOUT : timeout;
|
||||
s->m_ReceiveTimer.expires_from_now (boost::posix_time::seconds(t));
|
||||
s->m_ReceiveTimer.expires_from_now(boost::posix_time::seconds(t));
|
||||
int left = timeout - t;
|
||||
auto self = s->shared_from_this();
|
||||
self->m_ReceiveTimer.async_wait (
|
||||
[self, buffer, handler, left](const boost::system::error_code & ec)
|
||||
{
|
||||
self->m_ReceiveTimer.async_wait(
|
||||
[self, buffer, handler, left](const boost::system::error_code &ec) {
|
||||
self->HandleReceiveTimer(ec, buffer, handler, left);
|
||||
});
|
||||
}
|
||||
|
@ -347,33 +415,31 @@ 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)
|
||||
{
|
||||
handler(boost::system::error_code(), received);
|
||||
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);
|
||||
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
|
||||
{
|
||||
handler(boost::asio::error::make_error_code(boost::asio::error::operation_aborted), 0);
|
||||
} else {
|
||||
// timeout expired
|
||||
if (remainingTimeout <= 0)
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
|
||||
else
|
||||
{
|
||||
handler(boost::asio::error::make_error_code(boost::asio::error::timed_out), received);
|
||||
else {
|
||||
// itermediate interrupt
|
||||
SendUpdatedLeaseSet (); // send our leaseset if applicable
|
||||
AsyncReceive (buffer, handler, remainingTimeout);
|
||||
SendUpdatedLeaseSet(); // send our leaseset if applicable
|
||||
AsyncReceive(buffer, handler, remainingTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,69 +15,68 @@
|
|||
#include "Base.h"
|
||||
|
||||
namespace i2p {
|
||||
namespace data {
|
||||
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); }
|
||||
Tag() = default;
|
||||
|
||||
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; }
|
||||
Tag(const uint8_t *buf) { memcpy(m_Buf, buf, sz); }
|
||||
|
||||
uint8_t * operator()() { return m_Buf; }
|
||||
const uint8_t * operator()() const { return m_Buf; }
|
||||
bool operator==(const Tag &other) const { return !memcmp(m_Buf, other.m_Buf, sz); }
|
||||
|
||||
operator uint8_t * () { return m_Buf; }
|
||||
operator const uint8_t * () const { return m_Buf; }
|
||||
bool operator!=(const Tag &other) const { return !(*this == other); }
|
||||
|
||||
const uint8_t * data() const { return m_Buf; }
|
||||
const uint64_t * GetLL () const { return ll; }
|
||||
bool operator<(const Tag &other) const { return memcmp(m_Buf, other.m_Buf, sz) < 0; }
|
||||
|
||||
bool IsZero () const
|
||||
{
|
||||
for (size_t i = 0; i < sz/8; ++i)
|
||||
uint8_t *operator()() { return m_Buf; }
|
||||
|
||||
const uint8_t *operator()() const { return m_Buf; }
|
||||
|
||||
operator uint8_t *() { return m_Buf; }
|
||||
|
||||
operator const uint8_t *() const { return m_Buf; }
|
||||
|
||||
const uint8_t *data() const { return m_Buf; }
|
||||
|
||||
const uint64_t *GetLL() const { return ll; }
|
||||
|
||||
bool IsZero() const {
|
||||
for (size_t i = 0; i < sz / 8; ++i)
|
||||
if (ll[i]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Fill(uint8_t c)
|
||||
{
|
||||
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
|
||||
{
|
||||
char str[sz*2];
|
||||
size_t l = i2p::data::ByteStreamToBase64 (m_Buf, len, str, sz*2);
|
||||
return std::string (str, str + l);
|
||||
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
|
||||
{
|
||||
char str[sz*2];
|
||||
size_t l = i2p::data::ByteStreamToBase32 (m_Buf, len, str, sz*2);
|
||||
return std::string (str, str + l);
|
||||
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)
|
||||
{
|
||||
return i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||
size_t FromBase32(const std::string &s) {
|
||||
return i2p::data::Base32ToByteStream(s.c_str(), s.length(), m_Buf, sz);
|
||||
}
|
||||
|
||||
size_t FromBase64 (const std::string& s)
|
||||
{
|
||||
return i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz);
|
||||
size_t FromBase64(const std::string &s) {
|
||||
return i2p::data::Base64ToByteStream(s.c_str(), s.length(), m_Buf, sz);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -85,20 +84,18 @@ namespace data {
|
|||
union // 8 bytes aligned
|
||||
{
|
||||
uint8_t m_Buf[sz];
|
||||
uint64_t ll[sz/8];
|
||||
uint64_t ll[sz / 8];
|
||||
};
|
||||
};
|
||||
} // 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
|
||||
{
|
||||
return s.GetLL ()[0];
|
||||
template<size_t sz>
|
||||
struct hash<i2p::data::Tag<sz> > {
|
||||
size_t operator()(const i2p::data::Tag<sz> &s) const {
|
||||
return s.GetLL()[0];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,225 +22,184 @@
|
|||
#include "util.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef _WIN64
|
||||
#define _USE_32BIT_TIME_T
|
||||
#endif
|
||||
#ifndef _WIN64
|
||||
#define _USE_32BIT_TIME_T
|
||||
#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 ();
|
||||
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 ();
|
||||
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 ();
|
||||
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 ();
|
||||
std::chrono::system_clock::now().time_since_epoch()).count();
|
||||
}
|
||||
|
||||
static int64_t g_TimeOffset = 0; // in seconds
|
||||
|
||||
static void SyncTimeWithNTP (const std::string& address)
|
||||
{
|
||||
LogPrint (eLogInfo, "Timestamp: NTP request to ", 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)
|
||||
{
|
||||
auto it = boost::asio::ip::udp::resolver(service).resolve(
|
||||
boost::asio::ip::udp::resolver::query(address, "ntp"), 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 (i2p::context.SupportsV4 ()) found = true;
|
||||
}
|
||||
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;
|
||||
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())) {
|
||||
if (i2p::context.SupportsMesh()) found = true;
|
||||
} else if (i2p::context.SupportsV6()) found = true;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
it++;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
LogPrint (eLogError, "Timestamp: can't find compatible address for ", address);
|
||||
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)
|
||||
{
|
||||
boost::asio::ip::udp::socket socket(service);
|
||||
socket.open(ep.protocol(), ec);
|
||||
if (!ec) {
|
||||
uint8_t buf[48];// 48 bytes NTP request/response
|
||||
memset (buf, 0, 48);
|
||||
htobe32buf (buf, (3 << 27) | (3 << 24)); // RFC 4330
|
||||
memset(buf, 0, 48);
|
||||
htobe32buf(buf, (3 << 27) | (3 << 24)); // RFC 4330
|
||||
size_t len = 0;
|
||||
try
|
||||
{
|
||||
socket.send_to (boost::asio::buffer (buf, 48), ep);
|
||||
try {
|
||||
socket.send_to(boost::asio::buffer(buf, 48), ep);
|
||||
int i = 0;
|
||||
while (!socket.available() && i < 10) // 10 seconds max
|
||||
{
|
||||
std::this_thread::sleep_for (std::chrono::seconds(1));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
i++;
|
||||
}
|
||||
if (socket.available ())
|
||||
len = socket.receive_from (boost::asio::buffer (buf, 48), ep);
|
||||
if (socket.available())
|
||||
len = socket.receive_from(boost::asio::buffer(buf, 48), ep);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LogPrint (eLogError, "Timestamp: NTP error: ", e.what ());
|
||||
catch (std::exception &e) {
|
||||
LogPrint(eLogError, "Timestamp: NTP error: ", e.what());
|
||||
}
|
||||
if (len >= 8)
|
||||
{
|
||||
auto ourTs = GetLocalSecondsSinceEpoch ();
|
||||
uint32_t ts = bufbe32toh (buf + 32);
|
||||
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
|
||||
LogPrint (eLogError, "Timestamp: Couldn't open UDP socket");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Timestamp: Couldn't resolve address ", address);
|
||||
} else
|
||||
LogPrint(eLogError, "Timestamp: Couldn't open UDP socket");
|
||||
} 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);
|
||||
boost::split (m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on);
|
||||
std::string ntpservers;
|
||||
i2p::config::GetOption("nettime.ntpservers", ntpservers);
|
||||
boost::split(m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on);
|
||||
}
|
||||
|
||||
NTPTimeSync::~NTPTimeSync ()
|
||||
{
|
||||
Stop ();
|
||||
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
|
||||
LogPrint (eLogWarning, "Timestamp: No NTP server found");
|
||||
m_Service.post(std::bind(&NTPTimeSync::Sync, this));
|
||||
m_Thread.reset(new std::thread(std::bind(&NTPTimeSync::Run, this)));
|
||||
} 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)
|
||||
{
|
||||
m_Thread->join ();
|
||||
m_Thread.reset (nullptr);
|
||||
m_Timer.cancel();
|
||||
m_Service.stop();
|
||||
if (m_Thread) {
|
||||
m_Thread->join();
|
||||
m_Thread.reset(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTPTimeSync::Run ()
|
||||
{
|
||||
void NTPTimeSync::Run() {
|
||||
i2p::util::SetThreadName("Timesync");
|
||||
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Service.run ();
|
||||
while (m_IsRunning) {
|
||||
try {
|
||||
m_Service.run();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Timestamp: NTP time sync exception: ", ex.what ());
|
||||
catch (std::exception &ex) {
|
||||
LogPrint(eLogError, "Timestamp: NTP time sync exception: ", ex.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTPTimeSync::Sync ()
|
||||
{
|
||||
if (m_NTPServersList.size () > 0)
|
||||
SyncTimeWithNTP (m_NTPServersList[rand () % m_NTPServersList.size ()]);
|
||||
void NTPTimeSync::Sync() {
|
||||
if (m_NTPServersList.size() > 0)
|
||||
SyncTimeWithNTP(m_NTPServersList[rand() % m_NTPServersList.size()]);
|
||||
else
|
||||
m_IsRunning = false;
|
||||
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Sync ();
|
||||
Sync();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t GetMillisecondsSinceEpoch ()
|
||||
{
|
||||
return GetLocalMillisecondsSinceEpoch () + g_TimeOffset*1000;
|
||||
uint64_t GetMillisecondsSinceEpoch() {
|
||||
return GetLocalMillisecondsSinceEpoch() + g_TimeOffset * 1000;
|
||||
}
|
||||
|
||||
uint64_t GetSecondsSinceEpoch ()
|
||||
{
|
||||
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
|
||||
uint64_t GetSecondsSinceEpoch() {
|
||||
return GetLocalSecondsSinceEpoch() + g_TimeOffset;
|
||||
}
|
||||
|
||||
uint32_t GetMinutesSinceEpoch ()
|
||||
{
|
||||
return GetLocalMinutesSinceEpoch () + g_TimeOffset/60;
|
||||
uint32_t GetMinutesSinceEpoch() {
|
||||
return GetLocalMinutesSinceEpoch() + g_TimeOffset / 60;
|
||||
}
|
||||
|
||||
uint32_t GetHoursSinceEpoch ()
|
||||
{
|
||||
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;
|
||||
uint32_t GetHoursSinceEpoch() {
|
||||
return GetLocalHoursSinceEpoch() + g_TimeOffset / 3600;
|
||||
}
|
||||
|
||||
void GetCurrentDate (char * date)
|
||||
{
|
||||
GetDateString (GetSecondsSinceEpoch (), 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)));
|
||||
auto t = clock::to_time_t(clock::time_point(std::chrono::seconds(timestamp)));
|
||||
struct tm tm;
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&tm, &t);
|
||||
|
@ -251,9 +210,8 @@ namespace util
|
|||
#endif
|
||||
}
|
||||
|
||||
void AdjustTimeOffset (int64_t offset)
|
||||
{
|
||||
void AdjustTimeOffset(int64_t offset) {
|
||||
g_TimeOffset += offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,44 +15,48 @@
|
|||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
namespace util
|
||||
{
|
||||
uint64_t GetMillisecondsSinceEpoch ();
|
||||
uint64_t GetSecondsSinceEpoch ();
|
||||
uint32_t GetMinutesSinceEpoch ();
|
||||
uint32_t GetHoursSinceEpoch ();
|
||||
namespace i2p {
|
||||
namespace util {
|
||||
uint64_t GetMillisecondsSinceEpoch();
|
||||
|
||||
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 AdjustTimeOffset (int64_t offset); // in seconds from current
|
||||
uint64_t GetSecondsSinceEpoch();
|
||||
|
||||
class NTPTimeSync
|
||||
{
|
||||
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 AdjustTimeOffset(int64_t offset); // in seconds from current
|
||||
|
||||
class NTPTimeSync {
|
||||
public:
|
||||
|
||||
NTPTimeSync ();
|
||||
~NTPTimeSync ();
|
||||
NTPTimeSync();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
~NTPTimeSync();
|
||||
|
||||
void Start();
|
||||
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
|
||||
void Run ();
|
||||
void Sync ();
|
||||
void Run();
|
||||
|
||||
void Sync();
|
||||
|
||||
private:
|
||||
|
||||
bool m_IsRunning;
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
std::unique_ptr <std::thread> m_Thread;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
int m_SyncInterval;
|
||||
std::vector<std::string> m_NTPServersList;
|
||||
std::vector <std::string> m_NTPServersList;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,104 +15,88 @@
|
|||
#include "Transports.h"
|
||||
#include "TransitTunnel.h"
|
||||
|
||||
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)
|
||||
{
|
||||
m_Encryption.SetKeys (layerKey, ivKey);
|
||||
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) {
|
||||
m_Encryption.SetKeys(layerKey, ivKey);
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
EncryptTunnelMsg (tunnelMsg, tunnelMsg);
|
||||
void TransitTunnelParticipant::HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg) {
|
||||
EncryptTunnelMsg(tunnelMsg, tunnelMsg);
|
||||
|
||||
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
||||
htobe32buf (tunnelMsg->GetPayload (), GetNextTunnelID ());
|
||||
tunnelMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
m_TunnelDataMsgs.push_back (tunnelMsg);
|
||||
m_NumTransmittedBytes += tunnelMsg->GetLength();
|
||||
htobe32buf(tunnelMsg->GetPayload(), GetNextTunnelID());
|
||||
tunnelMsg->FillI2NPMessageHeader(eI2NPTunnelData);
|
||||
m_TunnelDataMsgs.push_back(tunnelMsg);
|
||||
}
|
||||
|
||||
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
|
||||
{
|
||||
if (!m_TunnelDataMsgs.empty ())
|
||||
{
|
||||
auto num = m_TunnelDataMsgs.size ();
|
||||
void TransitTunnelParticipant::FlushTunnelDataMsgs() {
|
||||
if (!m_TunnelDataMsgs.empty()) {
|
||||
auto num = m_TunnelDataMsgs.size();
|
||||
if (num > 1)
|
||||
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
|
||||
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
||||
m_TunnelDataMsgs.clear ();
|
||||
LogPrint(eLogDebug, "TransitTunnel: ", GetTunnelID(), "->", GetNextTunnelID(), " ", num);
|
||||
i2p::transport::transports.SendMessages(GetNextIdentHash(), m_TunnelDataMsgs);
|
||||
m_TunnelDataMsgs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
|
||||
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;
|
||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||
m_Gateway.PutTunnelDataMsg (block);
|
||||
m_Gateway.PutTunnelDataMsg(block);
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::FlushTunnelDataMsgs ()
|
||||
{
|
||||
void TransitTunnelGateway::FlushTunnelDataMsgs() {
|
||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||
m_Gateway.SendBuffer ();
|
||||
m_Gateway.SendBuffer();
|
||||
}
|
||||
|
||||
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg)
|
||||
{
|
||||
auto newMsg = CreateEmptyTunnelDataMsg (true);
|
||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
void TransitTunnelEndpoint::HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg) {
|
||||
auto newMsg = CreateEmptyTunnelDataMsg(true);
|
||||
EncryptTunnelMsg(tunnelMsg, newMsg);
|
||||
|
||||
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
|
||||
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
||||
LogPrint(eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID());
|
||||
m_Endpoint.HandleDecryptedTunnelDataMsg(newMsg);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
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) {
|
||||
LogPrint(eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
|
||||
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 {
|
||||
LogPrint(eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelParticipant>(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
|
||||
{
|
||||
LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,43 +19,45 @@
|
|||
#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,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey);
|
||||
TransitTunnel(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey);
|
||||
|
||||
virtual size_t GetNumTransmittedBytes () const { return 0; };
|
||||
virtual size_t GetNumTransmittedBytes() const { return 0; };
|
||||
|
||||
// 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);
|
||||
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,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_NumTransmittedBytes (0) {};
|
||||
~TransitTunnelParticipant ();
|
||||
TransitTunnelParticipant(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey) :
|
||||
TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_NumTransmittedBytes(0) {};
|
||||
|
||||
size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; };
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
|
||||
void FlushTunnelDataMsgs ();
|
||||
~TransitTunnelParticipant();
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_NumTransmittedBytes; };
|
||||
|
||||
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
|
||||
|
||||
void FlushTunnelDataMsgs();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -63,19 +65,20 @@ namespace tunnel
|
|||
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
||||
};
|
||||
|
||||
class TransitTunnelGateway: public TransitTunnel
|
||||
{
|
||||
class TransitTunnelGateway : public TransitTunnel {
|
||||
public:
|
||||
|
||||
TransitTunnelGateway (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
TransitTunnelGateway(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey) :
|
||||
TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_Gateway(this) {};
|
||||
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void FlushTunnelDataMsgs ();
|
||||
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||
void SendTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
|
||||
void FlushTunnelDataMsgs();
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_Gateway.GetNumSentBytes(); };
|
||||
|
||||
private:
|
||||
|
||||
|
@ -83,31 +86,31 @@ namespace tunnel
|
|||
TunnelGateway m_Gateway;
|
||||
};
|
||||
|
||||
class TransitTunnelEndpoint: public TransitTunnel
|
||||
{
|
||||
class TransitTunnelEndpoint : public TransitTunnel {
|
||||
public:
|
||||
|
||||
TransitTunnelEndpoint (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||
m_Endpoint (false) {}; // transit endpoint is always outbound
|
||||
TransitTunnelEndpoint(uint32_t receiveTunnelID,
|
||||
const uint8_t *nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t *layerKey, const uint8_t *ivKey) :
|
||||
TransitTunnel(receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||
m_Endpoint(false) {}; // transit endpoint is always outbound
|
||||
|
||||
void Cleanup () { m_Endpoint.Cleanup (); }
|
||||
void Cleanup() { m_Endpoint.Cleanup(); }
|
||||
|
||||
void HandleTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage>&& tunnelMsg);
|
||||
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
||||
void HandleTunnelDataMsg(std::shared_ptr<i2p::I2NPMessage> &&tunnelMsg);
|
||||
|
||||
size_t GetNumTransmittedBytes() const { return m_Endpoint.GetNumReceivedBytes(); }
|
||||
|
||||
private:
|
||||
|
||||
TunnelEndpoint m_Endpoint;
|
||||
};
|
||||
|
||||
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,48 +20,40 @@
|
|||
#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)
|
||||
{
|
||||
m_Stream << other.m_Stream.rdbuf ();
|
||||
SignedData() {}
|
||||
|
||||
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)
|
||||
{
|
||||
m_Stream.write ((char *)buf, len);
|
||||
void Insert(const uint8_t *buf, size_t len) {
|
||||
m_Stream.write((char *) buf, len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Insert (T t)
|
||||
{
|
||||
m_Stream.write ((char *)&t, sizeof (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
|
||||
{
|
||||
return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
||||
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
|
||||
{
|
||||
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
|
||||
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);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -69,50 +61,59 @@ 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 ())
|
||||
{
|
||||
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()) {
|
||||
if (router)
|
||||
m_RemoteIdentity = router->GetRouterIdentity ();
|
||||
m_RemoteIdentity = router->GetRouterIdentity();
|
||||
m_CreationTime = m_LastActivityTimestamp;
|
||||
}
|
||||
|
||||
virtual ~TransportSession () {};
|
||||
virtual void Done () = 0;
|
||||
virtual ~TransportSession() {};
|
||||
|
||||
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
|
||||
virtual void Done() = 0;
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity ()
|
||||
{
|
||||
std::string GetIdentHashBase64() const {
|
||||
return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : "";
|
||||
}
|
||||
|
||||
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; };
|
||||
size_t GetNumSentBytes() const { return m_NumSentBytes; };
|
||||
|
||||
int GetTerminationTimeout () const { return m_TerminationTimeout; };
|
||||
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
|
||||
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
||||
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
||||
size_t GetNumReceivedBytes() const { return m_NumReceivedBytes; };
|
||||
|
||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
void SetCreationTime (uint32_t ts) { m_CreationTime = ts; }; // for introducers
|
||||
bool IsOutgoing() const { return m_IsOutgoing; };
|
||||
|
||||
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;
|
||||
int GetTerminationTimeout() const { return m_TerminationTimeout; };
|
||||
|
||||
void SetTerminationTimeout(int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
|
||||
|
||||
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:
|
||||
|
||||
|
@ -124,7 +125,7 @@ namespace transport
|
|||
uint64_t m_LastActivityTimestamp;
|
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
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