diff --git a/AddressBook.cpp b/AddressBook.cpp index eba7f6b7..ed7b56ae 100644 --- a/AddressBook.cpp +++ b/AddressBook.cpp @@ -7,8 +7,7 @@ #include #include #include -#include -#include "base64.h" +#include "Base.h" #include "util.h" #include "Identity.h" #include "Log.h" @@ -26,8 +25,8 @@ namespace client public: AddressBookFilesystemStorage (); - bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const; - void AddAddress (const i2p::data::IdentityEx& address); + std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const; + void AddAddress (std::shared_ptr address); void RemoveAddress (const i2p::data::IdentHash& ident); int Load (std::map& addresses); @@ -50,7 +49,7 @@ namespace client } } - bool AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const + std::shared_ptr AddressBookFilesystemStorage::GetAddress (const i2p::data::IdentHash& ident) const { auto filename = GetPath () / (ident.ToBase32() + ".b32"); std::ifstream f(filename.c_str (), std::ifstream::binary); @@ -61,28 +60,28 @@ namespace client if (len < i2p::data::DEFAULT_IDENTITY_SIZE) { LogPrint (eLogError, "File ", filename, " is too short. ", len); - return false; + return nullptr; } f.seekg(0, std::ios::beg); uint8_t * buf = new uint8_t[len]; f.read((char *)buf, len); - address.FromBuffer (buf, len); + auto address = std::make_shared(buf, len); delete[] buf; - return true; + return address; } else - return false; + return nullptr; } - void AddressBookFilesystemStorage::AddAddress (const i2p::data::IdentityEx& address) + void AddressBookFilesystemStorage::AddAddress (std::shared_ptr address) { - auto filename = GetPath () / (address.GetIdentHash ().ToBase32() + ".b32"); + auto filename = GetPath () / (address->GetIdentHash ().ToBase32() + ".b32"); std::ofstream f (filename.c_str (), std::ofstream::binary | std::ofstream::out); if (f.is_open ()) { - size_t len = address.GetFullLen (); + size_t len = address->GetFullLen (); uint8_t * buf = new uint8_t[len]; - address.ToBuffer (buf, len); + address->ToBuffer (buf, len); f.write ((char *)buf, len); delete[] buf; } @@ -256,29 +255,29 @@ namespace client void AddressBook::InsertAddress (const std::string& address, const std::string& base64) { - i2p::data::IdentityEx ident; - ident.FromBase64 (base64); + auto ident = std::make_shared(); + ident->FromBase64 (base64); if (!m_Storage) m_Storage = CreateStorage (); m_Storage->AddAddress (ident); - m_Addresses[address] = ident.GetIdentHash (); - LogPrint (address,"->", ToAddress(ident.GetIdentHash ()), " added"); + m_Addresses[address] = ident->GetIdentHash (); + LogPrint (address,"->", ToAddress(ident->GetIdentHash ()), " added"); } - void AddressBook::InsertAddress (const i2p::data::IdentityEx& address) + void AddressBook::InsertAddress (std::shared_ptr address) { if (!m_Storage) m_Storage = CreateStorage (); m_Storage->AddAddress (address); } - bool AddressBook::GetAddress (const std::string& address, i2p::data::IdentityEx& identity) + std::shared_ptr AddressBook::GetAddress (const std::string& address) { if (!m_Storage) m_Storage = CreateStorage (); i2p::data::IdentHash ident; - if (!GetIdentHash (address, ident)) return false; - return m_Storage->GetAddress (ident, identity); + if (!GetIdentHash (address, ident)) return nullptr; + return m_Storage->GetAddress (ident); } void AddressBook::LoadHosts () @@ -332,10 +331,10 @@ namespace client std::string name = s.substr(0, pos++); std::string addr = s.substr(pos); - i2p::data::IdentityEx ident; - if (ident.FromBase64(addr)) + auto ident = std::make_shared (); + if (ident->FromBase64(addr)) { - m_Addresses[name] = ident.GetIdentHash (); + m_Addresses[name] = ident->GetIdentHash (); m_Storage->AddAddress (ident); numAddresses++; } @@ -415,11 +414,10 @@ namespace client { auto dest = i2p::client::context.GetSharedLocalDestination (); if (!dest) return; - if (m_IsLoaded && !m_IsDownloading && dest->IsReady ()) + if (m_IsLoaded && !m_IsDownloading && dest->IsReady () && !m_Subscriptions.empty ()) { // pick random subscription - CryptoPP::AutoSeededRandomPool rnd; - auto ind = rnd.GenerateWord32 (0, m_Subscriptions.size() - 1); + auto ind = rand () % m_Subscriptions.size(); m_IsDownloading = true; m_Subscriptions[ind]->CheckSubscription (); } diff --git a/AddressBook.h b/AddressBook.h index 6fdae9b1..b50b9d9b 100644 --- a/AddressBook.h +++ b/AddressBook.h @@ -7,8 +7,9 @@ #include #include #include +#include #include -#include "base64.h" +#include "Base.h" #include "util.h" #include "Identity.h" #include "Log.h" @@ -31,8 +32,8 @@ namespace client public: virtual ~AddressBookStorage () {}; - virtual bool GetAddress (const i2p::data::IdentHash& ident, i2p::data::IdentityEx& address) const = 0; - virtual void AddAddress (const i2p::data::IdentityEx& address) = 0; + virtual std::shared_ptr GetAddress (const i2p::data::IdentHash& ident) const = 0; + virtual void AddAddress (std::shared_ptr address) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; virtual int Load (std::map& addresses) = 0; @@ -49,16 +50,16 @@ namespace client void Start (); void Stop (); bool GetIdentHash (const std::string& address, i2p::data::IdentHash& ident); - bool GetAddress (const std::string& address, i2p::data::IdentityEx& identity); + std::shared_ptr GetAddress (const std::string& address); const i2p::data::IdentHash * FindAddress (const std::string& address); void InsertAddress (const std::string& address, const std::string& base64); // for jump service - void InsertAddress (const i2p::data::IdentityEx& address); + void InsertAddress (std::shared_ptr address); void LoadHostsFromStream (std::istream& f); void DownloadComplete (bool success); //This method returns the ".b32.i2p" address std::string ToAddress(const i2p::data::IdentHash& ident) { return GetB32Address(ident); } - std::string ToAddress(const i2p::data::IdentityEx& ident) { return ToAddress(ident.GetIdentHash ()); } + std::string ToAddress(std::shared_ptr ident) { return ToAddress(ident->GetIdentHash ()); } private: void StartSubscriptions (); diff --git a/BOB.cpp b/BOB.cpp index f5f11d39..15df456e 100644 --- a/BOB.cpp +++ b/BOB.cpp @@ -408,14 +408,14 @@ namespace client { LogPrint (eLogDebug, "BOB: newkeys"); m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (); - SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ()); + SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); } void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: setkeys ", operand); m_Keys.FromBase64 (operand); - SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ()); + SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); } void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len) @@ -427,7 +427,7 @@ namespace client void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len) { LogPrint (eLogDebug, "BOB: getdest"); - SendReplyOK (m_Keys.GetPublic ().ToBase64 ().c_str ()); + SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); } void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len) @@ -477,7 +477,7 @@ namespace client auto localDestination = m_CurrentDestination->GetLocalDestination (); auto leaseSet = localDestination->FindLeaseSet (ident); if (leaseSet) - SendReplyOK (leaseSet->GetIdentity ().ToBase64 ().c_str ()); + SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ()); else { auto s = shared_from_this (); @@ -485,7 +485,7 @@ namespace client [s](std::shared_ptr ls) { if (ls) - s->SendReplyOK (ls->GetIdentity ().ToBase64 ().c_str ()); + s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ()); else s->SendReplyError ("LeaseSet Not found"); } diff --git a/base64.cpp b/Base.cpp similarity index 77% rename from base64.cpp rename to Base.cpp index 3d1ec07e..0bc424e3 100644 --- a/base64.cpp +++ b/Base.cpp @@ -1,11 +1,11 @@ #include -#include "base64.h" +#include "Log.h" +#include "Base.h" namespace i2p { namespace data { - static void iT64Build(void); /* @@ -265,5 +265,69 @@ namespace data } return ret; } + + GzipInflator::GzipInflator (): m_IsDirty (false) + { + memset (&m_Inflator, 0, sizeof (m_Inflator)); + inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip + } + + GzipInflator::~GzipInflator () + { + inflateEnd (&m_Inflator); + } + + size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) + { + if (m_IsDirty) inflateReset (&m_Inflator); + m_IsDirty = true; + m_Inflator.next_in = const_cast(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) + return outLen - m_Inflator.avail_out; + else + { + LogPrint (eLogError, "Decompression error ", err); + return 0; + } + } + + 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); + } + + 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); + m_IsDirty = true; + m_Deflator.next_in = const_cast(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) + return outLen - m_Deflator.avail_out; + else + { + LogPrint (eLogError, "Compression error ", err); + return 0; + } + } } } + diff --git a/Base.h b/Base.h new file mode 100644 index 00000000..0c59ef03 --- /dev/null +++ b/Base.h @@ -0,0 +1,123 @@ +#ifndef BASE_H__ +#define BASE_H__ + +#include +#include +#include +#include + +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 * 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); + + template + class Tag + { + public: + + Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; + Tag (const Tag& ) = default; +#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it + Tag (Tag&& ) = default; +#endif + Tag () = default; + + Tag& operator= (const Tag& ) = default; +#ifndef _WIN32 + Tag& operator= (Tag&& ) = default; +#endif + + 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 uint64_t * GetLL () const { return ll; }; + + bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; + bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; + + bool IsZero () const + { + for (int i = 0; i < sz/8; i++) + if (ll[i]) return false; + return true; + } + + std::string ToBase64 () const + { + char str[sz*2]; + int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); + str[l] = 0; + return std::string (str); + } + + std::string ToBase32 () const + { + char str[sz*2]; + int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); + str[l] = 0; + return std::string (str); + } + + void FromBase32 (const std::string& s) + { + i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + + void FromBase64 (const std::string& s) + { + i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); + } + + private: + + union // 8 bytes alignment + { + uint8_t m_Buf[sz]; + uint64_t ll[sz/8]; + }; + }; + + class GzipInflator + { + public: + + GzipInflator (); + ~GzipInflator (); + + size_t Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); + + private: + + z_stream m_Inflator; + bool m_IsDirty; + }; + + class GzipDeflator + { + public: + + GzipDeflator (); + ~GzipDeflator (); + + void SetCompressionLevel (int level); + size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); + + private: + + z_stream m_Deflator; + bool m_IsDirty; + }; +} +} + +#endif diff --git a/ClientContext.cpp b/ClientContext.cpp index 9f14da90..0adeee9b 100644 --- a/ClientContext.cpp +++ b/ClientContext.cpp @@ -15,7 +15,7 @@ namespace client ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr), - m_BOBCommandChannel (nullptr), m_I2PControlService (nullptr) + m_BOBCommandChannel (nullptr) { } @@ -25,7 +25,6 @@ namespace client delete m_SocksProxy; delete m_SamBridge; delete m_BOBCommandChannel; - delete m_I2PControlService; } void ClientContext::Start () @@ -33,7 +32,7 @@ namespace client if (!m_SharedLocalDestination) { m_SharedLocalDestination = CreateNewLocalDestination (); // non-public, DSA - m_Destinations[m_SharedLocalDestination->GetIdentity ().GetIdentHash ()] = m_SharedLocalDestination; + m_Destinations[m_SharedLocalDestination->GetIdentity ()->GetIdentHash ()] = m_SharedLocalDestination; m_SharedLocalDestination->Start (); } @@ -93,14 +92,6 @@ namespace client LogPrint("BOB command channel started"); } - // I2P Control - int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0); - if (i2pcontrolPort) - { - m_I2PControlService = new I2PControlService (i2pcontrolPort); - m_I2PControlService->Start (); - LogPrint("I2PControl started"); - } m_AddressBook.Start (); } @@ -140,13 +131,6 @@ namespace client m_BOBCommandChannel = nullptr; LogPrint("BOB command channel stopped"); } - if (m_I2PControlService) - { - m_I2PControlService->Stop (); - delete m_I2PControlService; - m_I2PControlService = nullptr; - LogPrint("I2PControl stopped"); - } m_AddressBook.Stop (); for (auto it: m_Destinations) it.second->Stop (); @@ -168,7 +152,7 @@ namespace client s.read ((char *)buf, len); keys.FromBuffer (buf, len); delete[] buf; - LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " loaded"); + LogPrint ("Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded"); } else { @@ -181,15 +165,15 @@ namespace client f.write ((char *)buf, len); delete[] buf; - LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " created"); + LogPrint ("New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); } std::shared_ptr localDestination = nullptr; std::unique_lock l(m_DestinationsMutex); - auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ()); + auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); if (it != m_Destinations.end ()) { - LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " alreday exists"); + LogPrint (eLogWarning, "Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " alreday exists"); localDestination = it->second; } else @@ -230,10 +214,10 @@ namespace client std::shared_ptr ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params) { - auto it = m_Destinations.find (keys.GetPublic ().GetIdentHash ()); + auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); if (it != m_Destinations.end ()) { - LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ().GetIdentHash ()), " exists"); + LogPrint ("Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); if (!it->second->IsRunning ()) { it->second->Start (); @@ -243,7 +227,7 @@ namespace client } auto localDestination = std::make_shared (keys, isPublic, params); std::unique_lock l(m_DestinationsMutex); - m_Destinations[keys.GetPublic ().GetIdentHash ()] = localDestination; + m_Destinations[keys.GetPublic ()->GetIdentHash ()] = localDestination; localDestination->Start (); return localDestination; } diff --git a/ClientContext.h b/ClientContext.h index 0fe89fb8..762b2e75 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -11,7 +11,6 @@ #include "SAM.h" #include "BOB.h" #include "AddressBook.h" -#include "I2PControl.h" namespace i2p { @@ -72,7 +71,6 @@ namespace client std::map > m_ServerTunnels; // destination->tunnel SAMBridge * m_SamBridge; BOBCommandChannel * m_BOBCommandChannel; - I2PControlService * m_I2PControlService; public: // for HTTP diff --git a/aes.cpp b/Crypto.cpp similarity index 51% rename from aes.cpp rename to Crypto.cpp index 506e7ca8..831ecf30 100644 --- a/aes.cpp +++ b/Crypto.cpp @@ -1,13 +1,275 @@ -#include -#include "TunnelBase.h" -#include "aes.h" +#include +#include +#include +#include +#include +#include +#include "Log.h" +//#include "TunnelBase.h" +#include "Crypto.h" namespace i2p { namespace crypto -{ +{ + const uint8_t elgp_[256]= + { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; -#ifdef AESNI + const int elgg_ = 2; + + const uint8_t dsap_[128]= + { + 0x9c, 0x05, 0xb2, 0xaa, 0x96, 0x0d, 0x9b, 0x97, 0xb8, 0x93, 0x19, 0x63, 0xc9, 0xcc, 0x9e, 0x8c, + 0x30, 0x26, 0xe9, 0xb8, 0xed, 0x92, 0xfa, 0xd0, 0xa6, 0x9c, 0xc8, 0x86, 0xd5, 0xbf, 0x80, 0x15, + 0xfc, 0xad, 0xae, 0x31, 0xa0, 0xad, 0x18, 0xfa, 0xb3, 0xf0, 0x1b, 0x00, 0xa3, 0x58, 0xde, 0x23, + 0x76, 0x55, 0xc4, 0x96, 0x4a, 0xfa, 0xa2, 0xb3, 0x37, 0xe9, 0x6a, 0xd3, 0x16, 0xb9, 0xfb, 0x1c, + 0xc5, 0x64, 0xb5, 0xae, 0xc5, 0xb6, 0x9a, 0x9f, 0xf6, 0xc3, 0xe4, 0x54, 0x87, 0x07, 0xfe, 0xf8, + 0x50, 0x3d, 0x91, 0xdd, 0x86, 0x02, 0xe8, 0x67, 0xe6, 0xd3, 0x5d, 0x22, 0x35, 0xc1, 0x86, 0x9c, + 0xe2, 0x47, 0x9c, 0x3b, 0x9d, 0x54, 0x01, 0xde, 0x04, 0xe0, 0x72, 0x7f, 0xb3, 0x3d, 0x65, 0x11, + 0x28, 0x5d, 0x4c, 0xf2, 0x95, 0x38, 0xd9, 0xe3, 0xb6, 0x05, 0x1f, 0x5b, 0x22, 0xcc, 0x1c, 0x93 + }; + + const uint8_t dsaq_[20]= + { + 0xa5, 0xdf, 0xc2, 0x8f, 0xef, 0x4c, 0xa1, 0xe2, 0x86, 0x74, 0x4c, 0xd8, 0xee, 0xd9, 0xd2, 0x9d, + 0x68, 0x40, 0x46, 0xb7 + }; + + const uint8_t dsag_[128]= + { + 0x0c, 0x1f, 0x4d, 0x27, 0xd4, 0x00, 0x93, 0xb4, 0x29, 0xe9, 0x62, 0xd7, 0x22, 0x38, 0x24, 0xe0, + 0xbb, 0xc4, 0x7e, 0x7c, 0x83, 0x2a, 0x39, 0x23, 0x6f, 0xc6, 0x83, 0xaf, 0x84, 0x88, 0x95, 0x81, + 0x07, 0x5f, 0xf9, 0x08, 0x2e, 0xd3, 0x23, 0x53, 0xd4, 0x37, 0x4d, 0x73, 0x01, 0xcd, 0xa1, 0xd2, + 0x3c, 0x43, 0x1f, 0x46, 0x98, 0x59, 0x9d, 0xda, 0x02, 0x45, 0x18, 0x24, 0xff, 0x36, 0x97, 0x52, + 0x59, 0x36, 0x47, 0xcc, 0x3d, 0xdc, 0x19, 0x7d, 0xe9, 0x85, 0xe4, 0x3d, 0x13, 0x6c, 0xdc, 0xfc, + 0x6b, 0xd5, 0x40, 0x9c, 0xd2, 0xf4, 0x50, 0x82, 0x11, 0x42, 0xa5, 0xe6, 0xf8, 0xeb, 0x1c, 0x3a, + 0xb5, 0xd0, 0x48, 0x4b, 0x81, 0x29, 0xfc, 0xf1, 0x7b, 0xce, 0x4f, 0x7f, 0x33, 0x32, 0x1c, 0x3c, + 0xb3, 0xdb, 0xb1, 0x4a, 0x90, 0x5e, 0x7b, 0x2b, 0x3e, 0x93, 0xbe, 0x47, 0x08, 0xcb, 0xcc, 0x82 + }; + + const int rsae_ = 65537; + + const CryptoConstants& GetCryptoConstants () + { + static CryptoConstants cryptoConstants (elgp_, elgg_, dsap_, dsaq_, dsag_, rsae_); + return cryptoConstants; + } + + bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len) + { + int offset = len - BN_num_bytes (bn); + if (offset < 0) return false; + BN_bn2bin (bn, buf + offset); + memset (buf, 0, offset); + return true; + } + +// DH + + DHKeys::DHKeys (): m_IsUpdated (true) + { + m_DH = DH_new (); + m_DH->p = BN_dup (elgp); + m_DH->g = BN_dup (elgg); + m_DH->priv_key = NULL; + m_DH->pub_key = NULL; + } + + DHKeys::~DHKeys () + { + DH_free (m_DH); + } + + void DHKeys::GenerateKeys (uint8_t * priv, uint8_t * pub) + { + if (m_DH->priv_key) { BN_free (m_DH->priv_key); m_DH->priv_key = NULL; }; + if (m_DH->pub_key) { BN_free (m_DH->pub_key); m_DH->pub_key = NULL; }; + DH_generate_key (m_DH); + if (priv) bn2buf (m_DH->priv_key, priv, 256); + if (pub) bn2buf (m_DH->pub_key, pub, 256); + m_IsUpdated = true; + } + + const uint8_t * DHKeys::GetPublicKey () + { + if (m_IsUpdated) + { + bn2buf (m_DH->pub_key, m_PublicKey, 256); + BN_free (m_DH->pub_key); m_DH->pub_key = NULL; + m_IsUpdated= false; + } + return m_PublicKey; + } + + void DHKeys::Agree (const uint8_t * pub, uint8_t * shared) + { + BIGNUM * pk = BN_bin2bn (pub, 256, NULL); + DH_compute_key (shared, pk, m_DH); + BN_free (pk); + } + +// ElGamal + + ElGamalEncryption::ElGamalEncryption (const uint8_t * key) + { + ctx = BN_CTX_new (); + // select random k + BIGNUM * k = BN_new (); + BN_rand_range (k, elgp); + if (BN_is_zero (k)) BN_one (k); + // caulculate a + a = BN_new (); + BN_mod_exp (a, elgg, k, elgp, ctx); + BIGNUM * y = BN_new (); + BN_bin2bn (key, 256, y); + // calculate b1 + b1 = BN_new (); + BN_mod_exp (b1, y, k, elgp, ctx); + BN_free (y); + BN_free (k); + } + + ElGamalEncryption::~ElGamalEncryption () + { + BN_CTX_free (ctx); + BN_free (a); + BN_free (b1); + } + + void ElGamalEncryption::Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding) const + { + // create m + uint8_t m[255]; + m[0] = 0xFF; + memcpy (m+33, data, len); + SHA256 (m+33, 222, m+1); + // calculate b = b1*m mod p + BIGNUM * b = BN_new (); + BN_bin2bn (m, 255, b); + BN_mod_mul (b, b1, b, elgp, ctx); + // copy a and b + if (zeroPadding) + { + encrypted[0] = 0; + bn2buf (a, encrypted + 1, 256); + encrypted[257] = 0; + bn2buf (b, encrypted + 258, 256); + } + else + { + bn2buf (a, encrypted, 256); + bn2buf (b, encrypted + 256, 256); + } + BN_free (b); + } + + bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, + uint8_t * data, bool zeroPadding) + { + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * x = BN_new (), * a = BN_new (), * b = BN_new (); + BN_bin2bn (key, 256, x); + BN_sub (x, elgp, x); BN_sub_word (x, 1); // x = elgp - x- 1 + BN_bin2bn (zeroPadding ? encrypted + 1 : encrypted, 256, a); + BN_bin2bn (zeroPadding ? encrypted + 258 : encrypted + 256, 256, b); + // m = b*(a^x mod p) mod p + BN_mod_exp (x, a, x, elgp, ctx); + BN_mod_mul (b, b, x, elgp, ctx); + uint8_t m[255]; + bn2buf (b, m, 255); + BN_free (x); BN_free (a); BN_free (b); + BN_CTX_free (ctx); + uint8_t hash[32]; + SHA256 (m + 33, 222, hash); + if (memcmp (m + 1, hash, 32)) + { + LogPrint (eLogError, "ElGamal decrypt hash doesn't match"); + return false; + } + memcpy (data, m + 33, 222); + return true; + } + + void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub) + { +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) + RAND_bytes (priv, 256); + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * p = BN_new (); + BN_bin2bn (priv, 256, p); + BN_mod_exp (p, elgg, p, elgp, ctx); + bn2buf (p, pub, 256); + BN_free (p); + BN_CTX_free (ctx); +#else + DHKeys dh; + dh.GenerateKeys (priv, pub); + +#endif + } + +// HMAC + const uint64_t IPAD = 0x3636363636363636; + const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; + + void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest) + // key is 32 bytes + // digest is 16 bytes + // block size is 64 bytes + { + uint64_t buf[256]; + // ikeypad + buf[0] = key.GetLL ()[0] ^ IPAD; + buf[1] = key.GetLL ()[1] ^ IPAD; + buf[2] = key.GetLL ()[2] ^ IPAD; + buf[3] = key.GetLL ()[3] ^ IPAD; + buf[4] = IPAD; + buf[5] = IPAD; + buf[6] = IPAD; + buf[7] = IPAD; + // concatenate with msg + memcpy (buf + 8, msg, len); + // calculate first hash + uint8_t hash[16]; // MD5 + MD5((uint8_t *)buf, len + 64, hash); + + // okeypad + buf[0] = key.GetLL ()[0] ^ OPAD; + buf[1] = key.GetLL ()[1] ^ OPAD; + buf[2] = key.GetLL ()[2] ^ OPAD; + buf[3] = key.GetLL ()[3] ^ OPAD; + buf[4] = OPAD; + buf[5] = OPAD; + buf[6] = OPAD; + buf[7] = OPAD; + // copy first hash after okeypad + memcpy (buf + 8, hash, 16); + // fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P) + memset (buf + 10, 0, 16); + + // calculate digest + MD5((uint8_t *)buf, 96, digest); + } + +// AES + #ifdef AESNI #define KeyExpansion256(round0,round1) \ "pshufd $0xff, %%xmm2, %%xmm2 \n" \ @@ -311,7 +573,7 @@ namespace crypto #else m_IVEncryption.Encrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerEncryption.SetIV (out); - m_LayerEncryption.Encrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_LayerEncryption.Encrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data m_IVEncryption.Encrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv #endif } @@ -348,10 +610,10 @@ namespace crypto #else m_IVDecryption.Decrypt ((const ChipherBlock *)in, (ChipherBlock *)out); // iv m_LayerDecryption.SetIV (out); - m_LayerDecryption.Decrypt (in + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, out + 16); // data + m_LayerDecryption.Decrypt (in + 16, /*i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE*/1008, out + 16); // data m_IVDecryption.Decrypt ((ChipherBlock *)out, (ChipherBlock *)out); // double iv #endif - } + } } } diff --git a/aes.h b/Crypto.h similarity index 62% rename from aes.h rename to Crypto.h index 84ca1f17..d08e3b3c 100644 --- a/aes.h +++ b/Crypto.h @@ -1,15 +1,113 @@ -#ifndef AES_H__ -#define AES_H__ +#ifndef CRYPTO_H__ +#define CRYPTO_H__ #include -#include -#include -#include "Identity.h" +#include +#include +#include +#include +#include "Base.h" namespace i2p { namespace crypto -{ +{ + struct CryptoConstants + { + // DH/ElGamal + BIGNUM * elgp; + BIGNUM * elgg; + + // DSA + BIGNUM * dsap; + BIGNUM * dsaq; + BIGNUM * dsag; + + // RSA + BIGNUM * rsae; + + CryptoConstants (const uint8_t * elgp_, int elgg_, const uint8_t * dsap_, + const uint8_t * dsaq_, const uint8_t * dsag_, int rsae_) + { + elgp = BN_new (); + BN_bin2bn (elgp_, 256, elgp); + elgg = BN_new (); + BN_set_word (elgg, elgg_); + dsap = BN_new (); + BN_bin2bn (dsap_, 128, dsap); + dsaq = BN_new (); + BN_bin2bn (dsaq_, 20, dsaq); + dsag = BN_new (); + BN_bin2bn (dsag_, 128, dsag); + rsae = BN_new (); + BN_set_word (rsae, rsae_); + } + + ~CryptoConstants () + { + BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); + } + }; + + const CryptoConstants& GetCryptoConstants (); + + // DH/ElGamal + #define elgp GetCryptoConstants ().elgp + #define elgg GetCryptoConstants ().elgg + + // DSA + #define dsap GetCryptoConstants ().dsap + #define dsaq GetCryptoConstants ().dsaq + #define dsag GetCryptoConstants ().dsag + + // RSA + #define rsae GetCryptoConstants ().rsae + + bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len); + + // DH + class DHKeys + { + public: + + DHKeys (); + ~DHKeys (); + + void GenerateKeys (uint8_t * priv = nullptr, uint8_t * pub = nullptr); + const uint8_t * GetPublicKey (); + void Agree (const uint8_t * pub, uint8_t * shared); + + private: + + DH * m_DH; + uint8_t m_PublicKey[256]; + bool m_IsUpdated; + }; + + // ElGamal + class ElGamalEncryption + { + public: + + ElGamalEncryption (const uint8_t * key); + ~ElGamalEncryption (); + + void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const; + + private: + + BN_CTX * ctx; + BIGNUM * a, * b1; + }; + + bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, bool zeroPadding = false); + void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub); + + // HMAC + typedef i2p::data::Tag<32> MACKey; + void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest); + + // AES struct ChipherBlock { uint8_t buf[16]; @@ -95,7 +193,7 @@ namespace crypto typedef ECBEncryptionAESNI ECBEncryption; typedef ECBDecryptionAESNI ECBDecryption; -#else // use crypto++ +#else // use openssl class ECBEncryption { @@ -103,16 +201,16 @@ namespace crypto void SetKey (const AESKey& key) { - m_Encryption.SetKey (key, 32); + AES_set_encrypt_key (key, 256, &m_Key); } void Encrypt (const ChipherBlock * in, ChipherBlock * out) { - m_Encryption.ProcessData (out->buf, in->buf, 16); + AES_encrypt (in->buf, out->buf, &m_Key); } private: - CryptoPP::ECB_Mode::Encryption m_Encryption; + AES_KEY m_Key; }; class ECBDecryption @@ -121,16 +219,16 @@ namespace crypto void SetKey (const AESKey& key) { - m_Decryption.SetKey (key, 32); + AES_set_decrypt_key (key, 256, &m_Key); } void Decrypt (const ChipherBlock * in, ChipherBlock * out) { - m_Decryption.ProcessData (out->buf, in->buf, 16); + AES_decrypt (in->buf, out->buf, &m_Key); } private: - CryptoPP::ECB_Mode::Decryption m_Decryption; + AES_KEY m_Key; }; @@ -217,9 +315,8 @@ namespace crypto #else CBCDecryption m_LayerDecryption; #endif - }; -} -} + }; +} +} #endif - diff --git a/Daemon.cpp b/Daemon.cpp index 77cd0899..ee3dbe76 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -1,9 +1,11 @@ #include +#include +#include #include "Daemon.h" #include "Log.h" -#include "base64.h" +#include "Base.h" #include "version.h" #include "Transports.h" #include "NTCPSession.h" @@ -16,8 +18,13 @@ #include "Streaming.h" #include "Destination.h" #include "HTTPServer.h" +#include "I2PControl.h" #include "ClientContext.h" +#ifdef USE_UPNP +#include "UPnP.h" +#endif + namespace i2p { namespace util @@ -25,14 +32,15 @@ namespace i2p class Daemon_Singleton::Daemon_Singleton_Private { public: - Daemon_Singleton_Private() : httpServer(nullptr) - {}; - ~Daemon_Singleton_Private() - { - delete httpServer; - }; + Daemon_Singleton_Private() {}; + ~Daemon_Singleton_Private() {}; - i2p::util::HTTPServer *httpServer; + std::unique_ptr httpServer; + std::unique_ptr m_I2PControlService; + +#ifdef USE_UPNP + UPnP m_UPnP; +#endif }; Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {}; @@ -51,6 +59,7 @@ namespace i2p bool Daemon_Singleton::init(int argc, char* argv[]) { + SSL_library_init (); i2p::util::config::OptionParser(argc, argv); i2p::context.Init (); @@ -106,17 +115,29 @@ namespace i2p StartLog (""); // write to stdout } - d.httpServer = new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070)); + d.httpServer = std::unique_ptr(new i2p::util::HTTPServer(i2p::util::config::GetArg("-httpport", 7070))); d.httpServer->Start(); LogPrint("HTTP Server started"); i2p::data::netdb.Start(); LogPrint("NetDB started"); +#ifdef USE_UPNP + d.m_UPnP.Start (); + LogPrint(eLogInfo, "UPnP started"); +#endif i2p::transport::transports.Start(); LogPrint("Transports started"); i2p::tunnel::tunnels.Start(); LogPrint("Tunnels started"); i2p::client::context.Start (); LogPrint("Client started"); + // I2P Control + int i2pcontrolPort = i2p::util::config::GetArg("-i2pcontrolport", 0); + if (i2pcontrolPort) + { + d.m_I2PControlService = std::unique_ptr(new i2p::client::I2PControlService (i2pcontrolPort)); + d.m_I2PControlService->Start (); + LogPrint("I2PControl started"); + } return true; } @@ -127,17 +148,25 @@ namespace i2p LogPrint("Client stopped"); i2p::tunnel::tunnels.Stop(); LogPrint("Tunnels stopped"); +#ifdef USE_UPNP + d.m_UPnP.Stop (); + LogPrint(eLogInfo, "UPnP stopped"); +#endif i2p::transport::transports.Stop(); LogPrint("Transports stopped"); i2p::data::netdb.Stop(); LogPrint("NetDB stopped"); d.httpServer->Stop(); + d.httpServer = nullptr; LogPrint("HTTP Server stopped"); - + if (d.m_I2PControlService) + { + d.m_I2PControlService->Stop (); + d.m_I2PControlService = nullptr; + LogPrint("I2PControl stopped"); + } StopLog (); - delete d.httpServer; d.httpServer = nullptr; - return true; } } diff --git a/Datagram.cpp b/Datagram.cpp index 63b487ff..e065e3e7 100644 --- a/Datagram.cpp +++ b/Datagram.cpp @@ -1,7 +1,7 @@ #include #include -#include -#include +#include +#include #include "Log.h" #include "TunnelBase.h" #include "RouterContext.h" @@ -12,36 +12,40 @@ namespace i2p { namespace datagram { - DatagramDestination::DatagramDestination (i2p::client::ClientDestination& owner): + DatagramDestination::DatagramDestination (std::shared_ptr owner): m_Owner (owner), m_Receiver (nullptr) { } - + + DatagramDestination::~DatagramDestination () + { + } + void DatagramDestination::SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort, uint16_t toPort) { uint8_t buf[MAX_DATAGRAM_SIZE]; - auto identityLen = m_Owner.GetIdentity ().ToBuffer (buf, MAX_DATAGRAM_SIZE); + auto identityLen = m_Owner->GetIdentity ()->ToBuffer (buf, MAX_DATAGRAM_SIZE); uint8_t * signature = buf + identityLen; - auto signatureLen = m_Owner.GetIdentity ().GetSignatureLen (); + auto signatureLen = m_Owner->GetIdentity ()->GetSignatureLen (); uint8_t * buf1 = signature + signatureLen; size_t headerLen = identityLen + signatureLen; memcpy (buf1, payload, len); - if (m_Owner.GetIdentity ().GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) + if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest (hash, buf1, len); - m_Owner.Sign (hash, 32, signature); + SHA256(buf1, len, hash); + m_Owner->Sign (hash, 32, signature); } else - m_Owner.Sign (buf1, len, signature); + m_Owner->Sign (buf1, len, signature); auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort); - auto remote = m_Owner.FindLeaseSet (ident); + auto remote = m_Owner->FindLeaseSet (ident); if (remote) - m_Owner.GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote)); + m_Owner->GetService ().post (std::bind (&DatagramDestination::SendMsg, this, msg, remote)); else - m_Owner.RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg)); + m_Owner->RequestDestination (ident, std::bind (&DatagramDestination::HandleLeaseSetRequestComplete, this, std::placeholders::_1, msg)); } void DatagramDestination::HandleLeaseSetRequestComplete (std::shared_ptr remote, I2NPMessage * msg) @@ -54,13 +58,13 @@ namespace datagram void DatagramDestination::SendMsg (I2NPMessage * msg, std::shared_ptr remote) { - auto outboundTunnel = m_Owner.GetTunnelPool ()->GetNextOutboundTunnel (); + auto outboundTunnel = m_Owner->GetTunnelPool ()->GetNextOutboundTunnel (); auto leases = remote->GetNonExpiredLeases (); if (!leases.empty () && outboundTunnel) { std::vector msgs; - uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); - auto garlic = m_Owner.WrapMessage (remote, ToSharedI2NPMessage (msg), true); + uint32_t i = rand () % leases.size (); + auto garlic = m_Owner->WrapMessage (remote, ToSharedI2NPMessage (msg), true); msgs.push_back (i2p::tunnel::TunnelMessageBlock { i2p::tunnel::eDeliveryTypeTunnel, @@ -90,7 +94,7 @@ namespace datagram if (identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest (hash, buf + headerLen, len - headerLen); + SHA256(buf + headerLen, len - headerLen, hash); verified = identity.Verify (hash, 32, signature); } else @@ -113,37 +117,32 @@ namespace datagram void DatagramDestination::HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { // unzip it - CryptoPP::Gunzip decompressor; - decompressor.Put (buf, len); - decompressor.MessageEnd(); uint8_t uncompressed[MAX_DATAGRAM_SIZE]; - auto uncompressedLen = decompressor.MaxRetrievable (); - if (uncompressedLen <= MAX_DATAGRAM_SIZE) - { - decompressor.Get (uncompressed, uncompressedLen); + size_t uncompressedLen = m_Inflator.Inflate (buf, len, uncompressed, MAX_DATAGRAM_SIZE); + if (uncompressedLen) HandleDatagram (fromPort, toPort, uncompressed, uncompressedLen); - } - else - LogPrint ("Received datagram size ", uncompressedLen, " exceeds max size"); - } I2NPMessage * DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort) { I2NPMessage * msg = NewI2NPMessage (); - CryptoPP::Gzip compressor; // default level - compressor.Put (payload, len); - compressor.MessageEnd(); - int size = compressor.MaxRetrievable (); uint8_t * buf = msg->GetPayload (); - htobe32buf (buf, size); // length - buf += 4; - compressor.Get (buf, size); - htobe16buf (buf + 4, fromPort); // source port - htobe16buf (buf + 6, toPort); // destination port - buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol - msg->len += size + 4; - msg->FillI2NPMessageHeader (eI2NPData); + buf += 4; // reserve for length + size_t size = m_Deflator.Deflate (payload, len, 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] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol + msg->len += size + 4; + msg->FillI2NPMessageHeader (eI2NPData); + } + else + { + DeleteI2NPMessage (msg); + msg = nullptr; + } return msg; } } diff --git a/Datagram.h b/Datagram.h index f2e31304..7f6df921 100644 --- a/Datagram.h +++ b/Datagram.h @@ -5,6 +5,7 @@ #include #include #include +#include "Base.h" #include "Identity.h" #include "LeaseSet.h" #include "I2NPProtocol.h" @@ -24,8 +25,8 @@ namespace datagram public: - DatagramDestination (i2p::client::ClientDestination& owner); - ~DatagramDestination () {}; + DatagramDestination (std::shared_ptr owner); + ~DatagramDestination (); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash& ident, uint16_t fromPort = 0, uint16_t toPort = 0); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); @@ -46,9 +47,12 @@ namespace datagram private: - i2p::client::ClientDestination& m_Owner; + std::shared_ptr m_Owner; Receiver m_Receiver; // default std::map m_ReceiversByPorts; + + i2p::data::GzipInflator m_Inflator; + i2p::data::GzipDeflator m_Deflator; }; } } diff --git a/Destination.cpp b/Destination.cpp index e1c639c2..479006c8 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -1,12 +1,12 @@ #include #include #include +#include #include "Log.h" #include "util.h" -#include "ElGamal.h" +#include "Crypto.h" #include "Timestamp.h" #include "NetDb.h" -#include "AddressBook.h" #include "Destination.h" namespace i2p @@ -19,7 +19,7 @@ namespace client m_Keys (keys), m_IsPublic (isPublic), m_PublishReplyToken (0), m_DatagramDestination (nullptr), m_PublishConfirmationTimer (m_Service), m_CleanupTimer (m_Service) { - i2p::crypto::GenerateElGamalKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); + i2p::crypto::GenerateElGamalKeyPair(m_EncryptionPrivateKey, m_EncryptionPublicKey); int inboundTunnelLen = DEFAULT_INBOUND_TUNNEL_LENGTH; int outboundTunnelLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; int inboundTunnelsQuantity = DEFAULT_INBOUND_TUNNELS_QUANTITY; @@ -86,8 +86,7 @@ namespace client if (explicitPeers) m_Pool->SetExplicitPeers (explicitPeers); if (m_IsPublic) - LogPrint (eLogInfo, "Local address ", i2p::client::GetB32Address(GetIdentHash()), " created"); - m_StreamingDestination = std::make_shared (*this); // TODO: + LogPrint (eLogInfo, "Local address ", GetIdentHash().ToBase32 (), " created"); } ClientDestination::~ClientDestination () @@ -123,8 +122,9 @@ namespace client { m_IsRunning = true; m_Pool->SetLocalDestination (this); - m_Pool->SetActive (true); + m_Pool->SetActive (true); m_Thread = new std::thread (std::bind (&ClientDestination::Run, this)); + m_StreamingDestination = std::make_shared (shared_from_this ()); // TODO: m_StreamingDestination->Start (); for (auto it: m_StreamingDestinationsByPorts) it.second->Start (); @@ -141,7 +141,8 @@ namespace client { m_CleanupTimer.cancel (); m_IsRunning = false; - m_StreamingDestination->Stop (); + m_StreamingDestination->Stop (); + m_StreamingDestination = nullptr; for (auto it: m_StreamingDestinationsByPorts) it.second->Stop (); if (m_DatagramDestination) @@ -396,8 +397,8 @@ namespace client } m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); - m_PublishReplyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); - auto msg = WrapMessage (floodfill, ToSharedI2NPMessage (i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken))); + RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); + auto msg = WrapMessage (floodfill, i2p::CreateDatabaseStoreMsg (m_LeaseSet, m_PublishReplyToken)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&ClientDestination::HandlePublishConfirmationTimer, this, std::placeholders::_1)); @@ -507,7 +508,7 @@ namespace client std::shared_ptr ClientDestination::CreateStreamingDestination (int port) { - auto dest = std::make_shared (*this, port); + auto dest = std::make_shared (shared_from_this (), port); if (port) m_StreamingDestinationsByPorts[port] = dest; else // update default @@ -518,7 +519,7 @@ namespace client i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () { if (!m_DatagramDestination) - m_DatagramDestination = new i2p::datagram::DatagramDestination (*this); + m_DatagramDestination = new i2p::datagram::DatagramDestination (shared_from_this ()); return m_DatagramDestination; } @@ -529,7 +530,7 @@ namespace client if (requestComplete) requestComplete (false); return false; } - m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, this, dest, requestComplete)); + m_Service.post (std::bind (&ClientDestination::RequestLeaseSet, shared_from_this (), dest, requestComplete)); return true; } @@ -579,15 +580,14 @@ namespace client request->requestTime = i2p::util::GetSecondsSinceEpoch (); request->requestTimeoutTimer.cancel (); - CryptoPP::AutoSeededRandomPool rnd; uint8_t replyKey[32], replyTag[32]; - rnd.GenerateBlock (replyKey, 32); // random session key - rnd.GenerateBlock (replyTag, 32); // random session tag + RAND_bytes (replyKey, 32); // random session key + RAND_bytes (replyTag, 32); // random session tag AddSessionKey (replyKey, replyTag); auto msg = WrapMessage (nextFloodfill, - ToSharedI2NPMessage (CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, - replyTunnel.get (), replyKey, replyTag))); + CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, + replyTunnel.get (), replyKey, replyTag)); outboundTunnel->SendTunnelDataMsg ( { i2p::tunnel::TunnelMessageBlock @@ -646,7 +646,7 @@ namespace client CleanupRemoteLeaseSets (); m_CleanupTimer.expires_from_now (boost::posix_time::minutes (DESTINATION_CLEANUP_TIMEOUT)); m_CleanupTimer.async_wait (std::bind (&ClientDestination::HandleCleanupTimer, - this, std::placeholders::_1)); + shared_from_this (), std::placeholders::_1)); } } diff --git a/Destination.h b/Destination.h index c41ee9ca..0000014b 100644 --- a/Destination.h +++ b/Destination.h @@ -11,7 +11,7 @@ #include #include "Identity.h" #include "TunnelPool.h" -#include "CryptoConst.h" +#include "Crypto.h" #include "LeaseSet.h" #include "Garlic.h" #include "NetDb.h" @@ -45,7 +45,8 @@ namespace client typedef std::function stream)> StreamRequestComplete; - class ClientDestination: public i2p::garlic::GarlicDestination + class ClientDestination: public i2p::garlic::GarlicDestination, + public std::enable_shared_from_this { typedef std::function leaseSet)> RequestComplete; // leaseSet = nullptr means not found diff --git a/ElGamal.h b/ElGamal.h deleted file mode 100644 index 359de358..00000000 --- a/ElGamal.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef EL_GAMAL_H__ -#define EL_GAMAL_H__ - -#include -#include -#include -#include -#include -#include "CryptoConst.h" -#include "Log.h" - -namespace i2p -{ -namespace crypto -{ - - class ElGamalEncryption - { - public: - - ElGamalEncryption (const uint8_t * key) - { - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::Integer y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1); - a = a_exp_b_mod_c (elgg, k, elgp); - b1 = a_exp_b_mod_c (y, k, elgp); - } - - void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) const - { - // calculate b = b1*m mod p - uint8_t m[255]; - m[0] = 0xFF; - memcpy (m+33, data, len); - CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); - CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp)); - - // copy a and b - if (zeroPadding) - { - encrypted[0] = 0; - a.Encode (encrypted + 1, 256); - encrypted[257] = 0; - b.Encode (encrypted + 258, 256); - } - else - { - a.Encode (encrypted, 256); - b.Encode (encrypted + 256, 256); - } - } - - private: - - CryptoPP::Integer a, b1; - }; - - inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, - uint8_t * data, bool zeroPadding = false) - { - CryptoPP::Integer x(key, 256), a(zeroPadding? encrypted +1 : encrypted, 256), - b(zeroPadding? encrypted + 258 :encrypted + 256, 256); - uint8_t m[255]; - a_times_b_mod_c (b, a_exp_b_mod_c (a, elgp - x - 1, elgp), elgp).Encode (m, 255); - if (!CryptoPP::SHA256().VerifyDigest (m + 1, m + 33, 222)) - { - LogPrint ("ElGamal decrypt hash doesn't match"); - return false; - } - memcpy (data, m + 33, 222); - return true; - } - - inline void GenerateElGamalKeyPair (CryptoPP::RandomNumberGenerator& rnd, uint8_t * priv, uint8_t * pub) - { -#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) - rnd.GenerateBlock (priv, 256); - a_exp_b_mod_c (elgg, CryptoPP::Integer (priv, 256), elgp).Encode (pub, 256); -#else - CryptoPP::DH dh (elgp, elgg); - dh.GenerateKeyPair(rnd, priv, pub); -#endif - } -} -} - -#endif diff --git a/Garlic.cpp b/Garlic.cpp index fb67b0ae..f8acbe39 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -2,12 +2,14 @@ #include "I2PEndian.h" #include #include +#include +#include #include "RouterContext.h" #include "I2NPProtocol.h" #include "Tunnel.h" #include "TunnelPool.h" #include "Timestamp.h" -#include "Destination.h" +#include "Log.h" #include "Garlic.h" namespace i2p @@ -17,10 +19,11 @@ namespace garlic GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr destination, int numTags, bool attachLeaseSet): m_Owner (owner), m_Destination (destination), m_NumTags (numTags), - m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend) + m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), + m_ElGamalEncryption (new i2p::crypto::ElGamalEncryption (destination->GetEncryptionPublicKey ())) { // create new session tags and session key - m_Rnd.GenerateBlock (m_SessionKey, 32); + RAND_bytes (m_SessionKey, 32); m_Encryption.SetKey (m_SessionKey); } @@ -46,7 +49,7 @@ namespace garlic tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); for (int i = 0; i < m_NumTags; i++) { - m_Rnd.GenerateBlock (tags->sessionTags[i], 32); + RAND_bytes (tags->sessionTags[i], 32); tags->sessionTags[i].creationTime = tags->tagsCreationTime; } return tags; @@ -107,7 +110,7 @@ namespace garlic return !m_SessionTags.empty () || m_UnconfirmedTagsMsgs.empty (); } - std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) + std::shared_ptr GarlicRoutingSession::WrapSingleMessage (std::shared_ptr msg) { auto m = ToSharedI2NPMessage(NewI2NPMessage ()); m->Align (12); // in order to get buf aligned to 16 (12 + 4) @@ -145,10 +148,10 @@ namespace garlic // create ElGamal block ElGamalBlock elGamal; memcpy (elGamal.sessionKey, m_SessionKey, 32); - m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV + RAND_bytes (elGamal.preIV, 32); // Pre-IV uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); - m_Destination->GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); + SHA256(elGamal.preIV, 32, iv); + m_ElGamalEncryption->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); m_Encryption.SetIV (iv); buf += 514; len += 514; @@ -158,20 +161,20 @@ namespace garlic // session tag memcpy (buf, tag, 32); uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, tag, 32); + SHA256(tag, 32, iv); m_Encryption.SetIV (iv); buf += 32; len += 32; } // AES block - len += CreateAESBlock (buf, msg.get ()); // TODO + len += CreateAESBlock (buf, msg); htobe32buf (m->GetPayload (), len); m->len += len + 4; m->FillI2NPMessageHeader (eI2NPGarlic); return m; } - size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, const I2NPMessage * msg) + size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr msg) { size_t blockSize = 0; bool createNewTags = m_Owner && m_NumTags && ((int)m_SessionTags.size () <= m_NumTags*2/3); @@ -194,7 +197,7 @@ namespace garlic blockSize++; size_t len = CreateGarlicPayload (buf + blockSize, msg, newTags); htobe32buf (payloadSize, len); - CryptoPP::SHA256().CalculateDigest(payloadHash, buf + blockSize, len); + SHA256(buf + blockSize, len, payloadHash); blockSize += len; size_t rem = blockSize % 16; if (rem) @@ -203,10 +206,11 @@ namespace garlic return blockSize; } - size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, const I2NPMessage * msg, UnconfirmedTags * newTags) + size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec - uint32_t msgID = m_Rnd.GenerateWord32 (); + uint32_t msgID; + RAND_bytes ((uint8_t *)&msgID, 4); size_t size = 0; uint8_t * numCloves = payload + size; *numCloves = 0; @@ -243,8 +247,7 @@ namespace garlic m_LeaseSetSubmissionTime = i2p::util::GetMillisecondsSinceEpoch (); // clove if our leaseSet must be attached auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ()); - size += CreateGarlicClove (payload + size, leaseSet, false); - DeleteI2NPMessage (leaseSet); + size += CreateGarlicClove (payload + size, leaseSet, false); (*numCloves)++; } } @@ -263,7 +266,7 @@ namespace garlic return size; } - size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, const I2NPMessage * msg, bool isDestination) + size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec size_t size = 0; @@ -282,7 +285,9 @@ namespace garlic memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); - htobe32buf (buf + size, m_Rnd.GenerateWord32 ()); // CloveID + uint32_t cloveID; + RAND_bytes ((uint8_t *)&cloveID, 4); + htobe32buf (buf + size, cloveID); // CloveID size += 4; htobe64buf (buf + size, ts); // Expiration of clove size += 8; @@ -312,8 +317,8 @@ namespace garlic { //encrypt uint8_t key[32], tag[32]; - m_Rnd.GenerateBlock (key, 32); // random session key - m_Rnd.GenerateBlock (tag, 32); // random session tag + RAND_bytes (key, 32); // random session key + RAND_bytes (tag, 32); // random session tag m_Owner->SubmitSessionKey (key, tag); GarlicRoutingSession garlic (key, tag); msg = garlic.WrapSingleMessage (msg); @@ -322,7 +327,9 @@ namespace garlic size += msg->GetLength (); // fill clove uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec - htobe32buf (buf + size, m_Rnd.GenerateWord32 ()); // CloveID + uint32_t cloveID; + RAND_bytes ((uint8_t *)&cloveID, 4); + htobe32buf (buf + size, cloveID); // CloveID size += 4; htobe64buf (buf + size, ts); // Expiration of clove size += 8; @@ -376,7 +383,7 @@ namespace garlic if (length >= 32) { uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, buf, 32); + SHA256(buf, 32, iv); it->second->SetIV (iv); it->second->Decrypt (buf + 32, length - 32, buf + 32); HandleAESBlock (buf + 32, length - 32, it->second, msg->from); @@ -394,7 +401,7 @@ namespace garlic auto decryption = std::make_shared(); decryption->SetKey (elGamal.sessionKey); uint8_t iv[32]; // IV is first 16 bytes - CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); + SHA256(elGamal.preIV, 32, iv); decryption->SetIV (iv); decryption->Decrypt(buf + 514, length - 514, buf + 514); HandleAESBlock (buf + 514, length - 514, decryption, msg->from); @@ -458,7 +465,9 @@ namespace garlic buf++; // flag // payload - if (!CryptoPP::SHA256().VerifyDigest (payloadHash, buf, payloadSize)) // payload hash doesn't match + uint8_t digest[32]; + SHA256 (buf, payloadSize, digest); + if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match { LogPrint ("Wrong payload hash"); return; diff --git a/Garlic.h b/Garlic.h index 580cabec..716bc466 100644 --- a/Garlic.h +++ b/Garlic.h @@ -8,8 +8,7 @@ #include #include #include -#include -#include "aes.h" +#include "Crypto.h" #include "I2NPProtocol.h" #include "LeaseSet.h" #include "Queue.h" @@ -80,7 +79,7 @@ namespace garlic int numTags, bool attachLeaseSet); GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption ~GarlicRoutingSession (); - std::shared_ptr WrapSingleMessage (std::shared_ptr msg); + std::shared_ptr WrapSingleMessage (std::shared_ptr msg); void MessageConfirmed (uint32_t msgID); bool CleanupExpiredTags (); // returns true if something left @@ -91,9 +90,9 @@ namespace garlic private: - size_t CreateAESBlock (uint8_t * buf, const I2NPMessage * msg); - size_t CreateGarlicPayload (uint8_t * payload, const I2NPMessage * msg, UnconfirmedTags * newTags); - size_t CreateGarlicClove (uint8_t * buf, const I2NPMessage * msg, bool isDestination); + size_t CreateAESBlock (uint8_t * buf, std::shared_ptr msg); + size_t CreateGarlicPayload (uint8_t * payload, std::shared_ptr msg, UnconfirmedTags * newTags); + size_t CreateGarlicClove (uint8_t * buf, std::shared_ptr msg, bool isDestination); size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID); void TagsConfirmed (uint32_t msgID); @@ -113,7 +112,7 @@ namespace garlic uint64_t m_LeaseSetSubmissionTime; // in milliseconds i2p::crypto::CBCEncryption m_Encryption; - CryptoPP::AutoSeededRandomPool m_Rnd; + std::unique_ptr m_ElGamalEncryption; }; class GarlicDestination: public i2p::data::LocalDestination diff --git a/HTTPServer.cpp b/HTTPServer.cpp index c9048727..575b06b8 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -1,7 +1,7 @@ #include #include #include -#include "base64.h" +#include "Base.h" #include "Log.h" #include "Tunnel.h" #include "TransitTunnel.h" @@ -466,7 +466,8 @@ namespace util const char HTTP_COMMAND_TRANSIT_TUNNELS[] = "transit_tunnels"; const char HTTP_COMMAND_TRANSPORTS[] = "transports"; const char HTTP_COMMAND_START_ACCEPTING_TUNNELS[] = "start_accepting_tunnels"; - const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; + const char HTTP_COMMAND_STOP_ACCEPTING_TUNNELS[] = "stop_accepting_tunnels"; + const char HTTP_COMMAND_RUN_PEER_TEST[] = "run_peer_test"; const char HTTP_COMMAND_LOCAL_DESTINATIONS[] = "local_destinations"; const char HTTP_COMMAND_LOCAL_DESTINATION[] = "local_destination"; const char HTTP_PARAM_BASE32_ADDRESS[] = "b32"; @@ -702,6 +703,7 @@ namespace util s << "
Stop accepting tunnels
"; else s << "
Start accepting tunnels
"; + s << "
Run peer test
"; s << "

