";
@@ -321,11 +323,12 @@ namespace http {
void ShowLocalDestinations (std::stringstream& s)
{
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "
Local Destinations:\r\n
\r\n";
for (auto& it: i2p::client::context.GetDestinations ())
{
auto ident = it.second->GetIdentHash ();
- s << "
";
+ s << "";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "\r\n" << std::endl;
}
@@ -340,7 +343,7 @@ namespace http {
{
auto ident = dest->GetIdentHash ();
auto& name = dest->GetNickname ();
- s << "
[ ";
+ s << "[ ";
s << name << " ] ⇔ " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"
\r\n" << std::endl;
}
}
@@ -510,33 +513,34 @@ namespace http {
static void ShowCommands (std::stringstream& s, uint32_t token)
{
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
/* commands */
s << "
Router Commands\r\n
\r\n";
- s << "
Run peer test\r\n";
+ s << "
Run peer test\r\n";
//s << "
Reload config\r\n";
if (i2p::context.AcceptsTunnels ())
- s << "
Decline transit tunnels\r\n";
+ s << "
Decline transit tunnels\r\n";
else
- s << "
Accept transit tunnels\r\n";
+ s << "
Accept transit tunnels\r\n";
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
if (Daemon.gracefulShutdownInterval)
- s << "
Cancel graceful shutdown";
+ s << "
Cancel graceful shutdown";
else
- s << "
Start graceful shutdown\r\n";
+ s << "
Start graceful shutdown\r\n";
#elif defined(WIN32_APP)
if (i2p::util::DaemonWin32::Instance().isGraceful)
- s << "
Cancel graceful shutdown";
+ s << "
Cancel graceful shutdown";
else
- s << "
Graceful shutdown\r\n";
+ s << "
Graceful shutdown\r\n";
#endif
- s << "
Force shutdown\r\n";
+ s << "
Force shutdown\r\n";
s << "
\r\n
Logging level\r\n";
- s << "
[none] ";
- s << "
[error] ";
- s << "
[warn] ";
- s << "
[info] ";
- s << "
[debug]\r\n";
+ s << "
[none] ";
+ s << "
[error] ";
+ s << "
[warn] ";
+ s << "
[info] ";
+ s << "
[debug]\r\n";
}
void ShowTransitTunnels (std::stringstream& s)
@@ -653,6 +657,7 @@ namespace http {
void ShowSAMSessions (std::stringstream& s)
{
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
auto sam = i2p::client::context.GetSAMBridge ();
if (!sam) {
ShowError(s, "SAM disabled");
@@ -662,13 +667,14 @@ namespace http {
for (auto& it: sam->GetSessions ())
{
auto& name = it.second->localDestination->GetNickname ();
- s << "
";
+ s << "";
s << name << " (" << it.first << ")\r\n" << std::endl;
}
}
static void ShowSAMSession (std::stringstream& s, const std::string& id)
{
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "
SAM Session:\r\n
\r\n";
auto sam = i2p::client::context.GetSAMBridge ();
if (!sam) {
@@ -681,7 +687,7 @@ namespace http {
return;
}
auto& ident = session->localDestination->GetIdentHash();
- s << "
";
+ s << "";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "\r\n";
s << "
\r\n";
s << "
Streams:\r\n";
@@ -701,11 +707,12 @@ namespace http {
void ShowI2PTunnels (std::stringstream& s)
{
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "
Client Tunnels:\r\n
\r\n";
for (auto& it: i2p::client::context.GetClientTunnels ())
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << it.second->GetName () << " ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "
\r\n"<< std::endl;
@@ -714,7 +721,7 @@ namespace http {
if (httpProxy)
{
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << "HTTP Proxy" << " ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "
\r\n"<< std::endl;
@@ -723,7 +730,7 @@ namespace http {
if (socksProxy)
{
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << "SOCKS Proxy" << " ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "
\r\n"<< std::endl;
@@ -734,7 +741,7 @@ namespace http {
for (auto& it: serverTunnels)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << it.second->GetName () << " ⇒ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort ();
@@ -748,7 +755,7 @@ namespace http {
for (auto& it: clientForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << it.second->GetName () << " ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "
\r\n"<< std::endl;
@@ -761,7 +768,7 @@ namespace http {
for (auto& it: serverForwards)
{
auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
- s << "
";
+ s << "";
s << it.second->GetName () << " ⇐ ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "
\r\n"<< std::endl;
@@ -1025,10 +1032,12 @@ namespace http {
ShowError(s, "Unknown command: " + cmd);
return;
}
+ std::string webroot; i2p::config::GetOption("http.webroot", webroot);
+ std::string redirect = "5; url=" + webroot + "?page=commands";
s << "
SUCCESS: Command accepted
\r\n";
- s << "
Back to commands list\r\n";
+ s << "
Back to commands list\r\n";
s << "
You will be redirected in 5 seconds";
- res.add_header("Refresh", "5; url=/?page=commands");
+ res.add_header("Refresh", redirect.c_str());
}
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)
diff --git a/debian/docs b/debian/docs
index b67deb18..dfa6f572 100644
--- a/debian/docs
+++ b/debian/docs
@@ -2,3 +2,4 @@ README.md
contrib/i2pd.conf
contrib/subscriptions.txt
contrib/tunnels.conf
+contrib/tunnels.d
diff --git a/debian/i2pd.dirs b/debian/i2pd.dirs
index 736e23bd..3b643352 100644
--- a/debian/i2pd.dirs
+++ b/debian/i2pd.dirs
@@ -1,3 +1,2 @@
etc/i2pd
-etc/i2pd/tunnels.conf.d
var/lib/i2pd
diff --git a/debian/i2pd.install b/debian/i2pd.install
index cae69c0e..d20b2c17 100644
--- a/debian/i2pd.install
+++ b/debian/i2pd.install
@@ -3,5 +3,5 @@ contrib/i2pd.conf etc/i2pd/
contrib/tunnels.conf etc/i2pd/
contrib/subscriptions.txt etc/i2pd/
contrib/certificates/ usr/share/i2pd/
-contrib/tunnels.d/ etc/i2pd/tunnels.conf.d
+contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
contrib/apparmor/usr.sbin.i2pd etc/apparmor.d
diff --git a/debian/i2pd.links b/debian/i2pd.links
index 083bc6ca..a149967f 100644
--- a/debian/i2pd.links
+++ b/debian/i2pd.links
@@ -1,5 +1,5 @@
etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf
etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf
etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt
-etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.conf.d
+etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.d
usr/share/i2pd/certificates var/lib/i2pd/certificates
diff --git a/libi2pd/ChaCha20.cpp b/libi2pd/ChaCha20.cpp
index e43f1514..30e02f42 100644
--- a/libi2pd/ChaCha20.cpp
+++ b/libi2pd/ChaCha20.cpp
@@ -1,21 +1,23 @@
+/*
+* Copyright (c) 2013-2018, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*
+* Kovri go write your own code
+*
+*/
+
#include "ChaCha20.h"
-/**
- This code is licensed under the MCGSI Public License
- Copyright 2018 Jeff Becker
-
- Kovri go write your own code
-
- */
+#if LEGACY_OPENSSL
namespace i2p
{
namespace crypto
{
namespace chacha
{
-constexpr int rounds = 20;
-constexpr std::size_t blocksize = 64;
-
void u32t8le(uint32_t v, uint8_t * p)
{
p[0] = v & 0xff;
@@ -48,44 +50,18 @@ void quarterround(uint32_t *x, int a, int b, int c, int d)
x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7);
}
- struct State_t
- {
- State_t() {};
- State_t(State_t &&) = delete;
-
- State_t & operator += (const State_t & other)
- {
- for(int i = 0; i < 16; i++)
- data[i] += other.data[i];
- return *this;
- }
- void Copy(const State_t & other)
- {
- memcpy(data, other.data, sizeof(uint32_t) * 16);
- }
- uint32_t data[16];
- };
+void Chacha20Block::operator << (const Chacha20State & st)
+{
+ int i;
+ for (i = 0; i < 16; i++)
+ u32t8le(st.data[i], data + (i << 2));
+}
- struct Block_t
- {
- Block_t() {};
- Block_t(Block_t &&) = delete;
-
- uint8_t data[blocksize];
-
- void operator << (const State_t & st)
- {
- int i;
- for (i = 0; i < 16; i++)
- u32t8le(st.data[i], data + (i << 2));
- }
- };
-
-void block(const State_t &input, Block_t & block, int rounds)
+void block (Chacha20State &input, int rounds)
{
int i;
- State_t x;
+ Chacha20State x;
x.Copy(input);
for (i = rounds; i > 0; i -= 2)
@@ -100,48 +76,61 @@ void block(const State_t &input, Block_t & block, int rounds)
quarterround(x.data, 3, 4, 9, 14);
}
x += input;
- block << x;
+ input.block << x;
}
+
+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;
+ state.data[3] = 0x6b206574;
+ for (size_t i = 0; i < 8; i++)
+ state.data[4 + i] = chacha::u8t32le(key + i * 4);
+
+ state.data[12] = 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)
+{
+ state.data[12] = counter;
+ 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;
+ for (size_t i = 0; i < s; i++)
+ buf[i] ^= state.block.data[state.offset + i];
+ buf += s;
+ sz -= s;
+ state.offset = 0;
+ }
+ 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)
+ {
+ state.offset = j & 0x3F; // % 64
+ break;
+ }
+ buf[j] ^= state.block.data[j - i];
+ }
+ }
+}
} // namespace chacha
-
-
-
-
-void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
-{
- chacha::State_t state;
- chacha::Block_t block;
- size_t i, j;
-
- state.data[0] = 0x61707865;
- state.data[1] = 0x3320646e;
- state.data[2] = 0x79622d32;
- state.data[3] = 0x6b206574;
-
- for (i = 0; i < 8; i++)
- state.data[4 + i] = chacha::u8t32le(key + i * 4);
-
-
- state.data[12] = counter;
-
- for (i = 0; i < 3; i++)
- state.data[13 + i] = chacha::u8t32le(nonce + i * 4);
-
-
- for (i = 0; i < sz; i += chacha::blocksize)
- {
- chacha::block(state, block, chacha::rounds);
- state.data[12]++;
- for (j = i; j < i + chacha::blocksize; j++)
- {
- if (j >= sz) break;
- buf[j] ^= block.data[j - i];
- }
- }
-
}
-
}
-}
\ No newline at end of file
+#endif
+
diff --git a/libi2pd/ChaCha20.h b/libi2pd/ChaCha20.h
index c88325d5..a5a8aafc 100644
--- a/libi2pd/ChaCha20.h
+++ b/libi2pd/ChaCha20.h
@@ -1,26 +1,72 @@
-/**
- This code is licensed under the MCGSI Public License
- Copyright 2018 Jeff Becker
-
- Kovri go write your own code
-
- */
+/*
+* Copyright (c) 2013-2018, The PurpleI2P Project
+*
+* This file is part of Purple i2pd project and licensed under BSD3
+*
+* See full license text in LICENSE file at top of project tree
+*
+* Kovri go write your own code
+*
+*/
#ifndef LIBI2PD_CHACHA20_H
#define LIBI2PD_CHACHA20_H
#include
#include
+#include
+#include
+#include "Crypto.h"
+#if LEGACY_OPENSSL
namespace i2p
{
namespace crypto
{
- const std::size_t CHACHA20_KEY_BYTES = 32;
- const std::size_t CHACHA20_NOUNCE_BYTES = 12;
+ const std::size_t CHACHA20_KEY_BYTES = 32;
+ const std::size_t CHACHA20_NOUNCE_BYTES = 12;
+
+namespace chacha
+{
+ constexpr std::size_t blocksize = 64;
+ constexpr int rounds = 20;
- /** encrypt buf in place with chacha20 */
- void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * key, uint32_t counter=1);
+ struct Chacha20State;
+ struct Chacha20Block
+ {
+ Chacha20Block () {};
+ Chacha20Block (Chacha20Block &&) = delete;
+ uint8_t data[blocksize];
+
+ void operator << (const Chacha20State & st);
+ };
+
+ struct Chacha20State
+ {
+ Chacha20State (): offset (0) {};
+ 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)
+ {
+ 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
}
+}
}
+#endif
#endif
diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp
index cf6f9b56..0403275f 100644
--- a/libi2pd/Config.cpp
+++ b/libi2pd/Config.cpp
@@ -88,6 +88,7 @@ namespace config {
("http.pass", value()->default_value(""), "Password for basic auth (default: random, see logs)")
("http.strictheaders", value()->default_value(true), "Enable strict host checking on WebUI")
("http.hostname", value()->default_value("localhost"), "Expected hostname for WebUI")
+ ("http.webroot", value()->default_value("/"), "WebUI root path (default: / )")
;
options_description httpproxy("HTTP Proxy options");
@@ -236,10 +237,27 @@ namespace config {
options_description ntcp2("NTCP2 Options");
ntcp2.add_options()
("ntcp2.enabled", value()->default_value(true), "Enable NTCP2 (default: enabled)")
- ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)")
+ ("ntcp2.published", value()->default_value(false), "Publish NTCP2 (default: disabled)")
("ntcp2.port", value()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
;
+ options_description nettime("Time sync options");
+ nettime.add_options()
+ ("nettime.enabled", value()->default_value(false), "Disable time sync (default: disabled)")
+ ("nettime.ntpservers", value()->default_value(
+ "0.pool.ntp.org,"
+ "1.pool.ntp.org,"
+ "2.pool.ntp.org,"
+ "3.pool.ntp.org"
+ ), "Comma separated list of NTCP servers")
+ ("nettime.ntpsyncinterval", value()->default_value(72), "NTP sync interval in hours (default: 72)")
+ ;
+
+ options_description persist("Network information persisting options");
+ persist.add_options()
+ ("persist.profiles", value()->default_value(true), "Persist peer profiles (default: true)")
+ ;
+
m_OptionsDesc
.add(general)
.add(limits)
@@ -258,6 +276,8 @@ namespace config {
.add(websocket)
.add(exploratory)
.add(ntcp2)
+ .add(nettime)
+ .add(persist)
;
}
diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp
index ffd3c4ef..28df1399 100644
--- a/libi2pd/Crypto.cpp
+++ b/libi2pd/Crypto.cpp
@@ -1087,62 +1087,62 @@ namespace crypto
if (encrypt && len < msgLen + 16) return false;
bool ret = true;
#if LEGACY_OPENSSL
+ chacha::Chacha20State state;
// generate one time poly key
- uint8_t polyKey[64];
+ chacha::Chacha20Init (state, nonce, key, 0);
+ uint64_t polyKey[8];
memset(polyKey, 0, sizeof(polyKey));
- chacha20 (polyKey, 64, nonce, key, 0);
-
- // create Poly1305 message
+ chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
+ // create Poly1305 hash
+ Poly1305 polyHash (polyKey);
if (!ad) adLen = 0;
- std::vector polyMsg(adLen + msgLen + 3*16);
- size_t offset = 0;
uint8_t padding[16]; memset (padding, 0, 16);
if (ad)
{
- memcpy (polyMsg.data (), ad, adLen); offset += adLen; // additional authenticated data
+ polyHash.Update (ad, adLen);// additional authenticated data
auto rem = adLen & 0x0F; // %16
if (rem)
{
// padding1
rem = 16 - rem;
- memcpy (polyMsg.data () + offset, padding, rem); offset += rem;
+ polyHash.Update (padding, rem);
}
}
// encrypt/decrypt data and add to hash
+ Chacha20SetCounter (state, 1);
if (buf != msg)
memcpy (buf, msg, msgLen);
if (encrypt)
{
- chacha20 (buf, msgLen, nonce, key, 1); // encrypt
- memcpy (polyMsg.data () + offset, buf, msgLen); // after encryption
+ chacha::Chacha20Encrypt (state, buf, msgLen); // encrypt
+ polyHash.Update (buf, msgLen); // after encryption
}
else
{
- memcpy (polyMsg.data () + offset, buf, msgLen); // before decryption
- chacha20 (buf, msgLen, nonce, key, 1); // decrypt
+ polyHash.Update (buf, msgLen); // before decryption
+ chacha::Chacha20Encrypt (state, buf, msgLen); // decrypt
}
- offset += msgLen; // encrypted data
auto rem = msgLen & 0x0F; // %16
if (rem)
{
// padding2
rem = 16 - rem;
- memcpy (polyMsg.data () + offset, padding, rem); offset += rem;
+ polyHash.Update (padding, rem);
}
- htole64buf (polyMsg.data () + offset, adLen); offset += 8;
- htole64buf (polyMsg.data () + offset, msgLen); offset += 8;
-
+ // adLen and msgLen
+ htole64buf (padding, adLen);
+ htole64buf (padding + 8, msgLen);
+ polyHash.Update (padding, 16);
+
if (encrypt)
- {
// calculate Poly1305 tag and write in after encrypted data
- Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset);
- }
+ polyHash.Finish ((uint64_t *)(buf + msgLen));
else
{
- uint32_t tag[8];
+ uint64_t tag[4];
// calculate Poly1305 tag
- Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset);
+ polyHash.Finish (tag);
if (memcmp (tag, msg + msgLen, 16)) ret = false; // compare with provided
}
#else
@@ -1174,6 +1174,56 @@ namespace crypto
return ret;
}
+ void AEADChaCha20Poly1305Encrypt (std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
+ {
+ if (bufs.empty ()) return;
+#if LEGACY_OPENSSL
+ chacha::Chacha20State state;
+ // generate one time poly key
+ chacha::Chacha20Init (state, nonce, key, 0);
+ uint64_t polyKey[8];
+ memset(polyKey, 0, sizeof(polyKey));
+ chacha::Chacha20Encrypt (state, (uint8_t *)polyKey, 64);
+ Poly1305 polyHash (polyKey);
+ // encrypt buffers
+ Chacha20SetCounter (state, 1);
+ size_t size = 0;
+ for (auto& it: bufs)
+ {
+ chacha::Chacha20Encrypt (state, (uint8_t *)it.first, it.second);
+ polyHash.Update ((uint8_t *)it.first, it.second); // after encryption
+ size += it.second;
+ }
+ // padding
+ uint8_t padding[16];
+ memset (padding, 0, 16);
+ auto rem = size & 0x0F; // %16
+ if (rem)
+ {
+ // padding2
+ rem = 16 - rem;
+ polyHash.Update (padding, rem);
+ }
+ // adLen and msgLen
+ // adLen is always zero
+ htole64buf (padding + 8, size);
+ polyHash.Update (padding, 16);
+ // MAC
+ polyHash.Finish ((uint64_t *)mac);
+#else
+ int outlen = 0;
+ EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
+ EVP_EncryptInit_ex(ctx, EVP_chacha20_poly1305(), 0, 0, 0);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 12, 0);
+ EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce);
+ for (auto& it: bufs)
+ EVP_EncryptUpdate(ctx, (uint8_t *)it.first, &outlen, (uint8_t *)it.first, it.second);
+ EVP_EncryptFinal_ex(ctx, NULL, &outlen);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, mac);
+ EVP_CIPHER_CTX_free (ctx);
+#endif
+ }
+
// init and terminate
/* std::vector > m_OpenSSLMutexes;
diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h
index 5daf82b0..79d16e50 100644
--- a/libi2pd/Crypto.h
+++ b/libi2pd/Crypto.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#include
#include
#include
@@ -108,35 +109,16 @@ namespace crypto
void operator^=(const ChipherBlock& other) // XOR
{
-#ifdef __AVX__
- if (i2p::cpu::avx)
- {
- __asm__
- (
- "vmovups (%[buf]), %%xmm0 \n"
- "vmovups (%[other]), %%xmm1 \n"
- "vxorps %%xmm0, %%xmm1, %%xmm0 \n"
- "vmovups %%xmm0, (%[buf]) \n"
- :
- : [buf]"r"(buf), [other]"r"(other.buf)
- : "%xmm0", "%xmm1", "memory"
- );
- }
+ if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
+ {
+ for (int i = 0; i < 4; i++)
+ reinterpret_cast(buf)[i] ^= reinterpret_cast(other.buf)[i];
+ }
else
-#endif
- {
- if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
- {
- // we are good to cast to uint32_t *
- for (int i = 0; i < 4; i++)
- ((uint32_t *)buf)[i] ^= ((uint32_t *)other.buf)[i];
- }
- else
- {
- for (int i = 0; i < 16; i++)
- buf[i] ^= other.buf[i];
- }
- }
+ {
+ for (int i = 0; i < 16; i++)
+ buf[i] ^= other.buf[i];
+ }
}
};
@@ -301,6 +283,8 @@ 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
+ void AEADChaCha20Poly1305Encrypt (std::vector >& bufs, const uint8_t * key, const uint8_t * nonce, uint8_t * mac); // encrypt multiple buffers with zero ad
+
// init and terminate
void InitCrypto (bool precomputation);
void TerminateCrypto ();
diff --git a/libi2pd/Ed25519.cpp b/libi2pd/Ed25519.cpp
index 17264926..2c64c475 100644
--- a/libi2pd/Ed25519.cpp
+++ b/libi2pd/Ed25519.cpp
@@ -411,6 +411,7 @@ namespace crypto
}
}
+#if !OPENSSL_X25519
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
{
BN_CTX_start (ctx);
@@ -488,6 +489,7 @@ namespace crypto
EncodeBN (q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1);
}
+#endif
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
{
diff --git a/libi2pd/Ed25519.h b/libi2pd/Ed25519.h
index fc23a457..48b3a665 100644
--- a/libi2pd/Ed25519.h
+++ b/libi2pd/Ed25519.h
@@ -3,6 +3,7 @@
#include
#include
+#include "Crypto.h"
namespace i2p
{
@@ -75,8 +76,10 @@ namespace crypto
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;
+#endif
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;
@@ -100,8 +103,10 @@ namespace crypto
BIGNUM * DecodeBN (const uint8_t * buf) const;
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
+#if !OPENSSL_X25519
// for x25519
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
+#endif
private:
diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h
index 15e3a32c..5160acec 100644
--- a/libi2pd/I2NPProtocol.h
+++ b/libi2pd/I2NPProtocol.h
@@ -75,6 +75,7 @@ namespace i2p
enum I2NPMessageType
{
+ eI2NPDummyMsg = 0,
eI2NPDatabaseStore = 1,
eI2NPDatabaseLookup = 2,
eI2NPDatabaseSearchReply = 3,
diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp
index 8caafd2f..513aad08 100644
--- a/libi2pd/NTCP2.cpp
+++ b/libi2pd/NTCP2.cpp
@@ -695,8 +695,7 @@ namespace transport
SendTerminationAndTerminate (eNTCP2IncorrectSParameter);
return;
}
-
- i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // TODO: should insert ri and not parse it twice
+ i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice
// TODO: process options
// ready to communicate
@@ -861,7 +860,7 @@ namespace transport
case eNTCP2BlkRouterInfo:
{
LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]);
- i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1);
+ i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, frame + offset, size));
break;
}
case eNTCP2BlkI2NPMessage:
@@ -873,6 +872,7 @@ namespace transport
break;
}
auto nextMsg = NewI2NPMessage (size);
+ nextMsg->Align (12); // for possible tunnel msg
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
nextMsg->FromNTCP2 ();
diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h
index ec8ae527..eb46b2f8 100644
--- a/libi2pd/NTCP2.h
+++ b/libi2pd/NTCP2.h
@@ -73,6 +73,8 @@ namespace transport
eNTCP2Banned, // 17
};
+ // RouterInfo flags
+ const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
typedef std::array NTCP2FrameBuffer;
struct NTCP2Establisher
diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp
index 0add6f91..2e5c3a23 100644
--- a/libi2pd/NetDb.cpp
+++ b/libi2pd/NetDb.cpp
@@ -12,6 +12,7 @@
#include "I2NPProtocol.h"
#include "Tunnel.h"
#include "Transports.h"
+#include "NTCP2.h"
#include "RouterContext.h"
#include "Garlic.h"
#include "NetDb.hpp"
@@ -25,7 +26,7 @@ namespace data
{
NetDb netdb;
- NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false)
+ NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false)
{
}
@@ -43,10 +44,12 @@ namespace data
m_Families.LoadCertificates ();
Load ();
- uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
+ uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold
Reseed ();
+ i2p::config::GetOption("persist.profiles", m_PersistProfiles);
+
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&NetDb::Run, this));
}
@@ -55,8 +58,9 @@ namespace data
{
if (m_IsRunning)
{
- for (auto& it: m_RouterInfos)
- it.second->SaveProfile ();
+ if (m_PersistProfiles)
+ for (auto& it: m_RouterInfos)
+ it.second->SaveProfile ();
DeleteObsoleteProfiles ();
m_RouterInfos.clear ();
m_Floodfills.clear ();
@@ -98,6 +102,10 @@ namespace data
case eI2NPDatabaseLookup:
HandleDatabaseLookupMsg (msg);
break;
+ case eI2NPDummyMsg:
+ // plain RouterInfo from NTCP2 with flags for now
+ HandleNTCP2RouterInfoMsg (msg);
+ break;
default: // WTF?
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
//i2p::HandleI2NPMessage (msg);
@@ -162,22 +170,38 @@ namespace data
}
}
+ void NetDb::SetHidden(bool hide)
+ {
+ // TODO: remove reachable addresses from router info
+ m_HiddenMode = hide;
+ }
+
bool NetDb::AddRouterInfo (const uint8_t * buf, int len)
+ {
+ bool updated;
+ AddRouterInfo (buf, len, updated);
+ return updated;
+ }
+
+ std::shared_ptr NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
{
IdentityEx identity;
if (identity.FromBuffer (buf, len))
- return AddRouterInfo (identity.GetIdentHash (), buf, len);
- return false;
+ return AddRouterInfo (identity.GetIdentHash (), buf, len, updated);
+ updated = false;
+ return nullptr;
}
- void NetDb::SetHidden(bool hide) {
- // TODO: remove reachable addresses from router info
- m_HiddenMode = hide;
- }
-
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
{
- bool updated = true;
+ bool updated;
+ AddRouterInfo (ident, buf, len, updated);
+ return updated;
+ }
+
+ std::shared_ptr NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated)
+ {
+ updated = true;
auto r = FindRouter (ident);
if (r)
{
@@ -223,7 +247,7 @@ namespace data
}
// take care about requested destination
m_Requests.RequestComplete (ident, r);
- return updated;
+ return r;
}
bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len,
@@ -518,7 +542,7 @@ namespace data
{
if (it->second->IsUnreachable ())
{
- it->second->SaveProfile ();
+ if (m_PersistProfiles) it->second->SaveProfile ();
it = m_RouterInfos.erase (it);
continue;
}
@@ -570,6 +594,17 @@ namespace data
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
}
+ void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr m)
+ {
+ uint8_t flood = m->GetPayload ()[0] & NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD;
+ bool updated;
+ auto ri = AddRouterInfo (m->GetPayload () + 1, m->GetPayloadLength () - 1, updated); // without flags
+ if (flood && updated && context.IsFloodfill () && ri)
+ {
+ auto floodMsg = CreateDatabaseStoreMsg (ri, 0); // replyToken = 0
+ Flood (ri->GetIdentHash (), floodMsg);
+ }
+ }
void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m)
{
@@ -649,22 +684,7 @@ namespace data
{
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
- std::set excluded;
- excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
- excluded.insert (ident); // don't flood back
- for (int i = 0; i < 3; i++)
- {
- auto floodfill = GetClosestFloodfill (ident, excluded);
- if (floodfill)
- {
- auto h = floodfill->GetIdentHash();
- LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
- transports.SendMessage (h, CopyI2NPMessage(floodMsg));
- excluded.insert (h);
- }
- else
- break;
- }
+ Flood (ident, floodMsg);
}
else
LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
@@ -965,6 +985,26 @@ namespace data
}
}
+ void NetDb::Flood (const IdentHash& ident, std::shared_ptr floodMsg)
+ {
+ std::set excluded;
+ excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
+ excluded.insert (ident); // don't flood back
+ for (int i = 0; i < 3; i++)
+ {
+ auto floodfill = GetClosestFloodfill (ident, excluded);
+ if (floodfill)
+ {
+ auto h = floodfill->GetIdentHash();
+ LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
+ transports.SendMessage (h, CopyI2NPMessage(floodMsg));
+ excluded.insert (h);
+ }
+ else
+ break;
+ }
+ }
+
std::shared_ptr NetDb::GetRandomRouter () const
{
return GetRandomRouter (
diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp
index 18377b4f..b34458fb 100644
--- a/libi2pd/NetDb.hpp
+++ b/libi2pd/NetDb.hpp
@@ -65,7 +65,8 @@ namespace data
void HandleDatabaseStoreMsg (std::shared_ptr msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr msg);
void HandleDatabaseLookupMsg (std::shared_ptr msg);
-
+ void HandleNTCP2RouterInfoMsg (std::shared_ptr m);
+
std::shared_ptr GetRandomRouter () const;
std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith) const;
std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith) const;
@@ -110,13 +111,16 @@ namespace data
void Run (); // exploratory thread
void Explore (int numDestinations);
void Publish ();
+ void Flood (const IdentHash& ident, std::shared_ptr floodMsg);
void ManageLeaseSets ();
void ManageRequests ();
- void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
+ void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
- template
- std::shared_ptr GetRandomRouter (Filter filter) const;
+ std::shared_ptr AddRouterInfo (const uint8_t * buf, int len, bool& updated);
+ std::shared_ptr AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated);
+ template
+ std::shared_ptr GetRandomRouter (Filter filter) const;
private:
@@ -140,6 +144,8 @@ namespace data
friend class NetDbRequests;
NetDbRequests m_Requests;
+ bool m_PersistProfiles;
+
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr m_FloodfillBootstrap;
diff --git a/libi2pd/Poly1305.cpp b/libi2pd/Poly1305.cpp
index 9ee46640..4ce67d39 100644
--- a/libi2pd/Poly1305.cpp
+++ b/libi2pd/Poly1305.cpp
@@ -6,246 +6,20 @@
Kovri go write your own code
*/
+
+#if LEGACY_OPENSSL
namespace i2p
{
namespace crypto
{
- namespace poly1305
+
+ void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz)
{
-
- struct LongBlock
- {
- unsigned long data[17];
- operator unsigned long * ()
- {
- return data;
- }
- };
-
- struct Block
- {
- unsigned char data[17];
-
- operator uint8_t * ()
- {
- return data;
- }
-
- Block & operator += (const Block & other)
- {
- unsigned short u;
- unsigned int 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;
- }
- return *this;
- }
-
- 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;
- u >>= 8;
- }
- u += other.data[16];
- 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;
- u >>= 8;
- }
- data[16] += (unsigned char)u;
- return *this;
- }
-
- Block & operator = (const Block & other)
- {
- memcpy(data, other.data, sizeof(data));
- return *this;
- }
-
- Block & operator ~ ()
- {
- static const Block minusp = {
- 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0xfc
- };
- Block orig;
- unsigned char neg;
- unsigned int i;
- orig = *this;
- *this += minusp;
- neg = -(data[16] >> 7);
- for(i = 0; i < 17; i++)
- data[i] ^= neg & (orig.data[i] ^ data[i]);
-
- return *this;
- }
-
- void PutKey(const uint8_t * key)
- {
- data[0] = key[0] & 0xff;
- data[1] = key[1] & 0xff;
- data[2] = key[2] & 0xff;
- data[3] = key[3] & 0x0f;
- data[4] = key[4] & 0xfc;
- data[5] = key[5] & 0xff;
- data[6] = key[6] & 0xff;
- data[7] = key[7] & 0x0f;
- data[8] = key[8] & 0xfc;
- data[9] = key[9] & 0xff;
- data[10] = key[10] & 0xff;
- data[11] = key[11] & 0x0f;
- data[12] = key[12] & 0xfc;
- data[13] = key[13] & 0xff;
- data[14] = key[14] & 0xff;
- data[15] = key[15] & 0x0f;
- data[16] = 0;
- }
-
- void Put(const uint8_t * d, uint8_t last=0)
- {
- memcpy(data, d, 17);
- data[16] = last;
- }
- };
-
- struct Buffer
- {
- uint8_t data[POLY1305_BLOCK_BYTES];
-
- operator uint8_t * ()
- {
- return data;
- }
- };
- }
-
- struct Poly1305
- {
-#if (__GNUC__ == 4) && (__GNUC_MINOR__ < 8) // older than gcc 4.8
- Poly1305(const uint8_t * key) : m_Leftover(0), m_Final(0)
- {
- memset (&m_H, 0, sizeof (m_H));
-#else
- Poly1305(const uint8_t * key) : m_Leftover(0), m_H{0}, m_Final(0)
- {
-#endif
- m_R.PutKey(key);
- m_Pad.Put(key + 16);
- }
-
- void Update(const uint8_t * buf, size_t sz)
- {
- // process leftover
- if(m_Leftover)
- {
- size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
- 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;
- Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
- m_Leftover = 0;
- }
- // process blocks
- 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);
- m_Leftover += 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;
-
- unsigned int i, j;
- m_Msg.Put(buf, hi);
- /* h += m */
- m_H += m_Msg;
-
- /* 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 = i + 1; j < 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;
- }
- m_HR[i] = u;
- }
- /* (partial) h %= p */
- m_H %= m_HR;
- buf += POLY1305_BLOCK_BYTES;
- sz -= POLY1305_BLOCK_BYTES;
- }
- }
-
- void Finish(uint32_t *& out)
- {
- // process leftovers
- if(m_Leftover)
- {
- size_t idx = m_Leftover;
- m_Buffer[idx++] = 1;
- for(; idx < POLY1305_BLOCK_BYTES; idx++)
- m_Buffer[idx] = 0;
- m_Final = 1;
- Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
- }
-
- // freeze H
- ~m_H;
- // add pad
- m_H += m_Pad;
- // copy digest
- memcpy(out, m_H, 16);
- }
-
- size_t m_Leftover;
- poly1305::Buffer m_Buffer;
- poly1305::Block m_H;
- poly1305::Block m_R;
- poly1305::Block m_Pad;
- poly1305::Block m_Msg;
- poly1305::LongBlock m_HR;
- uint8_t m_Final;
-
- };
-
- void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz)
- {
- const uint8_t * k = (const uint8_t *) key;
- Poly1305 p(k);
+ Poly1305 p(key);
p.Update(buf, sz);
p.Finish(out);
- }
+ }
}
}
+#endif
+
diff --git a/libi2pd/Poly1305.h b/libi2pd/Poly1305.h
index 2c62c5aa..d9529c81 100644
--- a/libi2pd/Poly1305.h
+++ b/libi2pd/Poly1305.h
@@ -9,20 +9,253 @@
#define LIBI2PD_POLY1305_H
#include
#include
+#include "Crypto.h"
+#if LEGACY_OPENSSL
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;
+ 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
+ {
+ unsigned long data[17];
+ operator unsigned long * ()
+ {
+ return data;
+ }
+ };
+
+ struct Block
+ {
+ unsigned char data[17];
+
+ void Zero()
+ {
+ memset(data, 0, sizeof(data));
+ }
+
+ operator uint8_t * ()
+ {
+ return data;
+ }
+
+ Block & operator += (const Block & other)
+ {
+ unsigned short u;
+ unsigned int 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;
+ }
+ return *this;
+ }
+
+ 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;
+ u >>= 8;
+ }
+ u += other.data[16];
+ 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;
+ u >>= 8;
+ }
+ data[16] += (unsigned char)u;
+ return *this;
+ }
+
+ Block & operator = (const Block & other)
+ {
+ memcpy(data, other.data, sizeof(data));
+ return *this;
+ }
+
+ Block & operator ~ ()
+ {
+ static const Block minusp = {
+ 0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xfc
+ };
+ Block orig;
+ unsigned char neg;
+ unsigned int i;
+ orig = *this;
+ *this += minusp;
+ neg = -(data[16] >> 7);
+ 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;
+ data[0] = key[0] & 0xff;
+ data[1] = key[1] & 0xff;
+ data[2] = key[2] & 0xff;
+ data[3] = key[3] & 0x0f;
+ data[4] = key[4] & 0xfc;
+ data[5] = key[5] & 0xff;
+ data[6] = key[6] & 0xff;
+ data[7] = key[7] & 0x0f;
+ data[8] = key[8] & 0xfc;
+ data[9] = key[9] & 0xff;
+ data[10] = key[10] & 0xff;
+ data[11] = key[11] & 0x0f;
+ data[12] = key[12] & 0xfc;
+ data[13] = key[13] & 0xff;
+ data[14] = key[14] & 0xff;
+ data[15] = key[15] & 0x0f;
+ data[16] = 0;
+ }
+
+ template
+ void Put(const Int_t * d, uint8_t last=0)
+ {
+ memcpy(data, d, 16);
+ data[16] = last;
+ }
+ };
+
+ struct Buffer
+ {
+ uint8_t data[POLY1305_BLOCK_BYTES];
+
+ operator uint8_t * ()
+ {
+ return data;
+ }
+ };
+ }
+
+ struct Poly1305
+ {
+ Poly1305(const uint64_t * key)
+ {
+ m_Leftover = 0;
+ m_H.Zero();
+ m_Final = 0;
+ m_R.PutKey(key);
+ m_Pad.Put(key + 2);
+ }
+
+ void Update(const uint8_t * buf, size_t sz)
+ {
+ // process leftover
+ if(m_Leftover)
+ {
+ size_t want = POLY1305_BLOCK_BYTES - m_Leftover;
+ 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;
+ Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
+ m_Leftover = 0;
+ }
+ // process blocks
+ 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);
+ m_Leftover += 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;
+ unsigned int i, j;
+ m_Msg.Put(buf, hi);
+ /* h += m */
+ m_H += m_Msg;
+
+ /* 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 = i + 1; j < 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;
+ }
+ m_HR[i] = u;
+ }
+ /* (partial) h %= p */
+ m_H %= m_HR;
+ buf += POLY1305_BLOCK_BYTES;
+ sz -= POLY1305_BLOCK_BYTES;
+ }
+ }
+
+ void Finish(uint64_t * out)
+ {
+ // process leftovers
+ if(m_Leftover)
+ {
+ size_t idx = m_Leftover;
+ m_Buffer[idx++] = 1;
+ for(; idx < POLY1305_BLOCK_BYTES; idx++)
+ m_Buffer[idx] = 0;
+ m_Final = 1;
+ Blocks(m_Buffer, POLY1305_BLOCK_BYTES);
+ }
+
+ // freeze H
+ ~m_H;
+ // add pad
+ m_H += m_Pad;
+ // copy digest
+ memcpy(out, m_H, 16);
+ }
+
+ size_t m_Leftover;
+ poly1305::Buffer m_Buffer;
+ poly1305::Block m_H;
+ poly1305::Block m_R;
+ poly1305::Block m_Pad;
+ poly1305::Block m_Msg;
+ poly1305::LongBlock m_HR;
+ uint8_t m_Final;
+ };
+ void Poly1305HMAC(uint64_t * out, const uint64_t * key, const uint8_t * buf, std::size_t sz);
- void Poly1305HMAC(uint32_t * out, const uint32_t * key, const uint8_t * buf, std::size_t sz);
-
}
}
+#endif
#endif
diff --git a/libi2pd/Siphash.h b/libi2pd/Siphash.h
index aa8b8631..70822466 100644
--- a/libi2pd/Siphash.h
+++ b/libi2pd/Siphash.h
@@ -9,7 +9,9 @@
#define SIPHASH_H
#include
+#include "Crypto.h"
+#if !OPENSSL_SIPHASH
namespace i2p
{
namespace crypto
@@ -148,5 +150,6 @@ namespace crypto
}
}
}
+#endif
#endif
diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp
index 9e9b4e63..492e4559 100644
--- a/libi2pd/Timestamp.cpp
+++ b/libi2pd/Timestamp.cpp
@@ -1,6 +1,10 @@
#include
#include
+#include
+#include
#include
+#include
+#include "Config.h"
#include "Log.h"
#include "I2PEndian.h"
#include "Timestamp.h"
@@ -15,10 +19,30 @@ namespace i2p
{
namespace util
{
+ static uint64_t GetLocalMillisecondsSinceEpoch ()
+ {
+ return std::chrono::duration_cast(
+ std::chrono::system_clock::now().time_since_epoch()).count ();
+ }
+
+ static uint32_t GetLocalHoursSinceEpoch ()
+ {
+ return std::chrono::duration_cast(
+ std::chrono::system_clock::now().time_since_epoch()).count ();
+ }
+
+ static uint64_t GetLocalSecondsSinceEpoch ()
+ {
+ return std::chrono::duration_cast(
+ std::chrono::system_clock::now().time_since_epoch()).count ();
+ }
+
+
static int64_t g_TimeOffset = 0; // in seconds
- void SyncTimeWithNTP (const std::string& address)
+ static void SyncTimeWithNTP (const std::string& address)
{
+ LogPrint (eLogInfo, "Timestamp: NTP request to ", address);
boost::asio::io_service service;
boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp");
boost::system::error_code ec;
@@ -48,18 +72,111 @@ namespace util
}
catch (std::exception& e)
{
- LogPrint (eLogError, "NTP error: ", e.what ());
+ LogPrint (eLogError, "Timestamp: NTP error: ", e.what ());
}
if (len >= 8)
{
- auto ourTs = GetSecondsSinceEpoch ();
+ 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, 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 resove address ", address);
+ }
+
+ 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);
+ }
+
+ NTPTimeSync::~NTPTimeSync ()
+ {
+ Stop ();
+ }
+
+ 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");
+ }
+
+ 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);
+ }
+ }
+ }
+
+ void NTPTimeSync::Run ()
+ {
+ while (m_IsRunning)
+ {
+ try
+ {
+ m_Service.run ();
+ }
+ 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 ()]);
+ 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 (ecode != boost::asio::error::operation_aborted)
+ Sync ();
+ });
+ }
+ }
+
+ uint64_t GetMillisecondsSinceEpoch ()
+ {
+ return GetLocalMillisecondsSinceEpoch () + g_TimeOffset*1000;
+ }
+
+ uint32_t GetHoursSinceEpoch ()
+ {
+ return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;
+ }
+
+ uint64_t GetSecondsSinceEpoch ()
+ {
+ return GetLocalSecondsSinceEpoch () + g_TimeOffset;
}
}
}
diff --git a/libi2pd/Timestamp.h b/libi2pd/Timestamp.h
index cddc6518..e859f7f6 100644
--- a/libi2pd/Timestamp.h
+++ b/libi2pd/Timestamp.h
@@ -2,29 +2,43 @@
#define TIMESTAMP_H__
#include
-#include
+#include
+#include
+#include
+#include
namespace i2p
{
namespace util
{
- inline uint64_t GetMillisecondsSinceEpoch ()
- {
- return std::chrono::duration_cast(
- std::chrono::system_clock::now().time_since_epoch()).count ();
- }
+ uint64_t GetMillisecondsSinceEpoch ();
+ uint32_t GetHoursSinceEpoch ();
+ uint64_t GetSecondsSinceEpoch ();
- inline uint32_t GetHoursSinceEpoch ()
+ class NTPTimeSync
{
- return std::chrono::duration_cast(
- std::chrono::system_clock::now().time_since_epoch()).count ();
- }
+ public:
- inline uint64_t GetSecondsSinceEpoch ()
- {
- return std::chrono::duration_cast(
- std::chrono::system_clock::now().time_since_epoch()).count ();
- }
+ NTPTimeSync ();
+ ~NTPTimeSync ();
+
+ void Start ();
+ void Stop ();
+
+ private:
+
+ void Run ();
+ void Sync ();
+
+ private:
+
+ bool m_IsRunning;
+ std::unique_ptr m_Thread;
+ boost::asio::io_service m_Service;
+ boost::asio::deadline_timer m_Timer;
+ int m_SyncInterval;
+ std::vector m_NTPServersList;
+ };
}
}
diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp
index 6a833ae0..64f41afd 100644
--- a/libi2pd/Transports.cpp
+++ b/libi2pd/Transports.cpp
@@ -35,8 +35,11 @@ namespace transport
void DHKeysPairSupplier::Stop ()
{
- m_IsRunning = false;
- m_Acquired.notify_one ();
+ {
+ std::unique_lock l(m_AcquiredMutex);
+ m_IsRunning = false;
+ m_Acquired.notify_one ();
+ }
if (m_Thread)
{
m_Thread->join ();
@@ -50,19 +53,20 @@ namespace transport
while (m_IsRunning)
{
int num, total = 0;
- while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20)
+ while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
{
CreateDHKeysPairs (num);
total += num;
}
- if (total >= 20)
+ if (total >= 10)
{
LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time");
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
}
else
{
- std::unique_lock l(m_AcquiredMutex);
+ std::unique_lock l(m_AcquiredMutex);
+ if (!m_IsRunning) break;
m_Acquired.wait (l); // wait for element gets acquired
}
}
@@ -813,7 +817,6 @@ namespace transport
if (profile)
{
profile->TunnelNonReplied();
- profile->Save(it->first);
}
std::unique_lock l(m_PeersMutex);
it = m_Peers.erase (it);
diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp
index 1395c2e6..b558fca4 100644
--- a/libi2pd/util.cpp
+++ b/libi2pd/util.cpp
@@ -21,9 +21,9 @@
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+/* // No more needed. Exists in MinGW.
int inet_pton(int af, const char *src, void *dst)
-{ /* This function was written by Petar Korponai?. See
-http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */
+{ // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
struct sockaddr_storage ss;
int size = sizeof (ss);
char src_copy[INET6_ADDRSTRLEN + 1];
@@ -45,7 +45,7 @@ http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */
}
}
return 0;
-}
+}*/
#else /* !WIN32 => UNIX */
#include
#include
diff --git a/libi2pd_client/HTTPProxy.cpp b/libi2pd_client/HTTPProxy.cpp
index f0530ac1..e54ccda5 100644
--- a/libi2pd_client/HTTPProxy.cpp
+++ b/libi2pd_client/HTTPProxy.cpp
@@ -390,6 +390,10 @@ namespace proxy {
std::string origURI = m_ClientRequest.uri; // TODO: what do we need to change uri for?
m_ClientRequest.uri = m_ClientRequestURL.to_string();
+ // update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections
+ if(m_ClientRequest.method != "CONNECT")
+ m_ClientRequest.UpdateHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0");
+
m_ClientRequest.write(m_ClientRequestBuffer);
m_ClientRequestBuffer << m_recv_buf.substr(m_req_len);
diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml
index 16ae602a..f6b98ed7 100644
--- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml
+++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml
@@ -35,6 +35,7 @@
+
diff --git a/tests/test-aeadchacha20poly1305.cpp b/tests/test-aeadchacha20poly1305.cpp
index dcd4b4d6..d10ab2fc 100644
--- a/tests/test-aeadchacha20poly1305.cpp
+++ b/tests/test-aeadchacha20poly1305.cpp
@@ -51,4 +51,10 @@ int main ()
uint8_t buf1[114];
assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false));
assert (memcmp (buf1, text, 114) == 0);
+ // test encryption of multiple buffers
+ memcpy (buf, text, 114);
+ std::vector > bufs{ std::make_pair (buf, 50), std::make_pair (buf + 50, 50), std::make_pair (buf + 100, 14) };
+ i2p::crypto::AEADChaCha20Poly1305Encrypt (bufs, key, nonce, buf + 114);
+ i2p::crypto::AEADChaCha20Poly1305 (buf, 114, nullptr, 0, key, nonce, buf1, 114, false);
+ assert (memcmp (buf1, text, 114) == 0);
}