Flibusta

"; } @@ -720,6 +722,8 @@ namespace util StartAcceptingTunnels (s); else if (cmd == HTTP_COMMAND_STOP_ACCEPTING_TUNNELS) StopAcceptingTunnels (s); + else if (cmd == HTTP_COMMAND_RUN_PEER_TEST) + RunPeerTest (s); else if (cmd == HTTP_COMMAND_LOCAL_DESTINATIONS) ShowLocalDestinations (s); else if (cmd == HTTP_COMMAND_LOCAL_DESTINATION) @@ -751,11 +755,10 @@ namespace util if (it.second && it.second->IsEstablished ()) { // incoming connection doesn't have remote RI - auto outgoing = it.second->GetRemoteRouter (); - if (outgoing) s << "-->"; - s << it.second->GetRemoteIdentity ().GetIdentHash ().ToBase64 ().substr (0, 4) << ": " + if (it.second->IsOutgoing ()) s << "-->"; + s << i2p::data::GetIdentHashAbbreviation (it.second->GetRemoteIdentity ()->GetIdentHash ()) << ": " << it.second->GetSocket ().remote_endpoint().address ().to_string (); - if (!outgoing) s << "-->"; + if (!it.second->IsOutgoing ()) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; s << "
"; } @@ -769,11 +772,10 @@ namespace util for (auto it: ssuServer->GetSessions ()) { // incoming connections don't have remote router - auto outgoing = it.second->GetRemoteRouter (); auto endpoint = it.second->GetRemoteEndpoint (); - if (outgoing) s << "-->"; + if (it.second->IsOutgoing ()) s << "-->"; s << endpoint.address ().to_string () << ":" << endpoint.port (); - if (!outgoing) s << "-->"; + if (!it.second->IsOutgoing ()) s << "-->"; s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; if (it.second->GetRelayTag ()) s << " [itag:" << it.second->GetRelayTag () << "]"; @@ -789,7 +791,7 @@ namespace util for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) { - it->GetTunnelConfig ()->Print (s); + it->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; @@ -801,7 +803,7 @@ namespace util for (auto it: i2p::tunnel::tunnels.GetInboundTunnels ()) { - it.second->GetTunnelConfig ()->Print (s); + it.second->Print (s); auto state = it.second->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; @@ -844,7 +846,7 @@ namespace util auto dest = i2p::client::context.FindLocalDestination (ident); if (dest) { - s << "Base64:
" << dest->GetIdentity ().ToBase64 () << "

"; + s << "Base64:
" << dest->GetIdentity ()->ToBase64 () << "

"; s << "LeaseSets: " << dest->GetNumRemoteLeaseSets () << "
"; auto pool = dest->GetTunnelPool (); if (pool) @@ -852,7 +854,7 @@ namespace util s << "Tunnels:
"; for (auto it: pool->GetOutboundTunnels ()) { - it->GetTunnelConfig ()->Print (s); + it->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; @@ -862,7 +864,7 @@ namespace util } for (auto it: pool->GetInboundTunnels ()) { - it->GetTunnelConfig ()->Print (s); + it->Print (s); auto state = it->GetState (); if (state == i2p::tunnel::eTunnelStateFailed) s << " " << "Failed"; @@ -948,6 +950,12 @@ namespace util s << "Accepting tunnels stopped" << std::endl; } + void HTTPConnection::RunPeerTest (std::stringstream& s) + { + i2p::transport::transports.PeerTest (); + s << "Peer test" << std::endl; + } + void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) { std::string request = "GET " + uri + " HTTP/1.1\r\nHost:" + address + "\r\n"; @@ -1044,7 +1052,7 @@ namespace util HTTPServer::HTTPServer (int port): m_Thread (nullptr), m_Work (m_Service), - m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), + m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)), m_NewSocket (nullptr) { diff --git a/HTTPServer.h b/HTTPServer.h index b289cbc5..977938fb 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -73,6 +73,7 @@ namespace util void ShowSAMSession (const std::string& id, std::stringstream& s); void StartAcceptingTunnels (std::stringstream& s); void StopAcceptingTunnels (std::stringstream& s); + void RunPeerTest (std::stringstream& s); void FillContent (std::stringstream& s); std::string ExtractAddress (); void ExtractParams (const std::string& str, std::map& params); diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 8fd493f1..890ec6af 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -1,13 +1,15 @@ #include #include +#include +#include +#include "Base.h" +#include "Log.h" +#include "Crypto.h" #include "I2PEndian.h" -#include -#include "ElGamal.h" #include "Timestamp.h" #include "RouterContext.h" #include "NetDb.h" #include "Tunnel.h" -#include "base64.h" #include "Transports.h" #include "Garlic.h" #include "I2NPProtocol.h" @@ -44,10 +46,8 @@ namespace i2p void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID) { SetTypeID (msgType); - if (replyMsgID) // for tunnel creation - SetMsgID (replyMsgID); - else - SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); + if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4); + SetMsgID (replyMsgID); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number UpdateSize (); UpdateChks (); @@ -55,7 +55,9 @@ namespace i2p void I2NPMessage::RenewI2NPMessageHeader () { - SetMsgID (i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); + uint32_t msgID; + RAND_bytes ((uint8_t *)&msgID, 4); + SetMsgID (msgID); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + 5000); } @@ -98,7 +100,8 @@ namespace i2p } else // for SSU establishment { - htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, i2p::context.GetRandomNumberGenerator ().GenerateWord32 ()); + RAND_bytes ((uint8_t *)&msgID, 4); + htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, 2); // netID = 2 } m->len += DELIVERY_STATUS_SIZE; @@ -106,10 +109,10 @@ namespace i2p return ToSharedI2NPMessage (m); } - I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, + std::shared_ptr CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory, std::set * excludedPeers) { - I2NPMessage * m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage (); + auto m = ToSharedI2NPMessage (excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ()); uint8_t * buf = m->GetPayload (); memcpy (buf, key, 32); // key buf += 32; @@ -151,12 +154,12 @@ namespace i2p return m; } - I2NPMessage * CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, + std::shared_ptr CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, const std::set& excludedFloodfills, const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag) { int cnt = excludedFloodfills.size (); - I2NPMessage * m = cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage (); + auto m = ToSharedI2NPMessage (cnt > 0 ? NewI2NPMessage () : NewI2NPShortMessage ()); uint8_t * buf = m->GetPayload (); memcpy (buf, dest, 32); // key buf += 32; @@ -188,10 +191,10 @@ namespace i2p return m; } - I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, + std::shared_ptr CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers) { - I2NPMessage * m = NewI2NPShortMessage (); + auto m = ToSharedI2NPMessage (NewI2NPShortMessage ()); uint8_t * buf = m->GetPayload (); size_t len = 0; memcpy (buf, ident, 32); @@ -210,12 +213,12 @@ namespace i2p return m; } - I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr router, uint32_t replyToken) + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr router, uint32_t replyToken) { if (!router) // we send own RouterInfo router = context.GetSharedRouterInfo (); - I2NPMessage * m = NewI2NPShortMessage (); + auto m = ToSharedI2NPMessage (NewI2NPShortMessage ()); uint8_t * payload = m->GetPayload (); memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32); @@ -230,33 +233,27 @@ namespace i2p buf += 32; } - CryptoPP::Gzip compressor; - compressor.Put (router->GetBuffer (), router->GetBufferLen ()); - compressor.MessageEnd(); - auto size = compressor.MaxRetrievable (); - htobe16buf (buf, size); // size + uint8_t * sizePtr = buf; buf += 2; m->len += (buf - payload); // payload size - if (m->len + size > m->maxLen) + i2p::data::GzipDeflator deflator; + size_t size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len); + if (size) { - LogPrint (eLogInfo, "DatabaseStore message size is not enough for ", m->len + size); - auto newMsg = NewI2NPMessage (); - *newMsg = *m; - DeleteI2NPMessage (m); - m = newMsg; - buf = m->buf + m->len; + htobe16buf (sizePtr, size); // size + m->len += size; } - compressor.Get (buf, size); - m->len += size; - m->FillI2NPMessageHeader (eI2NPDatabaseStore); - + else + m = nullptr; + if (m) + m->FillI2NPMessageHeader (eI2NPDatabaseStore); return m; } - I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken) + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken) { if (!leaseSet) return nullptr; - I2NPMessage * m = NewI2NPShortMessage (); + auto m = ToSharedI2NPMessage (NewI2NPShortMessage ()); uint8_t * payload = m->GetPayload (); memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32); payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet @@ -313,8 +310,8 @@ namespace i2p record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30) //TODO: fill filler - CryptoPP::SHA256().CalculateDigest(record + BUILD_RESPONSE_RECORD_HASH_OFFSET, - record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1); // + 1 byte of ret + SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret + record + BUILD_RESPONSE_RECORD_HASH_OFFSET); // encrypt reply i2p::crypto::CBCEncryption encryption; for (int j = 0; j < num; j++) diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 0e6f5621..a4840217 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "I2PEndian.h" #include "Identity.h" #include "RouterInfo.h" @@ -132,7 +132,7 @@ namespace tunnel void UpdateChks () { uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest(hash, GetPayload (), GetPayloadLength ()); + SHA256(GetPayload (), GetPayloadLength (), hash); GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0]; } @@ -206,15 +206,15 @@ namespace tunnel std::shared_ptr CreateI2NPMessage (const uint8_t * buf, int len, std::shared_ptr from = nullptr); std::shared_ptr CreateDeliveryStatusMsg (uint32_t msgID); - I2NPMessage * CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, + std::shared_ptr CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, std::set * excludedPeers = nullptr); - I2NPMessage * CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, + std::shared_ptr CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, const std::set& excludedFloodfills, const i2p::tunnel::InboundTunnel * replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag); - I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers); + std::shared_ptr CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector routers); - I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr router = nullptr, uint32_t replyToken = 0); - I2NPMessage * CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0); + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr router = nullptr, uint32_t replyToken = 0); + std::shared_ptr CreateDatabaseStoreMsg (std::shared_ptr leaseSet, uint32_t replyToken = 0); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); diff --git a/I2PService.h b/I2PService.h index 37c06828..afac4ea4 100644 --- a/I2PService.h +++ b/I2PService.h @@ -83,11 +83,11 @@ namespace client public: TCPIPAcceptor (int port, std::shared_ptr localDestination = nullptr) : I2PService(localDestination), - m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), + m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)), m_Timer (GetService ()) {} TCPIPAcceptor (int port, i2p::data::SigningKeyType kt) : I2PService(kt), - m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), port)), + m_Acceptor (GetService (), boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4 (), port)), m_Timer (GetService ()) {} virtual ~TCPIPAcceptor () { TCPIPAcceptor::Stop(); } //If you override this make sure you call it from the children diff --git a/I2PTunnel.cpp b/I2PTunnel.cpp index a33a536d..dd2c31df 100644 --- a/I2PTunnel.cpp +++ b/I2PTunnel.cpp @@ -1,5 +1,5 @@ #include -#include "base64.h" +#include "Base.h" #include "Log.h" #include "Destination.h" #include "ClientContext.h" @@ -153,7 +153,7 @@ namespace client else { // send destination first like received from I2P - std::string dest = m_Stream->GetRemoteIdentity ().ToBase64 (); + std::string dest = m_Stream->GetRemoteIdentity ()->ToBase64 (); dest += "\n"; memcpy (m_StreamBuffer, dest.c_str (), dest.size ()); HandleStreamReceive (boost::system::error_code (), dest.size ()); @@ -369,9 +369,9 @@ namespace client { if (m_IsAccessList) { - if (!m_AccessList.count (stream->GetRemoteIdentity ().GetIdentHash ())) + if (!m_AccessList.count (stream->GetRemoteIdentity ()->GetIdentHash ())) { - LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ().GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped"); + LogPrint (eLogWarning, "Address ", stream->GetRemoteIdentity ()->GetIdentHash ().ToBase32 (), " is not in white list. Incoming connection dropped"); stream->Close (); return; } diff --git a/Identity.cpp b/Identity.cpp index 9dc96d01..78aeedd3 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -1,14 +1,12 @@ #include #include -#include -#include -#include -#include "base64.h" -#include "CryptoConst.h" -#include "ElGamal.h" -#include "RouterContext.h" -#include "Identity.h" +#include +#include +#include +#include "Crypto.h" #include "I2PEndian.h" +#include "Log.h" +#include "Identity.h" namespace i2p { @@ -31,12 +29,12 @@ namespace data IdentHash Identity::Hash () const { IdentHash hash; - CryptoPP::SHA256().CalculateDigest(hash, publicKey, DEFAULT_IDENTITY_SIZE); + SHA256(publicKey, DEFAULT_IDENTITY_SIZE, hash); return hash; } IdentityEx::IdentityEx (): - m_Verifier (nullptr), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { } @@ -52,14 +50,14 @@ namespace data case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: { size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 - i2p::context.GetRandomNumberGenerator ().GenerateBlock (m_StandardIdentity.signingKey, padding); + RAND_bytes (m_StandardIdentity.signingKey, padding); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH); break; } case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: { size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 - i2p::context.GetRandomNumberGenerator ().GenerateBlock (m_StandardIdentity.signingKey, padding); + RAND_bytes (m_StandardIdentity.signingKey, padding); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP384_KEY_LENGTH); break; } @@ -98,7 +96,7 @@ namespace data case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: { size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - i2p::context.GetRandomNumberGenerator ().GenerateBlock (m_StandardIdentity.signingKey, padding); + RAND_bytes (m_StandardIdentity.signingKey, padding); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH); break; } @@ -121,7 +119,7 @@ namespace data // calculate ident hash uint8_t * buf = new uint8_t[GetFullLen ()]; ToBuffer (buf, GetFullLen ()); - CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ()); + SHA256(buf, GetFullLen (), m_IdentHash); delete[] buf; } else // DSA-SHA1 @@ -136,20 +134,25 @@ namespace data } IdentityEx::IdentityEx (const uint8_t * buf, size_t len): - m_Verifier (nullptr), m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { FromBuffer (buf, len); } IdentityEx::IdentityEx (const IdentityEx& other): - m_Verifier (nullptr), m_ExtendedBuffer (nullptr) + m_ExtendedLen (0), m_ExtendedBuffer (nullptr) { *this = other; } + + IdentityEx::IdentityEx (const Identity& standard): + m_ExtendedLen (0), m_ExtendedBuffer (nullptr) + { + *this = standard; + } IdentityEx::~IdentityEx () { - delete m_Verifier; delete[] m_ExtendedBuffer; } @@ -168,7 +171,6 @@ namespace data else m_ExtendedBuffer = nullptr; - delete m_Verifier; m_Verifier = nullptr; return *this; @@ -183,7 +185,6 @@ namespace data m_ExtendedBuffer = nullptr; m_ExtendedLen = 0; - delete m_Verifier; m_Verifier = nullptr; return *this; @@ -218,9 +219,8 @@ namespace data m_ExtendedLen = 0; m_ExtendedBuffer = nullptr; } - CryptoPP::SHA256().CalculateDigest(m_IdentHash, buf, GetFullLen ()); + SHA256(buf, GetFullLen (), m_IdentHash); - delete m_Verifier; m_Verifier = nullptr; return GetFullLen (); @@ -302,18 +302,18 @@ namespace data switch (keyType) { case SIGNING_KEY_TYPE_DSA_SHA1: - m_Verifier = new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey); + m_Verifier.reset (new i2p::crypto::DSAVerifier (m_StandardIdentity.signingKey)); break; case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: { size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 - m_Verifier = new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding); + m_Verifier.reset (new i2p::crypto::ECDSAP256Verifier (m_StandardIdentity.signingKey + padding)); break; } case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: { size_t padding = 128 - i2p::crypto::ECDSAP384_KEY_LENGTH; // 32 = 128 - 96 - m_Verifier = new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding); + m_Verifier.reset (new i2p::crypto::ECDSAP384Verifier (m_StandardIdentity.signingKey + padding)); break; } case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: @@ -322,7 +322,7 @@ namespace data memcpy (signingKey, m_StandardIdentity.signingKey, 128); size_t excessLen = i2p::crypto::ECDSAP521_KEY_LENGTH - 128; // 4 = 132- 128 memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types - m_Verifier = new i2p::crypto::ECDSAP521Verifier (signingKey); + m_Verifier.reset (new i2p::crypto::ECDSAP521Verifier (signingKey)); break; } case SIGNING_KEY_TYPE_RSA_SHA256_2048: @@ -331,7 +331,7 @@ namespace data memcpy (signingKey, m_StandardIdentity.signingKey, 128); size_t excessLen = i2p::crypto::RSASHA2562048_KEY_LENGTH - 128; // 128 = 256- 128 memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types - m_Verifier = new i2p::crypto:: RSASHA2562048Verifier (signingKey); + m_Verifier.reset (new i2p::crypto:: RSASHA2562048Verifier (signingKey)); break; } case SIGNING_KEY_TYPE_RSA_SHA384_3072: @@ -340,7 +340,7 @@ namespace data memcpy (signingKey, m_StandardIdentity.signingKey, 128); size_t excessLen = i2p::crypto::RSASHA3843072_KEY_LENGTH - 128; // 256 = 384- 128 memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types - m_Verifier = new i2p::crypto:: RSASHA3843072Verifier (signingKey); + m_Verifier.reset (new i2p::crypto:: RSASHA3843072Verifier (signingKey)); break; } case SIGNING_KEY_TYPE_RSA_SHA512_4096: @@ -349,13 +349,13 @@ namespace data memcpy (signingKey, m_StandardIdentity.signingKey, 128); size_t excessLen = i2p::crypto::RSASHA5124096_KEY_LENGTH - 128; // 384 = 512- 128 memcpy (signingKey + 128, m_ExtendedBuffer + 4, excessLen); // right after signing and crypto key types - m_Verifier = new i2p::crypto:: RSASHA5124096Verifier (signingKey); + m_Verifier.reset (new i2p::crypto:: RSASHA5124096Verifier (signingKey)); break; } case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: { size_t padding = 128 - i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; // 96 = 128 - 32 - m_Verifier = new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding); + m_Verifier.reset (new i2p::crypto::EDDSA25519Verifier (m_StandardIdentity.signingKey + padding)); break; } default: @@ -363,19 +363,16 @@ namespace data } } - void IdentityEx::DropVerifier () + void IdentityEx::DropVerifier () const { - auto verifier = m_Verifier; - m_Verifier = nullptr; // TODO: make this atomic - delete verifier; + m_Verifier = nullptr; } PrivateKeys& PrivateKeys::operator=(const Keys& keys) { - m_Public = Identity (keys); + m_Public = std::make_shared(Identity (keys)); memcpy (m_PrivateKey, keys.privateKey, 256); // 256 - memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public.GetSigningPrivateKeyLen ()); - delete m_Signer; + memcpy (m_SigningPrivateKey, keys.signingPrivateKey, m_Public->GetSigningPrivateKeyLen ()); m_Signer = nullptr; CreateSigner (); return *this; @@ -383,10 +380,9 @@ namespace data PrivateKeys& PrivateKeys::operator=(const PrivateKeys& other) { - m_Public = other.m_Public; + m_Public = std::make_shared(*other.m_Public); memcpy (m_PrivateKey, other.m_PrivateKey, 256); // 256 - memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public.GetSigningPrivateKeyLen ()); - delete m_Signer; + memcpy (m_SigningPrivateKey, other.m_SigningPrivateKey, m_Public->GetSigningPrivateKeyLen ()); m_Signer = nullptr; CreateSigner (); return *this; @@ -394,13 +390,13 @@ namespace data size_t PrivateKeys::FromBuffer (const uint8_t * buf, size_t len) { - size_t ret = m_Public.FromBuffer (buf, len); + m_Public = std::make_shared(buf, len); + size_t ret = m_Public->GetFullLen (); memcpy (m_PrivateKey, buf + ret, 256); // private key always 256 ret += 256; - size_t signingPrivateKeySize = m_Public.GetSigningPrivateKeyLen (); + size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); ret += signingPrivateKeySize; - delete m_Signer; m_Signer = nullptr; CreateSigner (); return ret; @@ -408,10 +404,10 @@ namespace data size_t PrivateKeys::ToBuffer (uint8_t * buf, size_t len) const { - size_t ret = m_Public.ToBuffer (buf, len); + size_t ret = m_Public->ToBuffer (buf, len); memcpy (buf + ret, m_PrivateKey, 256); // private key always 256 ret += 256; - size_t signingPrivateKeySize = m_Public.GetSigningPrivateKeyLen (); + size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); memcpy (buf + ret, m_SigningPrivateKey, signingPrivateKeySize); ret += signingPrivateKeySize; return ret; @@ -442,39 +438,39 @@ namespace data void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const { if (m_Signer) - m_Signer->Sign (i2p::context.GetRandomNumberGenerator (), buf, len, signature); + m_Signer->Sign (buf, len, signature); } void PrivateKeys::CreateSigner () { - switch (m_Public.GetSigningKeyType ()) + switch (m_Public->GetSigningKeyType ()) { case SIGNING_KEY_TYPE_DSA_SHA1: - m_Signer = new i2p::crypto::DSASigner (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::DSASigner (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: - m_Signer = new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::ECDSAP256Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: - m_Signer = new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::ECDSAP384Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: - m_Signer = new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::ECDSAP521Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_RSA_SHA256_2048: - m_Signer = new i2p::crypto::RSASHA2562048Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::RSASHA2562048Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_RSA_SHA384_3072: - m_Signer = new i2p::crypto::RSASHA3843072Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::RSASHA3843072Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_RSA_SHA512_4096: - m_Signer = new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::RSASHA5124096Signer (m_SigningPrivateKey)); break; case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: - m_Signer = new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey); + m_Signer.reset (new i2p::crypto::EDDSA25519Signer (m_SigningPrivateKey)); break; default: - LogPrint ("Signing key type ", (int)m_Public.GetSigningKeyType (), " is not supported"); + LogPrint ("Signing key type ", (int)m_Public->GetSigningKeyType (), " is not supported"); } } @@ -483,39 +479,40 @@ namespace data if (type != SIGNING_KEY_TYPE_DSA_SHA1) { PrivateKeys keys; - auto& rnd = i2p::context.GetRandomNumberGenerator (); // signature uint8_t signingPublicKey[512]; // signing public key is 512 bytes max switch (type) { case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: - i2p::crypto::CreateECDSAP256RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateECDSAP256RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_ECDSA_SHA384_P384: - i2p::crypto::CreateECDSAP384RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateECDSAP384RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_ECDSA_SHA512_P521: - i2p::crypto::CreateECDSAP521RandomKeys (rnd, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateECDSAP521RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA256_2048: - i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA2562048_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA2562048_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA384_3072: - i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA3843072_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA3843072_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); break; case SIGNING_KEY_TYPE_RSA_SHA512_4096: - i2p::crypto::CreateRSARandomKeys (rnd, i2p::crypto::RSASHA5124096_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); + i2p::crypto::CreateRSARandomKeys (i2p::crypto::RSASHA5124096_KEY_LENGTH, keys.m_SigningPrivateKey, signingPublicKey); break; + case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: + i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); + break; default: LogPrint ("Signing key type ", (int)type, " is not supported. Create DSA-SHA1"); return PrivateKeys (i2p::data::CreateRandomKeys ()); // DSA-SHA1 } // encryption uint8_t publicKey[256]; - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - dh.GenerateKeyPair(rnd, keys.m_PrivateKey, publicKey); + i2p::crypto::GenerateElGamalKeyPair (keys.m_PrivateKey, publicKey); // identity - keys.m_Public = IdentityEx (publicKey, signingPublicKey, type); + keys.m_Public = std::make_shared (publicKey, signingPublicKey, type); keys.CreateSigner (); return keys; @@ -526,11 +523,10 @@ namespace data Keys CreateRandomKeys () { Keys keys; - auto& rnd = i2p::context.GetRandomNumberGenerator (); // encryption - i2p::crypto::GenerateElGamalKeyPair(rnd, keys.privateKey, keys.publicKey); + i2p::crypto::GenerateElGamalKeyPair(keys.privateKey, keys.publicKey); // signing - i2p::crypto::CreateDSARandomKeys (rnd, keys.signingPrivateKey, keys.signingKey); + i2p::crypto::CreateDSARandomKeys (keys.signingPrivateKey, keys.signingKey); return keys; } @@ -548,7 +544,7 @@ namespace data sprintf((char *)(buf + 32), "%04i%02i%02i", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); #endif IdentHash key; - CryptoPP::SHA256().CalculateDigest((uint8_t *)key, buf, 40); + SHA256(buf, 40, key); return key; } diff --git a/Identity.h b/Identity.h index 632c414a..1e7316af 100644 --- a/Identity.h +++ b/Identity.h @@ -5,84 +5,18 @@ #include #include #include -#include "base64.h" -#include "ElGamal.h" +#include "Base.h" #include "Signature.h" namespace i2p { namespace data { - template - class Tag - { - public: - - Tag (const uint8_t * buf) { memcpy (m_Buf, buf, sz); }; - Tag (const Tag& ) = default; -#ifndef _WIN32 // FIXME!!! msvs 2013 can't compile it - Tag (Tag&& ) = default; -#endif - Tag () = default; - - Tag& operator= (const Tag& ) = default; -#ifndef _WIN32 - Tag& operator= (Tag&& ) = default; -#endif - - 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 uint64_t * GetLL () const { return ll; }; - - bool operator== (const Tag& other) const { return !memcmp (m_Buf, other.m_Buf, sz); }; - bool operator< (const Tag& other) const { return memcmp (m_Buf, other.m_Buf, sz) < 0; }; - - bool IsZero () const - { - for (int i = 0; i < sz/8; i++) - if (ll[i]) return false; - return true; - } - - std::string ToBase64 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase64 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } - - std::string ToBase32 () const - { - char str[sz*2]; - int l = i2p::data::ByteStreamToBase32 (m_Buf, sz, str, sz*2); - str[l] = 0; - return std::string (str); - } - - void FromBase32 (const std::string& s) - { - i2p::data::Base32ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } - - void FromBase64 (const std::string& s) - { - i2p::data::Base64ToByteStream (s.c_str (), s.length (), m_Buf, sz); - } - - private: - - union // 8 bytes alignment - { - uint8_t m_Buf[sz]; - uint64_t ll[sz/8]; - }; - }; typedef Tag<32> IdentHash; + inline std::string GetIdentHashAbbreviation (const IdentHash& ident) + { + return ident.ToBase64 ().substr (0, 4); + } #pragma pack(1) struct Keys @@ -142,6 +76,7 @@ namespace data SigningKeyType type = SIGNING_KEY_TYPE_DSA_SHA1); 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); @@ -152,6 +87,7 @@ namespace data 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; }; size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetSigningPublicKeyLen () const; size_t GetSigningPrivateKeyLen () const; @@ -159,7 +95,7 @@ namespace data bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; SigningKeyType GetSigningKeyType () const; CryptoKeyType GetCryptoKeyType () const; - void DropVerifier (); // to save memory + void DropVerifier () const; // to save memory private: @@ -169,7 +105,7 @@ namespace data Identity m_StandardIdentity; IdentHash m_IdentHash; - mutable i2p::crypto::Verifier * m_Verifier; + mutable std::unique_ptr m_Verifier; size_t m_ExtendedLen; uint8_t * m_ExtendedBuffer; }; @@ -178,19 +114,19 @@ namespace data { public: - PrivateKeys (): m_Signer (nullptr) {}; - PrivateKeys (const PrivateKeys& other): m_Signer (nullptr) { *this = other; }; - PrivateKeys (const Keys& keys): m_Signer (nullptr) { *this = keys; }; + 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 () { delete m_Signer; }; + ~PrivateKeys () = default; - const IdentityEx& GetPublic () const { return m_Public; }; + std::shared_ptr GetPublic () const { return m_Public; }; const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const; - size_t GetFullLen () const { return m_Public.GetFullLen () + 256 + m_Public.GetSigningPrivateKeyLen (); }; + size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); }; size_t FromBuffer (const uint8_t * buf, size_t len); size_t ToBuffer (uint8_t * buf, size_t len) const; @@ -205,10 +141,10 @@ namespace data private: - IdentityEx m_Public; + std::shared_ptr m_Public; uint8_t m_PrivateKey[256]; uint8_t m_SigningPrivateKey[1024]; // assume private key doesn't exceed 1024 bytes - i2p::crypto::Signer * m_Signer; + std::unique_ptr m_Signer; }; // kademlia @@ -239,17 +175,6 @@ namespace data virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual bool IsDestination () const = 0; // for garlic - - std::unique_ptr& GetElGamalEncryption () const - { - if (!m_ElGamalEncryption) - m_ElGamalEncryption.reset (new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ())); - return m_ElGamalEncryption; - } - - private: - - mutable std::unique_ptr m_ElGamalEncryption; // use lazy initialization }; class LocalDestination @@ -261,8 +186,8 @@ namespace data virtual const uint8_t * GetEncryptionPrivateKey () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; - const IdentityEx& GetIdentity () const { return GetPrivateKeys ().GetPublic (); }; - const IdentHash& GetIdentHash () const { return GetIdentity ().GetIdentHash (); }; + std::shared_ptr GetIdentity () const { return GetPrivateKeys ().GetPublic (); }; + const IdentHash& GetIdentHash () const { return GetIdentity ()->GetIdentHash (); }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { GetPrivateKeys ().Sign (buf, len, signature); diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 77d11e1a..9a88401c 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -1,8 +1,6 @@ #include #include "I2PEndian.h" -#include -#include -#include "CryptoConst.h" +#include "Crypto.h" #include "Log.h" #include "Timestamp.h" #include "NetDb.h" @@ -37,17 +35,16 @@ namespace data return; } m_Buffer = new uint8_t[MAX_LS_BUFFER_SIZE]; - m_BufferLen = localDestination->GetIdentity ().ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); + m_BufferLen = localDestination->GetIdentity ()->ToBuffer (m_Buffer, MAX_LS_BUFFER_SIZE); memcpy (m_Buffer + m_BufferLen, localDestination->GetEncryptionPublicKey (), 256); m_BufferLen += 256; - auto signingKeyLen = localDestination->GetIdentity ().GetSigningPublicKeyLen (); + auto signingKeyLen = localDestination->GetIdentity ()->GetSigningPublicKeyLen (); memset (m_Buffer + m_BufferLen, 0, signingKeyLen); m_BufferLen += signingKeyLen; auto tunnels = pool.GetInboundTunnels (5); // 5 tunnels maximum m_Buffer[m_BufferLen] = tunnels.size (); // num leases m_BufferLen++; // leases - CryptoPP::AutoSeededRandomPool rnd; for (auto it: tunnels) { memcpy (m_Buffer + m_BufferLen, it->GetNextIdentHash (), 32); @@ -56,13 +53,13 @@ namespace data m_BufferLen += 4; // tunnel id uint64_t ts = it->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD; // 1 minute before expiration ts *= 1000; // in milliseconds - ts += rnd.GenerateWord32 (0, 5); // + random milliseconds + ts += rand () % 6; // + random milliseconds 0-5 htobe64buf (m_Buffer + m_BufferLen, ts); m_BufferLen += 8; // end date } // signature localDestination->Sign (m_Buffer, m_BufferLen, m_Buffer + m_BufferLen); - m_BufferLen += localDestination->GetIdentity ().GetSignatureLen (); + m_BufferLen += localDestination->GetIdentity ()->GetSignatureLen (); LogPrint ("Local LeaseSet of ", tunnels.size (), " leases created"); ReadFromBuffer (); @@ -79,15 +76,17 @@ namespace data } memcpy (m_Buffer, buf, len); m_BufferLen = len; - ReadFromBuffer (); + ReadFromBuffer (false); } - void LeaseSet::ReadFromBuffer () + void LeaseSet::ReadFromBuffer (bool readIdentity) { - size_t size = m_Identity.FromBuffer (m_Buffer, m_BufferLen); + if (readIdentity || !m_Identity) + m_Identity = std::make_shared(m_Buffer, m_BufferLen); + size_t size = m_Identity->GetFullLen (); memcpy (m_EncryptionKey, m_Buffer + size, 256); size += 256; // encryption key - size += m_Identity.GetSigningPublicKeyLen (); // unused signing key + size += m_Identity->GetSigningPublicKeyLen (); // unused signing key uint8_t num = m_Buffer[size]; size++; // num LogPrint ("LeaseSet num=", (int)num); @@ -116,7 +115,7 @@ namespace data } // verify - if (!m_Identity.Verify (m_Buffer, leases - m_Buffer, leases)) + if (!m_Identity->Verify (m_Buffer, leases - m_Buffer, leases)) { LogPrint (eLogWarning, "LeaseSet verification failed"); m_IsValid = false; diff --git a/LeaseSet.h b/LeaseSet.h index fee130ab..eec5d89e 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -40,14 +40,14 @@ namespace data LeaseSet (const i2p::tunnel::TunnelPool& pool); ~LeaseSet () { delete[] m_Buffer; }; void Update (const uint8_t * buf, size_t len); - const IdentityEx& GetIdentity () const { return m_Identity; }; + std::shared_ptr GetIdentity () const { return m_Identity; }; const uint8_t * GetBuffer () const { return m_Buffer; }; size_t GetBufferLen () const { return m_BufferLen; }; bool IsValid () const { return m_IsValid; }; // implements RoutingDestination - const IdentHash& GetIdentHash () const { return m_Identity.GetIdentHash (); }; + const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; const std::vector& GetLeases () const { return m_Leases; }; const std::vector GetNonExpiredLeases (bool withThreshold = true) const; bool HasExpiredLeases () const; @@ -57,13 +57,13 @@ namespace data private: - void ReadFromBuffer (); + void ReadFromBuffer (bool readIdentity = true); private: bool m_IsValid; std::vector m_Leases; - IdentityEx m_Identity; + std::shared_ptr m_Identity; uint8_t m_EncryptionKey[256]; uint8_t * m_Buffer; size_t m_BufferLen; diff --git a/Makefile b/Makefile index d256c36e..f65d7a13 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,8 @@ UNAME := $(shell uname -s) SHLIB := libi2pd.so +ARLIB := libi2pd.a +SHLIB_CLIENT := libi2pdclient.so +ARLIB_CLIENT := libi2pdclient.a I2PD := i2p GREP := fgrep DEPS := obj/make.dep @@ -22,12 +25,12 @@ else # win32 DAEMON_SRC += DaemonWin32.cpp endif -all: mk_build_dir $(SHLIB) $(I2PD) +all: mk_build_dir $(SHLIB) $(SHLIB_CLIENT) $(ARLIB) $(ARLIB_CLIENT) $(I2PD) mk_build_dir: mkdir -p obj -api: $(SHLIB) +api: $(SHLIB) $(ARLIB) ## NOTE: The NEEDED_CXXFLAGS are here so that CXXFLAGS can be specified at build time ## **without** overwriting the CXXFLAGS which we need in order to build. @@ -48,7 +51,7 @@ obj/%.o : %.cpp # '-' is 'ignore if missing' on first run -include $(DEPS) -$(I2PD): $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) +$(I2PD): $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) $(ARLIB) $(ARLIB_CLIENT) $(CXX) -o $@ $^ $(LDLIBS) $(LDFLAGS) $(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) @@ -56,9 +59,18 @@ ifneq ($(USE_STATIC),yes) $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ endif +$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) + $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ + +$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) + ar -r $@ $^ + +$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) + ar -r $@ $^ + clean: rm -rf obj - $(RM) $(I2PD) $(SHLIB) + $(RM) $(I2PD) $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) LATEST_TAG=$(shell git describe --tags --abbrev=0 master) dist: diff --git a/Makefile.bsd b/Makefile.bsd index c6c3ce65..72820069 100644 --- a/Makefile.bsd +++ b/Makefile.bsd @@ -9,4 +9,4 @@ CXXFLAGS = -O2 NEEDED_CXXFLAGS = -std=c++11 INCFLAGS = -I/usr/include/ -I/usr/local/include/ LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib -LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread +LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread diff --git a/Makefile.linux b/Makefile.linux index 8af84edf..78dcaaf0 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -33,11 +33,13 @@ ifeq ($(USE_STATIC),yes) LDLIBS += $(LIBDIR)/libboost_filesystem.a LDLIBS += $(LIBDIR)/libboost_regex.a LDLIBS += $(LIBDIR)/libboost_program_options.a - LDLIBS += $(LIBDIR)/libcryptopp.a + LDLIBS += $(LIBDIR)/libcrypto.a + LDLIBS += $(LIBDIR)/libssl.a + LDLIBS += $(LIBDIR)/libz.a LDLIBS += -lpthread -static-libstdc++ -static-libgcc USE_AESNI := no else - LDLIBS = -lcryptopp -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread + LDLIBS = -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_regex -lboost_program_options -lpthread endif # UPNP Support (miniupnpc 1.5 or 1.6) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 86418749..70fb8d25 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -1,12 +1,13 @@ #include #include +#include +#include +#include #include "I2PEndian.h" -#include -#include -#include "base64.h" +#include "Base.h" #include "Log.h" #include "Timestamp.h" -#include "CryptoConst.h" +#include "Crypto.h" #include "I2NPProtocol.h" #include "RouterContext.h" #include "Transports.h" @@ -35,15 +36,9 @@ namespace transport void NTCPSession::CreateAESKey (uint8_t * pubKey, i2p::crypto::AESKey& key) { - CryptoPP::DH dh (elgp, elgg); uint8_t sharedKey[256]; - if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) - { - LogPrint (eLogError, "Couldn't create shared key"); - Terminate (); - return; - }; - + m_DHKeysPair->Agree (pubKey, sharedKey); + uint8_t * aesKey = key; if (sharedKey[0] & 0x80) { @@ -97,11 +92,10 @@ namespace transport delete m_Establisher; m_Establisher = nullptr; - delete m_DHKeysPair; m_DHKeysPair = nullptr; SendTimeSyncMessage (); - m_SendQueue.push_back (ToSharedI2NPMessage(CreateDatabaseStoreMsg ())); // we tell immediately who we are + m_SendQueue.push_back (CreateDatabaseStoreMsg ()); // we tell immediately who we are transports.PeerConnected (shared_from_this ()); } @@ -111,10 +105,10 @@ namespace transport if (!m_DHKeysPair) m_DHKeysPair = transports.GetNextDHKeysPair (); // send Phase1 - const uint8_t * x = m_DHKeysPair->publicKey; + const uint8_t * x = m_DHKeysPair->GetPublicKey (); memcpy (m_Establisher->phase1.pubKey, x, 256); - CryptoPP::SHA256().CalculateDigest(m_Establisher->phase1.HXxorHI, x, 256); - const uint8_t * ident = m_RemoteIdentity.GetIdentHash (); + SHA256(x, 256, m_Establisher->phase1.HXxorHI); + const uint8_t * ident = m_RemoteIdentity->GetIdentHash (); for (int i = 0; i < 32; i++) m_Establisher->phase1.HXxorHI[i] ^= ident[i]; @@ -166,8 +160,8 @@ namespace transport { // verify ident uint8_t digest[32]; - CryptoPP::SHA256().CalculateDigest(digest, m_Establisher->phase1.pubKey, 256); - const uint8_t * ident = i2p::context.GetRouterInfo ().GetIdentHash (); + SHA256(m_Establisher->phase1.pubKey, 256, digest); + const uint8_t * ident = i2p::context.GetIdentHash (); for (int i = 0; i < 32; i++) { if ((m_Establisher->phase1.HXxorHI[i] ^ ident[i]) != digest[i]) @@ -186,12 +180,12 @@ namespace transport { if (!m_DHKeysPair) m_DHKeysPair = transports.GetNextDHKeysPair (); - const uint8_t * y = m_DHKeysPair->publicKey; + const uint8_t * y = m_DHKeysPair->GetPublicKey (); memcpy (m_Establisher->phase2.pubKey, y, 256); uint8_t xy[512]; memcpy (xy, m_Establisher->phase1.pubKey, 256); memcpy (xy + 256, y, 256); - CryptoPP::SHA256().CalculateDigest(m_Establisher->phase2.encrypted.hxy, xy, 512); + SHA256(xy, 512, m_Establisher->phase2.encrypted.hxy); uint32_t tsB = htobe32 (i2p::util::GetSecondsSinceEpoch ()); m_Establisher->phase2.encrypted.timestamp = tsB; // TODO: fill filler @@ -233,7 +227,7 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { // this RI is not valid - i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true); + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); transports.ReuseDHKeysPair (m_DHKeysPair); m_DHKeysPair = nullptr; Terminate (); @@ -251,9 +245,11 @@ namespace transport m_Decryption.Decrypt((uint8_t *)&m_Establisher->phase2.encrypted, sizeof(m_Establisher->phase2.encrypted), (uint8_t *)&m_Establisher->phase2.encrypted); // verify uint8_t xy[512]; - memcpy (xy, m_DHKeysPair->publicKey, 256); + memcpy (xy, m_DHKeysPair->GetPublicKey (), 256); memcpy (xy + 256, m_Establisher->phase2.pubKey, 256); - if (!CryptoPP::SHA256().VerifyDigest(m_Establisher->phase2.encrypted.hxy, xy, 512)) + uint8_t digest[32]; + SHA256 (xy, 512, digest); + if (memcmp(m_Establisher->phase2.encrypted.hxy, digest, 32)) { LogPrint (eLogError, "Incorrect hash"); transports.ReuseDHKeysPair (m_DHKeysPair); @@ -269,13 +265,13 @@ namespace transport { auto keys = i2p::context.GetPrivateKeys (); uint8_t * buf = m_ReceiveBuffer; - htobe16buf (buf, keys.GetPublic ().GetFullLen ()); + htobe16buf (buf, keys.GetPublic ()->GetFullLen ()); buf += 2; - buf += i2p::context.GetIdentity ().ToBuffer (buf, NTCP_BUFFER_SIZE); + buf += i2p::context.GetIdentity ()->ToBuffer (buf, NTCP_BUFFER_SIZE); uint32_t tsA = htobe32 (i2p::util::GetSecondsSinceEpoch ()); htobuf32(buf,tsA); buf += 4; - size_t signatureLen = keys.GetPublic ().GetSignatureLen (); + size_t signatureLen = keys.GetPublic ()->GetSignatureLen (); size_t len = (buf - m_ReceiveBuffer) + signatureLen; size_t paddingSize = len & 0x0F; // %16 if (paddingSize > 0) @@ -289,7 +285,7 @@ namespace transport SignedData s; s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase2.pubKey, 256); // y - s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident + s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident s.Insert (tsA); // tsA s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB s.Sign (keys, buf); @@ -310,7 +306,7 @@ namespace transport else { // wait for phase4 - auto signatureLen = m_RemoteIdentity.GetSignatureLen (); + auto signatureLen = m_RemoteIdentity->GetSignatureLen (); size_t paddingSize = signatureLen & 0x0F; // %16 if (paddingSize > 0) signatureLen += (16 - paddingSize); boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer, signatureLen), boost::asio::transfer_all (), @@ -332,20 +328,20 @@ namespace transport m_Decryption.Decrypt (m_ReceiveBuffer, bytes_transferred, m_ReceiveBuffer); uint8_t * buf = m_ReceiveBuffer; uint16_t size = bufbe16toh (buf); - m_RemoteIdentity.FromBuffer (buf + 2, size); - if (m_Server.FindNTCPSession (m_RemoteIdentity.GetIdentHash ())) + SetRemoteIdentity (std::make_shared (buf + 2, size)); + if (m_Server.FindNTCPSession (m_RemoteIdentity->GetIdentHash ())) { LogPrint (eLogError, "NTCP session already exists"); Terminate (); } - size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity.GetSignatureLen (); + size_t expectedSize = size + 2/*size*/ + 4/*timestamp*/ + m_RemoteIdentity->GetSignatureLen (); size_t paddingLen = expectedSize & 0x0F; if (paddingLen) paddingLen = (16 - paddingLen); if (expectedSize > NTCP_DEFAULT_PHASE3_SIZE) { // we need more bytes for Phase3 expectedSize += paddingLen; - boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize), boost::asio::transfer_all (), + boost::asio::async_read (m_Socket, boost::asio::buffer(m_ReceiveBuffer + NTCP_DEFAULT_PHASE3_SIZE, expectedSize - NTCP_DEFAULT_PHASE3_SIZE), boost::asio::transfer_all (), std::bind(&NTCPSession::HandlePhase3ExtraReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2, tsB, paddingLen)); } @@ -371,7 +367,7 @@ namespace transport void NTCPSession::HandlePhase3 (uint32_t tsB, size_t paddingLen) { - uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity.GetFullLen () + 2 /*size*/; + uint8_t * buf = m_ReceiveBuffer + m_RemoteIdentity->GetFullLen () + 2 /*size*/; uint32_t tsA = buf32toh(buf); buf += 4; buf += paddingLen; @@ -388,7 +384,6 @@ namespace transport Terminate (); return; } - m_RemoteIdentity.DropVerifier (); SendPhase4 (tsA, tsB); } @@ -398,11 +393,11 @@ namespace transport SignedData s; s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase2.pubKey, 256); // y - s.Insert (m_RemoteIdentity.GetIdentHash (), 32); // ident + s.Insert (m_RemoteIdentity->GetIdentHash (), 32); // ident s.Insert (tsA); // tsA s.Insert (tsB); // tsB auto keys = i2p::context.GetPrivateKeys (); - auto signatureLen = keys.GetPublic ().GetSignatureLen (); + auto signatureLen = keys.GetPublic ()->GetSignatureLen (); s.Sign (keys, m_ReceiveBuffer); size_t paddingSize = signatureLen & 0x0F; // %16 if (paddingSize > 0) signatureLen += (16 - paddingSize); @@ -440,7 +435,7 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { // this router doesn't like us - i2p::data::netdb.SetUnreachable (GetRemoteIdentity ().GetIdentHash (), true); + i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true); Terminate (); } } @@ -452,7 +447,7 @@ namespace transport SignedData s; s.Insert (m_Establisher->phase1.pubKey, 256); // x s.Insert (m_Establisher->phase2.pubKey, 256); // y - s.Insert (i2p::context.GetRouterInfo ().GetIdentHash (), 32); // ident + s.Insert (i2p::context.GetIdentHash (), 32); // ident s.Insert (tsA); // tsA s.Insert (m_Establisher->phase2.encrypted.timestamp); // tsB @@ -462,7 +457,6 @@ namespace transport Terminate (); return; } - m_RemoteIdentity.DropVerifier (); LogPrint (eLogInfo, "NTCP session to ", m_Socket.remote_endpoint (), " connected"); Connected (); @@ -583,7 +577,9 @@ namespace transport if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum { // we have a complete I2NP message - if (CryptoPP::Adler32().VerifyDigest (m_NextMessage->buf + m_NextMessageOffset - 4, m_NextMessage->buf, m_NextMessageOffset - 4)) + uint8_t checksum[4]; + htobe32buf (checksum, adler32 (adler32 (0, Z_NULL, 0), m_NextMessage->buf, m_NextMessageOffset - 4)); + if (!memcmp (m_NextMessage->buf + m_NextMessageOffset - 4, checksum, 4)) m_Handler.PutNextMessage (m_NextMessage); else LogPrint (eLogWarning, "Incorrect adler checksum of NTCP message. Dropped"); @@ -625,7 +621,7 @@ namespace transport int padding = 0; if (rem > 0) padding = 16 - rem; // TODO: fill padding - CryptoPP::Adler32().CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding); + htobe32buf (sendBuffer + len + 2 + padding, adler32 (adler32 (0, Z_NULL, 0), sendBuffer, len + 2+ padding)); int l = len + padding + 6; m_Encryption.Encrypt(sendBuffer, l, sendBuffer); @@ -799,19 +795,19 @@ namespace transport void NTCPServer::AddNTCPSession (std::shared_ptr session) { - if (session) + if (session && session->GetRemoteIdentity ()) { std::unique_lock l(m_NTCPSessionsMutex); - m_NTCPSessions[session->GetRemoteIdentity ().GetIdentHash ()] = session; + m_NTCPSessions[session->GetRemoteIdentity ()->GetIdentHash ()] = session; } } void NTCPServer::RemoveNTCPSession (std::shared_ptr session) { - if (session) + if (session && session->GetRemoteIdentity ()) { std::unique_lock l(m_NTCPSessionsMutex); - m_NTCPSessions.erase (session->GetRemoteIdentity ().GetIdentHash ()); + m_NTCPSessions.erase (session->GetRemoteIdentity ()->GetIdentHash ()); } } @@ -914,7 +910,7 @@ namespace transport { LogPrint (eLogError, "Connect error: ", ecode.message ()); if (ecode != boost::asio::error::operation_aborted) - i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ().GetIdentHash (), true); + i2p::data::netdb.SetUnreachable (conn->GetRemoteIdentity ()->GetIdentHash (), true); conn->Terminate (); } else diff --git a/NTCPSession.h b/NTCPSession.h index 2921e923..13e1656f 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -7,9 +7,7 @@ #include #include #include -#include -#include -#include "aes.h" +#include "Crypto.h" #include "Identity.h" #include "RouterInfo.h" #include "I2NPProtocol.h" diff --git a/NetDb.cpp b/NetDb.cpp index 39dd6430..5517ffdf 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -3,8 +3,9 @@ #include #include #include -#include -#include "base64.h" +#include +#include +#include "Base.h" #include "Log.h" #include "Timestamp.h" #include "I2NPProtocol.h" @@ -38,23 +39,8 @@ namespace data { Load (); if (m_RouterInfos.size () < 25) // reseed if # of router less than 50 - { - // try SU3 first Reseed (); - // deprecated - if (m_Reseeder) - { - // if still not enough download .dat files - int reseedRetries = 0; - while (m_RouterInfos.size () < 25 && reseedRetries < 5) - { - m_Reseeder->reseedNow(); - reseedRetries++; - Load (); - } - } - } m_IsRunning = true; m_Thread = new std::thread (std::bind (&NetDb::Run, this)); } @@ -245,6 +231,12 @@ namespace data return nullptr; } + std::shared_ptr NetDb::FindRouterProfile (const IdentHash& ident) const + { + auto router = FindRouter (ident); + return router ? router->GetProfile () : nullptr; + } + void NetDb::SetUnreachable (const IdentHash& ident, bool unreachable) { auto it = m_RouterInfos.find (ident); @@ -518,25 +510,10 @@ namespace data LogPrint ("Invalid RouterInfo length ", (int)size); return; } - try - { - CryptoPP::Gunzip decompressor; - decompressor.Put (buf + offset, size); - decompressor.MessageEnd(); - uint8_t uncompressed[2048]; - size_t uncomressedSize = decompressor.MaxRetrievable (); - if (uncomressedSize <= 2048) - { - decompressor.Get (uncompressed, uncomressedSize); - AddRouterInfo (ident, uncompressed, uncomressedSize); - } - else - LogPrint ("Invalid RouterInfo uncomressed length ", (int)uncomressedSize); - } - catch (CryptoPP::Exception& ex) - { - LogPrint (eLogError, "DatabaseStore: ", ex.what ()); - } + uint8_t uncompressed[2048]; + size_t uncompressedSize = m_Inflator.Inflate (buf + offset, size, uncompressed, 2048); + if (uncompressedSize) + AddRouterInfo (ident, uncompressed, uncompressedSize); } } @@ -575,7 +552,7 @@ namespace data { i2p::tunnel::eDeliveryTypeRouter, nextFloodfill->GetIdentHash (), 0, - ToSharedI2NPMessage (CreateDatabaseStoreMsg ()) + CreateDatabaseStoreMsg () }); // request destination @@ -679,7 +656,7 @@ namespace data excludedRouters.insert (r->GetIdentHash ()); } } - replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, routers)); + replyMsg = CreateDatabaseSearchReply (ident, routers); } else { @@ -692,7 +669,7 @@ namespace data LogPrint ("Requested RouterInfo ", key, " found"); router->LoadBuffer (); if (router->GetBuffer ()) - replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (router)); + replyMsg = CreateDatabaseStoreMsg (router); } } @@ -703,7 +680,7 @@ namespace data if (leaseSet) // we don't send back our LeaseSets { LogPrint ("Requested LeaseSet ", key, " found"); - replyMsg = ToSharedI2NPMessage (CreateDatabaseStoreMsg (leaseSet)); + replyMsg = CreateDatabaseStoreMsg (leaseSet); } } @@ -716,7 +693,7 @@ namespace data excludedRouters.insert (excluded); excluded += 32; } - replyMsg = ToSharedI2NPMessage (CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters))); + replyMsg = CreateDatabaseSearchReply (ident, GetClosestFloodfills (ident, 3, excludedRouters)); } } @@ -756,14 +733,13 @@ namespace data auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr; bool throughTunnels = outbound && inbound; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); uint8_t randomHash[32]; std::vector msgs; std::set floodfills; LogPrint ("Exploring new ", numDestinations, " routers ..."); for (int i = 0; i < numDestinations; i++) { - rnd.GenerateBlock (randomHash, 32); + RAND_bytes (randomHash, 32); auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory if (!dest) { @@ -782,7 +758,7 @@ namespace data { i2p::tunnel::eDeliveryTypeRouter, floodfill->GetIdentHash (), 0, - ToSharedI2NPMessage (CreateDatabaseStoreMsg ()) // tell floodfill about us + CreateDatabaseStoreMsg () // tell floodfill about us }); msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -809,9 +785,10 @@ namespace data auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded); if (floodfill) { - uint32_t replyToken = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); - LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation (), ". reply token=", replyToken); - transports.SendMessage (floodfill->GetIdentHash (), ToSharedI2NPMessage (CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken))); + uint32_t replyToken; + RAND_bytes ((uint8_t *)&replyToken, 4); + LogPrint ("Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); + transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); excluded.insert (floodfill->GetIdentHash ()); } } @@ -868,8 +845,8 @@ namespace data template std::shared_ptr NetDb::GetRandomRouter (Filter filter) const { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1); + if (!m_RouterInfos.size ()) return 0; + uint32_t ind = rand () % m_RouterInfos.size (); for (int j = 0; j < 2; j++) { uint32_t i = 0; diff --git a/NetDb.h b/NetDb.h index 71db2e52..237e5be1 100644 --- a/NetDb.h +++ b/NetDb.h @@ -9,6 +9,7 @@ #include #include #include +#include "Base.h" #include "Queue.h" #include "I2NPProtocol.h" #include "RouterInfo.h" @@ -38,6 +39,7 @@ namespace data void AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr from); std::shared_ptr FindRouter (const IdentHash& ident) const; std::shared_ptr FindLeaseSet (const IdentHash& destination) const; + std::shared_ptr FindRouterProfile (const IdentHash& ident) const; void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); @@ -91,6 +93,7 @@ namespace data std::thread * m_Thread; i2p::util::Queue > m_Queue; // of I2NPDatabaseStoreMsg + GzipInflator m_Inflator; Reseeder * m_Reseeder; friend class NetDbRequests; diff --git a/NetDbRequests.cpp b/NetDbRequests.cpp index 5f4a3e75..a8ccf3f9 100644 --- a/NetDbRequests.cpp +++ b/NetDbRequests.cpp @@ -11,21 +11,21 @@ namespace data std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { - I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); m_ExcludedPeers.insert (router->GetIdentHash ()); m_CreationTime = i2p::util::GetSecondsSinceEpoch (); - return ToSharedI2NPMessage (msg); + return msg; } std::shared_ptr RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) { - I2NPMessage * msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); m_ExcludedPeers.insert (floodfill); m_CreationTime = i2p::util::GetSecondsSinceEpoch (); - return ToSharedI2NPMessage (msg); + return msg; } void RequestedDestination::ClearExcludedPeers () diff --git a/Profiling.cpp b/Profiling.cpp index d0b8e85d..8b1a6bc3 100644 --- a/Profiling.cpp +++ b/Profiling.cpp @@ -1,8 +1,9 @@ #include #include #include -#include "base64.h" +#include "Base.h" #include "util.h" +#include "Log.h" #include "Profiling.h" namespace i2p diff --git a/Reseed.cpp b/Reseed.cpp index 9f137432..8d4baf8a 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -3,19 +3,17 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include +#include +#include +#include +#include +#include +#include #include "I2PEndian.h" #include "Reseed.h" #include "Log.h" #include "Identity.h" -#include "CryptoConst.h" +#include "Crypto.h" #include "NetDb.h" #include "util.h" @@ -24,27 +22,18 @@ namespace i2p { namespace data { - - static std::vector httpReseedHostList = { - "http://netdb.i2p2.no/", // only SU3 (v2) support - "http://i2p-netdb.innovatio.no/", - "http://193.150.121.66/netDb/" - }; - - static std::vector httpsReseedHostList = { - // "https://193.150.121.66/netDb/", // unstable - // "https://i2p-netdb.innovatio.no/",// Vuln to POODLE - "https://netdb.i2p2.no/", // Only SU3 (v2) support - "https://reseed.i2p-projekt.de/", // Only HTTPS - //"https://cowpuncher.drollette.com/netdb/", // returns error - "https://netdb.rows.io:444/", - "https://uk.reseed.i2p2.no:444/" - // following hosts are fine but don't support AES256 - /*"https://i2p.mooo.com/netDb/", - "https://link.mx24.eu/", // Only HTTPS and SU3 (v2) support - "https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v2) support - "https://ieb9oopo.mooo.com/" // Only HTTPS and SU3 (v2) support*/ - }; + static std::vector httpsReseedHostList = + { + "https://reseed.i2p-projekt.de/", // Only HTTPS + "https://i2pseed.zarrenspry.info/", // Only HTTPS and SU3 (v3) support + "https://i2p.mooo.com/netDb/", + "https://netdb.i2p2.no/", // Only SU3 (v3) support, SNI required + "https://us.reseed.i2p2.no:444/", + "https://uk.reseed.i2p2.no:444/", + "https://reseed.i2p.vzaws.com:8443/", // Only SU3 (v3) support + "https://user.mx24.eu/", // Only HTTPS and SU3 (v3) support + "https://ieb9oopo.mooo.com/" // Only HTTPS and SU3 (v3) support + }; Reseeder::Reseeder() { @@ -54,75 +43,11 @@ namespace data { } - bool Reseeder::reseedNow() - { - // This method is deprecated - try - { - std::string reseedHost = httpReseedHostList[(rand() % httpReseedHostList.size())]; - LogPrint("Reseeding from ", reseedHost); - std::string content = i2p::util::http::httpRequest(reseedHost); - if (content == "") - { - LogPrint("Reseed failed"); - return false; - } - boost::regex e("<\\s*A\\s+[^>]*href\\s*=\\s*\"([^\"]*)\"", boost::regex::normal | boost::regbase::icase); - boost::sregex_token_iterator i(content.begin(), content.end(), e, 1); - boost::sregex_token_iterator j; - //TODO: Ugly code, try to clean up. - //TODO: Try to reduce N number of variables - std::string name; - std::string routerInfo; - std::string tmpUrl; - std::string filename; - std::string ignoreFileSuffix = ".su3"; - boost::filesystem::path root = i2p::util::filesystem::GetDataDir(); - while (i != j) - { - name = *i++; - if (name.find(ignoreFileSuffix)!=std::string::npos) - continue; - LogPrint("Downloading ", name); - tmpUrl = reseedHost; - tmpUrl.append(name); - routerInfo = i2p::util::http::httpRequest(tmpUrl); - if (routerInfo.size()==0) - continue; - filename = root.string(); -#ifndef _WIN32 - filename += "/netDb/r"; -#else - filename += "\\netDb\\r"; -#endif - filename += name.at(11); // first char in id -#ifndef _WIN32 - filename.append("/"); -#else - filename.append("\\"); -#endif - filename.append(name.c_str()); - std::ofstream outfile (filename, std::ios::binary); - outfile << routerInfo; - outfile.close(); - } - return true; - } - catch (std::exception& ex) - { - //TODO: error reporting - return false; - } - return false; - } - int Reseeder::ReseedNowSU3 () { - CryptoPP::AutoSeededRandomPool rnd; - auto ind = rnd.GenerateWord32 (0, httpReseedHostList.size() - 1 + httpsReseedHostList.size () - 1); - std::string reseedHost = (ind < httpReseedHostList.size()) ? httpReseedHostList[ind] : - httpsReseedHostList[ind - httpReseedHostList.size()]; - return ReseedFromSU3 (reseedHost, ind >= httpReseedHostList.size()); + auto ind = rand () % httpsReseedHostList.size (); + std::string& reseedHost = httpsReseedHostList[ind]; + return ReseedFromSU3 (reseedHost, true); } int Reseeder::ReseedFromSU3 (const std::string& host, bool https) @@ -221,10 +146,27 @@ namespace data uint8_t * signature = new uint8_t[signatureLength]; s.read ((char *)signature, signatureLength); // RSA-raw - i2p::crypto::RSASHA5124096RawVerifier verifier(it->second); - verifier.Update (tbs, tbsLen); - if (!verifier.Verify (signature)) - LogPrint (eLogWarning, "SU3 signature verification failed"); + { + // calculate digest + uint8_t digest[64]; + 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, i2p::crypto::RSASHA5124096_KEY_LENGTH, n); + BN_mod_exp (s, s, i2p::crypto::rsae, 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, "SU3 signature verification failed"); + delete[] enSigBuf; + BN_free (s); BN_free (n); + BN_CTX_free (bnctx); + } + delete[] signature; delete[] tbs; s.seekg (pos, std::ios::beg); @@ -255,8 +197,9 @@ namespace data compressionMethod = le16toh (compressionMethod); s.seekg (4, std::ios::cur); // skip fields we don't care about uint32_t compressedSize, uncompressedSize; - uint8_t crc32[4]; - s.read ((char *)crc32, 4); + uint32_t crc_32; + s.read ((char *)&crc_32, 4); + crc_32 = le32toh (crc_32); s.read ((char *)&compressedSize, 4); compressedSize = le32toh (compressedSize); s.read ((char *)&uncompressedSize, 4); @@ -278,9 +221,9 @@ namespace data { LogPrint (eLogError, "SU3 archive data descriptor not found"); return numFiles; - } - - s.read ((char *)crc32, 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); @@ -301,25 +244,31 @@ namespace data s.read ((char *)compressed, compressedSize); if (compressionMethod) // we assume Deflate { - CryptoPP::Inflator decompressor; - decompressor.Put (compressed, compressedSize); - decompressor.MessageEnd(); - if (decompressor.MaxRetrievable () <= uncompressedSize) - { - uint8_t * uncompressed = new uint8_t[uncompressedSize]; - decompressor.Get (uncompressed, uncompressedSize); - if (CryptoPP::CRC32().VerifyDigest (crc32, uncompressed, uncompressedSize)) + z_stream inflator; + 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) + { + uncompressedSize -= inflator.avail_out; + if (crc32 (0, uncompressed, uncompressedSize) == crc_32) { i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize); numFiles++; - } + } else LogPrint (eLogError, "CRC32 verification failed"); - delete[] uncompressed; - } + } else - LogPrint (eLogError, "Actual uncompressed size ", decompressor.MaxRetrievable (), " exceed ", uncompressedSize, " from header"); - } + LogPrint (eLogError, "decompression error ", err); + delete[] uncompressed; + inflateEnd (&inflator); + } else // no compression { i2p::data::netdb.AddRouterInfo (compressed, compressedSize); @@ -362,111 +311,33 @@ namespace data return false; } - const char CERTIFICATE_HEADER[] = "-----BEGIN CERTIFICATE-----"; - const char CERTIFICATE_FOOTER[] = "-----END CERTIFICATE-----"; void Reseeder::LoadCertificate (const std::string& filename) { - std::ifstream s(filename, std::ifstream::binary); - if (s.is_open ()) - { - s.seekg (0, std::ios::end); - size_t len = s.tellg (); - s.seekg (0, std::ios::beg); - char buf[2048]; - s.read (buf, len); - std::string cert (buf, len); - // assume file in pem format - auto pos1 = cert.find (CERTIFICATE_HEADER); - auto pos2 = cert.find (CERTIFICATE_FOOTER); - if (pos1 == std::string::npos || pos2 == std::string::npos) - { - LogPrint (eLogError, "Malformed certificate file"); - return; + SSL_CTX * ctx = SSL_CTX_new (TLSv1_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) + { + // extract issuer name + char name[100]; + X509_NAME_oneline (X509_get_issuer_name(cert), name, 100); + // extract RSA key (we need n only, e = 65537) + RSA * key = X509_get_pubkey (cert)->pkey.rsa; + PublicKey value; + i2p::crypto::bn2buf (key->n, value, 512); + m_SigningKeys[name] = value; } - pos1 += strlen (CERTIFICATE_HEADER); - pos2 -= pos1; - std::string base64 = cert.substr (pos1, pos2); - - CryptoPP::ByteQueue queue; - CryptoPP::Base64Decoder decoder; // regular base64 rather than I2P - decoder.Attach (new CryptoPP::Redirector (queue)); - decoder.Put ((const uint8_t *)base64.data(), base64.length()); - decoder.MessageEnd (); - - LoadCertificate (queue); - } + SSL_free (ssl); + } else LogPrint (eLogError, "Can't open certificate file ", filename); + SSL_CTX_free (ctx); } - std::string Reseeder::LoadCertificate (CryptoPP::ByteQueue& queue) - { - // extract X.509 - CryptoPP::BERSequenceDecoder x509Cert (queue); - CryptoPP::BERSequenceDecoder tbsCert (x509Cert); - // version - uint32_t ver; - CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED); - CryptoPP::BERDecodeUnsigned(context, ver, CryptoPP::INTEGER); - // serial - CryptoPP::Integer serial; - serial.BERDecode(tbsCert); - // signature - CryptoPP::BERSequenceDecoder signature (tbsCert); - signature.SkipAll(); - - // issuer - std::string name; - CryptoPP::BERSequenceDecoder issuer (tbsCert); - { - CryptoPP::BERSetDecoder c (issuer); c.SkipAll(); - CryptoPP::BERSetDecoder st (issuer); st.SkipAll(); - CryptoPP::BERSetDecoder l (issuer); l.SkipAll(); - CryptoPP::BERSetDecoder o (issuer); o.SkipAll(); - CryptoPP::BERSetDecoder ou (issuer); ou.SkipAll(); - CryptoPP::BERSetDecoder cn (issuer); - { - CryptoPP::BERSequenceDecoder attributes (cn); - { - CryptoPP::BERGeneralDecoder ident(attributes, CryptoPP::OBJECT_IDENTIFIER); - ident.SkipAll (); - CryptoPP::BERDecodeTextString (attributes, name, CryptoPP::UTF8_STRING); - } - } - } - issuer.SkipAll(); - // validity - CryptoPP::BERSequenceDecoder validity (tbsCert); - validity.SkipAll(); - // subject - CryptoPP::BERSequenceDecoder subject (tbsCert); - subject.SkipAll(); - // public key - CryptoPP::BERSequenceDecoder publicKey (tbsCert); - { - CryptoPP::BERSequenceDecoder ident (publicKey); - ident.SkipAll (); - CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING); - key.Skip (1); // FIXME: probably bug in crypto++ - CryptoPP::BERSequenceDecoder keyPair (key); - CryptoPP::Integer n; - n.BERDecode (keyPair); - if (name.length () > 0) - { - PublicKey value; - n.Encode (value, 512); - m_SigningKeys[name] = value; - } - else - LogPrint (eLogWarning, "Unknown issuer. Skipped"); - } - publicKey.SkipAll(); - - tbsCert.SkipAll(); - x509Cert.SkipAll(); - return name; - } - void Reseeder::LoadCertificates () { boost::filesystem::path reseedDir = i2p::util::filesystem::GetCertificatesDir() / "reseed"; @@ -494,439 +365,50 @@ namespace data { i2p::util::http::url u(address); if (u.port_ == 80) u.port_ = 443; - TlsSession session (u.host_, u.port_); - - if (session.IsEstablished ()) - { - // send request - std::stringstream ss; - ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ - << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; - session.Send ((uint8_t *)ss.str ().c_str (), ss.str ().length ()); - // read response - std::stringstream rs; - while (session.Receive (rs)) - ; - return i2p::util::http::GetHttpContent (rs); - } - else - return ""; - } - -//------------------------------------------------------------- - - template - class TlsCipherMAC: public TlsCipher - { - public: - - TlsCipherMAC (const uint8_t * keys): m_Seqn (0) - { - memcpy (m_MacKey, keys, Hash::DIGESTSIZE); - } - - void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) - { - uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) - htobe64buf (header, m_Seqn); - header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 - htobe16buf (header + 11, len); - CryptoPP::HMAC hmac (m_MacKey, Hash::DIGESTSIZE); - hmac.Update (header, 13); - hmac.Update (buf, len); - hmac.Final (mac); - m_Seqn++; - } - - private: - - uint64_t m_Seqn; - uint8_t m_MacKey[Hash::DIGESTSIZE]; // client - }; - - template - class TlsCipher_AES_256_CBC: public TlsCipherMAC - { - public: - - TlsCipher_AES_256_CBC (const uint8_t * keys): TlsCipherMAC (keys) - { - m_Encryption.SetKey (keys + 2*Hash::DIGESTSIZE); - m_Decryption.SetKey (keys + 2*Hash::DIGESTSIZE + 32); - } - - size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) - { - size_t size = 0; - m_Rnd.GenerateBlock (out, 16); // iv - size += 16; - m_Encryption.SetIV (out); - memcpy (out + size, in, len); - size += len; - memcpy (out + size, mac, Hash::DIGESTSIZE); - size += Hash::DIGESTSIZE; - uint8_t paddingSize = size + 1; - paddingSize &= 0x0F; // %16 - if (paddingSize > 0) paddingSize = 16 - paddingSize; - memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size - size += paddingSize + 1; - m_Encryption.Encrypt (out + 16, size - 16, out + 16); - return size; - } - - size_t Decrypt (uint8_t * buf, size_t len) // payload is buf + 16 - { - m_Decryption.SetIV (buf); - m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); - return len - 16 - Hash::DIGESTSIZE - buf[len -1] - 1; // IV(16), mac(32 or 20) and padding - } - - size_t GetIVSize () const { return 16; }; - - private: - - CryptoPP::AutoSeededRandomPool m_Rnd; - i2p::crypto::CBCEncryption m_Encryption; - i2p::crypto::CBCDecryption m_Decryption; - }; - - - class TlsCipher_RC4_SHA: public TlsCipherMAC - { - public: - - TlsCipher_RC4_SHA (const uint8_t * keys): TlsCipherMAC (keys) + boost::asio::io_service service; + boost::system::error_code ecode; + auto it = boost::asio::ip::tcp::resolver(service).resolve ( + boost::asio::ip::tcp::resolver::query (u.host_, std::to_string (u.port_)), ecode); + if (!ecode) + { + boost::asio::ssl::context ctx(service, boost::asio::ssl::context::tlsv12); + ctx.set_verify_mode(boost::asio::ssl::context::verify_none); + boost::asio::ssl::stream s(service, ctx); + s.lowest_layer().connect (*it, ecode); + if (!ecode) { - m_Encryption.SetKey (keys + 40, 16); // 20 + 20 - m_Decryption.SetKey (keys + 56, 16); // 20 + 20 + 16 + s.handshake (boost::asio::ssl::stream_base::client, ecode); + if (!ecode) + { + LogPrint (eLogInfo, "Connected to ", u.host_, ":", u.port_); + // send request + std::stringstream ss; + ss << "GET " << u.path_ << " HTTP/1.1\r\nHost: " << u.host_ + << "\r\nAccept: */*\r\n" << "User-Agent: Wget/1.11.4\r\n" << "Connection: close\r\n\r\n"; + s.write_some (boost::asio::buffer (ss.str ())); + // read response + std::stringstream rs; + char response[1024]; size_t l = 0; + do + { + l = s.read_some (boost::asio::buffer (response, 1024), ecode); + if (l) rs.write (response, l); + } + while (!ecode && l); + // process response + return i2p::util::http::GetHttpContent (rs); + } + else + LogPrint (eLogError, "SSL handshake failed: ", ecode.message ()); } - - size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) - { - memcpy (out, in, len); - memcpy (out + len, mac, 20); - m_Encryption.ProcessData (out, out, len + 20); - return len + 20; - } - - size_t Decrypt (uint8_t * buf, size_t len) - { - m_Decryption.ProcessData (buf, buf, len); - return len - 20; - } - - private: - - CryptoPP::Weak1::ARC4 m_Encryption, m_Decryption; - }; - - - TlsSession::TlsSession (const std::string& host, int port): - m_IsEstablished (false), m_Cipher (nullptr) - { - m_Site.connect(host, boost::lexical_cast(port)); - if (m_Site.good ()) - Handshake (); - else - LogPrint (eLogError, "Can't connect to ", host, ":", port); - } - - TlsSession::~TlsSession () - { - delete m_Cipher; - } - - void TlsSession::Handshake () - { - static uint8_t clientHello[] = - { - 0x16, // handshake - 0x03, 0x03, // version (TLS 1.2) - 0x00, 0x33, // length of handshake - // handshake - 0x01, // handshake type (client hello) - 0x00, 0x00, 0x2F, // length of handshake payload - // client hello - 0x03, 0x03, // highest version supported (TLS 1.2) - 0x45, 0xFA, 0x01, 0x19, 0x74, 0x55, 0x18, 0x36, - 0x42, 0x05, 0xC1, 0xDD, 0x4A, 0x21, 0x80, 0x80, - 0xEC, 0x37, 0x11, 0x93, 0x16, 0xF4, 0x66, 0x00, - 0x12, 0x67, 0xAB, 0xBA, 0xFF, 0x29, 0x13, 0x9E, // 32 random bytes - 0x00, // session id length - 0x00, 0x06, // chiper suites length - 0x00, 0x3D, // RSA_WITH_AES_256_CBC_SHA256 - 0x00, 0x35, // RSA_WITH_AES_256_CBC_SHA - 0x00, 0x05, // RSA_WITH_RC4_128_SHA - 0x01, // compression methods length - 0x00, // no compression - 0x00, 0x00 // extensions length - }; - - static uint8_t changeCipherSpecs[] = - { - 0x14, // change cipher specs - 0x03, 0x03, // version (TLS 1.2) - 0x00, 0x01, // length - 0x01 // type - }; - - // send ClientHello - m_Site.write ((char *)clientHello, sizeof (clientHello)); - m_FinishedHash.Update (clientHello + 5, sizeof (clientHello) - 5); - // read ServerHello - uint8_t type; - m_Site.read ((char *)&type, 1); - uint16_t version; - m_Site.read ((char *)&version, 2); - uint16_t length; - m_Site.read ((char *)&length, 2); - length = be16toh (length); - char * serverHello = new char[length]; - m_Site.read (serverHello, length); - m_FinishedHash.Update ((uint8_t *)serverHello, length); - uint8_t serverRandom[32]; - if (serverHello[0] == 0x02) // handshake type server hello - memcpy (serverRandom, serverHello + 6, 32); - else - LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); - uint8_t sessionIDLen = serverHello[38]; // 6 + 32 - char * cipherSuite = serverHello + 39 + sessionIDLen; - if (cipherSuite[1] == 0x3D || cipherSuite[1] == 0x35 || cipherSuite[1] == 0x05) - m_IsEstablished = true; - else - LogPrint (eLogError, "Unsupported cipher ", (int)cipherSuite[0], ",", (int)cipherSuite[1]); - // read Certificate - m_Site.read ((char *)&type, 1); - m_Site.read ((char *)&version, 2); - m_Site.read ((char *)&length, 2); - length = be16toh (length); - char * certificate = new char[length]; - m_Site.read (certificate, length); - m_FinishedHash.Update ((uint8_t *)certificate, length); - CryptoPP::RSA::PublicKey publicKey; - // 0 - handshake type - // 1 - 3 - handshake payload length - // 4 - 6 - length of array of certificates - // 7 - 9 - length of certificate - if (certificate[0] == 0x0B) // handshake type certificate - publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10); - else - LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]); - // read ServerHelloDone - m_Site.read ((char *)&type, 1); - m_Site.read ((char *)&version, 2); - m_Site.read ((char *)&length, 2); - length = be16toh (length); - char * serverHelloDone = new char[length]; - m_Site.read (serverHelloDone, length); - m_FinishedHash.Update ((uint8_t *)serverHelloDone, length); - if (serverHelloDone[0] != 0x0E) // handshake type hello done - LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]); - // our turn now - // generate secret key - uint8_t secret[48]; - secret[0] = 3; secret[1] = 3; // version - CryptoPP::AutoSeededRandomPool rnd; - rnd.GenerateBlock (secret + 2, 46); // 46 random bytes - // encrypt RSA - CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); - size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key) - uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length - htobe16buf (encrypted, encryptedLen); // first two bytes means length - encryptor.Encrypt (rnd, secret, 48, encrypted + 2); - // send ClientKeyExchange - // 0x10 - handshake type "client key exchange" - SendHandshakeMsg (0x10, encrypted, encryptedLen + 2); - delete[] encrypted; - // send ChangeCipherSpecs - m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs)); - // calculate master secret - uint8_t random[64]; - memcpy (random, clientHello + 11, 32); - memcpy (random + 32, serverRandom, 32); - PRF (secret, "master secret", random, 64, 48, m_MasterSecret); - // create keys - memcpy (random, serverRandom, 32); - memcpy (random + 32, clientHello + 11, 32); - uint8_t keys[128]; // clientMACKey(32 or 20), serverMACKey(32 or 20), clientKey(32), serverKey(32) - PRF (m_MasterSecret, "key expansion", random, 64, 128, keys); - // create cipher - if (cipherSuite[1] == 0x3D) - { - LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA256"); - m_Cipher = new TlsCipher_AES_256_CBC (keys); + else + LogPrint (eLogError, "Couldn't connect to ", u.host_, ": ", ecode.message ()); } - else if (cipherSuite[1] == 0x35) - { - LogPrint (eLogInfo, "Chiper suite is RSA_WITH_AES_256_CBC_SHA"); - m_Cipher = new TlsCipher_AES_256_CBC (keys); - } else - { - // TODO: - if (cipherSuite[1] == 0x05) - LogPrint (eLogInfo, "Chiper suite is RSA_WITH_RC4_128_SHA"); - m_Cipher = new TlsCipher_RC4_SHA (keys); - } - // send finished - SendFinishedMsg (); - // read ChangeCipherSpecs - uint8_t changeCipherSpecs1[6]; - m_Site.read ((char *)changeCipherSpecs1, 6); - // read finished - m_Site.read ((char *)&type, 1); - m_Site.read ((char *)&version, 2); - m_Site.read ((char *)&length, 2); - length = be16toh (length); - char * finished1 = new char[length]; - m_Site.read (finished1, length); - m_Cipher->Decrypt ((uint8_t *)finished1, length); // for streaming ciphers - delete[] finished1; - - delete[] serverHello; - delete[] certificate; - delete[] serverHelloDone; - } - - void TlsSession::SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len) - { - uint8_t handshakeHeader[9]; - handshakeHeader[0] = 0x16; // handshake - handshakeHeader[1] = 0x03; handshakeHeader[2] = 0x03; // version is always TLS 1.2 (3,3) - htobe16buf (handshakeHeader + 3, len + 4); // length of payload - //payload starts - handshakeHeader[5] = handshakeType; // handshake type - handshakeHeader[6] = 0; // highest byte of payload length is always zero - htobe16buf (handshakeHeader + 7, len); // length of data - m_Site.write ((char *)handshakeHeader, 9); - m_FinishedHash.Update (handshakeHeader + 5, 4); // only payload counts - m_Site.write ((char *)data, len); - m_FinishedHash.Update (data, len); - } - - void TlsSession::SendFinishedMsg () - { - // 0x16 handshake - // 0x03, 0x03 version (TLS 1.2) - // 2 bytes length of handshake (80 or 64 bytes) - // handshake (encrypted) - // unencrypted context - // 0x14 handshake type (finished) - // 0x00, 0x00, 0x0C length of handshake payload - // 12 bytes of verified data - - uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; - finishedPayload[0] = 0x14; // handshake type (finished) - finishedPayload[1] = 0; finishedPayload[2] = 0; finishedPayload[3] = 0x0C; // 12 bytes - m_FinishedHash.Final (finishedHashDigest); - PRF (m_MasterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4); - uint8_t mac[32]; - m_Cipher->CalculateMAC (0x16, finishedPayload, 16, mac); - size_t encryptedPayloadSize = m_Cipher->Encrypt (finishedPayload, 16, mac, encryptedPayload); - uint8_t finished[5]; - finished[0] = 0x16; // handshake - finished[1] = 0x03; finished[2] = 0x03; // version is always TLS 1.2 (3,3) - htobe16buf (finished + 3, encryptedPayloadSize); // length of payload - m_Site.write ((char *)finished, sizeof (finished)); - m_Site.write ((char *)encryptedPayload, encryptedPayloadSize); - } - - void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, - size_t len, uint8_t * buf) - { - // secret is assumed 48 bytes - // random is not more than 64 bytes - CryptoPP::HMAC hmac (secret, 48); - uint8_t seed[96]; size_t seedLen; - seedLen = strlen (label); - memcpy (seed, label, seedLen); - memcpy (seed + seedLen, random, randomLen); - seedLen += randomLen; - - size_t offset = 0; - uint8_t a[128]; - hmac.CalculateDigest (a, seed, seedLen); - while (offset < len) - { - memcpy (a + 32, seed, seedLen); - hmac.CalculateDigest (buf + offset, a, seedLen + 32); - offset += 32; - hmac.CalculateDigest (a, a, 32); - } - } - - CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) - { - CryptoPP::ByteQueue queue; - queue.Put (certificate, len); - queue.MessageEnd (); - // extract X.509 - CryptoPP::BERSequenceDecoder x509Cert (queue); - CryptoPP::BERSequenceDecoder tbsCert (x509Cert); - // version - uint32_t ver; - CryptoPP::BERGeneralDecoder context (tbsCert, CryptoPP::CONTEXT_SPECIFIC | CryptoPP::CONSTRUCTED); - CryptoPP::BERDecodeUnsigned(context, ver, CryptoPP::INTEGER); - // serial - CryptoPP::Integer serial; - serial.BERDecode(tbsCert); - // signature - CryptoPP::BERSequenceDecoder signature (tbsCert); - signature.SkipAll(); - // issuer - CryptoPP::BERSequenceDecoder issuer (tbsCert); - issuer.SkipAll(); - // validity - CryptoPP::BERSequenceDecoder validity (tbsCert); - validity.SkipAll(); - // subject - CryptoPP::BERSequenceDecoder subject (tbsCert); - subject.SkipAll(); - // public key - CryptoPP::BERSequenceDecoder publicKey (tbsCert); - CryptoPP::BERSequenceDecoder ident (publicKey); - ident.SkipAll (); - CryptoPP::BERGeneralDecoder key (publicKey, CryptoPP::BIT_STRING); - key.Skip (1); // FIXME: probably bug in crypto++ - CryptoPP::BERSequenceDecoder keyPair (key); - CryptoPP::Integer n, e; - n.BERDecode (keyPair); - e.BERDecode (keyPair); - - CryptoPP::RSA::PublicKey ret; - ret.Initialize (n, e); - return ret; - } - - void TlsSession::Send (const uint8_t * buf, size_t len) - { - uint8_t * out = new uint8_t[len + 64 + 5]; // 64 = 32 mac + 16 iv + upto 16 padding, 5 = header - out[0] = 0x17; // application data - out[1] = 0x03; out[2] = 0x03; // version - uint8_t mac[32]; - m_Cipher->CalculateMAC (0x17, buf, len, mac); - size_t encryptedLen = m_Cipher->Encrypt (buf, len, mac, out + 5); - htobe16buf (out + 3, encryptedLen); - m_Site.write ((char *)out, encryptedLen + 5); - delete[] out; - } - - bool TlsSession::Receive (std::ostream& rs) - { - if (m_Site.eof ()) return false; - uint8_t type; uint16_t version, length; - m_Site.read ((char *)&type, 1); - m_Site.read ((char *)&version, 2); - m_Site.read ((char *)&length, 2); - length = be16toh (length); - uint8_t * buf = new uint8_t[length]; - m_Site.read ((char *)buf, length); - size_t decryptedLen = m_Cipher->Decrypt (buf, length); - rs.write ((char *)buf + m_Cipher->GetIVSize (), decryptedLen); - delete[] buf; - return true; - } + LogPrint (eLogError, "Couldn't resolve address ", u.host_, ": ", ecode.message ()); + return ""; + } } } diff --git a/Reseed.h b/Reseed.h index 3c92d066..aec8389c 100644 --- a/Reseed.h +++ b/Reseed.h @@ -5,11 +5,8 @@ #include #include #include -#include -#include -#include #include "Identity.h" -#include "aes.h" +#include "Crypto.h" namespace i2p { @@ -24,7 +21,6 @@ namespace data Reseeder(); ~Reseeder(); - bool reseedNow(); // depreacted int ReseedNowSU3 (); void LoadCertificates (); @@ -32,8 +28,7 @@ namespace data private: void LoadCertificate (const std::string& filename); - std::string LoadCertificate (CryptoPP::ByteQueue& queue); // returns issuer's name - + int ReseedFromSU3 (const std::string& host, bool https = false); int ProcessSU3File (const char * filename); int ProcessSU3Stream (std::istream& s); @@ -46,49 +41,6 @@ namespace data std::map m_SigningKeys; }; - - - class TlsCipher - { - public: - - virtual ~TlsCipher () {}; - - virtual void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) = 0; - virtual size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) = 0; - virtual size_t Decrypt (uint8_t * buf, size_t len) = 0; - virtual size_t GetIVSize () const { return 0; }; // override for AES - }; - - - class TlsSession - { - public: - - TlsSession (const std::string& host, int port); - ~TlsSession (); - void Send (const uint8_t * buf, size_t len); - bool Receive (std::ostream& rs); - bool IsEstablished () const { return m_IsEstablished; }; - - private: - - void Handshake (); - void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, size_t len); - void SendFinishedMsg (); - CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); - - void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, - size_t len, uint8_t * buf); - - private: - - bool m_IsEstablished; - boost::asio::ip::tcp::iostream m_Site; - CryptoPP::SHA256 m_FinishedHash; - uint8_t m_MasterSecret[64]; // actual size is 48, but must be multiple of 32 - TlsCipher * m_Cipher; - }; } } diff --git a/RouterContext.cpp b/RouterContext.cpp index c9328b5c..ca4b269a 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -1,14 +1,13 @@ #include -#include -#include #include -#include "CryptoConst.h" -#include "RouterContext.h" +#include "Crypto.h" #include "Timestamp.h" #include "I2NPProtocol.h" #include "NetDb.h" #include "util.h" #include "version.h" +#include "Log.h" +#include "RouterContext.h" namespace i2p { @@ -22,6 +21,7 @@ namespace i2p void RouterContext::Init () { + srand (i2p::util::GetMillisecondsSinceEpoch () % 1000); m_StartupTime = i2p::util::GetSecondsSinceEpoch (); if (!Load ()) CreateNewRouter (); @@ -41,7 +41,7 @@ namespace i2p routerInfo.SetRouterIdentity (GetIdentity ()); int port = i2p::util::config::GetArg("-port", 0); if (!port) - port = m_Rnd.GenerateWord32 (9111, 30777); // I2P network ports range + port = rand () % (30777 - 9111) + 9111; // I2P network ports range routerInfo.AddSSUAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port, routerInfo.GetIdentHash ()); routerInfo.AddNTCPAddress (i2p::util::config::GetCharArg("-host", "127.0.0.1"), port); routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | @@ -51,6 +51,7 @@ namespace i2p routerInfo.SetProperty ("router.version", I2P_VERSION); routerInfo.SetProperty ("stat_uptime", "90m"); routerInfo.CreateBuffer (m_Keys); + m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); } @@ -61,6 +62,25 @@ namespace i2p m_LastUpdateTime = i2p::util::GetSecondsSinceEpoch (); } + void RouterContext::SetStatus (RouterStatus status) + { + if (status != m_Status) + { + m_Status = status; + switch (m_Status) + { + case eRouterStatusOK: + SetReachable (); + break; + case eRouterStatusFirewalled: + SetUnreachable (); + break; + default: + ; + } + } + } + void RouterContext::UpdatePort (int port) { bool updated = false; @@ -92,16 +112,11 @@ namespace i2p UpdateRouterInfo (); } - bool RouterContext::AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag) + bool RouterContext::AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer) { - bool ret = false; - auto address = routerInfo.GetSSUAddress (); - if (address) - { - ret = m_RouterInfo.AddIntroducer (address, tag); - if (ret) - UpdateRouterInfo (); - } + bool ret = m_RouterInfo.AddIntroducer (introducer); + if (ret) + UpdateRouterInfo (); return ret; } @@ -188,7 +203,7 @@ namespace i2p { if (addresses[i].transportStyle == i2p::data::RouterInfo::eTransportSSU) { - // insert NTCP address with host/port form SSU + // insert NTCP address with host/port from SSU m_RouterInfo.AddNTCPAddress (addresses[i].host.to_string ().c_str (), addresses[i].port); break; } @@ -267,6 +282,7 @@ namespace i2p m_Keys = keys; i2p::data::RouterInfo routerInfo(i2p::util::filesystem::GetFullPath (ROUTER_INFO)); // TODO + m_RouterInfo.SetRouterIdentity (GetIdentity ()); m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION); m_RouterInfo.SetProperty ("router.version", I2P_VERSION); @@ -283,7 +299,7 @@ namespace i2p i2p::data::Keys keys; memcpy (keys.privateKey, m_Keys.GetPrivateKey (), sizeof (keys.privateKey)); memcpy (keys.signingPrivateKey, m_Keys.GetSigningPrivateKey (), sizeof (keys.signingPrivateKey)); - auto& ident = GetIdentity ().GetStandardIdentity (); + auto& ident = GetIdentity ()->GetStandardIdentity (); memcpy (keys.publicKey, ident.publicKey, sizeof (keys.publicKey)); memcpy (keys.signingKey, ident.signingKey, sizeof (keys.signingKey)); fk.write ((char *)&keys, sizeof (keys)); diff --git a/RouterContext.h b/RouterContext.h index 2689d025..541b78d1 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include "Identity.h" #include "RouterInfo.h" #include "Garlic.h" @@ -41,16 +39,15 @@ namespace i2p return std::shared_ptr (&m_RouterInfo, [](const i2p::data::RouterInfo *) {}); } - CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; }; uint32_t GetUptime () const; uint32_t GetStartupTime () const { return m_StartupTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; RouterStatus GetStatus () const { return m_Status; }; - void SetStatus (RouterStatus status) { m_Status = status; }; + void SetStatus (RouterStatus status); void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon - bool AddIntroducer (const i2p::data::RouterInfo& routerInfo, uint32_t tag); + bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); bool IsUnreachable () const; void SetUnreachable (); @@ -69,7 +66,7 @@ namespace i2p // implements LocalDestination const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const uint8_t * GetEncryptionPrivateKey () const { return m_Keys.GetPrivateKey (); }; - const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ().GetStandardIdentity ().publicKey; }; + const uint8_t * GetEncryptionPublicKey () const { return GetIdentity ()->GetStandardIdentity ().publicKey; }; void SetLeaseSetUpdated () {}; // implements GarlicDestination @@ -93,7 +90,6 @@ namespace i2p i2p::data::RouterInfo m_RouterInfo; i2p::data::PrivateKeys m_Keys; - CryptoPP::AutoSeededRandomPool m_Rnd; uint64_t m_LastUpdateTime; bool m_AcceptsTunnels, m_IsFloodfill; uint64_t m_StartupTime; // in seconds since epoch diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 403b711c..037297e0 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -3,15 +3,11 @@ #include "I2PEndian.h" #include #include -#include -#include -#include "CryptoConst.h" -#include "base64.h" +#include "Crypto.h" +#include "Base.h" #include "Timestamp.h" #include "Log.h" #include "RouterInfo.h" -#include "RouterContext.h" - namespace i2p { @@ -41,21 +37,38 @@ namespace data void RouterInfo::Update (const uint8_t * buf, int len) { - if (!m_Buffer) - m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; - m_IsUpdated = true; - m_IsUnreachable = false; - m_SupportedTransports = 0; - m_Caps = 0; - m_Addresses.clear (); - m_Properties.clear (); - memcpy (m_Buffer, buf, len); - m_BufferLen = len; - ReadFromBuffer (true); - // don't delete buffer until save to file + // verify signature since we have indentity already + int l = len - m_RouterIdentity->GetSignatureLen (); + if (m_RouterIdentity->Verify (buf, l, buf + l)) + { + // clean up + m_IsUpdated = true; + m_IsUnreachable = false; + m_SupportedTransports = 0; + m_Caps = 0; + m_Addresses.clear (); + m_Properties.clear (); + // copy buffer + if (!m_Buffer) + m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; + memcpy (m_Buffer, buf, len); + m_BufferLen = len; + // skip identity + size_t identityLen = m_RouterIdentity->GetFullLen (); + // read new RI + std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen)); + ReadFromStream (str); + // don't delete buffer until saved to the file + } + else + { + LogPrint (eLogError, "RouterInfo signature verification failed"); + m_IsUnreachable = true; + } + m_RouterIdentity->DropVerifier (); } - void RouterInfo::SetRouterIdentity (const IdentityEx& identity) + void RouterInfo::SetRouterIdentity (std::shared_ptr identity) { m_RouterIdentity = identity; m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); @@ -94,19 +107,20 @@ namespace data void RouterInfo::ReadFromBuffer (bool verifySignature) { - size_t identityLen = m_RouterIdentity.FromBuffer (m_Buffer, m_BufferLen); + m_RouterIdentity = std::make_shared(m_Buffer, m_BufferLen); + size_t identityLen = m_RouterIdentity->GetFullLen (); std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen)); ReadFromStream (str); if (verifySignature) { // verify signature - int l = m_BufferLen - m_RouterIdentity.GetSignatureLen (); - if (!m_RouterIdentity.Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l)) + int l = m_BufferLen - m_RouterIdentity->GetSignatureLen (); + if (!m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l)) { - LogPrint (eLogError, "signature verification failed"); + LogPrint (eLogError, "RouterInfo signature verification failed"); m_IsUnreachable = true; } - m_RouterIdentity.DropVerifier (); + m_RouterIdentity->DropVerifier (); } } @@ -419,7 +433,7 @@ namespace data if (!m_Buffer) { if (LoadFile ()) - LogPrint ("Buffer for ", GetIdentHashAbbreviation (), " loaded from file"); + LogPrint ("Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file"); } return m_Buffer; } @@ -429,7 +443,7 @@ namespace data m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); // refresh timstamp std::stringstream s; uint8_t ident[1024]; - auto identLen = privateKeys.GetPublic ().ToBuffer (ident, 1024); + auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024); s.write ((char *)ident, identLen); WriteToStream (s); m_BufferLen = s.str ().size (); @@ -438,7 +452,7 @@ namespace data memcpy (m_Buffer, s.str ().c_str (), m_BufferLen); // signature privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen); - m_BufferLen += privateKeys.GetPublic ().GetSignatureLen (); + m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen (); } void RouterInfo::SaveToFile (const std::string& fullPath) @@ -481,6 +495,8 @@ namespace data addr.cost = 2; addr.date = 0; addr.mtu = 0; + for (auto it: m_Addresses) // don't insert same address twice + if (it == addr) return; m_Addresses.push_back(addr); m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eNTCPV4; } @@ -495,26 +511,23 @@ namespace data addr.date = 0; addr.mtu = mtu; memcpy (addr.key, key, 32); + for (auto it: m_Addresses) // don't insert same address twice + if (it == addr) return; m_Addresses.push_back(addr); m_SupportedTransports |= addr.host.is_v6 () ? eNTCPV6 : eSSUV4; m_Caps |= eSSUTesting; m_Caps |= eSSUIntroducer; } - bool RouterInfo::AddIntroducer (const Address * address, uint32_t tag) + bool RouterInfo::AddIntroducer (const Introducer& introducer) { for (auto& addr : m_Addresses) { if (addr.transportStyle == eTransportSSU && addr.host.is_v4 ()) { for (auto intro: addr.introducers) - if (intro.iTag == tag) return false; // already presented - Introducer x; - x.iHost = address->host; - x.iPort = address->port; - x.iTag = tag; - memcpy (x.iKey, address->key, 32); // TODO: replace to Tag<32> - addr.introducers.push_back (x); + if (intro.iTag == introducer.iTag) return false; // already presented + addr.introducers.push_back (introducer); return true; } } diff --git a/RouterInfo.h b/RouterInfo.h index 376dfdc7..a7ab2102 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -58,11 +58,12 @@ namespace data eTransportSSU }; + typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey struct Introducer { boost::asio::ip::address iHost; int iPort; - Tag<32> iKey; + IntroKey iKey; uint32_t iTag; }; @@ -75,7 +76,7 @@ namespace data uint64_t date; uint8_t cost; // SSU only - Tag<32> key; // intro key for SSU + IntroKey key; // intro key for SSU std::vector introducers; bool IsCompatible (const boost::asio::ip::address& other) const @@ -83,6 +84,16 @@ namespace data return (host.is_v4 () && other.is_v4 ()) || (host.is_v6 () && other.is_v6 ()); } + + bool operator==(const Address& other) const + { + return transportStyle == other.transportStyle && host == other.host && port == other.port; + } + + bool operator!=(const Address& other) const + { + return !(*this == other); + } }; RouterInfo (const std::string& fullPath); @@ -92,10 +103,9 @@ namespace data RouterInfo (const uint8_t * buf, int len); ~RouterInfo (); - const IdentityEx& GetRouterIdentity () const { return m_RouterIdentity; }; - void SetRouterIdentity (const IdentityEx& identity); + std::shared_ptr GetRouterIdentity () const { return m_RouterIdentity; }; + void SetRouterIdentity (std::shared_ptr identity); std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; - std::string GetIdentHashAbbreviation () const { return GetIdentHash ().ToBase64 ().substr (0, 4); }; uint64_t GetTimestamp () const { return m_Timestamp; }; std::vector
& GetAddresses () { return m_Addresses; }; const Address * GetNTCPAddress (bool v4only = true) const; @@ -104,7 +114,7 @@ namespace data void AddNTCPAddress (const char * host, int port); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); - bool AddIntroducer (const Address * address, uint32_t tag); + bool AddIntroducer (const Introducer& introducer); bool RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void SetProperty (const std::string& key, const std::string& value); // called from RouterContext only void DeleteProperty (const std::string& key); // called from RouterContext only @@ -145,8 +155,8 @@ namespace data void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; // implements RoutingDestination - const IdentHash& GetIdentHash () const { return m_RouterIdentity.GetIdentHash (); }; - const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity.GetStandardIdentity ().publicKey; }; + const IdentHash& GetIdentHash () const { return m_RouterIdentity->GetIdentHash (); }; + const uint8_t * GetEncryptionPublicKey () const { return m_RouterIdentity->GetStandardIdentity ().publicKey; }; bool IsDestination () const { return false; }; @@ -166,7 +176,7 @@ namespace data private: std::string m_FullPath; - IdentityEx m_RouterIdentity; + std::shared_ptr m_RouterIdentity; uint8_t * m_Buffer; int m_BufferLen; uint64_t m_Timestamp; diff --git a/SAM.cpp b/SAM.cpp index 7db1e1bb..dc592f51 100644 --- a/SAM.cpp +++ b/SAM.cpp @@ -4,7 +4,7 @@ #include #endif #include -#include "base64.h" +#include "Base.h" #include "Identity.h" #include "Log.h" #include "Destination.h" @@ -189,6 +189,8 @@ namespace client if (ecode != boost::asio::error::operation_aborted) Terminate (); } + else if (m_SocketType == eSAMSocketTypeStream) + HandleReceived (ecode, bytes_transferred); else { bytes_transferred += m_BufferOffset; @@ -342,17 +344,17 @@ namespace client m_Session = m_Owner.FindSession (id); if (m_Session) { - i2p::data::IdentityEx dest; - size_t len = dest.FromBase64(destination); + auto dest = std::make_shared (); + size_t len = dest->FromBase64(destination); if (len > 0) { context.GetAddressBook().InsertAddress(dest); - auto leaseSet = m_Session->localDestination->FindLeaseSet(dest.GetIdentHash()); + auto leaseSet = m_Session->localDestination->FindLeaseSet(dest->GetIdentHash()); if (leaseSet) Connect(leaseSet); else { - m_Session->localDestination->RequestDestination(dest.GetIdentHash(), + m_Session->localDestination->RequestDestination(dest->GetIdentHash(), std::bind(&SAMSocket::HandleConnectLeaseSetRequestComplete, shared_from_this(), std::placeholders::_1)); } @@ -451,7 +453,7 @@ namespace client keys.GetPublic ().ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #else size_t len = snprintf (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_DEST_REPLY, - keys.GetPublic ().ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); + keys.GetPublic ()->ToBase64 ().c_str (), keys.ToBase64 ().c_str ()); #endif SendMessageReply (m_Buffer, len, false); } @@ -462,11 +464,11 @@ namespace client std::map params; ExtractParams (buf, params); std::string& name = params[SAM_PARAM_NAME]; - i2p::data::IdentityEx identity; + std::shared_ptr identity; i2p::data::IdentHash ident; if (name == "ME") SendNamingLookupReply (m_Session->localDestination->GetIdentity ()); - else if (context.GetAddressBook ().GetAddress (name, identity)) + else if ((identity = context.GetAddressBook ().GetAddress (name)) != nullptr) SendNamingLookupReply (identity); else if (m_Session && m_Session->localDestination && context.GetAddressBook ().GetIdentHash (name, ident)) @@ -512,9 +514,9 @@ namespace client } } - void SAMSocket::SendNamingLookupReply (const i2p::data::IdentityEx& identity) + void SAMSocket::SendNamingLookupReply (std::shared_ptr identity) { - auto base64 = identity.ToBase64 (); + auto base64 = identity->ToBase64 (); #ifdef _MSC_VER size_t l = sprintf_s (m_Buffer, SAM_SOCKET_BUFFER_SIZE, SAM_NAMING_REPLY, base64.c_str ()); #else @@ -631,7 +633,7 @@ namespace client { // send remote peer address uint8_t ident[1024]; - size_t l = stream->GetRemoteIdentity ().ToBuffer (ident, 1024); + size_t l = stream->GetRemoteIdentity ()->ToBuffer (ident, 1024); size_t l1 = i2p::data::ByteStreamToBase64 (ident, l, (char *)m_StreamBuffer, SAM_SOCKET_BUFFER_SIZE); m_StreamBuffer[l1] = '\n'; HandleI2PReceive (boost::system::error_code (), l1 +1); // we send identity like it has been received from stream diff --git a/SAM.h b/SAM.h index 7684d461..c5017b83 100644 --- a/SAM.h +++ b/SAM.h @@ -111,7 +111,7 @@ namespace client void Connect (std::shared_ptr remote); void HandleConnectLeaseSetRequestComplete (std::shared_ptr leaseSet); - void SendNamingLookupReply (const i2p::data::IdentityEx& identity); + void SendNamingLookupReply (std::shared_ptr identity); void HandleNamingLookupLeaseSetRequestComplete (std::shared_ptr leaseSet, i2p::data::IdentHash ident); void HandleSessionReadinessCheckTimer (const boost::system::error_code& ecode); void SendSessionCreateReplyOk (); diff --git a/SSU.cpp b/SSU.cpp index 9c12441a..d4b2b05d 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -283,7 +283,11 @@ namespace transport boost::asio::ip::udp::endpoint remoteEndpoint (address->host, address->port); auto it = m_Sessions.find (remoteEndpoint); if (it != m_Sessions.end ()) + { session = it->second; + if (peerTest && session->GetState () == eSessionStateEstablished) + session->SendPeerTest (); + } else { // otherwise create new session @@ -295,7 +299,7 @@ namespace transport if (!router->UsesIntroducer ()) { // connect directly - LogPrint ("Creating new SSU session to [", router->GetIdentHashAbbreviation (), "] ", + LogPrint ("Creating new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ", remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ()); session->Connect (); } @@ -331,7 +335,7 @@ namespace transport m_Sessions[introducerEndpoint] = introducerSession; } // introduce - LogPrint ("Introduce new SSU session to [", router->GetIdentHashAbbreviation (), + LogPrint ("Introduce new SSU session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] through introducer ", introducer->iHost, ":", introducer->iPort); session->WaitForIntroduction (); if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable @@ -339,7 +343,7 @@ namespace transport uint8_t buf[1]; Send (buf, 0, remoteEndpoint); // send HolePunch } - introducerSession->Introduce (introducer->iTag, introducer->iKey); + introducerSession->Introduce (*introducer); } else { @@ -352,7 +356,7 @@ namespace transport } } else - LogPrint (eLogWarning, "Router ", router->GetIdentHashAbbreviation (), " doesn't have SSU address"); + LogPrint (eLogWarning, "Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address"); } return session; } @@ -383,7 +387,7 @@ namespace transport if (filter (s.second)) filteredSessions.push_back (s.second); if (filteredSessions.size () > 0) { - auto ind = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, filteredSessions.size ()-1); + auto ind = rand () % filteredSessions.size (); return filteredSessions[ind]; } return nullptr; @@ -468,10 +472,15 @@ namespace transport { for (auto it1: introducers) { - auto router = it1->GetRemoteRouter (); - if (router && i2p::context.AddIntroducer (*router, it1->GetRelayTag ())) + auto& ep = it1->GetRemoteEndpoint (); + i2p::data::RouterInfo::Introducer introducer; + introducer.iHost = ep.address (); + introducer.iPort = ep.port (); + introducer.iTag = it1->GetRelayTag (); + introducer.iKey = it1->GetIntroKey (); + if (i2p::context.AddIntroducer (introducer)) { - newList.push_back (it1->GetRemoteEndpoint ()); + newList.push_back (ep); if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break; } } diff --git a/SSU.h b/SSU.h index 1033a2bf..db9d57eb 100644 --- a/SSU.h +++ b/SSU.h @@ -9,7 +9,7 @@ #include #include #include -#include "aes.h" +#include "Crypto.h" #include "I2PEndian.h" #include "Identity.h" #include "RouterInfo.h" diff --git a/SSUData.cpp b/SSUData.cpp index 5c0c03dd..77c2470f 100644 --- a/SSUData.cpp +++ b/SSUData.cpp @@ -26,13 +26,10 @@ namespace transport SSUData::SSUData (SSUSession& session): m_Session (session), m_ResendTimer (session.GetService ()), m_DecayTimer (session.GetService ()), - m_IncompleteMessagesCleanupTimer (session.GetService ()) + m_IncompleteMessagesCleanupTimer (session.GetService ()), + m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE), + m_PacketSize (m_MaxPacketSize) { - m_MaxPacketSize = session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE; - m_PacketSize = m_MaxPacketSize; - auto remoteRouter = session.GetRemoteRouter (); - if (remoteRouter) - AdjustPacketSize (*remoteRouter); } SSUData::~SSUData () @@ -51,9 +48,10 @@ namespace transport m_IncompleteMessagesCleanupTimer.cancel (); } - void SSUData::AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter) + void SSUData::AdjustPacketSize (std::shared_ptr remoteRouter) { - auto ssuAddress = remoteRouter.GetSSUAddress (); + if (remoteRouter) return; + auto ssuAddress = remoteRouter->GetSSUAddress (); if (ssuAddress && ssuAddress->mtu) { if (m_Session.IsV6 ()) @@ -80,7 +78,7 @@ namespace transport { auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent); if (routerInfo) - AdjustPacketSize (*routerInfo); + AdjustPacketSize (routerInfo); } void SSUData::ProcessSentMessageAck (uint32_t msgID) @@ -372,7 +370,7 @@ namespace transport payload++; *payload = 1; // number of ACKs payload++; - *(uint32_t *)(payload) = htobe32 (msgID); // msgID + htobe32buf (payload, msgID); // msgID payload += 4; *payload = 0; // number of fragments diff --git a/SSUData.h b/SSUData.h index 60d5057e..d571bed3 100644 --- a/SSUData.h +++ b/SSUData.h @@ -80,7 +80,7 @@ namespace transport { public: - SSUData (SSUSession& session); + SSUData (SSUSession& session); ~SSUData (); void Start (); @@ -90,6 +90,7 @@ namespace transport void FlushReceivedMessage (); void Send (std::shared_ptr msg); + void AdjustPacketSize (std::shared_ptr remoteRouter); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); private: @@ -109,7 +110,6 @@ namespace transport void ScheduleIncompleteMessagesCleanup (); void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode); - void AdjustPacketSize (const i2p::data::RouterInfo& remoteRouter); private: diff --git a/SSUSession.cpp b/SSUSession.cpp index 3900e7de..be020729 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -1,7 +1,7 @@ #include -#include -#include -#include "CryptoConst.h" +#include +#include +#include #include "Log.h" #include "Timestamp.h" #include "RouterContext.h" @@ -16,9 +16,22 @@ namespace transport SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, std::shared_ptr router, bool peerTest ): TransportSession (router), m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_Timer (GetService ()), - m_PeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false), + m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false), m_RelayTag (0),m_Data (*this), m_IsDataReceived (false) - { + { + if (router) + { + // we are client + auto address = router->GetSSUAddress (); + if (address) m_IntroKey = address->key; + m_Data.AdjustPacketSize (router); // mtu + } + else + { + // we are server + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (address) m_IntroKey = address->key; + } m_CreationTime = i2p::util::GetSecondsSinceEpoch (); } @@ -33,13 +46,8 @@ namespace transport void SSUSession::CreateAESandMacKey (const uint8_t * pubKey) { - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); uint8_t sharedKey[256]; - if (!dh.Agree (sharedKey, m_DHKeysPair->privateKey, pubKey)) - { - LogPrint (eLogError, "Couldn't create shared key"); - return; - }; + m_DHKeysPair->Agree (pubKey, sharedKey); uint8_t * sessionKey = m_SessionKey, * macKey = m_MacKey; if (sharedKey[0] & 0x80) @@ -68,7 +76,7 @@ namespace transport } memcpy (sessionKey, nonZero, 32); - CryptoPP::SHA256().CalculateDigest(macKey, nonZero, 64 - (nonZero - sharedKey)); + SHA256(nonZero, 64 - (nonZero - sharedKey), macKey); } m_IsSessionKey = true; m_SessionKeyEncryption.SetKey (m_SessionKey); @@ -97,9 +105,8 @@ namespace transport else { // try intro key depending on side - auto introKey = GetIntroKey (); - if (introKey && Validate (buf, len, introKey)) - Decrypt (buf, len, introKey); + if (Validate (buf, len, m_IntroKey)) + Decrypt (buf, len, m_IntroKey); else { // try own intro key @@ -184,7 +191,7 @@ namespace transport void SSUSession::ProcessSessionCreated (uint8_t * buf, size_t len) { - if (!m_RemoteRouter || !m_DHKeysPair) + if (!IsOutgoing () || !m_DHKeysPair) { LogPrint (eLogWarning, "Unsolicited session created message"); return; @@ -196,7 +203,7 @@ namespace transport uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * y = payload; CreateAESandMacKey (y); - s.Insert (m_DHKeysPair->publicKey, 256); // x + s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x s.Insert (y, 256); // y payload += 256; uint8_t addressSize = *payload; @@ -232,7 +239,7 @@ namespace transport payload += 4; // relayTag payload += 4; // signed on time // decrypt signature - size_t signatureLen = m_RemoteIdentity.GetSignatureLen (); + size_t signatureLen = m_RemoteIdentity->GetSignatureLen (); size_t paddingSize = signatureLen & 0x0F; // %16 if (paddingSize > 0) signatureLen += (16 - paddingSize); //TODO: since we are accessing a uint8_t this is unlikely to crash due to alignment but should be improved @@ -240,8 +247,7 @@ namespace transport m_SessionKeyDecryption.Decrypt (payload, signatureLen, payload); // verify if (!s.Verify (m_RemoteIdentity, payload)) - LogPrint (eLogError, "SSU signature verification failed"); - m_RemoteIdentity.DropVerifier (); + LogPrint (eLogError, "Session created SSU signature verification failed"); SendSessionConfirmed (y, ourAddress, addressSize + 2); } @@ -253,31 +259,28 @@ namespace transport payload++; // identity fragment info uint16_t identitySize = bufbe16toh (payload); payload += 2; // size of identity fragment - m_RemoteIdentity.FromBuffer (payload, identitySize); - m_Data.UpdatePacketSize (m_RemoteIdentity.GetIdentHash ()); + SetRemoteIdentity (std::make_shared (payload, identitySize)); + m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ()); payload += identitySize; // identity + if (m_SignedData) + m_SignedData->Insert (payload, 4); // insert Alice's signed on time payload += 4; // signed-on time - size_t paddingSize = (payload - buf) + m_RemoteIdentity.GetSignatureLen (); + size_t paddingSize = (payload - buf) + m_RemoteIdentity->GetSignatureLen (); paddingSize &= 0x0F; // %16 if (paddingSize > 0) paddingSize = 16 - paddingSize; payload += paddingSize; - // TODO: verify signature (need data from session request), payload points to signature + // verify + if (m_SignedData && !m_SignedData->Verify (m_RemoteIdentity, payload)) + LogPrint (eLogError, "Session confirmed SSU signature verification failed"); m_Data.Send (CreateDeliveryStatusMsg (0)); Established (); } void SSUSession::SendSessionRequest () - { - auto introKey = GetIntroKey (); - if (!introKey) - { - LogPrint (eLogError, "SSU is not supported"); - return; - } - + { uint8_t buf[320 + 18]; // 304 bytes for ipv4, 320 for ipv6 uint8_t * payload = buf + sizeof (SSUHeader); - memcpy (payload, m_DHKeysPair->publicKey, 256); // x + memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x bool isV4 = m_RemoteEndpoint.address ().is_v4 (); if (isV4) { @@ -291,13 +294,12 @@ namespace transport } uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, isV4 ? 304 : 320, introKey, iv, introKey); + RAND_bytes (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, isV4 ? 304 : 320, m_IntroKey, iv, m_IntroKey); m_Server.Send (buf, isV4 ? 304 : 320, m_RemoteEndpoint); } - void SSUSession::SendRelayRequest (uint32_t iTag, const uint8_t * iKey) + void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer) { auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); if (!address) @@ -308,7 +310,7 @@ namespace transport uint8_t buf[96 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); - htobe32buf (payload, iTag); + htobe32buf (payload, introducer.iTag); payload += 4; *payload = 0; // no address payload++; @@ -318,35 +320,32 @@ namespace transport payload++; memcpy (payload, (const uint8_t *)address->key, 32); payload += 32; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - htobe32buf (payload, rnd.GenerateWord32 ()); // nonce + RAND_bytes (payload, 4); // nonce uint8_t iv[16]; - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv if (m_State == eSessionStateEstablished) FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey); else - FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, iKey, iv, iKey); + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); m_Server.Send (buf, 96, m_RemoteEndpoint); } void SSUSession::SendSessionCreated (const uint8_t * x) { - auto introKey = GetIntroKey (); auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : i2p::context.GetRouterInfo ().GetSSUAddress (true); //v4 only - if (!introKey || !address) + if (!address) { LogPrint (eLogError, "SSU is not supported"); return; } - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time s.Insert (x, 256); // x uint8_t buf[384 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); - memcpy (payload, m_DHKeysPair->publicKey, 256); + memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); s.Insert (payload, 256); // y payload += 256; if (m_RemoteEndpoint.address ().is_v4 ()) @@ -378,7 +377,7 @@ namespace transport uint32_t relayTag = 0; if (i2p::context.GetRouterInfo ().IsIntroducer ()) { - relayTag = rnd.GenerateWord32 (); + RAND_bytes((uint8_t *)&relayTag, 4); if (!relayTag) relayTag = 1; m_Server.AddRelay (relayTag, m_RemoteEndpoint); } @@ -386,14 +385,18 @@ namespace transport payload += 4; // relay tag htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time payload += 4; - s.Insert (payload - 8, 8); // relayTag and signed on time + s.Insert (payload - 8, 4); // relayTag + // we have to store this signed data for session confirmed + // same data but signed on time, it will Alice's there + m_SignedData = std::unique_ptr(new SignedData (s)); + s.Insert (payload - 4, 4); // BOB's signed on time s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature // TODO: fill padding with random data uint8_t iv[16]; - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv // encrypt signature and padding with newly created session key - size_t signatureLen = i2p::context.GetIdentity ().GetSignatureLen (); + size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); size_t paddingSize = signatureLen & 0x0F; // %16 if (paddingSize > 0) signatureLen += (16 - paddingSize); m_SessionKeyEncryption.SetIV (iv); @@ -402,7 +405,7 @@ namespace transport size_t msgLen = payload - buf; // encrypt message with intro key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, introKey, iv, introKey); + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey); Send (buf, msgLen); } @@ -412,15 +415,15 @@ namespace transport uint8_t * payload = buf + sizeof (SSUHeader); *payload = 1; // 1 fragment payload++; // info - size_t identLen = i2p::context.GetIdentity ().GetFullLen (); // 387+ bytes + size_t identLen = i2p::context.GetIdentity ()->GetFullLen (); // 387+ bytes htobe16buf (payload, identLen); payload += 2; // cursize - i2p::context.GetIdentity ().ToBuffer (payload, identLen); + i2p::context.GetIdentity ()->ToBuffer (payload, identLen); payload += identLen; uint32_t signedOnTime = i2p::util::GetSecondsSinceEpoch (); htobe32buf (payload, signedOnTime); // signed on time payload += 4; - auto signatureLen = i2p::context.GetIdentity ().GetSignatureLen (); + auto signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); size_t paddingSize = ((payload - buf) + signatureLen)%16; if (paddingSize > 0) paddingSize = 16 - paddingSize; // TODO: fill padding @@ -428,7 +431,7 @@ namespace transport // signature SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time - s.Insert (m_DHKeysPair->publicKey, 256); // x + s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x s.Insert (y, 256); // y s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party if (m_RemoteEndpoint.address ().is_v4 ()) @@ -443,8 +446,7 @@ namespace transport size_t msgLen = payload - buf; uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv // encrypt message with session key FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, msgLen, m_SessionKey, iv, m_MacKey); Send (buf, msgLen); @@ -519,8 +521,7 @@ namespace transport { // ecrypt with Alice's intro key uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey); m_Server.Send (buf, isV4 ? 64 : 80, from); } @@ -546,8 +547,7 @@ namespace transport payload += 2; // port *payload = 0; // challenge size uint8_t iv[16]; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey); m_Server.Send (buf, 48, session->m_RemoteEndpoint); LogPrint (eLogDebug, "SSU relay intro sent"); @@ -602,7 +602,7 @@ namespace transport } void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, - const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) + const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey) { if (len < sizeof (SSUHeader)) { @@ -635,7 +635,7 @@ namespace transport } //TODO: we are using a dirty solution here but should work for now SSUHeader * header = (SSUHeader *)buf; - i2p::context.GetRandomNumberGenerator ().GenerateBlock (header->iv, 16); // random iv + RAND_bytes (header->iv, 16); // random iv m_SessionKeyEncryption.SetIV (header->iv); header->flag = payloadType << 4; // MSB is 0 htobe32buf (&(header->time), i2p::util::GetSecondsSinceEpoch ()); @@ -648,7 +648,7 @@ namespace transport i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac); } - void SSUSession::Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey) + void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey) { if (len < sizeof (SSUHeader)) { @@ -683,7 +683,7 @@ namespace transport } } - bool SSUSession::Validate (uint8_t * buf, size_t len, const uint8_t * macKey) + bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey) { if (len < sizeof (SSUHeader)) { @@ -715,7 +715,7 @@ namespace transport void SSUSession::WaitForConnect () { - if (!m_RemoteRouter) // incoming session + if (!IsOutgoing ()) // incoming session ScheduleConnectTimer (); else LogPrint (eLogError, "SSU wait for connect for outgoing session"); @@ -739,7 +739,7 @@ namespace transport } } - void SSUSession::Introduce (uint32_t iTag, const uint8_t * iKey) + void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer) { if (m_State == eSessionStateUnknown) { @@ -748,7 +748,7 @@ namespace transport m_Timer.async_wait (std::bind (&SSUSession::HandleConnectTimer, shared_from_this (), std::placeholders::_1)); } - SendRelayRequest (iTag, iKey); + SendRelayRequest (introducer); } void SSUSession::WaitForIntroduction () @@ -777,15 +777,12 @@ namespace transport void SSUSession::Established () { m_State = eSessionStateEstablished; - if (m_DHKeysPair) - { - delete m_DHKeysPair; - m_DHKeysPair = nullptr; - } + m_DHKeysPair = nullptr; + m_SignedData = nullptr; m_Data.Start (); - m_Data.Send (ToSharedI2NPMessage(CreateDatabaseStoreMsg ())); + m_Data.Send (CreateDatabaseStoreMsg ()); transports.PeerConnected (shared_from_this ()); - if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ())) + if (m_IsPeerTest) SendPeerTest (); ScheduleTermination (); } @@ -816,21 +813,6 @@ namespace transport } } - const uint8_t * SSUSession::GetIntroKey () const - { - if (m_RemoteRouter) - { - // we are client - auto address = m_RemoteRouter->GetSSUAddress (); - return address ? (const uint8_t *)address->key : nullptr; - } - else - { - // we are server - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); - return address ? (const uint8_t *)address->key : nullptr; - } - } void SSUSession::SendI2NPMessages (const std::vector >& msgs) { @@ -994,8 +976,7 @@ namespace transport memcpy (payload, introKey, 32); // intro key // send - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (iv, 16); // random iv + RAND_bytes (iv, 16); // random iv if (toAddress) { // encrypt message with specified intro key @@ -1021,9 +1002,10 @@ namespace transport LogPrint (eLogError, "SSU is not supported. Can't send peer test"); return; } - uint32_t nonce = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); + uint32_t nonce; + RAND_bytes ((uint8_t *)&nonce, 4); if (!nonce) nonce = 1; - m_PeerTest = false; + m_IsPeerTest = false; m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1); SendPeerTest (nonce, 0, 0, address->key, false, false); // address and port always zero for Alice } diff --git a/SSUSession.h b/SSUSession.h index 6c222185..99be99a8 100644 --- a/SSUSession.h +++ b/SSUSession.h @@ -4,8 +4,7 @@ #include #include #include -#include "aes.h" -#include "hmac.h" +#include "Crypto.h" #include "I2NPProtocol.h" #include "TransportSession.h" #include "SSUData.h" @@ -70,7 +69,7 @@ namespace transport void Connect (); void WaitForConnect (); - void Introduce (uint32_t iTag, const uint8_t * iKey); + void Introduce (const i2p::data::RouterInfo::Introducer& introducer); void WaitForIntroduction (); void Close (); void Done (); @@ -85,6 +84,7 @@ namespace transport void SendKeepAlive (); uint32_t GetRelayTag () const { return m_RelayTag; }; + const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; }; uint32_t GetCreationTime () const { return m_CreationTime; }; void FlushData (); @@ -98,7 +98,7 @@ namespace transport void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); - void SendRelayRequest (uint32_t iTag, const uint8_t * iKey); + void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); @@ -120,12 +120,11 @@ namespace transport 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 uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey); + 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); void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key - void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey); + 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 uint8_t * macKey); - const uint8_t * GetIntroKey () const; + bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey); void ScheduleTermination (); void HandleTerminationTimer (const boost::system::error_code& ecode); @@ -136,7 +135,7 @@ namespace transport SSUServer& m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; boost::asio::deadline_timer m_Timer; - bool m_PeerTest; + bool m_IsPeerTest; SessionState m_State; bool m_IsSessionKey; uint32_t m_RelayTag; @@ -144,9 +143,11 @@ namespace transport i2p::crypto::CBCDecryption m_SessionKeyDecryption; i2p::crypto::AESKey m_SessionKey; i2p::crypto::MACKey m_MacKey; + i2p::data::RouterInfo::IntroKey m_IntroKey; uint32_t m_CreationTime; // seconds since epoch SSUData m_Data; bool m_IsDataReceived; + std::unique_ptr m_SignedData; // we need it for SessionConfirmed only }; diff --git a/Signature.cpp b/Signature.cpp index 603ba6eb..40947aa6 100644 --- a/Signature.cpp +++ b/Signature.cpp @@ -1,6 +1,4 @@ #include -#include -#include #include "Log.h" #include "Signature.h" @@ -14,82 +12,360 @@ namespace crypto Ed25519 () { - q = CryptoPP::Integer::Power2 (255) - CryptoPP::Integer (19); // 2^255-19 - l = CryptoPP::Integer::Power2 (252) + CryptoPP::Integer ("27742317777372353535851937790883648493"); + BN_CTX * ctx = BN_CTX_new (); + BIGNUM * two = BN_new (), * tmp = BN_new (); + BN_set_word (two, 2); + + q = BN_new (); + // 2^255-19 + BN_set_word (tmp, 255); + BN_exp (q, two, tmp, ctx); + BN_sub_word (q, 19); + // q_2 = q-2 + q_2 = BN_dup (q); + BN_sub_word (q_2, 2); + + l = BN_new (); // 2^252 + 27742317777372353535851937790883648493 - d = CryptoPP::Integer (-121665) * CryptoPP::Integer (121666).InverseMod (q); // -121665/121666 - I = a_exp_b_mod_c (CryptoPP::Integer::Two (), (q - CryptoPP::Integer::One ()).DividedBy (4), q); - B = DecodePoint (CryptoPP::Integer (4)*CryptoPP::Integer (5).InverseMod (q)); + BN_set_word (tmp, 252); + BN_exp (l, two, tmp, ctx); + 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); + Inv (tmp, ctx); + BN_set_word (d, 121665); + BN_set_negative (d, -1); + BN_mul (d, d, tmp, 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_mod_exp (I, two, tmp, q, ctx); + + // 4*inv(5) + BIGNUM * By = BN_new (); + BN_set_word (By, 5); + Inv (By, 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 + B = {Bx, By}; + + BN_free (two); + BN_free (tmp); + + // precalculate Bi + Bi[0] = { BN_dup (Bx), BN_dup (By) }; + for (int i = 1; i < 256; i++) + Bi[i] = Double (Bi[i-1], ctx); + + BN_CTX_free (ctx); } - CryptoPP::ECP::Point DecodePublicKey (const uint8_t * key) const + ~Ed25519 () { - return DecodePoint (CryptoPP::Integer (key, 32)); + BN_free (q); + BN_free (l); + BN_free (d); + BN_free (I); + BN_free (q_2); + BN_free (two_252_2); } - CryptoPP::ECP::Point GeneratePublicKey (const uint8_t * privateKey) const + + EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const { - return Mul (B, CryptoPP::Integer (privateKey, 32)); + return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian } - private: + EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const + { + return DecodePoint (buf, ctx); + } + + void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf) const + { + EncodePoint (publicKey, buf); + } - CryptoPP::ECP::Point Sum (const CryptoPP::ECP::Point& p1, const CryptoPP::ECP::Point& p2) const + bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature, BN_CTX * ctx) const { - CryptoPP::Integer m = d*p1.x*p2.x*p1.y*p2.y, - x = a_times_b_mod_c (p1.x*p2.y + p2.x*p1.y, (CryptoPP::Integer::One() + m).InverseMod (q), q), - y = a_times_b_mod_c (p1.y*p2.y + p1.x*p2.x, (CryptoPP::Integer::One() - m).InverseMod (q), q); - return CryptoPP::ECP::Point {x, y}; + BIGNUM * h = DecodeBN (digest, 64); + // signature 0..31 - R, 32..63 - S + bool passed = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx) /*S*/ == + Sum (DecodePoint (signature, ctx) /*R*/, Mul (publicKey, h, ctx), ctx); + BN_free (h); + if (!passed) + LogPrint (eLogError, "25519 signature verification failed"); + return passed; } - CryptoPP::ECP::Point Mul (const CryptoPP::ECP::Point& p, const CryptoPP::Integer& e) const + void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, + uint8_t * signature, BN_CTX * bnCtx) const { - CryptoPP::ECP::Point res {0, 1}; - if (!e.IsZero ()) + // 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 + uint8_t digest[64]; + SHA512_Final (digest, &ctx); + BIGNUM * r = DecodeBN (digest, 32); // DecodeBN (digest, 64); // for test vectors + // calculate R + uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf + EncodePoint (MulB (digest, 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 * s = DecodeBN (digest, 64); + // S = (r + s*a) % l + BIGNUM * a = DecodeBN (expandedPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); // left half of expanded key + BN_mul (s, s, a, bnCtx); + BN_add (s, s, r); + BN_mod (s, s, l, bnCtx); // % l + memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2); + EncodeBN (s, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S + BN_free (r); BN_free (s); BN_free (a); + } + + private: + + EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const + { + BIGNUM * xx = BN_new (), * yy = BN_new (); + // m = d*p1.x*p2.x*p1.y*p2.y + BN_mul (xx, p1.x, p2.x, ctx); + BN_mul (yy, p1.y, p2.y, ctx); + BIGNUM * m = BN_dup (d); + BN_mul (m, m, xx, ctx); + BN_mul (m, m, yy, ctx); + // x = (p1.x*p2.y + p2.x*p1.y)*inv(1 + m) + // y = (p1.y*p2.y + p1.x*p2.x)*inv(1 - m) + + // use one inversion instead two + // m1 = 1-m + BIGNUM * m1 = BN_new (); + BN_one (m1); + BN_sub (m1, m1, m); + // m = m+1 + BN_add_word (m, 1); + // y = (p1.y*p2.y + p1.x*p2.x)*m + BIGNUM * y = BN_new (); + BN_add (y, xx, yy); + BN_mod_mul (y, y, m, q, ctx); + // x = (p1.x*p2.y + p2.x*p1.y)*m1 + BIGNUM * x = BN_new (); + BN_mul (yy, p1.x, p2.y, ctx); + BN_mul (xx, p2.x, p1.y, ctx); + BN_add (x, xx, yy); + BN_mod_mul (x, x, m1, q, ctx); + // denominator m = m*m1 + BN_mod_mul (m, m, m1, q, ctx); + Inv (m, ctx); + BN_mod_mul (x, x, m, q, ctx); // x = x/m + BN_mod_mul (y, y, m, q, ctx); // y = y/m + + BN_free (xx);BN_free (yy); BN_free (m); BN_free (m1); + return EDDSAPoint {x, y}; + } + + EDDSAPoint Double (const EDDSAPoint& p, BN_CTX * ctx) const + { + BIGNUM * pxy = BN_new (); + BN_mul (pxy, p.x, p.y, ctx); + // m = d*(p.x*p.y)^2 + BIGNUM * m = BN_new (); + BN_sqr (m, pxy, ctx); + BN_mul (m, m, d, ctx); + // x = (2*p.x*p.y)*inv(1 + m) + // y = (p.x^2 + p.y^2)*inv(1 - m) + + // use one inversion instead two + // m1 = 1-m + BIGNUM * m1 = BN_new (); + BN_one (m1); + BN_sub (m1, m1, m); + // m = m+1 + BN_add_word (m, 1); + // x = 2*p.x*p.y*m1 + BN_mul_word (pxy, 2); + BIGNUM * x = BN_new (); + BN_mod_mul (x, pxy, m1, q, ctx); + // y = (p.x^2 + p.y^2)*m + BIGNUM * y = BN_new (); + BN_sqr (pxy, p.x, ctx); + BN_sqr (y, p.y, ctx); + BN_add (pxy, pxy, y); + BN_mod_mul (y, pxy, m, q, ctx); + // denominator m = m*m1 + BN_mod_mul (m, m, m1, q, ctx); + Inv (m, ctx); + BN_mod_mul (x, x, m, q, ctx); // x = x/m + BN_mod_mul (y, y, m, q, ctx); // y = y/m + + BN_free (pxy); BN_free (m); BN_free (m1); + return EDDSAPoint {x, y}; + } + + EDDSAPoint 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)) { - auto bitCount = e.BitCount (); + int bitCount = BN_num_bits (e); for (int i = bitCount - 1; i >= 0; i--) { - res = Sum (res, res); - if (e.GetBit (i)) res = Sum (res, p); + res = Double (res, ctx); + if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); } } return res; } + + EDDSAPoint 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}; + for (int i = 0; i < 32; i++) + { + for (int j = 0; j < 8; j++) + if (e[i] & (1 << j)) // from lowest to highest bit + res = Sum (res, Bi[i*8 + j], ctx); + } + return res; + } + + void Inv (BIGNUM * x, BN_CTX * ctx) const + { + BN_mod_exp (x, x, q_2, q, ctx); + } - bool IsOnCurve (const CryptoPP::ECP::Point& p) const + bool IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const { - auto x2 = p.x.Squared(), y2 = p.y.Squared (); - return (y2 - x2 - CryptoPP::Integer::One() - d*x2*y2).Modulo (q).IsZero (); + BIGNUM * x2 = BN_new (); + BN_sqr (x2, p.x, ctx); // x^2 + BIGNUM * y2 = BN_new (); + BN_sqr (y2, p.y, ctx); // y^2 + // y^2 - x^2 - 1 - d*x^2*y^2 + BIGNUM * tmp = BN_new (); + 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_free (x2); + BN_free (y2); + BN_free (tmp); + return ret; } - CryptoPP::Integer RecoverX (const CryptoPP::Integer& y) const + BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const { - auto y2 = y.Squared (); - auto xx = (y2 - CryptoPP::Integer::One())*(d*y2 + CryptoPP::Integer::One()).InverseMod (q); - auto x = a_exp_b_mod_c (xx, (q + CryptoPP::Integer (3)).DividedBy (8), q); - if (!(x.Squared () - xx).Modulo (q).IsZero ()) - x = a_times_b_mod_c (x, I, q); - if (x.IsOdd ()) x = q - x; + BIGNUM * y2 = BN_new (); + BN_sqr (y2, y, ctx); // y^2 + // xx = (y^2 -1)*inv(d*y^2 +1) + BIGNUM * xx = BN_new (); + BN_mul (xx, d, y2, ctx); + BN_add_word (xx, 1); + Inv (xx, 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); + // 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_free (y2); + BN_free (xx); return x; } - CryptoPP::ECP::Point DecodePoint (const CryptoPP::Integer& y) const + EDDSAPoint DecodePoint (const uint8_t * buf, BN_CTX * ctx) const { - auto x = RecoverX (y); - CryptoPP::ECP::Point p {x, y}; - if (!IsOnCurve (p)) + // 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 { - LogPrint (eLogError, "Decoded point is not on 25519"); - return CryptoPP::ECP::Point {0, 1}; + 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); + auto x = RecoverX (y, ctx); + if (BN_is_bit_set (x, 0) != isHighestBitSet) + BN_sub (x, q, x); // x = q - x + EDDSAPoint p {x, y}; + if (!IsOnCurve (p, ctx)) + LogPrint (eLogError, "Decoded point is not on 25519"); return p; } + + void 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 + } - private: + BIGNUM * DecodeBN (const uint8_t * buf, size_t len) 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 + { + buf1[i] = buf[len -1 - i]; + buf1[len -1 - i] = buf[i]; + } + BIGNUM * res = BN_new (); + BN_bin2bn (buf1, len, res); + return res; + } + + void 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 + { + uint8_t tmp = buf[i]; + buf[i] = buf[len -1 - i]; + buf[len -1 - i] = tmp; + } + } - CryptoPP::Integer q, l, d, I; - CryptoPP::ECP::Point B; // base point + private: + + BIGNUM * q, * l, * d, * I; + EDDSAPoint B; // base point + // transient values + BIGNUM * q_2; // q-2 + BIGNUM * two_252_2; // 2^252-2 + EDDSAPoint Bi[256]; // m_Bi[i] = 2^i*B for i-th bit }; static std::unique_ptr g_Ed25519; @@ -98,22 +374,44 @@ namespace crypto if (!g_Ed25519) g_Ed25519.reset (new Ed25519 ()); return g_Ed25519; - } + } - EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey): - m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey)) + EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey): + m_Ctx (BN_CTX_new ()), + m_PublicKey (GetEd25519 ()->DecodePublicKey (signingKey, m_Ctx)) { + memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); } bool EDDSA25519Verifier::Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - return true; // TODO: + 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 + uint8_t digest[64]; + SHA512_Final (digest, &ctx); + return GetEd25519 ()->Verify (m_PublicKey, digest, signature, m_Ctx); } - void EDDSA25519Signer::Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const + EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey): + m_Ctx (BN_CTX_new ()) + { + // expand key + SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey); + m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits + m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x1F; // drop first 3 bits + m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit + // generate and encode public key + auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, m_Ctx); + GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded); + } + + void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const { - // TODO + GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature, m_Ctx); } } } diff --git a/Signature.h b/Signature.h index acfaa62f..423559a3 100644 --- a/Signature.h +++ b/Signature.h @@ -2,13 +2,15 @@ #define SIGNATURE_H__ #include -#include -#include -#include -#include -#include -#include -#include "CryptoConst.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "Crypto.h" namespace i2p { @@ -30,7 +32,7 @@ namespace crypto public: virtual ~Signer () {}; - virtual void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const = 0; + virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; }; const size_t DSA_PUBLIC_KEY_LENGTH = 128; @@ -42,13 +44,32 @@ namespace crypto DSAVerifier (const uint8_t * signingKey) { - m_PublicKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingKey, DSA_PUBLIC_KEY_LENGTH)); + m_PublicKey = DSA_new (); + m_PublicKey->p = BN_dup (dsap); + m_PublicKey->q = BN_dup (dsaq); + m_PublicKey->g = BN_dup (dsag); + m_PublicKey->priv_key = NULL; + m_PublicKey->pub_key = BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL); } - + + ~DSAVerifier () + { + DSA_free (m_PublicKey); + } + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - CryptoPP::DSA::Verifier verifier (m_PublicKey); - return verifier.VerifyMessage (buf, len, signature, DSA_SIGNATURE_LENGTH); + // calculate SHA1 digest + uint8_t digest[20]; + SHA1 (buf, len, digest); + // signature + DSA_SIG * sig = DSA_SIG_new(); + sig->r = BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL); + sig->s = BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL); + // DSA verification + int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); + DSA_SIG_free(sig); + return ret; } size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; }; @@ -56,7 +77,7 @@ namespace crypto private: - CryptoPP::DSA::PublicKey m_PublicKey; + DSA * m_PublicKey; }; class DSASigner: public Signer @@ -65,189 +86,219 @@ namespace crypto DSASigner (const uint8_t * signingPrivateKey) { - m_PrivateKey.Initialize (dsap, dsaq, dsag, CryptoPP::Integer (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH)); + m_PrivateKey = DSA_new (); + m_PrivateKey->p = BN_dup (dsap); + m_PrivateKey->q = BN_dup (dsaq); + m_PrivateKey->g = BN_dup (dsag); + m_PrivateKey->priv_key = BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL); + m_PrivateKey->pub_key = NULL; } - void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const + ~DSASigner () { - CryptoPP::DSA::Signer signer (m_PrivateKey); - signer.SignMessage (rnd, buf, len, signature); + DSA_free (m_PrivateKey); + } + + 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); + bn2buf (sig->r, signature, DSA_SIGNATURE_LENGTH/2); + bn2buf (sig->s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); + DSA_SIG_free(sig); } private: - CryptoPP::DSA::PrivateKey m_PrivateKey; + DSA * m_PrivateKey; }; - inline void CreateDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - CryptoPP::DSA::PrivateKey privateKey; - CryptoPP::DSA::PublicKey publicKey; - privateKey.Initialize (rnd, dsap, dsaq, dsag); - privateKey.MakePublicKey (publicKey); - privateKey.GetPrivateExponent ().Encode (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); - publicKey.GetPublicElement ().Encode (signingPublicKey, DSA_PUBLIC_KEY_LENGTH); + DSA * dsa = DSA_new (); + dsa->p = BN_dup (dsap); + dsa->q = BN_dup (dsaq); + dsa->g = BN_dup (dsag); + dsa->priv_key = NULL; + dsa->pub_key = NULL; + DSA_generate_key (dsa); + bn2buf (dsa->priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); + bn2buf (dsa->pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); + DSA_free (dsa); + } - template + struct SHA256Hash + { + static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) + { + SHA256 (buf, len, digest); + } + + enum { hashLen = 32 }; + }; + + struct SHA384Hash + { + static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) + { + SHA384 (buf, len, digest); + } + + enum { hashLen = 48 }; + }; + + struct SHA512Hash + { + static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) + { + SHA512 (buf, len, digest); + } + + enum { hashLen = 64 }; + }; + + template class ECDSAVerifier: public Verifier { public: - template - ECDSAVerifier (Curve curve, const uint8_t * signingKey) + ECDSAVerifier (const uint8_t * signingKey) { - m_PublicKey.Initialize (curve, - CryptoPP::ECP::Point (CryptoPP::Integer (signingKey, keyLen/2), - CryptoPP::Integer (signingKey + keyLen/2, keyLen/2))); + m_PublicKey = EC_KEY_new_by_curve_name (curve); + EC_KEY_set_public_key_affine_coordinates (m_PublicKey, + BN_bin2bn (signingKey, keyLen/2, NULL), + BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL)); } + ~ECDSAVerifier () + { + EC_KEY_free (m_PublicKey); + } + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - typename CryptoPP::ECDSA::Verifier verifier (m_PublicKey); - return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length + uint8_t digest[Hash::hashLen]; + Hash::CalculateHash (buf, len, digest); + ECDSA_SIG * sig = ECDSA_SIG_new(); + sig->r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); + sig->s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); + // ECDSA verification + 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 + private: - typename CryptoPP::ECDSA::PublicKey m_PublicKey; + EC_KEY * m_PublicKey; }; - template + template class ECDSASigner: public Signer { public: - template - ECDSASigner (Curve curve, const uint8_t * signingPrivateKey, size_t keyLen) + ECDSASigner (const uint8_t * signingPrivateKey) { - m_PrivateKey.Initialize (curve, CryptoPP::Integer (signingPrivateKey, keyLen/2)); // private key length + m_PrivateKey = EC_KEY_new_by_curve_name (curve); + EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL)); } - void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const + ~ECDSASigner () { - typename CryptoPP::ECDSA::Signer signer (m_PrivateKey); - signer.SignMessage (rnd, buf, len, signature); + EC_KEY_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); + ECDSA_SIG * sig = ECDSA_do_sign (digest, Hash::hashLen, m_PrivateKey); + // signatureLen = keyLen + bn2buf (sig->r, signature, keyLen/2); + bn2buf (sig->s, signature + keyLen/2, keyLen/2); + ECDSA_SIG_free(sig); } private: - typename CryptoPP::ECDSA::PrivateKey m_PrivateKey; + EC_KEY * m_PrivateKey; }; - template - inline void CreateECDSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, Curve curve, - size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + inline void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - typename CryptoPP::ECDSA::PrivateKey privateKey; - typename CryptoPP::ECDSA::PublicKey publicKey; - privateKey.Initialize (rnd, curve); - privateKey.MakePublicKey (publicKey); - privateKey.GetPrivateExponent ().Encode (signingPrivateKey, keyLen/2); - auto q = publicKey.GetPublicElement (); - q.x.Encode (signingPublicKey, keyLen/2); - q.y.Encode (signingPublicKey + keyLen/2, keyLen/2); - } + 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 const size_t ECDSAP256_KEY_LENGTH = 64; - class ECDSAP256Verifier: public ECDSAVerifier - { - public: - - ECDSAP256Verifier (const uint8_t * signingKey): - ECDSAVerifier (CryptoPP::ASN1::secp256r1(), signingKey) - { - } - }; - - class ECDSAP256Signer: public ECDSASigner - { - public: + typedef ECDSAVerifier ECDSAP256Verifier; + typedef ECDSASigner ECDSAP256Signer; - ECDSAP256Signer (const uint8_t * signingPrivateKey): - ECDSASigner (CryptoPP::ASN1::secp256r1(), signingPrivateKey, ECDSAP256_KEY_LENGTH) - { - } - }; - - inline void CreateECDSAP256RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - CreateECDSARandomKeys (rnd, CryptoPP::ASN1::secp256r1(), ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); + CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); } // ECDSA_SHA384_P384 const size_t ECDSAP384_KEY_LENGTH = 96; - class ECDSAP384Verifier: public ECDSAVerifier - { - public: - - ECDSAP384Verifier (const uint8_t * signingKey): - ECDSAVerifier (CryptoPP::ASN1::secp384r1(), signingKey) - { - } - }; + typedef ECDSAVerifier ECDSAP384Verifier; + typedef ECDSASigner ECDSAP384Signer; - class ECDSAP384Signer: public ECDSASigner + inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - public: - - ECDSAP384Signer (const uint8_t * signingPrivateKey): - ECDSASigner (CryptoPP::ASN1::secp384r1(), signingPrivateKey, ECDSAP384_KEY_LENGTH) - { - } - }; - - inline void CreateECDSAP384RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) - { - CreateECDSARandomKeys (rnd, CryptoPP::ASN1::secp384r1(), ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); + CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); } // ECDSA_SHA512_P521 const size_t ECDSAP521_KEY_LENGTH = 132; - class ECDSAP521Verifier: public ECDSAVerifier - { - public: + typedef ECDSAVerifier ECDSAP521Verifier; + typedef ECDSASigner ECDSAP521Signer; - ECDSAP521Verifier (const uint8_t * signingKey): - ECDSAVerifier (CryptoPP::ASN1::secp521r1(), signingKey) - { - } - }; - - class ECDSAP521Signer: public ECDSASigner - { - public: - - ECDSAP521Signer (const uint8_t * signingPrivateKey): - ECDSASigner (CryptoPP::ASN1::secp521r1(), signingPrivateKey, ECDSAP521_KEY_LENGTH) - { - } - }; - - inline void CreateECDSAP521RandomKeys (CryptoPP::RandomNumberGenerator& rnd, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + inline void CreateECDSAP521RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - CreateECDSARandomKeys (rnd, CryptoPP::ASN1::secp521r1(), ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); + CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); } // RSA - template + template class RSAVerifier: public Verifier { public: RSAVerifier (const uint8_t * signingKey) { - m_PublicKey.Initialize (CryptoPP::Integer (signingKey, keyLen), CryptoPP::Integer (rsae)); + m_PublicKey = RSA_new (); + memset (m_PublicKey, 0, sizeof (RSA)); + m_PublicKey->e = BN_dup (rsae); + m_PublicKey->n = BN_bin2bn (signingKey, keyLen, NULL); } + ~RSAVerifier () + { + RSA_free (m_PublicKey); + } + bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const { - typename CryptoPP::RSASS::Verifier verifier (m_PublicKey); - return verifier.VerifyMessage (buf, len, signature, keyLen); // signature length + uint8_t digest[Hash::hashLen]; + Hash::CalculateHash (buf, len, digest); + return RSA_verify (type, digest, Hash::hashLen, signature, GetSignatureLen (), m_PublicKey); } size_t GetPublicKeyLen () const { return keyLen; } size_t GetSignatureLen () const { return keyLen; } @@ -255,163 +306,92 @@ namespace crypto private: - CryptoPP::RSA::PublicKey m_PublicKey; + RSA * m_PublicKey; }; - template + template class RSASigner: public Signer { public: - RSASigner (const uint8_t * signingPrivateKey, size_t keyLen) + RSASigner (const uint8_t * signingPrivateKey) { - m_PrivateKey.Initialize (CryptoPP::Integer (signingPrivateKey, keyLen/2), - rsae, - CryptoPP::Integer (signingPrivateKey + keyLen/2, keyLen/2)); + m_PrivateKey = RSA_new (); + memset (m_PrivateKey, 0, sizeof (RSA)); + m_PrivateKey->e = BN_dup (rsae); + m_PrivateKey->n = BN_bin2bn (signingPrivateKey, keyLen, NULL); + m_PrivateKey->d = BN_bin2bn (signingPrivateKey + keyLen, keyLen, NULL); } - void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const + ~RSASigner () { - typename CryptoPP::RSASS::Signer signer (m_PrivateKey); - signer.SignMessage (rnd, buf, len, signature); + RSA_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); + unsigned int signatureLen = keyLen; + RSA_sign (type, digest, Hash::hashLen, signature, &signatureLen, m_PrivateKey); } private: - CryptoPP::RSA::PrivateKey m_PrivateKey; + RSA * m_PrivateKey; }; - inline void CreateRSARandomKeys (CryptoPP::RandomNumberGenerator& rnd, - size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) { - CryptoPP::RSA::PrivateKey privateKey; - privateKey.Initialize (rnd, publicKeyLen*8, rsae); - privateKey.GetModulus ().Encode (signingPrivateKey, publicKeyLen); - privateKey.GetPrivateExponent ().Encode (signingPrivateKey + publicKeyLen, publicKeyLen); - privateKey.GetModulus ().Encode (signingPublicKey, publicKeyLen); + RSA * rsa = RSA_new (); + RSA_generate_key_ex (rsa, publicKeyLen*8, rsae, NULL); + bn2buf (rsa->n, signingPrivateKey, publicKeyLen); + bn2buf (rsa->d, signingPrivateKey + publicKeyLen, publicKeyLen); + bn2buf (rsa->n, signingPublicKey, publicKeyLen); + RSA_free (rsa); } - // RSA_SHA256_2048 const size_t RSASHA2562048_KEY_LENGTH = 256; - class RSASHA2562048Verifier: public RSAVerifier - { - public: - - RSASHA2562048Verifier (const uint8_t * signingKey): RSAVerifier (signingKey) - { - } - }; - - class RSASHA2562048Signer: public RSASigner - { - public: - - RSASHA2562048Signer (const uint8_t * signingPrivateKey): - RSASigner (signingPrivateKey, RSASHA2562048_KEY_LENGTH*2) - { - } - }; + typedef RSAVerifier RSASHA2562048Verifier; + typedef RSASigner RSASHA2562048Signer; // RSA_SHA384_3072 const size_t RSASHA3843072_KEY_LENGTH = 384; - class RSASHA3843072Verifier: public RSAVerifier - { - public: - - RSASHA3843072Verifier (const uint8_t * signingKey): RSAVerifier (signingKey) - { - } - }; - - class RSASHA3843072Signer: public RSASigner - { - public: - - RSASHA3843072Signer (const uint8_t * signingPrivateKey): - RSASigner (signingPrivateKey, RSASHA3843072_KEY_LENGTH*2) - { - } - }; + typedef RSAVerifier RSASHA3843072Verifier; + typedef RSASigner RSASHA3843072Signer; // RSA_SHA512_4096 const size_t RSASHA5124096_KEY_LENGTH = 512; - class RSASHA5124096Verifier: public RSAVerifier - { - public: - - RSASHA5124096Verifier (const uint8_t * signingKey): RSAVerifier (signingKey) - { - } - }; - - class RSASHA5124096Signer: public RSASigner - { - public: - - RSASHA5124096Signer (const uint8_t * signingPrivateKey): - RSASigner (signingPrivateKey, RSASHA5124096_KEY_LENGTH*2) - { - } - }; + typedef RSAVerifier RSASHA5124096Verifier; + typedef RSASigner RSASHA5124096Signer; -// Raw verifiers - class RawVerifier - { - public: - - virtual ~RawVerifier () {}; - virtual void Update (const uint8_t * buf, size_t len) = 0; - virtual bool Verify (const uint8_t * signature) = 0; - }; - - template - class RSARawVerifier: public RawVerifier + // EdDSA + struct EDDSAPoint { - public: - - RSARawVerifier (const uint8_t * signingKey): - n (signingKey, keyLen) - { - } - - void Update (const uint8_t * buf, size_t len) - { - m_Hash.Update (buf, len); - } - - bool Verify (const uint8_t * signature) - { - // RSA encryption first - CryptoPP::Integer enSig (a_exp_b_mod_c (CryptoPP::Integer (signature, keyLen), - CryptoPP::Integer (i2p::crypto::rsae), n)); // s^e mod n - uint8_t enSigBuf[keyLen]; - enSig.Encode (enSigBuf, keyLen); - - uint8_t digest[Hash::DIGESTSIZE]; - m_Hash.Final (digest); - if ((int)keyLen < Hash::DIGESTSIZE) return false; // can't verify digest longer than key - // we assume digest is right aligned, at least for PKCS#1 v1.5 padding - return !memcmp (enSigBuf + (keyLen - Hash::DIGESTSIZE), digest, Hash::DIGESTSIZE); - } - - private: - - CryptoPP::Integer n; // RSA modulus - Hash m_Hash; + BIGNUM * x, * y; + EDDSAPoint (): x(nullptr), y(nullptr) {}; + EDDSAPoint (EDDSAPoint&& other): x(nullptr), y(nullptr) + { *this = std::move (other); }; + EDDSAPoint (BIGNUM * x1, BIGNUM * y1): x(x1), y(y1) {}; + ~EDDSAPoint () { BN_free (x); BN_free (y); }; + + EDDSAPoint& operator= (EDDSAPoint&& other) + { + if (x) BN_free (x); + if (y) BN_free (y); + x = other.x; other.x = nullptr; + y = other.y; other.y = nullptr; + return *this; + } + + bool operator== (const EDDSAPoint& other) const + { + return !BN_cmp (x, other.x) && !BN_cmp (y, other.y); + } }; - class RSASHA5124096RawVerifier: public RSARawVerifier - { - public: - - RSASHA5124096RawVerifier (const uint8_t * signingKey): RSARawVerifier (signingKey) - { - } - }; - - // EdDSA const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; const size_t EDDSA25519_SIGNATURE_LENGTH = 64; const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; @@ -420,24 +400,41 @@ namespace crypto public: EDDSA25519Verifier (const uint8_t * signingKey); + ~EDDSA25519Verifier () { BN_CTX_free (m_Ctx); }; 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: - - CryptoPP::ECP::Point m_PublicKey; + + BN_CTX * m_Ctx; + EDDSAPoint m_PublicKey; + uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; }; class EDDSA25519Signer: public Signer { public: - EDDSA25519Signer (const uint8_t * signingPrivateKey) {}; + EDDSA25519Signer (const uint8_t * signingPrivateKey); + ~EDDSA25519Signer () { BN_CTX_free (m_Ctx); }; + void Sign (const uint8_t * buf, int len, uint8_t * signature) const; + const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; + + private: - void Sign (CryptoPP::RandomNumberGenerator& rnd, const uint8_t * buf, int len, uint8_t * signature) const; + BN_CTX * m_Ctx; + uint8_t m_ExpandedPrivateKey[64]; + uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; }; + + inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) + { + RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); + EDDSA25519Signer signer (signingPrivateKey); + memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); + } } } diff --git a/Streaming.cpp b/Streaming.cpp index 785e2987..bb84a955 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,4 +1,4 @@ -#include +#include #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" @@ -20,7 +20,7 @@ namespace stream m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0) { - m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); + RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); m_RemoteIdentity = remote->GetIdentity (); m_CurrentRemoteLease.endDate = 0; } @@ -32,7 +32,7 @@ namespace stream m_NumSentBytes (0), m_NumReceivedBytes (0), m_Port (0), m_WindowSize (MIN_WINDOW_SIZE), m_RTT (INITIAL_RTT), m_RTO (INITIAL_RTO), m_LastWindowSizeIncreaseTime (0), m_NumResendAttempts (0) { - m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); + RAND_bytes ((uint8_t *)&m_RecvStreamID, 4); } Stream::~Stream () @@ -182,10 +182,11 @@ namespace stream if (flags & PACKET_FLAG_FROM_INCLUDED) { - optionData += m_RemoteIdentity.FromBuffer (optionData, packet->GetOptionSize ()); - LogPrint (eLogInfo, "From identity ", m_RemoteIdentity.GetIdentHash ().ToBase64 ()); + m_RemoteIdentity = std::make_shared(optionData, packet->GetOptionSize ()); + optionData += m_RemoteIdentity->GetFullLen (); + LogPrint (eLogInfo, "From identity ", m_RemoteIdentity->GetIdentHash ().ToBase64 ()); if (!m_RemoteLeaseSet) - LogPrint (eLogDebug, "Incoming stream from ", m_RemoteIdentity.GetIdentHash ().ToBase64 ()); + LogPrint (eLogDebug, "Incoming stream from ", m_RemoteIdentity->GetIdentHash ().ToBase64 ()); } if (flags & PACKET_FLAG_MAX_PACKET_SIZE_INCLUDED) @@ -199,10 +200,10 @@ namespace stream { LogPrint (eLogDebug, "Signature"); uint8_t signature[256]; - auto signatureLen = m_RemoteIdentity.GetSignatureLen (); + auto signatureLen = m_RemoteIdentity->GetSignatureLen (); memcpy (signature, optionData, signatureLen); memset (const_cast(optionData), 0, signatureLen); - if (!m_RemoteIdentity.Verify (packet->GetBuffer (), packet->GetLength (), signature)) + if (!m_RemoteIdentity->Verify (packet->GetBuffer (), packet->GetLength (), signature)) { LogPrint (eLogError, "Signature verification failed"); Close (); @@ -353,11 +354,11 @@ namespace stream if (isNoAck) flags |= PACKET_FLAG_NO_ACK; htobe16buf (packet + size, flags); size += 2; // flags - size_t identityLen = m_LocalDestination.GetOwner ().GetIdentity ().GetFullLen (); - size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen (); + size_t identityLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetFullLen (); + size_t signatureLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetSignatureLen (); htobe16buf (packet + size, identityLen + signatureLen + 2); // identity + signature + packet size size += 2; // options size - m_LocalDestination.GetOwner ().GetIdentity ().ToBuffer (packet + size, identityLen); + m_LocalDestination.GetOwner ()->GetIdentity ()->ToBuffer (packet + size, identityLen); size += identityLen; // from htobe16buf (packet + size, STREAMING_MTU); size += 2; // max packet size @@ -366,7 +367,7 @@ namespace stream size += signatureLen; // signature m_SendBuffer.read ((char *)(packet + size), STREAMING_MTU - size); size += m_SendBuffer.gcount (); // payload - m_LocalDestination.GetOwner ().Sign (packet, size, signature); + m_LocalDestination.GetOwner ()->Sign (packet, size, signature); } else { @@ -528,13 +529,13 @@ namespace stream size++; // resend delay htobe16buf (packet + size, PACKET_FLAG_CLOSE | PACKET_FLAG_SIGNATURE_INCLUDED); size += 2; // flags - size_t signatureLen = m_LocalDestination.GetOwner ().GetIdentity ().GetSignatureLen (); + size_t signatureLen = m_LocalDestination.GetOwner ()->GetIdentity ()->GetSignatureLen (); htobe16buf (packet + size, signatureLen); // signature only size += 2; // options size uint8_t * signature = packet + size; memset (packet + size, 0, signatureLen); size += signatureLen; // signature - m_LocalDestination.GetOwner ().Sign (packet, size, signature); + m_LocalDestination.GetOwner ()->Sign (packet, size, signature); p->len = size; m_Service.post (std::bind (&Stream::SendPacket, shared_from_this (), p)); @@ -597,15 +598,15 @@ namespace stream } } if (!m_CurrentOutboundTunnel || !m_CurrentOutboundTunnel->IsEstablished ()) - m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); + m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNewOutboundTunnel (m_CurrentOutboundTunnel); if (!m_CurrentOutboundTunnel) { LogPrint (eLogError, "No outbound tunnels in the pool"); return; } - auto ts = i2p::util::GetMillisecondsSinceEpoch (); - if (ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000) + auto ts = i2p::util::GetMillisecondsSinceEpoch (); + if (!m_CurrentRemoteLease.endDate || ts >= m_CurrentRemoteLease.endDate - i2p::tunnel::TUNNEL_EXPIRATION_THRESHOLD*1000) UpdateCurrentRemoteLease (true); if (ts < m_CurrentRemoteLease.endDate) { @@ -681,7 +682,7 @@ namespace stream break; case 3: // pick another outbound tunnel - m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ().GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); + m_CurrentOutboundTunnel = m_LocalDestination.GetOwner ()->GetTunnelPool ()->GetNextOutboundTunnel (m_CurrentOutboundTunnel); LogPrint (eLogWarning, "Another outbound tunnel has been selected for stream"); break; default: ; @@ -713,19 +714,19 @@ namespace stream { if (!m_RemoteLeaseSet) { - m_RemoteLeaseSet = m_LocalDestination.GetOwner ().FindLeaseSet (m_RemoteIdentity.GetIdentHash ()); + m_RemoteLeaseSet = m_LocalDestination.GetOwner ()->FindLeaseSet (m_RemoteIdentity->GetIdentHash ()); if (!m_RemoteLeaseSet) - LogPrint ("LeaseSet ", m_RemoteIdentity.GetIdentHash ().ToBase64 (), " not found"); + LogPrint ("LeaseSet ", m_RemoteIdentity->GetIdentHash ().ToBase64 (), " not found"); } if (m_RemoteLeaseSet) { if (!m_RoutingSession) - m_RoutingSession = m_LocalDestination.GetOwner ().GetRoutingSession (m_RemoteLeaseSet, 32); + m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, 32); auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (false); // try without threshold first if (leases.empty ()) { expired = false; - m_LocalDestination.GetOwner ().RequestDestination (m_RemoteIdentity.GetIdentHash ()); // time to re-request + m_LocalDestination.GetOwner ()->RequestDestination (m_RemoteIdentity->GetIdentHash ()); // time to re-request leases = m_RemoteLeaseSet->GetNonExpiredLeases (true); // then with threshold } if (!leases.empty ()) @@ -743,7 +744,7 @@ namespace stream } if (!updated) { - uint32_t i = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (0, leases.size () - 1); + uint32_t i = rand () % leases.size (); if (m_CurrentRemoteLease.endDate && leases[i].tunnelID == m_CurrentRemoteLease.tunnelID) // make sure we don't select previous i = (i + 1) % leases.size (); // if so, pick next @@ -764,27 +765,36 @@ namespace stream std::shared_ptr Stream::CreateDataMessage (const uint8_t * payload, size_t len) { auto msg = ToSharedI2NPMessage (NewI2NPShortMessage ()); - CryptoPP::Gzip compressor; if (len <= i2p::stream::COMPRESSION_THRESHOLD_SIZE) - compressor.SetDeflateLevel (CryptoPP::Gzip::MIN_DEFLATE_LEVEL); + m_LocalDestination.m_Deflator.SetCompressionLevel (Z_NO_COMPRESSION); else - compressor.SetDeflateLevel (CryptoPP::Gzip::DEFAULT_DEFLATE_LEVEL); - compressor.Put (payload, len); - compressor.MessageEnd(); - int size = compressor.MaxRetrievable (); + m_LocalDestination.m_Deflator.SetCompressionLevel (Z_DEFAULT_COMPRESSION); uint8_t * buf = msg->GetPayload (); - htobe32buf (buf, size); // length - buf += 4; - compressor.Get (buf, size); - htobe16buf (buf + 4, m_LocalDestination.GetLocalPort ()); // source port - htobe16buf (buf + 6, m_Port); // destination port - buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol - msg->len += size + 4; - msg->FillI2NPMessageHeader (eI2NPData); - + buf += 4; // reserve for lengthlength + size_t size = m_LocalDestination.m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len); + if (size) + { + htobe32buf (msg->GetPayload (), size); // length + htobe16buf (buf + 4, m_LocalDestination.GetLocalPort ()); // source port + htobe16buf (buf + 6, m_Port); // destination port + buf[9] = i2p::client::PROTOCOL_TYPE_STREAMING; // streaming protocol + msg->len += size + 4; + msg->FillI2NPMessageHeader (eI2NPData); + } + else + msg = nullptr; return msg; } + + StreamingDestination::StreamingDestination (std::shared_ptr owner, uint16_t localPort): + m_Owner (owner), m_LocalPort (localPort) + { + } + StreamingDestination::~StreamingDestination () + { + } + void StreamingDestination::Start () { } @@ -845,7 +855,7 @@ namespace stream std::shared_ptr StreamingDestination::CreateNewOutgoingStream (std::shared_ptr remote, int port) { - auto s = std::make_shared (m_Owner.GetService (), *this, remote, port); + auto s = std::make_shared (m_Owner->GetService (), *this, remote, port); std::unique_lock l(m_StreamsMutex); m_Streams[s->GetRecvStreamID ()] = s; return s; @@ -853,7 +863,7 @@ namespace stream std::shared_ptr StreamingDestination::CreateNewIncomingStream () { - auto s = std::make_shared (m_Owner.GetService (), *this); + auto s = std::make_shared (m_Owner->GetService (), *this); std::unique_lock l(m_StreamsMutex); m_Streams[s->GetRecvStreamID ()] = s; return s; @@ -873,22 +883,13 @@ namespace stream void StreamingDestination::HandleDataMessagePayload (const uint8_t * buf, size_t len) { // unzip it - CryptoPP::Gunzip decompressor; - decompressor.Put (buf, len); - decompressor.MessageEnd(); Packet * uncompressed = new Packet; uncompressed->offset = 0; - uncompressed->len = decompressor.MaxRetrievable (); - if (uncompressed->len <= MAX_PACKET_SIZE) - { - decompressor.Get (uncompressed->buf, uncompressed->len); + uncompressed->len = m_Inflator.Inflate (buf, len, uncompressed->buf, MAX_PACKET_SIZE); + if (uncompressed->len) HandleNextPacket (uncompressed); - } else - { - LogPrint ("Received packet size ", uncompressed->len, " exceeds max packet size. Skipped"); delete uncompressed; - } } } } diff --git a/Streaming.h b/Streaming.h index 7e2aaa71..580ddf7c 100644 --- a/Streaming.h +++ b/Streaming.h @@ -11,6 +11,7 @@ #include #include #include +#include "Base.h" #include "I2PEndian.h" #include "Identity.h" #include "LeaseSet.h" @@ -107,7 +108,7 @@ namespace stream uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; std::shared_ptr GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; - const i2p::data::IdentityEx& GetRemoteIdentity () const { return m_RemoteIdentity; }; + std::shared_ptr GetRemoteIdentity () const { return m_RemoteIdentity; }; bool IsOpen () const { return m_Status == eStreamStatusOpen; }; bool IsEstablished () const { return m_SendStreamID; }; StreamStatus GetStatus () const { return m_Status; }; @@ -166,7 +167,7 @@ namespace stream StreamStatus m_Status; bool m_IsAckSendScheduled; StreamingDestination& m_LocalDestination; - i2p::data::IdentityEx m_RemoteIdentity; + std::shared_ptr m_RemoteIdentity; std::shared_ptr m_RemoteLeaseSet; std::shared_ptr m_RoutingSession; i2p::data::Lease m_CurrentRemoteLease; @@ -192,9 +193,8 @@ namespace stream typedef std::function)> Acceptor; - StreamingDestination (i2p::client::ClientDestination& owner, uint16_t localPort = 0): - m_Owner (owner), m_LocalPort (localPort) {}; - ~StreamingDestination () {}; + StreamingDestination (std::shared_ptr owner, uint16_t localPort = 0); + ~StreamingDestination (); void Start (); void Stop (); @@ -204,7 +204,7 @@ namespace stream void SetAcceptor (const Acceptor& acceptor) { m_Acceptor = acceptor; }; void ResetAcceptor () { if (m_Acceptor) m_Acceptor (nullptr); m_Acceptor = nullptr; }; bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; - i2p::client::ClientDestination& GetOwner () { return m_Owner; }; + std::shared_ptr GetOwner () const { return m_Owner; }; uint16_t GetLocalPort () const { return m_LocalPort; }; void HandleDataMessagePayload (const uint8_t * buf, size_t len); @@ -216,7 +216,7 @@ namespace stream private: - i2p::client::ClientDestination& m_Owner; + std::shared_ptr m_Owner; uint16_t m_LocalPort; std::mutex m_StreamsMutex; std::map > m_Streams; @@ -224,6 +224,9 @@ namespace stream public: + i2p::data::GzipInflator m_Inflator; + i2p::data::GzipDeflator m_Deflator; + // for HTTP only const decltype(m_Streams)& GetStreams () const { return m_Streams; }; }; diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index ad6aa0b3..beb09da7 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -14,8 +14,7 @@ namespace tunnel TransitTunnel::TransitTunnel (uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * layerKey,const uint8_t * ivKey): - m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID), - m_NextIdent (nextIdent) + TunnelBase (receiveTunnelID, nextTunnelID, nextIdent) { m_Encryption.SetKeys (layerKey, ivKey); } @@ -54,12 +53,12 @@ namespace tunnel void TransitTunnel::SendTunnelDataMsg (std::shared_ptr msg) { - LogPrint (eLogError, "We are not a gateway for transit tunnel ", m_TunnelID); + LogPrint (eLogError, "We are not a gateway for transit tunnel ", GetTunnelID ()); } void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr tunnelMsg) { - LogPrint (eLogError, "Incoming tunnel message is not supported ", m_TunnelID); + LogPrint (eLogError, "Incoming tunnel message is not supported ", GetTunnelID ()); } void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr msg) diff --git a/TransitTunnel.h b/TransitTunnel.h index 79bb99bb..e611d685 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -5,7 +5,7 @@ #include #include #include -#include "aes.h" +#include "Crypto.h" #include "I2NPProtocol.h" #include "TunnelEndpoint.h" #include "TunnelGateway.h" @@ -24,20 +24,12 @@ namespace tunnel const uint8_t * layerKey,const uint8_t * ivKey); virtual size_t GetNumTransmittedBytes () const { return 0; }; - - uint32_t GetTunnelID () const { return m_TunnelID; }; // implements TunnelBase void SendTunnelDataMsg (std::shared_ptr msg); void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); - void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); - uint32_t GetNextTunnelID () const { return m_NextTunnelID; }; - const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; }; - + void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); private: - - uint32_t m_TunnelID, m_NextTunnelID; - i2p::data::IdentHash m_NextIdent; i2p::crypto::TunnelEncryption m_Encryption; }; diff --git a/TransportSession.h b/TransportSession.h index f8da2b4d..608e72d1 100644 --- a/TransportSession.h +++ b/TransportSession.h @@ -6,6 +6,7 @@ #include #include #include "Identity.h" +#include "Crypto.h" #include "RouterInfo.h" #include "I2NPProtocol.h" @@ -13,17 +14,15 @@ namespace i2p { namespace transport { - struct DHKeysPair // transient keys for transport sessions - { - uint8_t publicKey[256]; - uint8_t privateKey[256]; - }; - class SignedData { public: - SignedData () {}; + SignedData () {} + SignedData (const SignedData& other) + { + m_Stream << other.m_Stream.rdbuf (); + } void Insert (const uint8_t * buf, size_t len) { m_Stream.write ((char *)buf, len); @@ -35,9 +34,9 @@ namespace transport m_Stream.write ((char *)&t, sizeof (T)); } - bool Verify (const i2p::data::IdentityEx& ident, const uint8_t * signature) const + bool Verify (std::shared_ptr ident, const uint8_t * signature) const { - return ident.Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); + return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); } void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const @@ -54,31 +53,31 @@ namespace transport { public: - TransportSession (std::shared_ptr in_RemoteRouter): - m_RemoteRouter (in_RemoteRouter), m_DHKeysPair (nullptr), - m_NumSentBytes (0), m_NumReceivedBytes (0) + TransportSession (std::shared_ptr router): + m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router) { - if (m_RemoteRouter) - m_RemoteIdentity = m_RemoteRouter->GetRouterIdentity (); + if (router) + m_RemoteIdentity = router->GetRouterIdentity (); } - virtual ~TransportSession () { delete m_DHKeysPair; }; + virtual ~TransportSession () {}; virtual void Done () = 0; - std::shared_ptr GetRemoteRouter () { return m_RemoteRouter; }; - const i2p::data::IdentityEx& GetRemoteIdentity () { return m_RemoteIdentity; }; - + std::shared_ptr GetRemoteIdentity () { return m_RemoteIdentity; }; + void SetRemoteIdentity (std::shared_ptr ident) { m_RemoteIdentity = ident; }; + size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; + bool IsOutgoing () const { return m_IsOutgoing; }; virtual void SendI2NPMessages (const std::vector >& msgs) = 0; protected: - std::shared_ptr m_RemoteRouter; - i2p::data::IdentityEx m_RemoteIdentity; - DHKeysPair * m_DHKeysPair; // X - for client and Y - for server + std::shared_ptr m_RemoteIdentity; + std::shared_ptr m_DHKeysPair; // X - for client and Y - for server size_t m_NumSentBytes, m_NumReceivedBytes; + bool m_IsOutgoing; }; } } diff --git a/Transports.cpp b/Transports.cpp index da07dc1d..635c5e04 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -1,6 +1,6 @@ -#include +#include #include "Log.h" -#include "CryptoConst.h" +#include "Crypto.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "NetDb.h" @@ -56,18 +56,18 @@ namespace transport { if (num > 0) { - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); + i2p::crypto::DHKeys dh; for (int i = 0; i < num; i++) { - i2p::transport::DHKeysPair * pair = new i2p::transport::DHKeysPair (); - dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey); + auto pair = std::make_shared (); + pair->GenerateKeys (); std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); } } } - DHKeysPair * DHKeysPairSupplier::Acquire () + std::shared_ptr DHKeysPairSupplier::Acquire () { if (!m_Queue.empty ()) { @@ -78,15 +78,14 @@ namespace transport return pair; } else // queue is empty, create new - { - DHKeysPair * pair = new DHKeysPair (); - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - dh.GenerateKeyPair(m_Rnd, pair->privateKey, pair->publicKey); + { + auto pair = std::make_shared (); + pair->GenerateKeys (); return pair; } } - void DHKeysPairSupplier::Return (DHKeysPair * pair) + void DHKeysPairSupplier::Return (std::shared_ptr pair) { std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); @@ -109,10 +108,6 @@ namespace transport void Transports::Start () { -#ifdef USE_UPNP - m_UPnP.Start (); - LogPrint(eLogInfo, "UPnP started"); -#endif m_DHKeysPairSupplier.Start (); m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); @@ -145,10 +140,6 @@ namespace transport void Transports::Stop () { -#ifdef USE_UPNP - m_UPnP.Stop (); - LogPrint(eLogInfo, "UPnP stopped"); -#endif m_PeerCleanupTimer.cancel (); m_Peers.clear (); if (m_SSUServer) @@ -412,13 +403,34 @@ namespace transport else LogPrint (eLogError, "Can't detect external IP. SSU is not available"); } - - DHKeysPair * Transports::GetNextDHKeysPair () + + void Transports::PeerTest () + { + if (m_SSUServer) + { + bool statusChanged = false; + for (int i = 0; i < 5; i++) + { + auto router = i2p::data::netdb.GetRandomPeerTestRouter (); + if (router && router->IsSSU ()) + { + if (!statusChanged) + { + statusChanged = true; + i2p::context.SetStatus (eRouterStatusTesting); // first time only + } + m_SSUServer->GetSession (router, true); // peer test + } + } + } + } + + std::shared_ptr Transports::GetNextDHKeysPair () { return m_DHKeysPairSupplier.Acquire (); } - void Transports::ReuseDHKeysPair (DHKeysPair * pair) + void Transports::ReuseDHKeysPair (std::shared_ptr pair) { m_DHKeysPairSupplier.Return (pair); } @@ -427,7 +439,8 @@ namespace transport { m_Service.post([session, this]() { - auto ident = session->GetRemoteIdentity ().GetIdentHash (); + if (!session->GetRemoteIdentity ()) return; + auto ident = session->GetRemoteIdentity ()->GetIdentHash (); auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { @@ -444,7 +457,8 @@ namespace transport { m_Service.post([session, this]() { - auto ident = session->GetRemoteIdentity ().GetIdentHash (); + if (!session->GetRemoteIdentity ()) return; + auto ident = session->GetRemoteIdentity ()->GetIdentHash (); auto it = m_Peers.find (ident); if (it != m_Peers.end ()) { @@ -491,9 +505,9 @@ namespace transport std::shared_ptr Transports::GetRandomPeer () const { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + if (!m_Peers.size ()) return nullptr; auto it = m_Peers.begin (); - std::advance (it, rnd.GenerateWord32 (0, m_Peers.size () - 1)); + std::advance (it, rand () % m_Peers.size ()); return it != m_Peers.end () ? it->second.router : nullptr; } } diff --git a/Transports.h b/Transports.h index 15ad980e..63506c13 100644 --- a/Transports.h +++ b/Transports.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include "TransportSession.h" #include "NTCPSession.h" @@ -20,10 +19,6 @@ #include "I2NPProtocol.h" #include "Identity.h" -#ifdef USE_UPNP -#include "UPnP.h" -#endif - namespace i2p { namespace transport @@ -36,8 +31,8 @@ namespace transport ~DHKeysPairSupplier (); void Start (); void Stop (); - DHKeysPair * Acquire (); - void Return (DHKeysPair * pair); + std::shared_ptr Acquire (); + void Return (std::shared_ptr pair); private: @@ -47,13 +42,12 @@ namespace transport private: const int m_QueueSize; - std::queue m_Queue; + std::queue > m_Queue; bool m_IsRunning; std::thread * m_Thread; std::condition_variable m_Acquired; std::mutex m_AcquiredMutex; - CryptoPP::AutoSeededRandomPool m_Rnd; }; struct Peer @@ -84,8 +78,8 @@ namespace transport void Stop (); boost::asio::io_service& GetService () { return m_Service; }; - i2p::transport::DHKeysPair * GetNextDHKeysPair (); - void ReuseDHKeysPair (DHKeysPair * pair); + std::shared_ptr GetNextDHKeysPair (); + void ReuseDHKeysPair (std::shared_ptr pair); void SendMessage (const i2p::data::IdentHash& ident, std::shared_ptr msg); void SendMessages (const i2p::data::IdentHash& ident, const std::vector >& msgs); @@ -105,6 +99,8 @@ namespace transport size_t GetNumPeers () const { return m_Peers.size (); }; std::shared_ptr GetRandomPeer () const; + void PeerTest (); + private: void Run (); @@ -141,10 +137,6 @@ namespace transport uint64_t m_LastInBandwidthUpdateBytes, m_LastOutBandwidthUpdateBytes; uint64_t m_LastBandwidthUpdateTime; -#ifdef USE_UPNP - UPnP m_UPnP; -#endif - public: // for HTTP only diff --git a/Tunnel.cpp b/Tunnel.cpp index 0c5600e7..6443180f 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "RouterContext.h" #include "Log.h" #include "Timestamp.h" @@ -18,6 +18,7 @@ namespace tunnel { Tunnel::Tunnel (std::shared_ptr config): + TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false) { } @@ -28,7 +29,6 @@ namespace tunnel void Tunnel::Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel) { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); auto numHops = m_Config->GetNumHops (); int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; auto msg = NewI2NPShortMessage (); @@ -46,9 +46,13 @@ namespace tunnel int i = 0; while (hop) { + uint32_t msgID; + if (hop->next) // we set replyMsgID for last hop only + RAND_bytes ((uint8_t *)&msgID, 4); + else + msgID = replyMsgID; int idx = recordIndicies[i]; - hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, - hop->next ? rnd.GenerateWord32 () : replyMsgID); // we set replyMsgID for last hop only + hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID); hop->recordIndex = idx; i++; hop = hop->next; @@ -57,7 +61,7 @@ namespace tunnel for (int i = numHops; i < numRecords; i++) { int idx = recordIndicies[i]; - rnd.GenerateBlock (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE); + RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE); } // decrypt real records @@ -120,7 +124,9 @@ namespace tunnel const uint8_t * record = msg + 1 + hop->recordIndex*TUNNEL_BUILD_RECORD_SIZE; uint8_t ret = record[BUILD_RESPONSE_RECORD_RET_OFFSET]; LogPrint ("Ret code=", (int)ret); - hop->router->GetProfile ()->TunnelBuildResponse (ret); + auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ()); + if (profile) + profile->TunnelBuildResponse (ret); if (ret) // if any of participants declined the tunnel is not established established = false; @@ -128,13 +134,16 @@ namespace tunnel } if (established) { - // change reply keys to layer keys - hop = m_Config->GetFirstHop (); + // create tunnel decryptions from layer and iv keys in reverse order + hop = m_Config->GetLastHop (); while (hop) { - hop->decryption.SetKeys (hop->layerKey, hop->ivKey); - hop = hop->next; + auto tunnelHop = new TunnelHop{ .ident = hop->ident }; + tunnelHop->decryption.SetKeys (hop->layerKey, hop->ivKey); + m_Hops.push_back (std::unique_ptr(tunnelHop)); + hop = hop->prev; } + m_Config = nullptr; } if (established) m_State = eTunnelStateEstablished; return established; @@ -144,13 +153,11 @@ namespace tunnel { const uint8_t * inPayload = in->GetPayload () + 4; uint8_t * outPayload = out->GetPayload () + 4; - TunnelHopConfig * hop = m_Config->GetLastHop (); - while (hop) - { - hop->decryption.Decrypt (inPayload, outPayload); - hop = hop->prev; + for (auto& it: m_Hops) + { + it->decryption.Decrypt (inPayload, outPayload); inPayload = outPayload; - } + } } void Tunnel::SendTunnelDataMsg (std::shared_ptr msg) @@ -158,6 +165,22 @@ namespace tunnel LogPrint (eLogInfo, "Can't send I2NP messages without delivery instructions"); } + std::vector > Tunnel::GetPeers () const + { + auto peers = GetInvertedPeers (); + std::reverse (peers.begin (), peers.end ()); + return peers; + } + + std::vector > Tunnel::GetInvertedPeers () const + { + // hops are in inverted order + std::vector > ret; + for (auto& it: m_Hops) + ret.push_back (it->ident); + return ret; + } + void InboundTunnel::HandleTunnelDataMsg (std::shared_ptr msg) { if (IsFailed ()) SetState (eTunnelStateEstablished); // incoming messages means a tunnel is alive @@ -167,6 +190,13 @@ namespace tunnel m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); } + void InboundTunnel::Print (std::stringstream& s) const + { + s << "-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID (); + s << "-->" << (GetNumHops () - 1) << " hops "; + s << GetTunnelID () << ":me"; + } + void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg) { TunnelMessageBlock block; @@ -202,6 +232,12 @@ namespace tunnel LogPrint (eLogError, "Incoming message for outbound tunnel ", GetTunnelID ()); } + void OutboundTunnel::Print (std::stringstream& s) const + { + s << "me-->" << i2p::data::GetIdentHashAbbreviation (GetNextIdentHash ()) << ":" << GetNextTunnelID (); + s << "-->" << (GetNumHops () - 1) << " hops-->"; + } + Tunnels tunnels; Tunnels::Tunnels (): m_IsRunning (false), m_Thread (nullptr), @@ -272,8 +308,8 @@ namespace tunnel std::shared_ptr Tunnels::GetNextOutboundTunnel () { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint32_t ind = rnd.GenerateWord32 (0, m_OutboundTunnels.size () - 1), i = 0; + if (!m_OutboundTunnels.size ()) return nullptr; + uint32_t ind = rand () % m_OutboundTunnels.size (), i = 0; std::shared_ptr tunnel; for (auto it: m_OutboundTunnels) { @@ -482,8 +518,12 @@ namespace tunnel auto hop = config->GetFirstHop (); while (hop) { - if (hop->router) - hop->router->GetProfile ()->TunnelNonReplied (); + if (hop->ident) + { + auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ()); + if (profile) + profile->TunnelNonReplied (); + } hop = hop->next; } } @@ -553,8 +593,8 @@ namespace tunnel if (!inboundTunnel || !router) return; LogPrint ("Creating one hop outbound tunnel..."); CreateTunnel ( - std::make_shared (std::vector > { router }, - inboundTunnel->GetTunnelConfig ()) + std::make_shared (std::vector > { router->GetRouterIdentity () }, + inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ()) ); } } @@ -609,7 +649,7 @@ namespace tunnel auto router = i2p::data::netdb.GetRandomRouter (); LogPrint ("Creating one hop inbound tunnel..."); CreateTunnel ( - std::make_shared (std::vector > { router }) + std::make_shared (std::vector > { router->GetRouterIdentity () }) ); } } @@ -662,7 +702,8 @@ namespace tunnel std::shared_ptr Tunnels::CreateTunnel (std::shared_ptr config, std::shared_ptr outboundTunnel) { auto newTunnel = std::make_shared (config); - uint32_t replyMsgID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); + uint32_t replyMsgID; + RAND_bytes ((uint8_t *)&replyMsgID, 4); AddPendingTunnel (replyMsgID, newTunnel); newTunnel->Build (replyMsgID, outboundTunnel); return newTunnel; @@ -695,7 +736,9 @@ namespace tunnel if (!pool) { // build symmetric outbound tunnel - CreateTunnel (newTunnel->GetTunnelConfig ()->Invert (), GetNextOutboundTunnel ()); + CreateTunnel (std::make_shared(newTunnel->GetInvertedPeers (), + newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()), + GetNextOutboundTunnel ()); } else { @@ -710,9 +753,9 @@ namespace tunnel void Tunnels::CreateZeroHopsInboundTunnel () { CreateTunnel ( - std::make_shared (std::vector > + std::make_shared (std::vector > { - i2p::context.GetSharedRouterInfo () + i2p::context.GetIdentity () })); } diff --git a/Tunnel.h b/Tunnel.h index e75de74b..20e02c1b 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -10,6 +10,7 @@ #include #include #include "Queue.h" +#include "Crypto.h" #include "TunnelConfig.h" #include "TunnelPool.h" #include "TransitTunnel.h" @@ -43,6 +44,12 @@ namespace tunnel class InboundTunnel; class Tunnel: public TunnelBase { + struct TunnelHop + { + std::shared_ptr ident; + i2p::crypto::TunnelDecryption decryption; + }; + public: Tunnel (std::shared_ptr config); @@ -51,8 +58,11 @@ namespace tunnel void Build (uint32_t replyMsgID, std::shared_ptr outboundTunnel = nullptr); std::shared_ptr GetTunnelConfig () const { return m_Config; } + std::vector > GetPeers () const; + std::vector > GetInvertedPeers () const; TunnelState GetState () const { return m_State; }; void SetState (TunnelState state) { m_State = state; }; + int GetNumHops () const { return m_Hops.size (); } bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsFailed () const { return m_State == eTunnelStateFailed; }; bool IsRecreated () const { return m_IsRecreated; }; @@ -66,12 +76,11 @@ namespace tunnel // implements TunnelBase void SendTunnelDataMsg (std::shared_ptr msg); void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out); - uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; }; - const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); }; - + private: std::shared_ptr m_Config; + std::vector > m_Hops; std::shared_ptr m_Pool; // pool, tunnel belongs to, or null TunnelState m_State; bool m_IsRecreated; @@ -81,22 +90,23 @@ namespace tunnel { public: - OutboundTunnel (std::shared_ptr config): Tunnel (config), m_Gateway (this) {}; + OutboundTunnel (std::shared_ptr config): + Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr msg); void SendTunnelDataMsg (const std::vector& msgs); // multiple messages - std::shared_ptr GetEndpointRouter () const - { return GetTunnelConfig ()->GetLastHop ()->router; }; + const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; - + void Print (std::stringstream& s) const; + // implements TunnelBase void HandleTunnelDataMsg (std::shared_ptr tunnelMsg); - uint32_t GetTunnelID () const { return GetNextTunnelID (); }; private: std::mutex m_SendMutex; TunnelGateway m_Gateway; + i2p::data::IdentHash m_EndpointIdentHash; }; class InboundTunnel: public Tunnel, public std::enable_shared_from_this @@ -106,9 +116,8 @@ namespace tunnel InboundTunnel (std::shared_ptr config): Tunnel (config), m_Endpoint (true) {}; void HandleTunnelDataMsg (std::shared_ptr msg); size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; - - // implements TunnelBase - uint32_t GetTunnelID () const { return GetTunnelConfig ()->GetLastHop ()->nextTunnelID; }; + void Print (std::stringstream& s) const; + private: TunnelEndpoint m_Endpoint; diff --git a/TunnelBase.h b/TunnelBase.h index 76175d0a..bec06400 100644 --- a/TunnelBase.h +++ b/TunnelBase.h @@ -33,23 +33,26 @@ namespace tunnel { public: - //WARNING!!! GetSecondsSinceEpoch() return uint64_t - TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; + TunnelBase (uint32_t tunnelID, uint32_t nextTunnelID, i2p::data::IdentHash nextIdent): + m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent), + m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; virtual ~TunnelBase () {}; virtual void HandleTunnelDataMsg (std::shared_ptr tunnelMsg) = 0; virtual void SendTunnelDataMsg (std::shared_ptr msg) = 0; virtual void FlushTunnelDataMsgs () {}; virtual void EncryptTunnelMsg (std::shared_ptr in, std::shared_ptr out) = 0; - virtual uint32_t GetNextTunnelID () const = 0; - virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0; - virtual uint32_t GetTunnelID () const = 0; // as known at our side + uint32_t GetNextTunnelID () const { return m_NextTunnelID; }; + const i2p::data::IdentHash& GetNextIdentHash () const { return m_NextIdent; }; + virtual uint32_t GetTunnelID () const { return m_TunnelID; }; // as known at our side uint32_t GetCreationTime () const { return m_CreationTime; }; void SetCreationTime (uint32_t t) { m_CreationTime = t; }; private: - + + uint32_t m_TunnelID, m_NextTunnelID; + i2p::data::IdentHash m_NextIdent; uint32_t m_CreationTime; // seconds since epoch }; diff --git a/TunnelConfig.h b/TunnelConfig.h index d9827fe8..d2164d86 100644 --- a/TunnelConfig.h +++ b/TunnelConfig.h @@ -5,8 +5,9 @@ #include #include #include -#include "aes.h" -#include "RouterInfo.h" +#include +#include "Crypto.h" +#include "Identity.h" #include "RouterContext.h" #include "Timestamp.h" @@ -16,7 +17,8 @@ namespace tunnel { struct TunnelHopConfig { - std::shared_ptr router, nextRouter; + std::shared_ptr ident; + i2p::data::IdentHash nextIdent; uint32_t tunnelID, nextTunnelID; uint8_t layerKey[32]; uint8_t ivKey[32]; @@ -25,19 +27,17 @@ namespace tunnel bool isGateway, isEndpoint; TunnelHopConfig * next, * prev; - i2p::crypto::TunnelDecryption decryption; int recordIndex; // record # in tunnel build message - TunnelHopConfig (std::shared_ptr r) + TunnelHopConfig (std::shared_ptr r) { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (layerKey, 32); - rnd.GenerateBlock (ivKey, 32); - rnd.GenerateBlock (replyIV, 16); - tunnelID = rnd.GenerateWord32 (); + RAND_bytes (layerKey, 32); + RAND_bytes (ivKey, 32); + RAND_bytes (replyIV, 16); + RAND_bytes ((uint8_t *)&tunnelID, 4); isGateway = true; isEndpoint = true; - router = r; + ident = r; //nextRouter = nullptr; nextTunnelID = 0; @@ -45,18 +45,17 @@ namespace tunnel prev = nullptr; } - void SetNextRouter (std::shared_ptr r) + void SetNextIdent (const i2p::data::IdentHash& ident) { - nextRouter = r; + nextIdent = ident; isEndpoint = false; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - nextTunnelID = rnd.GenerateWord32 (); + RAND_bytes ((uint8_t *)&nextTunnelID, 4); } - void SetReplyHop (const TunnelHopConfig * replyFirstHop) + void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) { - nextRouter = replyFirstHop->router; - nextTunnelID = replyFirstHop->tunnelID; + nextIdent = replyIdent; + nextTunnelID = replyTunnelID; isEndpoint = true; } @@ -68,7 +67,7 @@ namespace tunnel next->prev = this; next->isGateway = false; isEndpoint = false; - nextRouter = next->router; + nextIdent = next->ident->GetIdentHash (); nextTunnelID = next->tunnelID; } } @@ -88,9 +87,9 @@ namespace tunnel { uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); - memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, router->GetIdentHash (), 32); + memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, ident->GetIdentHash (), 32); htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID); - memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextRouter->GetIdentHash (), 32); + memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32); memcpy (clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, layerKey, 32); memcpy (clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, ivKey, 32); memcpy (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET, replyKey, 32); @@ -102,8 +101,9 @@ namespace tunnel htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ()); htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID); // TODO: fill padding - router->GetElGamalEncryption ()->Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET); - memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)router->GetIdentHash (), 16); + i2p::crypto::ElGamalEncryption elGamalEncryption (ident->GetEncryptionPublicKey ()); + elGamalEncryption.Encrypt (clearText, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET); + memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); } }; @@ -111,29 +111,18 @@ namespace tunnel { public: + TunnelConfig (std::vector > peers) // inbound + { + CreatePeers (peers); + m_LastHop->SetNextIdent (i2p::context.GetIdentHash ()); + } - TunnelConfig (std::vector > peers, - std::shared_ptr replyTunnelConfig = nullptr) // replyTunnelConfig=nullptr means inbound + TunnelConfig (std::vector > peers, + uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) // outbound { - TunnelHopConfig * prev = nullptr; - for (auto it: peers) - { - auto hop = new TunnelHopConfig (it); - if (prev) - prev->SetNext (hop); - else - m_FirstHop = hop; - prev = hop; - } - m_LastHop = prev; - - if (replyTunnelConfig) // outbound - { - m_FirstHop->isGateway = false; - m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); - } - else // inbound - m_LastHop->SetNextRouter (i2p::context.GetSharedRouterInfo ()); + CreatePeers (peers); + m_FirstHop->isGateway = false; + m_LastHop->SetReplyHop (replyTunnelID, replyIdent); } ~TunnelConfig () @@ -172,13 +161,35 @@ namespace tunnel bool IsInbound () const { return m_FirstHop->isGateway; } - std::vector > GetPeers () const + uint32_t GetTunnelID () const + { + if (!m_FirstHop) return 0; + return IsInbound () ? m_LastHop->nextTunnelID : m_FirstHop->tunnelID; + } + + uint32_t GetNextTunnelID () const + { + if (!m_FirstHop) return 0; + return m_FirstHop->tunnelID; + } + + const i2p::data::IdentHash& GetNextIdentHash () const + { + return m_FirstHop->ident->GetIdentHash (); + } + + const i2p::data::IdentHash& GetLastIdentHash () const + { + return m_LastHop->ident->GetIdentHash (); + } + + std::vector > GetPeers () const { - std::vector > peers; + std::vector > peers; TunnelHopConfig * hop = m_FirstHop; while (hop) { - peers.push_back (hop->router); + peers.push_back (hop->ident); hop = hop->next; } return peers; @@ -192,7 +203,7 @@ namespace tunnel s << "-->" << m_FirstHop->tunnelID; while (hop) { - s << ":" << hop->router->GetIdentHashAbbreviation () << "-->"; + s << ":" << GetIdentHashAbbreviation (hop->ident->GetIdentHash ()) << "-->"; if (!hop->isEndpoint) s << hop->nextTunnelID; else @@ -202,19 +213,6 @@ namespace tunnel // we didn't reach enpoint that mean we are last hop s << ":me"; } - - std::shared_ptr Invert () const - { - auto peers = GetPeers (); - std::reverse (peers.begin (), peers.end ()); - // we use ourself as reply tunnel for outbound tunnel - return IsInbound () ? std::make_shared(peers, shared_from_this ()) : std::make_shared(peers); - } - - std::shared_ptr Clone (std::shared_ptr replyTunnelConfig = nullptr) const - { - return std::make_shared (GetPeers (), replyTunnelConfig); - } private: @@ -222,6 +220,22 @@ namespace tunnel TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr) { } + + template + void CreatePeers (const Peers& peers) + { + TunnelHopConfig * prev = nullptr; + for (auto it: peers) + { + auto hop = new TunnelHopConfig (it); + if (prev) + prev->SetNext (hop); + else + m_FirstHop = hop; + prev = hop; + } + m_LastHop = prev; + } private: diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index 9d1425e1..fe161652 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -1,5 +1,6 @@ #include "I2PEndian.h" #include +#include #include "Log.h" #include "NetDb.h" #include "I2NPProtocol.h" @@ -27,7 +28,7 @@ namespace tunnel // verify checksum memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest (hash, fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16); // payload + iv + SHA256(fragment, TUNNEL_DATA_MSG_SIZE -(fragment - msg->GetPayload ()) + 16, hash); // payload + iv if (memcmp (hash, decrypted, 4)) { LogPrint (eLogError, "TunnelMessage: checksum verification failed"); diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index b05a342c..adc1bef6 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -1,6 +1,7 @@ #include +#include +#include #include "I2PEndian.h" -#include #include "Log.h" #include "RouterContext.h" #include "Transports.h" @@ -13,7 +14,7 @@ namespace tunnel TunnelGatewayBuffer::TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) { - context.GetRandomNumberGenerator ().GenerateBlock (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); + RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++) if (!m_NonZeroRandomBuffer[i]) m_NonZeroRandomBuffer[i] = 1; } @@ -159,18 +160,17 @@ namespace tunnel m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE; uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload (); htobe32buf (buf, m_TunnelID); - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (buf + 4, 16); // original IV + RAND_bytes (buf + 4, 16); // original IV memcpy (payload + size, buf + 4, 16); // copy IV for checksum uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest (hash, payload, size+16); + SHA256(payload, size+16, hash); memcpy (buf+20, hash, 4); // checksum payload[-1] = 0; // zero ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 if (paddingSize > 0) { // non-zero padding - auto randomOffset = rnd.GenerateWord32 (0, TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize); + auto randomOffset = rand () % (TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize + 1); memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize); } diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 0f0eb709..922ae34b 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -1,11 +1,13 @@ #include +#include #include "I2PEndian.h" -#include "CryptoConst.h" +#include "Crypto.h" #include "Tunnel.h" #include "NetDb.h" #include "Timestamp.h" #include "Garlic.h" #include "Transports.h" +#include "Log.h" #include "TunnelPool.h" namespace i2p @@ -141,8 +143,7 @@ namespace tunnel typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const { if (tunnels.empty ()) return nullptr; - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint32_t ind = rnd.GenerateWord32 (0, tunnels.size ()/2), i = 0; + uint32_t ind = rand () % (tunnels.size ()/2 + 1), i = 0; typename TTunnels::value_type tunnel = nullptr; for (auto it: tunnels) { @@ -165,7 +166,7 @@ namespace tunnel { std::unique_lock l(m_OutboundTunnelsMutex); for (auto it: m_OutboundTunnels) - if (it->IsEstablished () && old->GetEndpointRouter ()->GetIdentHash () == it->GetEndpointRouter ()->GetIdentHash ()) + if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ()) { tunnel = it; break; @@ -200,7 +201,6 @@ namespace tunnel void TunnelPool::TestTunnels () { - auto& rnd = i2p::context.GetRandomNumberGenerator (); for (auto it: m_Tests) { LogPrint ("Tunnel test ", (int)it.first, " failed"); @@ -251,7 +251,8 @@ namespace tunnel } if (!failed) { - uint32_t msgID = rnd.GenerateWord32 (); + uint32_t msgID; + RAND_bytes ((uint8_t *)&msgID, 4); m_Tests[msgID] = std::make_pair (*it1, *it2); (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), CreateDeliveryStatusMsg (msgID)); @@ -306,9 +307,9 @@ namespace tunnel return hop; } - bool TunnelPool::SelectPeers (std::vector >& hops, bool isInbound) + bool TunnelPool::SelectPeers (std::vector >& peers, bool isInbound) { - if (m_ExplicitPeers) return SelectExplicitPeers (hops, isInbound); + if (m_ExplicitPeers) return SelectExplicitPeers (peers, isInbound); auto prevHop = i2p::context.GetSharedRouterInfo (); int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; if (i2p::transport::transports.GetNumPeers () > 25) @@ -317,7 +318,7 @@ namespace tunnel if (r && !r->GetProfile ()->IsBad ()) { prevHop = r; - hops.push_back (r); + peers.push_back (r->GetRouterIdentity ()); numHops--; } } @@ -331,12 +332,12 @@ namespace tunnel return false; } prevHop = hop; - hops.push_back (hop); + peers.push_back (hop->GetRouterIdentity ()); } return true; } - bool TunnelPool::SelectExplicitPeers (std::vector >& hops, bool isInbound) + bool TunnelPool::SelectExplicitPeers (std::vector >& peers, bool isInbound) { int size = m_ExplicitPeers->size (); std::vector peerIndicies; @@ -349,7 +350,7 @@ namespace tunnel auto& ident = (*m_ExplicitPeers)[peerIndicies[i]]; auto r = i2p::data::netdb.FindRouter (ident); if (r) - hops.push_back (r); + peers.push_back (r->GetRouterIdentity ()); else { LogPrint (eLogInfo, "Can't find router for ", ident.ToBase64 ()); @@ -366,11 +367,11 @@ namespace tunnel if (!outboundTunnel) outboundTunnel = tunnels.GetNextOutboundTunnel (); LogPrint ("Creating destination inbound tunnel..."); - std::vector > hops; - if (SelectPeers (hops, true)) + std::vector > peers; + if (SelectPeers (peers, true)) { - std::reverse (hops.begin (), hops.end ()); - auto tunnel = tunnels.CreateTunnel (std::make_shared (hops), outboundTunnel); + std::reverse (peers.begin (), peers.end ()); + auto tunnel = tunnels.CreateTunnel (std::make_shared (peers), outboundTunnel); tunnel->SetTunnelPool (shared_from_this ()); } else @@ -383,7 +384,7 @@ namespace tunnel if (!outboundTunnel) outboundTunnel = tunnels.GetNextOutboundTunnel (); LogPrint ("Re-creating destination inbound tunnel..."); - auto newTunnel = tunnels.CreateTunnel (tunnel->GetTunnelConfig ()->Clone (), outboundTunnel); + auto newTunnel = tunnels.CreateTunnel (std::make_shared(tunnel->GetPeers ()), outboundTunnel); newTunnel->SetTunnelPool (shared_from_this()); } @@ -395,11 +396,11 @@ namespace tunnel if (inboundTunnel) { LogPrint ("Creating destination outbound tunnel..."); - std::vector > hops; - if (SelectPeers (hops, false)) + std::vector > peers; + if (SelectPeers (peers, false)) { auto tunnel = tunnels.CreateTunnel ( - std::make_shared (hops, inboundTunnel->GetTunnelConfig ())); + std::make_shared (peers, inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())); tunnel->SetTunnelPool (shared_from_this ()); } else @@ -418,7 +419,8 @@ namespace tunnel { LogPrint ("Re-creating destination outbound tunnel..."); auto newTunnel = tunnels.CreateTunnel ( - tunnel->GetTunnelConfig ()->Clone (inboundTunnel->GetTunnelConfig ())); + std::make_shared (tunnel->GetPeers (), + inboundTunnel->GetNextTunnelID (), inboundTunnel->GetNextIdentHash ())); newTunnel->SetTunnelPool (shared_from_this ()); } else @@ -428,7 +430,7 @@ namespace tunnel void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr outboundTunnel) { LogPrint (eLogInfo, "Creating paired inbound tunnel..."); - auto tunnel = tunnels.CreateTunnel (outboundTunnel->GetTunnelConfig ()->Invert (), outboundTunnel); + auto tunnel = tunnels.CreateTunnel (std::make_shared(outboundTunnel->GetInvertedPeers ()), outboundTunnel); tunnel->SetTunnelPool (shared_from_this ()); } } diff --git a/TunnelPool.h b/TunnelPool.h index 2d4203ef..a836162f 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -62,8 +62,8 @@ namespace tunnel template typename TTunnels::value_type GetNextTunnel (TTunnels& tunnels, typename TTunnels::value_type excluded) const; std::shared_ptr SelectNextHop (std::shared_ptr prevHop) const; - bool SelectPeers (std::vector >& hops, bool isInbound); - bool SelectExplicitPeers (std::vector >& hops, bool isInbound); + bool SelectPeers (std::vector >& hops, bool isInbound); + bool SelectExplicitPeers (std::vector >& hops, bool isInbound); private: diff --git a/api.cpp b/api.cpp index 6f3c8c4c..eb64309a 100644 --- a/api.cpp +++ b/api.cpp @@ -26,7 +26,7 @@ namespace api if (logStream) StartLog (logStream); else - StartLog (i2p::util::filesystem::GetAppName () + ".log"); + StartLog (i2p::util::filesystem::GetFullPath (i2p::util::filesystem::GetAppName () + ".log")); i2p::data::netdb.Start(); LogPrint("NetDB started"); i2p::transport::transports.Start(); @@ -47,39 +47,41 @@ namespace api StopLog (); } - i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, + void RunPeerTest () + { + i2p::transport::transports.PeerTest (); + } + + std::shared_ptr CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, const std::map * params) { - auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); localDestination->Start (); return localDestination; } - i2p::client::ClientDestination * CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, + std::shared_ptr CreateLocalDestination (bool isPublic, i2p::data::SigningKeyType sigType, const std::map * params) { i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType); - auto localDestination = new i2p::client::ClientDestination (keys, isPublic, params); + auto localDestination = std::make_shared (keys, isPublic, params); localDestination->Start (); return localDestination; } - void DestroyLocalDestination (i2p::client::ClientDestination * dest) + void DestroyLocalDestination (std::shared_ptr dest) { if (dest) - { dest->Stop (); - delete dest; - } } - void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote) + void RequestLeaseSet (std::shared_ptr dest, const i2p::data::IdentHash& remote) { if (dest) dest->RequestDestination (remote); } - std::shared_ptr CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote) + std::shared_ptr CreateStream (std::shared_ptr dest, const i2p::data::IdentHash& remote) { if (!dest) return nullptr; auto leaseSet = dest->FindLeaseSet (remote); @@ -96,7 +98,7 @@ namespace api } } - void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor) + void AcceptStream (std::shared_ptr dest, const i2p::stream::StreamingDestination::Acceptor& acceptor) { if (dest) dest->AcceptStreams (acceptor); diff --git a/api.h b/api.h index 894aff49..d34f8ae4 100644 --- a/api.h +++ b/api.h @@ -16,18 +16,19 @@ namespace api void StartI2P (std::ostream * logStream = nullptr); // write system log to logStream, if not specified to .log in application's folder void StopI2P (); - + void RunPeerTest (); // should be called after UPnP + // destinations - i2p::client::ClientDestination * CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, + std::shared_ptr CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, const std::map * params = nullptr); - i2p::client::ClientDestination * CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256, + std::shared_ptr CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256, const std::map * params = nullptr); // transient destinations usually not published - void DestroyLocalDestination (i2p::client::ClientDestination * dest); + void DestroyLocalDestination (std::shared_ptr dest); // streams - void RequestLeaseSet (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote); - std::shared_ptr CreateStream (i2p::client::ClientDestination * dest, const i2p::data::IdentHash& remote); - void AcceptStream (i2p::client::ClientDestination * dest, const i2p::stream::StreamingDestination::Acceptor& acceptor); + void RequestLeaseSet (std::shared_ptr dest, const i2p::data::IdentHash& remote); + std::shared_ptr CreateStream (std::shared_ptr dest, const i2p::data::IdentHash& remote); + void AcceptStream (std::shared_ptr dest, const i2p::stream::StreamingDestination::Acceptor& acceptor); void DestroyStream (std::shared_ptr stream); } } diff --git a/base64.h b/base64.h deleted file mode 100644 index c0ce1495..00000000 --- a/base64.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BASE64_H -#define BASE64_H - -#include -#include - -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 * 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); -} -} - -#endif - diff --git a/contrib/certificates/reseed/parg_at_mail.i2p.crt b/contrib/certificates/reseed/parg_at_mail.i2p.crt new file mode 100644 index 00000000..e78b264c --- /dev/null +++ b/contrib/certificates/reseed/parg_at_mail.i2p.crt @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF1TCCA7+gAwIBAgIRAPmuHtSxMcNIUXNc0N4+7RIwCwYJKoZIhvcNAQELMG0x +CzAJBgNVBAYTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAK +BgNVBAsTA0kyUDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMRYwFAYDVQQDDA1w +YXJnQG1haWwuaTJwMB4XDTE1MDUxOTIwMjExM1oXDTI1MDUxOTIwMjExM1owbTEL +MAkGA1UEBhMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoG +A1UECxMDSTJQMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxFjAUBgNVBAMMDXBh +cmdAbWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/jINR +maFCnuCZwofrhtJoneIuJn6kauYYfjPF/nRrPffiooX2vo0Tp6cpTAulMul0Nh2I +/trJSbBqzneg+0zDS2wpLb1U7FJ5WGqb+yk7eo8X+Upjsuu4JoFr6ap81+J5oFBR +zTyYba6TYYwAZoBXAkY3qMjbfbYkqceY/p5WqAhEO7N4/DVLRA42FsQQMFwJYHnD +SgcyrTXiBbWJzvEF/4LSpL2CXB3Efkti/1MggVhXBu83PSkPvYQQTGFmwKP+ivVZ +V339xNGGKqPd+B1LOI8xUEAGGbOgfdB3c/x8weOwRip6bp+0SfLcVHO9X1lD95SA +dvtz2qABWDhqcMTyfJIEuOQSpQO6DhhBViHR2cjcu+z5Ugf+X6ZWhtFMBJsLb0Um +R3gKhPaMizCYVW6uRyA1B5SnO3Pd1ve1qX+K1h+NZPXoMpBxmyg+ds/WuhmAZUEB +bzUr7DczImb29WlBFCbYjA/fBN8QOc2qZpQFckY4CrBhCmFevxSpwHOxSkVEeXet +tYZ2BZIxN+I5p5SZc+6Ba1O3hqJsqv4D8H4TqXYZaw50ySRYIl9LDAEYp7owZzwA +oMxmjnsZBVtkGZpKk/RColQVLT/xmUqDJPQlWRw2te7tr1LiH2ZkVu7TUuhIep+i +4U8H4S9+zNQEAyn87L589AsGQ9hRtwrUOqy1ywIDAQABo3QwcjAOBgNVHQ8BAf8E +BAMCAIQwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA8GA1UdEwEB/wQF +MAMBAf8wFgYDVR0OBA8EDXBhcmdAbWFpbC5pMnAwGAYDVR0jBBEwD4ANcGFyZ0Bt +YWlsLmkycDALBgkqhkiG9w0BAQsDggIBAGaVJunmmO0EfDuTAN8Psjq7YVwwSyMk +6h1dMHz/U1GwY/jjKIIyfzKh6SfZmBfQT5fnGLM84m1O0267s9PZpHFcw9Kn+KQ4 +YkfzVaYgsADjeyqQ1XIHJ/CZ60BWCs9aqWgYoTscbTtadaGscFBTegispkt8+Mj6 +aaEQnajCD4f2GFHEi0miG+gRu6MDgqG2ka5tg3j+zfSDiq5lclq5qS97Lu/EVLRr +HlLKBDPnLKeGYnPOAlzTNqwWtvLho7jIFHt7DP1Qzn3nvDoOQb40ToHCAAcMr9jy +ncS6Eo4veeWeaSIGMnaDuzZoTWadizZo1G9z3ADMXRJ5IxdLKbBZiSkCHuAMnDSe +NKREmXewzjtRQBgf7RkyU0JwIqTKJsLTMX8oLecyvZHunmuKkqpJ/AgIyRB2X/nz +/LFeg4cru20Q+mpzVBnZPCS6X45jbew14ajURRgp4MrX52Ph+9/mS4RVQhHL+GDU +4OwF6tkqFD0umw1Gn1CAvKPOn9EVHa7nLDYxPo9LEX7Dnb5WkwKDqtALrcMDYjJr +4TqJFbsijYehVn+kFQ4I4aN54ECzwu9RKmebrXyDDe0e0fErRsF5+qII8/wOo4WT +XUjHCvK6THeaC8k5jcostgVszIx7rwqXj1ailbV/nAFr8NgADs04//5DJA0ieD+4 +N1tGWBZt9Prq +-----END CERTIFICATE----- diff --git a/contrib/certificates/reseed/sindu_at_mail.i2p.crt b/contrib/certificates/reseed/sindu_at_mail.i2p.crt deleted file mode 100644 index be1010f9..00000000 --- a/contrib/certificates/reseed/sindu_at_mail.i2p.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFezCCA2OgAwIBAgIEPSs1SjANBgkqhkiG9w0BAQ0FADBuMQswCQYDVQQGEwJY -WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc2luZHVAbWFpbC5p -MnAwHhcNMTQwNzIxMDAwNjUwWhcNMjQwNzIwMDAwNjUwWjBuMQswCQYDVQQGEwJY -WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEXMBUGA1UEAwwOc2luZHVAbWFpbC5p -MnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnYMNclgj1gIJfot6f -65jbcXpcqf9hhL/uYiU4+uxVevWyJvNHpMzhPWNN4l3HihJJsINsPs/MsZ83Guva -GW5S/93I617kyjs/ZVpEtfABGewho0m9VCBV2/N1mJpHvvR+9OR+YVuWlTB/8sTG -2smdRj/dkKvewN5PSTQH350yT18NR/DmZUU1Iwa7vrNw8ol3rP3qx9UGpFN3JE7V -Q9cA1nktMiFUm76eOPOoln04WDqW2rvArXzvhSApvt0JsLBrZDzM3cx2Rc2UdjIC -h+Ha+G4CLjszfZfQAFJYPred38Gg6wuXiza/wCBSPiB92i94hIQF/OSeukaMiqwG -dRAcBT84/U9bddqHlIICw14PkNHOGUyJGjGKWQl/2bLX43ghWkUJmsTXS3iVcOTc -gb/7MoCRBdL0q2GyEJXuAoKXD9VqD3g+EdcBTQxS9lhZ0iTR7423pg6FP43VMEUC -HUi/BOX1tCY6iRzD1Su6ISIx7klH/sAWWa+SybLFXWtZJxHXXJICiBHJWRbWgtlu -5V+at66yg/LNpyfW3Am08gDV0kiWUBN2Ct4TX9PAQmNDisNgi2AzdZHIfX6tRpU8 -UnNcnZGOh4+HXQwJtI0y83C8TsXJUFYfGFWqXN69sMEmgtX8/w+YUqjtb2GcX1HN -6z9u9lH40JCFHTA/clPqOSQ+MQIDAQABoyEwHzAdBgNVHQ4EFgQU4R6x7ArVpSVs -b8VTBXmodXzyraEwDQYJKoZIhvcNAQENBQADggIBAJEHLSDBRU2x6EalmN2W952p -MEO5lGD+ZfUVK0c44t1O53naffwZx9QmDmrC4TjeQrLOpAXLQ8GJHAGeZVmYRgkf -OioKde5uuqVcxqNxArO8VyYGwsuNVPCaBV+SyIO+EmWogidSIrOP2WsRRS2NBhLV -2dp3TvMeod9bPwRl00guvv9iqL0UVSpQSlfGkAQTVpyADOaQHOzeoCpmtPOfB6OK -syB/Z/6HElKoUbvhynaASLgmo3wM93PVJQ2Ho294bQHtDl2qcOksJQvWfCgi7Zrt -KuHaM/a2kItzI6JmyNFXgsKQSDJ4UvoppppgD7K48zOtSipGuZAADC5w5HdVvIGJ -1Czva8kTcmC6AMc+4tACGqYZEAEokkeXn+pIIqKVj2eQukT/0dLGGHbKmxp3Z0f2 -pIH2Draq8JPdacr9P/xqEWUuViaOuC5OBjY8Fg3fmVCpwefIuk+DBhbJjEugB0Cu -brJpqNznoYahkbyAXIA8T+QJYMhoGWmaIcaPWK6K3nArvaxzwJbb9Egyivhyp9Rr -r2QMEZ+cPO8p1mEhKpL/wGqAzYyla8SJ06PzLc1lQeGiClu1nbZj5AgkZ1DLa8SD -iO7+e6rS0q1bzc7smE5JzZRiOVqKij/ReKa2uebLLI4wgAhz5ymaD1HfZY+3dV9T -WX89Xn2UyQf5kHifiDKL ------END CERTIFICATE----- diff --git a/filelist.mk b/filelist.mk index 623a1b33..f040183f 100644 --- a/filelist.mk +++ b/filelist.mk @@ -1,25 +1,16 @@ -COMMON_SRC = \ - CryptoConst.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ +LIB_SRC = \ + Crypto.cpp Datagram.cpp Garlic.cpp I2NPProtocol.cpp LeaseSet.cpp \ Log.cpp NTCPSession.cpp NetDb.cpp NetDbRequests.cpp Profiling.cpp \ Reseed.cpp RouterContext.cpp RouterInfo.cpp Signature.cpp SSU.cpp \ SSUSession.cpp SSUData.cpp Streaming.cpp Identity.cpp TransitTunnel.cpp \ Transports.cpp Tunnel.cpp TunnelEndpoint.cpp TunnelPool.cpp TunnelGateway.cpp \ - Destination.cpp UPnP.cpp util.cpp aes.cpp base64.cpp - - -ifeq ($(UNAME),Darwin) -# This is needed on OS X for some reason I don't understand (yet). -# Else will get linker error about unknown symbols. - torkel - COMMON_SRC += \ - AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp SAM.cpp SOCKS.cpp \ - UPnP.cpp HTTPServer.cpp HTTPProxy.cpp i2p.cpp DaemonLinux.cpp I2PControl.cpp -endif + Destination.cpp Base.cpp util.cpp api.cpp +LIB_CLIENT_SRC = \ + AddressBook.cpp BOB.cpp ClientContext.cpp I2PTunnel.cpp I2PService.cpp \ + SAM.cpp SOCKS.cpp HTTPProxy.cpp # also: Daemon{Linux,Win32}.cpp will be added later -DAEMON_SRC = $(COMMON_SRC) \ - AddressBook.cpp BOB.cpp ClientContext.cpp Daemon.cpp I2PTunnel.cpp I2PService.cpp \ - SAM.cpp SOCKS.cpp HTTPServer.cpp HTTPProxy.cpp I2PControl.cpp i2p.cpp +DAEMON_SRC = \ + HTTPServer.cpp I2PControl.cpp UPnP.cpp Daemon.cpp i2pd.cpp -LIB_SRC := $(COMMON_SRC) \ - api.cpp diff --git a/hmac.h b/hmac.h deleted file mode 100644 index 0b76ceee..00000000 --- a/hmac.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef HMAC_H__ -#define HMAC_H__ - -#include -#include -#define CRYPTOPP_ENABLE_NAMESPACE_WEAK 1 -#include -#include "Identity.h" - -namespace i2p -{ -namespace crypto -{ - const uint64_t IPAD = 0x3636363636363636; - const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; - - typedef i2p::data::Tag<32> MACKey; - - inline void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest) - // key is 32 bytes - // digest is 16 bytes - // block size is 64 bytes - { - uint64_t buf[256]; - // ikeypad - buf[0] = key.GetLL ()[0] ^ IPAD; - buf[1] = key.GetLL ()[1] ^ IPAD; - buf[2] = key.GetLL ()[2] ^ IPAD; - buf[3] = key.GetLL ()[3] ^ IPAD; - buf[4] = IPAD; - buf[5] = IPAD; - buf[6] = IPAD; - buf[7] = IPAD; - // concatenate with msg - memcpy (buf + 8, msg, len); - // calculate first hash - uint8_t hash[16]; // MD5 - CryptoPP::Weak1::MD5().CalculateDigest (hash, (uint8_t *)buf, len + 64); - - // okeypad - buf[0] = key.GetLL ()[0] ^ OPAD; - buf[1] = key.GetLL ()[1] ^ OPAD; - buf[2] = key.GetLL ()[2] ^ OPAD; - buf[3] = key.GetLL ()[3] ^ OPAD; - buf[4] = OPAD; - buf[5] = OPAD; - buf[6] = OPAD; - buf[7] = OPAD; - // copy first hash after okeypad - memcpy (buf + 8, hash, 16); - // fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P) - memset (buf + 10, 0, 16); - - // calculate digest - CryptoPP::Weak1::MD5().CalculateDigest (digest, (uint8_t *)buf, 96); - } -} -} - -#endif - diff --git a/i2p.cpp b/i2pd.cpp similarity index 80% rename from i2p.cpp rename to i2pd.cpp index 25fe29b0..32749d16 100644 --- a/i2p.cpp +++ b/i2pd.cpp @@ -1,7 +1,6 @@ #include #include #include "Daemon.h" -#include "Reseed.h" int main( int argc, char* argv[] ) { @@ -10,10 +9,10 @@ int main( int argc, char* argv[] ) { while (Daemon.running) { - //TODO Meeh: Find something better to do here. std::this_thread::sleep_for (std::chrono::seconds(1)); } } Daemon.stop(); return EXIT_SUCCESS; } + diff --git a/version.h b/version.h index bdff9c2e..141664b5 100644 --- a/version.h +++ b/version.h @@ -2,7 +2,7 @@ #define _VERSION_H_ #define CODENAME "Purple" -#define VERSION "0.10.0" -#define I2P_VERSION "0.9.20" +#define VERSION "2.0.0" +#define I2P_VERSION "0.9.22" #endif