Browse Source

Merge pull request #5 from orignal/master

Merge pull request from orignal/master
pull/77/head
chertov 10 years ago
parent
commit
68a08c2237
  1. 66
      CryptoConst.cpp
  2. 62
      CryptoConst.h
  3. 9
      Daemon.cpp
  4. 4
      Daemon.h
  5. 32
      Garlic.cpp
  6. 12
      Garlic.h
  7. 5
      HTTPServer.cpp
  8. 93
      I2NPProtocol.cpp
  9. 6
      I2NPProtocol.h
  10. 23
      I2PEndian.h
  11. 15
      Identity.cpp
  12. 13
      Identity.h
  13. 23
      Log.cpp
  14. 14
      Log.h
  15. 13
      Makefile
  16. 43
      Makefile.osx
  17. 30
      NTCPSession.cpp
  18. 5
      NTCPSession.h
  19. 42
      NetDb.cpp
  20. 10
      NetDb.h
  21. 3
      RouterInfo.cpp
  22. 5
      RouterInfo.h
  23. 205
      SSU.cpp
  24. 40
      SSU.h
  25. 95
      SSUData.cpp
  26. 8
      SSUData.h
  27. 9
      Streaming.cpp
  28. 14
      TransitTunnel.cpp
  29. 8
      TransitTunnel.h
  30. 83
      Tunnel.cpp
  31. 13
      Tunnel.h
  32. 9
      TunnelConfig.h
  33. 19
      TunnelEndpoint.cpp
  34. 7
      TunnelEndpoint.h
  35. 23
      TunnelPool.cpp
  36. 4
      TunnelPool.h
  37. 357
      aes.cpp
  38. 188
      aes.h
  39. 44
      hmac.h
  40. 2
      i2p.cpp

66
CryptoConst.cpp

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
#include <inttypes.h>
#include "CryptoConst.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
};
const CryptoPP::Integer elgp (elgp_, 256);
const CryptoPP::Integer 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 CryptoPP::Integer dsap (dsap_, 128);
const CryptoPP::Integer dsaq (dsaq_, 20);
const CryptoPP::Integer dsag (dsag_, 128);
}
}

62
CryptoConst.h

@ -8,66 +8,14 @@ namespace i2p @@ -8,66 +8,14 @@ namespace i2p
namespace crypto
{
// DH
extern const CryptoPP::Integer elgp;
extern const CryptoPP::Integer elgg;
inline const CryptoPP::Integer& get_elgp ()
{
static const CryptoPP::Integer elgp_ (
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
"83655D23DCA3AD961C62F356208552BB9ED529077096966D"
"670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
"E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
"DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
"15728E5A8AACAA68FFFFFFFFFFFFFFFF"
"h");
return elgp_;
}
#define elgp get_elgp()
inline const CryptoPP::Integer& get_elgg ()
{
static const CryptoPP::Integer elgg_ (2);
return elgg_;
}
#define elgg get_elgg()
// DSA
inline const CryptoPP::Integer& get_dsap ()
{
static const CryptoPP::Integer dsap_ (
"9c05b2aa960d9b97b8931963c9cc9e8c3026e9b8ed92fad0a69cc886d5bf8015fcadae31"
"a0ad18fab3f01b00a358de237655c4964afaa2b337e96ad316b9fb1cc564b5aec5b69a9f"
"f6c3e4548707fef8503d91dd8602e867e6d35d2235c1869ce2479c3b9d5401de04e0727f"
"b33d6511285d4cf29538d9e3b6051f5b22cc1c93"
"h");
return dsap_;
}
#define dsap get_dsap()
inline const CryptoPP::Integer& get_dsaq ()
{
static const CryptoPP::Integer dsaq_ (
"a5dfc28fef4ca1e286744cd8eed9d29d684046b7"
"h");
return dsaq_;
}
#define dsaq get_dsaq()
inline const CryptoPP::Integer& get_dsag ()
{
static const CryptoPP::Integer dsag_ (
"c1f4d27d40093b429e962d7223824e0bbc47e7c832a39236fc683af84889581075ff9082"
"ed32353d4374d7301cda1d23c431f4698599dda02451824ff369752593647cc3ddc197de"
"985e43d136cdcfc6bd5409cd2f450821142a5e6f8eb1c3ab5d0484b8129fcf17bce4f7f3"
"3321c3cb3dbb14a905e7b2b3e93be4708cbcc82"
"h");
return dsag_;
}
#define dsag get_dsag()
extern const CryptoPP::Integer dsap;
extern const CryptoPP::Integer dsaq;
extern const CryptoPP::Integer dsag;
}
}

9
Daemon.cpp

@ -53,7 +53,7 @@ namespace i2p @@ -53,7 +53,7 @@ namespace i2p
//TODO: This is an ugly workaround. fix it.
//TODO: Autodetect public IP.
i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
i2p::util::config::GetArg("-port", 17070));
i2p::util::config::GetArg("-port", 17007));
if (isLogging == 1)
{
@ -63,12 +63,7 @@ namespace i2p @@ -63,12 +63,7 @@ namespace i2p
#else
logfile_path.append("\\debug.log");
#endif
logfile.open(logfile_path, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
if (!logfile.is_open())
exit(-17);
LogPrint("Logging to file enabled.");
g_Log.SetLogFile (logfile_path);
LogPrint("CMD parameters:");
for (int i = 0; i < argc; ++i)

4
Daemon.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
#pragma once
#include <fstream>
#include <string>
#ifdef _WIN32
#define Daemon i2p::util::DaemonWin32::Instance()
@ -24,8 +24,6 @@ namespace i2p @@ -24,8 +24,6 @@ namespace i2p
int running;
std::ofstream logfile;
protected:
Daemon_Singleton();
virtual ~Daemon_Singleton();

32
Garlic.cpp

@ -20,6 +20,7 @@ namespace garlic @@ -20,6 +20,7 @@ namespace garlic
{
// create new session tags and session key
m_Rnd.GenerateBlock (m_SessionKey, 32);
m_Encryption.SetKey (m_SessionKey);
if (m_NumTags > 0)
{
m_SessionTags = new uint8_t[m_NumTags*32];
@ -77,7 +78,7 @@ namespace garlic @@ -77,7 +78,7 @@ namespace garlic
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);
m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv);
m_Encryption.SetIV (iv);
buf += 514;
len += 514;
}
@ -87,7 +88,7 @@ namespace garlic @@ -87,7 +88,7 @@ namespace garlic
memcpy (buf, m_SessionTags + m_NextTag*32, 32);
uint8_t iv[32]; // IV is first 16 bytes
CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags + m_NextTag*32, 32);
m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv);
m_Encryption.SetIV (iv);
buf += 32;
len += 32;
@ -132,7 +133,7 @@ namespace garlic @@ -132,7 +133,7 @@ namespace garlic
size_t rem = blockSize % 16;
if (rem)
blockSize += (16-rem); //padding
m_Encryption.ProcessData(buf, buf, blockSize);
m_Encryption.Encrypt(buf, blockSize, buf);
return blockSize;
}
@ -248,6 +249,9 @@ namespace garlic @@ -248,6 +249,9 @@ namespace garlic
for (auto it: m_Sessions)
delete it.second;
m_Sessions.clear ();
for (auto it: m_SessionDecryptions)
delete it;
m_SessionDecryptions.clear ();
}
I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg)
@ -298,13 +302,12 @@ namespace garlic @@ -298,13 +302,12 @@ namespace garlic
if (it != m_SessionTags.end ())
{
// existing session
std::string sessionKey (it->second);
m_SessionTags.erase (it); // tag might be used only once
uint8_t iv[32]; // IV is first 16 bytes
CryptoPP::SHA256().CalculateDigest(iv, buf, 32);
m_Decryption.SetKeyWithIV ((uint8_t *)sessionKey.c_str (), 32, iv); // tag is mapped to 32 bytes key
m_Decryption.ProcessData(buf + 32, buf + 32, length - 32);
HandleAESBlock (buf + 32, length - 32, (uint8_t *)sessionKey.c_str ());
it->second->SetIV (iv);
it->second->Decrypt (buf + 32, length - 32, buf + 32);
HandleAESBlock (buf + 32, length - 32, it->second);
m_SessionTags.erase (it); // tag might be used only once
}
else
{
@ -317,11 +320,14 @@ namespace garlic @@ -317,11 +320,14 @@ namespace garlic
pool ? pool->GetEncryptionPrivateKey () : i2p::context.GetPrivateKey (),
buf, (uint8_t *)&elGamal, true))
{
i2p::crypto::CBCDecryption * decryption = new i2p::crypto::CBCDecryption;
m_SessionDecryptions.push_back (decryption);
decryption->SetKey (elGamal.sessionKey);
uint8_t iv[32]; // IV is first 16 bytes
CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32);
m_Decryption.SetKeyWithIV (elGamal.sessionKey, 32, iv);
m_Decryption.ProcessData(buf + 514, buf + 514, length - 514);
HandleAESBlock (buf + 514, length - 514, elGamal.sessionKey);
decryption->SetIV (iv);
decryption->Decrypt(buf + 514, length - 514, buf + 514);
HandleAESBlock (buf + 514, length - 514, decryption);
}
else
LogPrint ("Failed to decrypt garlic");
@ -329,12 +335,12 @@ namespace garlic @@ -329,12 +335,12 @@ namespace garlic
DeleteI2NPMessage (msg);
}
void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, uint8_t * sessionKey)
void GarlicRouting::HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption)
{
uint16_t tagCount = be16toh (*(uint16_t *)buf);
buf += 2;
for (int i = 0; i < tagCount; i++)
m_SessionTags[std::string ((const char *)(buf + i*32), 32)] = std::string ((const char *)sessionKey, 32);
m_SessionTags[std::string ((const char *)(buf + i*32), 32)] = decryption;
buf += tagCount*32;
uint32_t payloadSize = be32toh (*(uint32_t *)buf);
if (payloadSize > len)

12
Garlic.h

@ -3,11 +3,11 @@ @@ -3,11 +3,11 @@
#include <inttypes.h>
#include <map>
#include <list>
#include <string>
#include <thread>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include <cryptopp/osrng.h>
#include "aes.h"
#include "I2NPProtocol.h"
#include "LeaseSet.h"
#include "Tunnel.h"
@ -68,7 +68,7 @@ namespace garlic @@ -68,7 +68,7 @@ namespace garlic
uint8_t * m_SessionTags; // m_NumTags*32 bytes
uint32_t m_TagsCreationTime; // seconds since epoch
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::AutoSeededRandomPool m_Rnd;
};
@ -93,7 +93,7 @@ namespace garlic @@ -93,7 +93,7 @@ namespace garlic
void Run ();
void ProcessGarlicMessage (I2NPMessage * msg);
void HandleAESBlock (uint8_t * buf, size_t len, uint8_t * sessionKey);
void HandleAESBlock (uint8_t * buf, size_t len, i2p::crypto::CBCDecryption * decryption);
void HandleGarlicPayload (uint8_t * buf, size_t len);
private:
@ -105,8 +105,8 @@ namespace garlic @@ -105,8 +105,8 @@ namespace garlic
std::map<i2p::data::IdentHash, GarlicRoutingSession *> m_Sessions;
std::map<uint32_t, GarlicRoutingSession *> m_CreatedSessions; // msgID -> session
// incoming session
std::map<std::string, std::string> m_SessionTags; // tag -> key
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
std::list<i2p::crypto::CBCDecryption *> m_SessionDecryptions; // multiple tags refer to one decyption
std::map<std::string, i2p::crypto::CBCDecryption *> m_SessionTags; // tag -> decryption
};
extern GarlicRouting routing;

5
HTTPServer.cpp

@ -238,7 +238,7 @@ namespace util @@ -238,7 +238,7 @@ namespace util
void HTTPConnection::FillContent (std::stringstream& s)
{
s << "Data path: " << i2p::util::filesystem::GetDataDir().string() << "<BR>" << "<BR>";
s << "Our external address:" << "<BR>" << "<BR>";
s << "Our external address:" << "<BR>";
for (auto& address : i2p::context.GetRouterInfo().GetAddresses())
{
switch (address.transportStyle)
@ -254,6 +254,9 @@ namespace util @@ -254,6 +254,9 @@ namespace util
}
s << address.host.to_string() << ":" << address.port << "<BR>";
}
s << "<BR>Routers: " << i2p::data::netdb.GetNumRouters () << " ";
s << "Floodfills: " << i2p::data::netdb.GetNumFloodfills () << " ";
s << "LeaseSets: " << i2p::data::netdb.GetNumLeaseSets () << "<BR>";
s << "<P>Tunnels</P>";
for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ())

93
I2NPProtocol.cpp

@ -1,8 +1,6 @@ @@ -1,8 +1,6 @@
#include <string.h>
#include "I2PEndian.h"
#include <cryptopp/sha.h>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include <cryptopp/gzip.h>
#include "ElGamal.h"
#include "Timestamp.h"
@ -236,37 +234,14 @@ namespace i2p @@ -236,37 +234,14 @@ namespace i2p
memcpy (record.toPeer, (const uint8_t *)router.GetIdentHash (), 16);
}
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
int num = buf[0];
LogPrint ("VariableTunnelBuild ", num, " records");
i2p::tunnel::Tunnel * tunnel = i2p::tunnel::tunnels.GetPendingTunnel (replyMsgID);
if (tunnel)
{
// endpoint of inbound tunnel
LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
i2p::tunnel::tunnels.AddInboundTunnel (static_cast<i2p::tunnel::InboundTunnel *>(tunnel));
}
else
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
delete tunnel;
}
}
else
bool HandleBuildRequestRecords (int num, I2NPBuildRequestRecordElGamalEncrypted * records, I2NPBuildRequestRecordClearText& clearText)
{
I2NPBuildRequestRecordElGamalEncrypted * records = (I2NPBuildRequestRecordElGamalEncrypted *)(buf+1);
for (int i = 0; i < num; i++)
{
if (!memcmp (records[i].toPeer, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{
LogPrint ("Record ",i," is ours");
I2NPBuildRequestRecordClearText clearText;
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKey (), records[i].encrypted, (uint8_t *)&clearText);
i2p::tunnel::TransitTunnel * transitTunnel =
@ -282,13 +257,46 @@ namespace i2p @@ -282,13 +257,46 @@ namespace i2p
//TODO: fill filler
CryptoPP::SHA256().CalculateDigest(reply->hash, reply->padding, sizeof (reply->padding) + 1); // + 1 byte of ret
// encrypt reply
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encryption;
i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++)
{
encryption.SetKeyWithIV (clearText.replyKey, 32, clearText.replyIV);
encryption.ProcessData((uint8_t *)(records + j), (uint8_t *)(records + j), sizeof (records[j]));
encryption.SetKey (clearText.replyKey);
encryption.SetIV (clearText.replyIV);
encryption.Encrypt((uint8_t *)(records + j), sizeof (records[j]), (uint8_t *)(records + j));
}
return true;
}
}
return false;
}
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{
int num = buf[0];
LogPrint ("VariableTunnelBuild ", num, " records");
i2p::tunnel::Tunnel * tunnel = i2p::tunnel::tunnels.GetPendingTunnel (replyMsgID);
if (tunnel)
{
// endpoint of inbound tunnel
LogPrint ("VariableTunnelBuild reply for tunnel ", tunnel->GetTunnelID ());
if (tunnel->HandleTunnelBuildResponse (buf, len))
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
i2p::tunnel::tunnels.AddInboundTunnel (static_cast<i2p::tunnel::InboundTunnel *>(tunnel));
}
else
{
LogPrint ("Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
delete tunnel;
}
}
else
{
I2NPBuildRequestRecordElGamalEncrypted * records = (I2NPBuildRequestRecordElGamalEncrypted *)(buf+1);
I2NPBuildRequestRecordClearText clearText;
if (HandleBuildRequestRecords (num, records, clearText))
{
if (clearText.flag & 0x40) // we are endpoint of outboud tunnel
{
// so we send it to reply tunnel
@ -300,10 +308,27 @@ namespace i2p @@ -300,10 +308,27 @@ namespace i2p
else
i2p::transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
return;
}
}
}
void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
{
I2NPBuildRequestRecordClearText clearText;
if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, (I2NPBuildRequestRecordElGamalEncrypted *)buf, clearText))
{
if (clearText.flag & 0x40) // we are endpoint of outbound tunnel
{
// so we send it to reply tunnel
i2p::transports.SendMessage (clearText.nextIdent,
CreateTunnelGatewayMsg (be32toh (clearText.nextTunnel),
eI2NPTunnelBuildReply, buf, len,
be32toh (clearText.nextMessageID)));
}
else
i2p::transports.SendMessage (clearText.nextIdent,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, be32toh (clearText.nextMessageID)));
}
}
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
@ -444,6 +469,14 @@ namespace i2p @@ -444,6 +469,14 @@ namespace i2p
LogPrint ("VariableTunnelBuildReply");
HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break;
case eI2NPTunnelBuild:
LogPrint ("TunnelBuild");
HandleTunnelBuildMsg (buf, size);
break;
case eI2NPTunnelBuildReply:
LogPrint ("TunnelBuildReply");
// TODO:
break;
case eI2NPDatabaseLookup:
LogPrint ("DatabaseLookup");
HandleDatabaseLookupMsg (buf, size);

6
I2NPProtocol.h

@ -87,10 +87,14 @@ namespace i2p @@ -87,10 +87,14 @@ namespace i2p
eI2NPTunnelData = 18,
eI2NPTunnelGateway = 19,
eI2NPData = 20,
eI2NPTunnelBuild = 21,
eI2NPTunnelBuildReply = 22,
eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24
};
const int NUM_TUNNEL_BUILD_RECORDS = 8;
namespace tunnel
{
class InboundTunnel;
@ -165,8 +169,10 @@ namespace tunnel @@ -165,8 +169,10 @@ namespace tunnel
const I2NPBuildRequestRecordClearText& clearText,
I2NPBuildRequestRecordElGamalEncrypted& record);
bool HandleBuildRequestRecords (int num, I2NPBuildRequestRecordElGamalEncrypted * records, I2NPBuildRequestRecordClearText& clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
I2NPMessage * CreateTunnelDataMsg (const uint8_t * buf);
I2NPMessage * CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);

23
I2PEndian.h

@ -5,11 +5,27 @@ @@ -5,11 +5,27 @@
#include <endian.h>
#elif __FreeBSD__
#include <sys/endian.h>
#elif __MACH__ // Mac OS X
#include <machine/endian.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#else
#include <cstdint>
uint16_t htobe16(uint16_t int16);
uint32_t htobe32(uint32_t int32);
uint64_t htobe64(uint64_t int64);
@ -21,3 +37,4 @@ uint64_t be64toh(uint64_t big64); @@ -21,3 +37,4 @@ uint64_t be64toh(uint64_t big64);
#endif
#endif // I2PENDIAN_H__

15
Identity.cpp

@ -22,14 +22,14 @@ namespace data @@ -22,14 +22,14 @@ namespace data
bool Identity::FromBase64 (const std::string& s)
{
size_t count = Base64ToByteStream (s.c_str(), s.length(), reinterpret_cast<uint8_t*> (this), sizeof (Identity));
size_t count = Base64ToByteStream (s.c_str(), s.length(), publicKey, sizeof (Identity));
return count == sizeof(Identity);
}
IdentHash Identity::Hash()
IdentHash Identity::Hash() const
{
IdentHash hash;
CryptoPP::SHA256().CalculateDigest(reinterpret_cast<uint8_t*>(&hash), reinterpret_cast<uint8_t*> (this), sizeof (Identity));
CryptoPP::SHA256().CalculateDigest(hash, publicKey, sizeof (Identity));
return hash;
}
@ -98,12 +98,11 @@ namespace data @@ -98,12 +98,11 @@ namespace data
XORMetric operator^(const RoutingKey& key1, const RoutingKey& key2)
{
// TODO: implementation depends on CPU
XORMetric m;
((uint64_t *)m.metric)[0] = ((uint64_t *)key1.hash)[0] ^ ((uint64_t *)key2.hash)[0];
((uint64_t *)m.metric)[1] = ((uint64_t *)key1.hash)[1] ^ ((uint64_t *)key2.hash)[1];
((uint64_t *)m.metric)[2] = ((uint64_t *)key1.hash)[2] ^ ((uint64_t *)key2.hash)[2];
((uint64_t *)m.metric)[3] = ((uint64_t *)key1.hash)[3] ^ ((uint64_t *)key2.hash)[3];
m.metric_ll[0] = key1.hash_ll[0] ^ key2.hash_ll[0];
m.metric_ll[1] = key1.hash_ll[1] ^ key2.hash_ll[1];
m.metric_ll[2] = key1.hash_ll[2] ^ key2.hash_ll[2];
m.metric_ll[3] = key1.hash_ll[3] ^ key2.hash_ll[3];
return m;
}
}

13
Identity.h

@ -35,7 +35,7 @@ namespace data @@ -35,7 +35,7 @@ namespace data
Identity& operator=(const Keys& keys);
bool FromBase64(const std::string& );
IdentHash Hash();
IdentHash Hash() const;
};
struct PrivateKeys // for eepsites
@ -44,6 +44,10 @@ namespace data @@ -44,6 +44,10 @@ namespace data
uint8_t privateKey[256];
uint8_t signingPrivateKey[20];
PrivateKeys () = default;
PrivateKeys (const PrivateKeys& ) = default;
PrivateKeys (const Keys& keys) { *this = keys; };
PrivateKeys& operator=(const Keys& keys);
};
@ -85,14 +89,19 @@ namespace data @@ -85,14 +89,19 @@ namespace data
void CreateRandomDHKeysPair (DHKeysPair * keys); // for transport sessions
// kademlia
struct RoutingKey
union RoutingKey
{
uint8_t hash[32];
uint64_t hash_ll[4];
};
struct XORMetric
{
union
{
uint8_t metric[32];
uint64_t metric_ll[4];
};
void SetMin () { memset (metric, 0, 32); };
void SetMax () { memset (metric, 0xFF, 32); };

23
Log.cpp

@ -1,20 +1,29 @@ @@ -1,20 +1,29 @@
#include "Log.h"
#include "Daemon.h"
Log g_Log;
void LogMsg::Process()
{
if (Daemon.isLogging == 1 && Daemon.logfile.is_open())
Daemon.logfile << s.str();
output << s.str();
std::cout << s.str (); // TODO: delete later
}
void Log::Flush ()
{
if (Daemon.isLogging == 1 && Daemon.logfile.is_open())
Daemon.logfile.flush();
if (m_LogFile)
m_LogFile->flush();
}
void Log::SetLogFile (const std::string& fullFilePath)
{
if (m_LogFile) delete m_LogFile;
m_LogFile = new std::ofstream (fullFilePath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc);
if (m_LogFile->is_open ())
LogPrint("Logging to file ", fullFilePath, " enabled.");
else
{
delete m_LogFile;
m_LogFile = nullptr;
}
}

14
Log.h

@ -1,8 +1,10 @@ @@ -1,8 +1,10 @@
#ifndef LOG_H__
#define LOG_H__
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <functional>
#include "Queue.h"
@ -20,11 +22,19 @@ class Log: public i2p::util::MsgQueue<LogMsg> @@ -20,11 +22,19 @@ class Log: public i2p::util::MsgQueue<LogMsg>
{
public:
Log () { SetOnEmpty (std::bind (&Log::Flush, this)); };
Log (): m_LogFile (nullptr) { SetOnEmpty (std::bind (&Log::Flush, this)); };
~Log () { delete m_LogFile; };
void SetLogFile (const std::string& fullFilePath);
std::ofstream * GetLogFile () const { return m_LogFile; };
private:
void Flush ();
private:
std::ofstream * m_LogFile;
};
extern Log g_Log;
@ -45,7 +55,7 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args) @@ -45,7 +55,7 @@ void LogPrint (std::stringstream& s, TValue arg, TArgs... args)
template<typename... TArgs>
void LogPrint (TArgs... args)
{
LogMsg * msg = new LogMsg ();
LogMsg * msg = g_Log.GetLogFile () ? new LogMsg (*g_Log.GetLogFile ()) : new LogMsg ();
LogPrint (msg->s, args...);
msg->s << std::endl;
g_Log.Put (msg);

13
Makefile

@ -1,16 +1,21 @@ @@ -1,16 +1,21 @@
CC = g++
CFLAGS = -g -Wall -std=c++0x
OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o \
obj/Daemon.o obj/DaemonLinux.o obj/SSUData.o
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o
INCFLAGS =
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
CPU_FLAGS = -DAESNI
endif
all: obj i2p
i2p: $(OBJECTS:obj/%=obj/%)
@ -20,7 +25,7 @@ i2p: $(OBJECTS:obj/%=obj/%) @@ -20,7 +25,7 @@ i2p: $(OBJECTS:obj/%=obj/%)
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS)
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj:
mkdir -p obj

43
Makefile.osx vendored

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
#CC = clang++
CC = g++
CFLAGS = -g -Wall -std=c++11 -lstdc++
OBJECTS = obj/CryptoConst.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \
obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \
obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \
obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \
obj/UPnP.o obj/TunnelPool.o obj/HTTPProxy.o obj/AddressBook.o obj/Daemon.o \
obj/DaemonLinux.o obj/SSUData.o obj/i2p.o obj/aes.o
INCFLAGS = -DCRYPTOPP_DISABLE_ASM
LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread
LIBS =
#check if AES-NI is supported by CPU
ifneq ($(shell grep -c aes /proc/cpuinfo),0)
CPU_FLAGS = -DAESNI
endif
# Apple Mac OSX
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
endif
all: obj i2p
i2p: $(OBJECTS:obj/%=obj/%)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
.SUFFIXES:
.SUFFIXES: .c .cc .C .cpp .o
obj/%.o : %.cpp
$(CC) -o $@ $< -c $(CFLAGS) $(INCFLAGS) $(CPU_FLAGS)
obj:
mkdir -p obj
clean:
rm -fr obj i2p
.PHONY: all
.PHONY: clean

30
NTCPSession.cpp

@ -183,10 +183,12 @@ namespace ntcp @@ -183,10 +183,12 @@ namespace ntcp
uint8_t aesKey[32];
CreateAESKey (m_Phase1.pubKey, aesKey);
m_Encryption.SetKeyWithIV (aesKey, 32, y + 240);
m_Decryption.SetKeyWithIV (aesKey, 32, m_Phase1.HXxorHI + 16);
m_Encryption.SetKey (aesKey);
m_Encryption.SetIV (y + 240);
m_Decryption.SetKey (aesKey);
m_Decryption.SetIV (m_Phase1.HXxorHI + 16);
m_Encryption.ProcessData((uint8_t *)&m_Phase2.encrypted, (uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted));
m_Encryption.Encrypt ((uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted), (uint8_t *)&m_Phase2.encrypted);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Phase2, sizeof (m_Phase2)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase2Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsB));
@ -222,10 +224,12 @@ namespace ntcp @@ -222,10 +224,12 @@ namespace ntcp
uint8_t aesKey[32];
CreateAESKey (m_Phase2.pubKey, aesKey);
m_Decryption.SetKeyWithIV (aesKey, 32, m_Phase2.pubKey + 240);
m_Encryption.SetKeyWithIV (aesKey, 32, m_Phase1.HXxorHI + 16);
m_Decryption.SetKey (aesKey);
m_Decryption.SetIV (m_Phase2.pubKey + 240);
m_Encryption.SetKey (aesKey);
m_Encryption.SetIV (m_Phase1.HXxorHI + 16);
m_Decryption.ProcessData((uint8_t *)&m_Phase2.encrypted, (uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted));
m_Decryption.Decrypt((uint8_t *)&m_Phase2.encrypted, sizeof(m_Phase2.encrypted), (uint8_t *)&m_Phase2.encrypted);
// verify
uint8_t xy[512], hxy[32];
memcpy (xy, m_DHKeysPair->publicKey, 256);
@ -256,7 +260,7 @@ namespace ntcp @@ -256,7 +260,7 @@ namespace ntcp
s.tsB = m_Phase2.encrypted.timestamp;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Phase3.signature);
m_Encryption.ProcessData((uint8_t *)&m_Phase3, (uint8_t *)&m_Phase3, sizeof(m_Phase3));
m_Encryption.Encrypt((uint8_t *)&m_Phase3, sizeof(m_Phase3), (uint8_t *)&m_Phase3);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Phase3, sizeof (m_Phase3)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase3Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, tsA));
@ -288,7 +292,7 @@ namespace ntcp @@ -288,7 +292,7 @@ namespace ntcp
else
{
LogPrint ("Phase 3 received: ", bytes_transferred);
m_Decryption.ProcessData((uint8_t *)&m_Phase3, (uint8_t *)&m_Phase3, sizeof(m_Phase3));
m_Decryption.Decrypt ((uint8_t *)&m_Phase3, sizeof(m_Phase3), (uint8_t *)&m_Phase3);
m_RemoteRouterInfo.SetRouterIdentity (m_Phase3.ident);
SignedData s;
@ -321,7 +325,7 @@ namespace ntcp @@ -321,7 +325,7 @@ namespace ntcp
s.tsA = m_Phase3.timestamp;
s.tsB = tsB;
i2p::context.Sign ((uint8_t *)&s, sizeof (s), m_Phase4.signature);
m_Encryption.ProcessData((uint8_t *)&m_Phase4, (uint8_t *)&m_Phase4, sizeof(m_Phase4));
m_Encryption.Encrypt ((uint8_t *)&m_Phase4, sizeof(m_Phase4), (uint8_t *)&m_Phase4);
boost::asio::async_write (m_Socket, boost::asio::buffer (&m_Phase4, sizeof (m_Phase4)), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandlePhase4Sent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
@ -355,7 +359,7 @@ namespace ntcp @@ -355,7 +359,7 @@ namespace ntcp
else
{
LogPrint ("Phase 4 received: ", bytes_transferred);
m_Decryption.ProcessData((uint8_t *)&m_Phase4, (uint8_t *)&m_Phase4, sizeof(m_Phase4));
m_Decryption.Decrypt((uint8_t *)&m_Phase4, sizeof(m_Phase4), (uint8_t *)&m_Phase4);
// verify signature
SignedData s;
@ -426,7 +430,7 @@ namespace ntcp @@ -426,7 +430,7 @@ namespace ntcp
m_NextMessage = i2p::NewI2NPMessage ();
m_NextMessageOffset = 0;
m_Decryption.ProcessData (m_NextMessage->buf, encrypted, 16);
m_Decryption.Decrypt (encrypted, m_NextMessage->buf);
uint16_t dataSize = be16toh (*(uint16_t *)m_NextMessage->buf);
if (dataSize)
{
@ -446,7 +450,7 @@ namespace ntcp @@ -446,7 +450,7 @@ namespace ntcp
}
else // message continues
{
m_Decryption.ProcessData (m_NextMessage->buf + m_NextMessageOffset, encrypted, 16);
m_Decryption.Decrypt (encrypted, m_NextMessage->buf + m_NextMessageOffset);
m_NextMessageOffset += 16;
}
@ -490,7 +494,7 @@ namespace ntcp @@ -490,7 +494,7 @@ namespace ntcp
m_Adler.CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding);
int l = len + padding + 6;
m_Encryption.ProcessData(sendBuffer, sendBuffer, l);
m_Encryption.Encrypt(sendBuffer, l, sendBuffer);
boost::asio::async_write (m_Socket, boost::asio::buffer (sendBuffer, l), boost::asio::transfer_all (),
boost::bind(&NTCPSession::HandleSent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, msg));

5
NTCPSession.h

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include <cryptopp/adler32.h>
#include "aes.h"
#include "Identity.h"
#include "RouterInfo.h"
#include "I2NPProtocol.h"
@ -123,8 +124,8 @@ namespace ntcp @@ -123,8 +124,8 @@ namespace ntcp
bool m_IsEstablished;
i2p::data::DHKeysPair * m_DHKeysPair; // X - for client and Y - for server
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
i2p::crypto::CBCDecryption m_Decryption;
i2p::crypto::CBCEncryption m_Encryption;
CryptoPP::Adler32 m_Adler;
i2p::data::RouterInfo& m_RemoteRouterInfo;

42
NetDb.cpp

@ -122,7 +122,10 @@ namespace data @@ -122,7 +122,10 @@ namespace data
}
}
else // if no new DatabaseStore coming, explore it
Explore ();
{
auto numRouters = m_RouterInfos.size ();
Explore (numRouters < 1500 ? 5 : 1);
}
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts - lastSave >= 60) // save routers and validate subscriptions every minute
@ -532,23 +535,29 @@ namespace data @@ -532,23 +535,29 @@ namespace data
i2p::DeleteI2NPMessage (msg);
}
void NetDb::Explore ()
void NetDb::Explore (int numDestinations)
{
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr;
if (outbound && inbound)
{
bool throughTunnels = outbound && inbound;
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
uint8_t randomHash[32];
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
std::set<const RouterInfo *> floodfills;
LogPrint ("Exploring new ", numDestinations, " routers ...");
for (int i = 0; i < numDestinations; i++)
{
rnd.GenerateBlock (randomHash, 32);
RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true);
dest->SetLastOutboundTunnel (outbound);
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
if (floodfill)
if (floodfill && !floodfills.count (floodfill)) // request floodfill only once
{
LogPrint ("Exploring new routers ...");
std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
floodfills.insert (floodfill);
if (throughTunnels)
{
dest->SetLastOutboundTunnel (outbound);
msgs.push_back (i2p::tunnel::TunnelMessageBlock
{
i2p::tunnel::eDeliveryTypeRouter,
@ -561,11 +570,19 @@ namespace data @@ -561,11 +570,19 @@ namespace data
floodfill->GetIdentHash (), 0,
dest->CreateRequestMessage (floodfill, inbound) // explore
});
outbound->SendTunnelDataMsg (msgs);
}
else
{
dest->SetLastOutboundTunnel (nullptr);
dest->SetLastReplyTunnel (nullptr);
i2p::transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
}
}
else
DeleteRequestedDestination (dest);
}
if (throughTunnels && msgs.size () > 0)
outbound->SendTunnelDataMsg (msgs);
}
void NetDb::Publish ()
@ -616,7 +633,7 @@ namespace data @@ -616,7 +633,7 @@ namespace data
}
}
const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, uint8_t caps) const
const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith) const
{
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1);
@ -627,9 +644,8 @@ namespace data @@ -627,9 +644,8 @@ namespace data
{
if (i >= ind)
{
if (!it.second->IsUnreachable () &&
(!compatibleWith || it.second->IsCompatible (*compatibleWith)) &&
(!caps || (it.second->GetCaps () & caps) == caps))
if (!it.second->IsUnreachable () && !it.second->IsHidden () &&
(!compatibleWith || it.second->IsCompatible (*compatibleWith)))
return it.second;
}
else

10
NetDb.h

@ -33,6 +33,7 @@ namespace data @@ -33,6 +33,7 @@ namespace data
void ClearExcludedPeers ();
const RouterInfo * GetLastRouter () const { return m_LastRouter; };
const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; };
void SetLastReplyTunnel (i2p::tunnel::InboundTunnel * tunnel) { m_LastReplyTunnel = tunnel; };
bool IsExploratory () const { return m_IsExploratory; };
bool IsLeaseSet () const { return m_IsLeaseSet; };
bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); };
@ -75,17 +76,22 @@ namespace data @@ -75,17 +76,22 @@ namespace data
void HandleDatabaseStoreMsg (uint8_t * buf, size_t len);
void HandleDatabaseSearchReplyMsg (I2NPMessage * msg);
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr, uint8_t caps = 0) const;
const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr) const;
void PostI2NPMsg (I2NPMessage * msg);
// for web interface
int GetNumRouters () const { return m_RouterInfos.size (); };
int GetNumFloodfills () const { return m_Floodfills.size (); };
int GetNumLeaseSets () const { return m_LeaseSets.size (); };
private:
bool CreateNetDb(boost::filesystem::path directory);
void Load (const char * directory);
void SaveUpdated (const char * directory);
void Run (); // exploratory thread
void Explore ();
void Explore (int numDestinations);
void Publish ();
void ValidateSubscriptions ();
const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;

3
RouterInfo.cpp

@ -215,6 +215,9 @@ namespace data @@ -215,6 +215,9 @@ namespace data
case 'C':
m_Caps |= Caps::eSSUIntroducer;
break;
case 'H':
m_Caps |= Caps::eHidden;
break;
default: ;
}
cap++;

5
RouterInfo.h

@ -31,7 +31,8 @@ namespace data @@ -31,7 +31,8 @@ namespace data
eHighBandwidth = 0x02,
eReachable = 0x04,
eSSUTesting = 0x08,
eSSUIntroducer = 0x10
eSSUIntroducer = 0x10,
eHidden = 0x20
};
enum TransportStyle
@ -88,6 +89,8 @@ namespace data @@ -88,6 +89,8 @@ namespace data
bool UsesIntroducer () const;
bool IsIntroducer () const { return m_Caps & eSSUIntroducer; };
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
bool IsHidden () const { return m_Caps & eHidden; };
uint8_t GetCaps () const { return m_Caps; };
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };

205
SSU.cpp

@ -29,7 +29,7 @@ namespace ssu @@ -29,7 +29,7 @@ namespace ssu
delete m_DHKeysPair;
}
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey)
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
{
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
uint8_t sharedKey[256];
@ -41,14 +41,14 @@ namespace ssu @@ -41,14 +41,14 @@ namespace ssu
if (sharedKey[0] & 0x80)
{
aesKey[0] = 0;
memcpy (aesKey + 1, sharedKey, 31);
memcpy (macKey, sharedKey + 31, 32);
m_SessionKey[0] = 0;
memcpy (m_SessionKey + 1, sharedKey, 31);
memcpy (m_MacKey, sharedKey + 31, 32);
}
else if (sharedKey[0])
{
memcpy (aesKey, sharedKey, 32);
memcpy (macKey, sharedKey + 32, 32);
memcpy (m_SessionKey, sharedKey, 32);
memcpy (m_MacKey, sharedKey + 32, 32);
}
else
{
@ -64,10 +64,12 @@ namespace ssu @@ -64,10 +64,12 @@ namespace ssu
}
}
memcpy (aesKey, nonZero, 32);
CryptoPP::SHA256().CalculateDigest(macKey, nonZero, 64 - (nonZero - sharedKey));
memcpy (m_SessionKey, nonZero, 32);
CryptoPP::SHA256().CalculateDigest(m_MacKey, nonZero, 64 - (nonZero - sharedKey));
}
m_IsSessionKey = true;
m_SessionKeyEncryption.SetKey (m_SessionKey);
m_SessionKeyDecryption.SetKey (m_SessionKey);
}
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
@ -82,8 +84,13 @@ namespace ssu @@ -82,8 +84,13 @@ namespace ssu
else
{
ScheduleTermination ();
// check for duplicate
const uint8_t * iv = ((SSUHeader *)buf)->iv;
if (m_ReceivedIVs.count (iv)) return; // duplicate detected
m_ReceivedIVs.insert (iv);
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
Decrypt (buf, len, m_SessionKey);
DecryptSessionKey (buf, len);
else
{
// try intro key depending on side
@ -161,10 +168,9 @@ namespace ssu @@ -161,10 +168,9 @@ namespace ssu
void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{
m_State = eSessionStateRequestReceived;
LogPrint ("Session request received");
m_RemoteEndpoint = senderEndpoint;
CreateAESandMacKey (buf + sizeof (SSUHeader), m_SessionKey, m_MacKey);
CreateAESandMacKey (buf + sizeof (SSUHeader));
SendSessionCreated (buf + sizeof (SSUHeader));
}
@ -176,13 +182,12 @@ namespace ssu @@ -176,13 +182,12 @@ namespace ssu
return;
}
m_State = eSessionStateCreatedReceived;
LogPrint ("Session created received");
m_Timer.cancel (); // connect timer
uint8_t signedData[532]; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t * y = payload;
CreateAESandMacKey (y, m_SessionKey, m_MacKey);
CreateAESandMacKey (y);
memcpy (signedData, m_DHKeysPair->publicKey, 256); // x
memcpy (signedData + 256, y, 256); // y
payload += 256;
@ -202,8 +207,8 @@ namespace ssu @@ -202,8 +207,8 @@ namespace ssu
payload += 4; // relayTag
payload += 4; // signed on time
// decrypt DSA signature
m_Decryption.SetKeyWithIV (m_SessionKey, 32, ((SSUHeader *)buf)->iv);
m_Decryption.ProcessData (payload, payload, 48);
m_SessionKeyDecryption.SetIV (((SSUHeader *)buf)->iv);
m_SessionKeyDecryption.Decrypt (payload, 48, payload);
// verify
CryptoPP::DSA::PublicKey pubKey;
pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_RemoteRouter->GetRouterIdentity ().signingKey, 128));
@ -216,9 +221,7 @@ namespace ssu @@ -216,9 +221,7 @@ namespace ssu
void SSUSession::ProcessSessionConfirmed (uint8_t * buf, size_t len)
{
m_State = eSessionStateConfirmedReceived;
LogPrint ("Session confirmed received");
m_State = eSessionStateEstablished;
SendI2NPMessage (CreateDeliveryStatusMsg (0));
Established ();
}
@ -242,8 +245,6 @@ namespace ssu @@ -242,8 +245,6 @@ namespace ssu
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey);
m_State = eSessionStateRequestSent;
m_Server.Send (buf, 304, m_RemoteEndpoint);
}
@ -276,10 +277,7 @@ namespace ssu @@ -276,10 +277,7 @@ namespace ssu
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);
m_State = eSessionStateRelayRequestSent;
}
m_Server.Send (buf, 96, m_RemoteEndpoint);
}
@ -327,13 +325,12 @@ namespace ssu @@ -327,13 +325,12 @@ namespace ssu
uint8_t iv[16];
rnd.GenerateBlock (iv, 16); // random iv
// encrypt signature and 8 bytes padding with newly created session key
m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv);
m_Encryption.ProcessData (payload, payload, 48);
m_SessionKeyEncryption.SetIV (iv);
m_SessionKeyEncryption.Encrypt (payload, 48, payload);
// encrypt message with intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey);
m_State = eSessionStateCreatedSent;
m_Server.Send (buf, 368, m_RemoteEndpoint);
Send (buf, 368);
}
void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress)
@ -371,8 +368,7 @@ namespace ssu @@ -371,8 +368,7 @@ namespace ssu
rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CONFIRMED, buf, 480, m_SessionKey, iv, m_MacKey);
m_State = eSessionStateConfirmedSent;
m_Server.Send (buf, 480, m_RemoteEndpoint);
Send (buf, 480);
}
void SSUSession::ProcessRelayRequest (uint8_t * buf, size_t len)
@ -499,15 +495,37 @@ namespace ssu @@ -499,15 +495,37 @@ namespace ssu
header->time = htobe32 (i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
m_Encryption.SetKeyWithIV (aesKey, 32, iv);
encryptedLen = (encryptedLen>>4)<<4; // make sure 16 bytes boundary
m_Encryption.ProcessData (encrypted, encrypted, encryptedLen);
i2p::crypto::CBCEncryption encryption;
encryption.SetKey (aesKey);
encryption.SetIV (iv);
encryption.Encrypt (encrypted, encryptedLen, encrypted);
// assume actual buffer size is 18 (16 + 2) bytes more
memcpy (buf + len, iv, 16);
*(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen);
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac);
}
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len)
{
if (len < sizeof (SSUHeader))
{
LogPrint ("Unexpected SSU packet length ", len);
return;
}
SSUHeader * header = (SSUHeader *)buf;
i2p::context.GetRandomNumberGenerator ().GenerateBlock (header->iv, 16); // random iv
m_SessionKeyEncryption.SetIV (header->iv);
header->flag = payloadType << 4; // MSB is 0
header->time = htobe32 (i2p::util::GetSecondsSinceEpoch ());
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
m_SessionKeyEncryption.Encrypt (encrypted, encryptedLen, encrypted);
// assume actual buffer size is 18 (16 + 2) bytes more
memcpy (buf + len, header->iv, 16);
*(uint16_t *)(buf + len + 16) = htobe16 (encryptedLen);
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
}
void SSUSession::Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey)
{
if (len < sizeof (SSUHeader))
@ -518,9 +536,27 @@ namespace ssu @@ -518,9 +536,27 @@ namespace ssu
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
m_Decryption.SetKeyWithIV (aesKey, 32, header->iv);
encryptedLen = (encryptedLen>>4)<<4; // make sure 16 bytes boundary
m_Decryption.ProcessData (encrypted, encrypted, encryptedLen);
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (aesKey);
decryption.SetIV (header->iv);
decryption.Decrypt (encrypted, encryptedLen, encrypted);
}
void SSUSession::DecryptSessionKey (uint8_t * buf, size_t len)
{
if (len < sizeof (SSUHeader))
{
LogPrint ("Unexpected SSU packet length ", len);
return;
}
SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf);
if (encryptedLen > 0)
{
m_SessionKeyDecryption.SetIV (header->iv);
m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted);
}
}
bool SSUSession::Validate (uint8_t * buf, size_t len, const uint8_t * macKey)
@ -602,7 +638,7 @@ namespace ssu @@ -602,7 +638,7 @@ namespace ssu
if (!m_DelayedMessages.empty ())
{
for (auto it :m_DelayedMessages)
Send (it);
m_Data.Send (it);
m_DelayedMessages.clear ();
}
if (m_PeerTest && (m_RemoteRouter && m_RemoteRouter->IsPeerTesting ()))
@ -658,7 +694,7 @@ namespace ssu @@ -658,7 +694,7 @@ namespace ssu
if (msg)
{
if (m_State == eSessionStateEstablished)
Send (msg);
m_Data.Send (msg);
else
m_DelayedMessages.push_back (msg);
}
@ -771,100 +807,26 @@ namespace ssu @@ -771,100 +807,26 @@ namespace ssu
memset (payload, 0, 6); // address and port always zero for Alice
payload += 6; // address and port
memcpy (payload, introKey, 32); // intro key
uint8_t iv[16];
rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, m_SessionKey, iv, m_MacKey);
m_Server.Send (buf, 80, m_RemoteEndpoint);
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80);
Send (buf, 80);
}
void SSUSession::SendMsgAck (uint32_t msgID)
{
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
uint8_t iv[16];
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
payload++;
*payload = 1; // number of ACKs
payload++;
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4;
*payload = 0; // number of fragments
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48, m_SessionKey, iv, m_MacKey);
m_Server.Send (buf, 48, m_RemoteEndpoint);
}
void SSUSession::SendSesionDestroyed ()
{
if (m_IsSessionKey)
{
uint8_t buf[48 + 18], iv[16];
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey);
m_Server.Send (buf, 48, m_RemoteEndpoint);
}
}
void SSUSession::Send (i2p::I2NPMessage * msg)
{
uint32_t msgID = htobe32 (msg->ToSSU ());
size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength ();
uint8_t * msgBuf = msg->GetSSUHeader ();
uint32_t fragmentNum = 0;
while (len > 0)
{
uint8_t buf[SSU_MTU + 18], iv[16], * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
payload++;
*payload = 1; // always 1 message fragment per message
payload++;
*(uint32_t *)payload = msgID;
payload += 4;
bool isLast = (len <= payloadSize);
size_t size = isLast ? len : payloadSize;
uint32_t fragmentInfo = (fragmentNum << 17);
if (isLast)
fragmentInfo |= 0x010000;
fragmentInfo |= size;
fragmentInfo = htobe32 (fragmentInfo);
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
payload += 3;
memcpy (payload, msgBuf, size);
size += payload - buf;
if (size & 0x0F) // make sure 16 bytes boundary
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (iv, 16); // random iv
uint8_t buf[48 + 18];
// encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size, m_SessionKey, iv, m_MacKey);
m_Server.Send (buf, size, m_RemoteEndpoint);
if (!isLast)
{
len -= payloadSize;
msgBuf += payloadSize;
}
else
len = 0;
fragmentNum++;
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48);
Send (buf, 48);
}
}
void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
{
uint8_t buf[SSU_MTU + 18];
uint8_t iv[16];
size_t msgSize = len + sizeof (SSUHeader);
if (msgSize > SSU_MTU)
{
@ -872,11 +834,14 @@ namespace ssu @@ -872,11 +834,14 @@ namespace ssu
return;
}
memcpy (buf + sizeof (SSUHeader), payload, len);
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
rnd.GenerateBlock (iv, 16); // random iv
// encrypt message with session key
FillHeaderAndEncrypt (type, buf, msgSize, m_SessionKey, iv, m_MacKey);
m_Server.Send (buf, msgSize, m_RemoteEndpoint);
FillHeaderAndEncrypt (type, buf, msgSize);
Send (buf, msgSize);
}
void SSUSession::Send (const uint8_t * buf, size_t size)
{
m_Server.Send (buf, size, m_RemoteEndpoint);
}
SSUServer::SSUServer (int port): m_Thread (nullptr), m_Work (m_Service),
@ -941,7 +906,7 @@ namespace ssu @@ -941,7 +906,7 @@ namespace ssu
return nullptr;
}
void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
{
m_Socket.send_to (boost::asio::buffer (buf, len), to);
LogPrint ("SSU sent ", len, " bytes");

40
SSU.h

@ -2,13 +2,13 @@ @@ -2,13 +2,13 @@
#define SSU_H__
#include <inttypes.h>
#include <string.h>
#include <map>
#include <list>
#include <set>
#include <thread>
#include <boost/asio.hpp>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include "aes.h"
#include "I2PEndian.h"
#include "Identity.h"
#include "RouterInfo.h"
@ -49,14 +49,6 @@ namespace ssu @@ -49,14 +49,6 @@ namespace ssu
enum SessionState
{
eSessionStateUnknown,
eSessionStateRequestSent,
eSessionStateRequestReceived,
eSessionStateCreatedSent,
eSessionStateCreatedReceived,
eSessionStateConfirmedSent,
eSessionStateConfirmedReceived,
eSessionStateRelayRequestSent,
eSessionStateRelayRequestReceived,
eSessionStateIntroduced,
eSessionStateEstablished,
eSessionStateFailed
@ -85,7 +77,7 @@ namespace ssu @@ -85,7 +77,7 @@ namespace ssu
private:
void CreateAESandMacKey (const uint8_t * pubKey, uint8_t * aesKey, uint8_t * macKey);
void CreateAESandMacKey (const uint8_t * pubKey);
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);
@ -106,13 +98,14 @@ namespace ssu @@ -106,13 +98,14 @@ namespace ssu
void ProcessPeerTest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, uint32_t address, uint16_t port, uint8_t * introKey); // Charlie to Alice
void ProcessData (uint8_t * buf, size_t len);
void SendMsgAck (uint32_t msgID);
void SendSesionDestroyed ();
void Send (i2p::I2NPMessage * msg);
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); // with session key
void Decrypt (uint8_t * buf, size_t len, const uint8_t * 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;
@ -121,6 +114,20 @@ namespace ssu @@ -121,6 +114,20 @@ namespace ssu
private:
union IV
{
uint8_t buf[16];
uint64_t ll[2];
IV (const IV&) = default;
IV (const uint8_t * iv) { memcpy (buf, iv, 16); };
bool operator< (const IV& other) const
{
if (ll[0] != other.ll[0]) return ll[0] < other.ll[0];
return ll[1] < other.ll[1];
};
};
friend class SSUData; // TODO: change in later
SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
@ -132,10 +139,11 @@ namespace ssu @@ -132,10 +139,11 @@ namespace ssu
bool m_IsSessionKey;
uint32_t m_RelayTag;
std::set<uint32_t> m_PeerTestNonces;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_Encryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_Decryption;
i2p::crypto::CBCEncryption m_SessionKeyEncryption;
i2p::crypto::CBCDecryption m_SessionKeyDecryption;
uint8_t m_SessionKey[32], m_MacKey[32];
std::list<i2p::I2NPMessage *> m_DelayedMessages;
std::set<IV> m_ReceivedIVs;
SSUData m_Data;
};
@ -155,7 +163,7 @@ namespace ssu @@ -155,7 +163,7 @@ namespace ssu
boost::asio::io_service& GetService () { return m_Socket.get_io_service(); };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay);
SSUSession * FindRelaySession (uint32_t tag);

95
SSUData.cpp

@ -19,6 +19,23 @@ namespace ssu @@ -19,6 +19,23 @@ namespace ssu
DeleteI2NPMessage (it.second->msg);
delete it.second;
}
for (auto it: m_SentMessages)
{
for (auto f: it.second)
delete[] f;
}
}
void SSUData::ProcessSentMessageAck (uint32_t msgID)
{
auto it = m_SentMessages.find (msgID);
if (it != m_SentMessages.end ())
{
// delete all ack-ed message's fragments
for (auto f: it->second)
delete[] f;
m_SentMessages.erase (it);
}
}
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
@ -32,7 +49,8 @@ namespace ssu @@ -32,7 +49,8 @@ namespace ssu
// explicit ACKs
uint8_t numAcks =*buf;
buf++;
// TODO: process ACKs
for (int i = 0; i < numAcks; i++)
ProcessSentMessageAck (be32toh (((uint32_t *)buf)[i]));
buf += numAcks*4;
}
if (flag & DATA_FLAG_ACK_BITFIELDS_INCLUDED)
@ -43,7 +61,7 @@ namespace ssu @@ -43,7 +61,7 @@ namespace ssu
for (int i = 0; i < numBitfields; i++)
{
buf += 4; // msgID
// TODO: process ACH bitfields
// TODO: process individual Ack bitfields
while (*buf & 0x80) // not last
buf++;
buf++; // last byte
@ -90,6 +108,8 @@ namespace ssu @@ -90,6 +108,8 @@ namespace ssu
if (isLast)
{
if (!msg)
DeleteI2NPMessage (it->second->msg);
delete it->second;
m_IncomleteMessages.erase (it);
}
@ -111,7 +131,7 @@ namespace ssu @@ -111,7 +131,7 @@ namespace ssu
m_IncomleteMessages[msgID] = new IncompleteMessage (msg);
if (isLast)
{
m_Session.SendMsgAck (msgID);
SendMsgAck (msgID);
msg->FromSSU (msgID);
if (m_Session.GetState () == eSessionStateEstablished)
i2p::HandleI2NPMessage (msg);
@ -133,6 +153,75 @@ namespace ssu @@ -133,6 +153,75 @@ namespace ssu
}
}
void SSUData::Send (i2p::I2NPMessage * msg)
{
uint32_t msgID = msg->ToSSU ();
auto fragments = m_SentMessages[msgID];
msgID = htobe32 (msgID);
size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength ();
uint8_t * msgBuf = msg->GetSSUHeader ();
uint32_t fragmentNum = 0;
while (len > 0)
{
uint8_t * buf = new uint8_t[SSU_MTU + 18];
fragments.push_back (buf);
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_WANT_REPLY; // for compatibility
payload++;
*payload = 1; // always 1 message fragment per message
payload++;
*(uint32_t *)payload = msgID;
payload += 4;
bool isLast = (len <= payloadSize);
size_t size = isLast ? len : payloadSize;
uint32_t fragmentInfo = (fragmentNum << 17);
if (isLast)
fragmentInfo |= 0x010000;
fragmentInfo |= size;
fragmentInfo = htobe32 (fragmentInfo);
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
payload += 3;
memcpy (payload, msgBuf, size);
size += payload - buf;
if (size & 0x0F) // make sure 16 bytes boundary
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
m_Session.Send (buf, size);
if (!isLast)
{
len -= payloadSize;
msgBuf += payloadSize;
}
else
len = 0;
fragmentNum++;
}
DeleteI2NPMessage (msg);
}
void SSUData::SendMsgAck (uint32_t msgID)
{
uint8_t buf[48 + 18]; // actual length is 44 = 37 + 7 but pad it to multiple of 16
uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_EXPLICIT_ACKS_INCLUDED; // flag
payload++;
*payload = 1; // number of ACKs
payload++;
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4;
*payload = 0; // number of fragments
// encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
m_Session.Send (buf, 48);
}
}
}

8
SSUData.h

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
#include <inttypes.h>
#include <map>
#include <vector>
#include "I2NPProtocol.h"
namespace i2p
@ -27,6 +28,12 @@ namespace ssu @@ -27,6 +28,12 @@ namespace ssu
~SSUData ();
void ProcessMessage (uint8_t * buf, size_t len);
void Send (i2p::I2NPMessage * msg);
private:
void SendMsgAck (uint32_t msgID);
void ProcessSentMessageAck (uint32_t msgID);
private:
@ -40,6 +47,7 @@ namespace ssu @@ -40,6 +47,7 @@ namespace ssu
SSUSession& m_Session;
std::map<uint32_t, IncompleteMessage *> m_IncomleteMessages;
std::map<uint32_t, std::vector<uint8_t *> > m_SentMessages; // msgID -> fragments
};
}
}

9
Streaming.cpp

@ -334,12 +334,13 @@ namespace stream @@ -334,12 +334,13 @@ namespace stream
StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr)
{
m_Keys = i2p::data::CreateRandomKeys ();
m_IdentHash = m_Keys.pub.Hash ();
m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
}
StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr)
@ -349,9 +350,13 @@ namespace stream @@ -349,9 +350,13 @@ namespace stream
s.read ((char *)&m_Keys, sizeof (m_Keys));
else
LogPrint ("Can't open file ", fullPath);
m_IdentHash = m_Keys.pub.Hash ();
m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag,
CryptoPP::Integer (m_Keys.signingPrivateKey, 20));
CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg);
dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (*this, 3); // 3-hops tunnel
}
StreamingDestination::~StreamingDestination ()

14
TransitTunnel.cpp

@ -17,22 +17,12 @@ namespace tunnel @@ -17,22 +17,12 @@ namespace tunnel
m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID),
m_NextIdent (nextIdent), m_NumTransmittedBytes (0)
{
memcpy (m_LayerKey, layerKey, 32);
memcpy (m_IVKey, ivKey, 32);
m_Encryption.SetKeys (layerKey, ivKey);
}
void TransitTunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg)
{
uint8_t * payload = tunnelMsg->GetPayload () + 4;
m_ECBEncryption.SetKey (m_IVKey, 32);
m_ECBEncryption.ProcessData(payload, payload, 16); // iv
m_CBCEncryption.SetKeyWithIV (m_LayerKey, 32, payload);
m_CBCEncryption.ProcessData(payload + 16, payload + 16, TUNNEL_DATA_ENCRYPTED_SIZE); // payload
m_ECBEncryption.SetKey (m_IVKey, 32);
m_ECBEncryption.ProcessData(payload, payload, 16); // double iv encryption
m_Encryption.Encrypt (tunnelMsg->GetPayload () + 4);
}
void TransitTunnel::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg)

8
TransitTunnel.h

@ -2,8 +2,7 @@ @@ -2,8 +2,7 @@
#define TRANSIT_TUNNEL_H__
#include <inttypes.h>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include "aes.h"
#include "I2NPProtocol.h"
#include "TunnelEndpoint.h"
#include "TunnelGateway.h"
@ -36,12 +35,9 @@ namespace tunnel @@ -36,12 +35,9 @@ namespace tunnel
uint32_t m_TunnelID, m_NextTunnelID;
i2p::data::IdentHash m_NextIdent;
uint8_t m_LayerKey[32];
uint8_t m_IVKey[32];
size_t m_NumTransmittedBytes;
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption m_ECBEncryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption m_CBCEncryption;
i2p::crypto::TunnelEncryption m_Encryption;
};
class TransitTunnelGateway: public TransitTunnel

83
Tunnel.cpp

@ -27,7 +27,7 @@ namespace tunnel @@ -27,7 +27,7 @@ namespace tunnel
void Tunnel::Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel)
{
CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator ();
size_t numRecords = m_Config->GetNumHops ();
int numRecords = m_Config->GetNumHops () + 1; // +1 fake record. TODO:
I2NPMessage * msg = NewI2NPMessage ();
*msg->GetPayload () = numRecords;
msg->len += numRecords*sizeof (I2NPBuildRequestRecordElGamalEncrypted) + 1;
@ -48,21 +48,33 @@ namespace tunnel @@ -48,21 +48,33 @@ namespace tunnel
hop->next ? rnd.GenerateWord32 () : replyMsgID, // we set replyMsgID for last hop only
hop->isGateway, hop->isEndpoint),
records[i]);
hop->recordIndex = i; //TODO:
i++;
hop = hop->next;
}
// fill up fake records with random data
while (i < numRecords)
{
rnd.GenerateBlock ((uint8_t *)(records + i), sizeof (records[i]));
i++;
}
i2p::crypto::CBCDecryption decryption;
hop = m_Config->GetLastHop ()->prev;
size_t ind = numRecords - 1;
while (hop)
{
for (size_t i = ind; i < numRecords; i++)
decryption.SetKey (hop->replyKey);
// decrypt records after current hop
TunnelHopConfig * hop1 = hop->next;
while (hop1)
{
m_CBCDecryption.SetKeyWithIV (hop->replyKey, 32, hop->replyIV);
m_CBCDecryption.ProcessData((uint8_t *)&records[i], (uint8_t *)&records[i], sizeof (I2NPBuildRequestRecordElGamalEncrypted));
decryption.SetIV (hop->replyIV);
decryption.Decrypt((uint8_t *)&records[hop1->recordIndex],
sizeof (I2NPBuildRequestRecordElGamalEncrypted),
(uint8_t *)&records[hop1->recordIndex]);
hop1 = hop1->next;
}
hop = hop->prev;
ind--;
}
FillI2NPMessageHeader (msg, eI2NPVariableTunnelBuild);
@ -76,43 +88,51 @@ namespace tunnel @@ -76,43 +88,51 @@ namespace tunnel
{
LogPrint ("TunnelBuildResponse ", (int)msg[0], " records.");
i2p::crypto::CBCDecryption decryption;
TunnelHopConfig * hop = m_Config->GetLastHop ();
int num = msg[0];
while (hop)
{
for (int i = 0; i < num; i++)
decryption.SetKey (hop->replyKey);
// decrypt records before and including current hop
TunnelHopConfig * hop1 = hop;
while (hop1)
{
uint8_t * record = msg + 1 + i*sizeof (I2NPBuildResponseRecord);
m_CBCDecryption.SetKeyWithIV(hop->replyKey, 32, hop->replyIV);
m_CBCDecryption.ProcessData(record, record, sizeof (I2NPBuildResponseRecord));
auto idx = hop1->recordIndex;
if (idx >= 0 && idx < msg[0])
{
uint8_t * record = msg + 1 + idx*sizeof (I2NPBuildResponseRecord);
decryption.SetIV (hop->replyIV);
decryption.Decrypt(record, sizeof (I2NPBuildResponseRecord), record);
}
else
LogPrint ("Tunnel hop index ", idx, " is out of range");
hop1 = hop1->prev;
}
hop = hop->prev;
num--;
}
m_IsEstablished = true;
for (int i = 0; i < msg[0]; i++)
hop = m_Config->GetFirstHop ();
while (hop)
{
I2NPBuildResponseRecord * record = (I2NPBuildResponseRecord *)(msg + 1 + i*sizeof (I2NPBuildResponseRecord));
I2NPBuildResponseRecord * record = (I2NPBuildResponseRecord *)(msg + 1 + hop->recordIndex*sizeof (I2NPBuildResponseRecord));
LogPrint ("Ret code=", (int)record->ret);
if (record->ret)
// if any of participants declined the tunnel is not established
m_IsEstablished = false;
hop = hop->next;
}
return m_IsEstablished;
}
void Tunnel::LayerDecrypt (const uint8_t * in, size_t len, const uint8_t * layerKey,
const uint8_t * iv, uint8_t * out)
if (m_IsEstablished)
{
m_CBCDecryption.SetKeyWithIV (layerKey, 32, iv);
m_CBCDecryption.ProcessData(out, in, len);
}
void Tunnel::IVDecrypt (const uint8_t * in, const uint8_t * ivKey, uint8_t * out)
// change reply keys to layer keys
hop = m_Config->GetFirstHop ();
while (hop)
{
m_ECBDecryption.SetKey (ivKey, 32);
m_ECBDecryption.ProcessData(out, in, 16);
hop->decryption.SetKeys (hop->layerKey, hop->ivKey);
hop = hop->next;
}
}
return m_IsEstablished;
}
void Tunnel::EncryptTunnelMsg (I2NPMessage * tunnelMsg)
@ -121,10 +141,7 @@ namespace tunnel @@ -121,10 +141,7 @@ namespace tunnel
TunnelHopConfig * hop = m_Config->GetLastHop ();
while (hop)
{
// iv + data
IVDecrypt (payload, hop->ivKey, payload);
LayerDecrypt (payload + 16, TUNNEL_DATA_ENCRYPTED_SIZE, hop->layerKey, payload, payload+16);
IVDecrypt (payload, hop->ivKey, payload);
hop->decryption.Decrypt (payload);
hop = hop->prev;
}
}
@ -258,9 +275,9 @@ namespace tunnel @@ -258,9 +275,9 @@ namespace tunnel
return tunnel;
}
TunnelPool * Tunnels::CreateTunnelPool (i2p::data::LocalDestination& localDestination)
TunnelPool * Tunnels::CreateTunnelPool (i2p::data::LocalDestination& localDestination, int numHops)
{
auto pool = new TunnelPool (localDestination);
auto pool = new TunnelPool (localDestination, numHops);
m_Pools[pool->GetIdentHash ()] = pool;
return pool;
}
@ -424,7 +441,7 @@ namespace tunnel @@ -424,7 +441,7 @@ namespace tunnel
LogPrint ("Creating zero hops inbound tunnel...");
CreateZeroHopsInboundTunnel ();
if (!m_ExploratoryPool)
m_ExploratoryPool = CreateTunnelPool (i2p::context);
m_ExploratoryPool = CreateTunnelPool (i2p::context, 2); // 2-hop exploratory
return;
}

13
Tunnel.h

@ -8,8 +8,6 @@ @@ -8,8 +8,6 @@
#include <string>
#include <thread>
#include <mutex>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
#include "Queue.h"
#include "TunnelConfig.h"
#include "TunnelPool.h"
@ -51,20 +49,11 @@ namespace tunnel @@ -51,20 +49,11 @@ namespace tunnel
uint32_t GetNextTunnelID () const { return m_Config->GetFirstHop ()->tunnelID; };
const i2p::data::IdentHash& GetNextIdentHash () const { return m_Config->GetFirstHop ()->router->GetIdentHash (); };
private:
void LayerDecrypt (const uint8_t * in, size_t len, const uint8_t * layerKey,
const uint8_t * iv, uint8_t * out);
void IVDecrypt (const uint8_t * in, const uint8_t * ivKey, uint8_t * out);
private:
TunnelConfig * m_Config;
TunnelPool * m_Pool; // pool, tunnel belongs to, or null
bool m_IsEstablished, m_IsFailed;
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption m_ECBDecryption;
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption m_CBCDecryption;
};
class OutboundTunnel: public Tunnel
@ -125,7 +114,7 @@ namespace tunnel @@ -125,7 +114,7 @@ namespace tunnel
void PostTunnelData (I2NPMessage * msg);
template<class TTunnel>
TTunnel * CreateTunnel (TunnelConfig * config, OutboundTunnel * outboundTunnel = 0);
TunnelPool * CreateTunnelPool (i2p::data::LocalDestination& localDestination);
TunnelPool * CreateTunnelPool (i2p::data::LocalDestination& localDestination, int numHops);
void DeleteTunnelPool (TunnelPool * pool);
private:

9
TunnelConfig.h

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
#include <inttypes.h>
#include <sstream>
#include <vector>
#include "aes.h"
#include "RouterInfo.h"
#include "RouterContext.h"
@ -22,6 +23,8 @@ namespace tunnel @@ -22,6 +23,8 @@ namespace tunnel
bool isGateway, isEndpoint;
TunnelHopConfig * next, * prev;
i2p::crypto::TunnelDecryption decryption;
int recordIndex; // record # in tunnel build message
TunnelHopConfig (const i2p::data::RouterInfo * r)
{
@ -131,9 +134,9 @@ namespace tunnel @@ -131,9 +134,9 @@ namespace tunnel
return m_LastHop;
}
size_t GetNumHops () const
int GetNumHops () const
{
size_t num = 0;
int num = 0;
TunnelHopConfig * hop = m_FirstHop;
while (hop)
{
@ -180,6 +183,8 @@ namespace tunnel @@ -180,6 +183,8 @@ namespace tunnel
newConfig->m_LastHop = newHop;
if (hop->isGateway) // inbound tunnel
newHop->SetReplyHop (m_FirstHop); // use it as reply tunnel
else
newHop->SetNextRouter (&i2p::context.GetRouterInfo ());
}
if (!hop->next) newConfig->m_FirstHop = newHop; // last hop

19
TunnelEndpoint.cpp

@ -26,7 +26,8 @@ namespace tunnel @@ -26,7 +26,8 @@ namespace tunnel
bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
uint32_t msgID = 0;
TunnelMessageBlock m;
int fragmentNum = 0;
TunnelMessageBlockEx m;
if (!isFollowOnFragment)
{
// first fragment
@ -68,7 +69,7 @@ namespace tunnel @@ -68,7 +69,7 @@ namespace tunnel
// follow on
msgID = be32toh (*(uint32_t *)fragment); // MessageID
fragment += 4;
int fragmentNum = (flag >> 1) & 0x3F; // 6 bits
fragmentNum = (flag >> 1) & 0x3F; // 6 bits
isLastFragment = flag & 0x01;
LogPrint ("Follow on fragment ", fragmentNum, " of message ", msgID, isLastFragment ? " last" : " non-last");
}
@ -101,22 +102,34 @@ namespace tunnel @@ -101,22 +102,34 @@ namespace tunnel
if (msgID) // msgID is presented, assume message is fragmented
{
if (!isFollowOnFragment) // create new incomlete message
{
m.nextFragmentNum = 1;
m_IncompleteMessages[msgID] = m;
}
else
{
auto it = m_IncompleteMessages.find (msgID);
if (it != m_IncompleteMessages.end())
{
if (fragmentNum == it->second.nextFragmentNum)
{
I2NPMessage * incompleteMessage = it->second.data;
memcpy (incompleteMessage->buf + incompleteMessage->len, fragment, size); // concatenate fragment
incompleteMessage->len += size;
// TODO: check fragmentNum sequence
if (isLastFragment)
{
// message complete
HandleNextMessage (it->second);
m_IncompleteMessages.erase (it);
}
else
it->second.nextFragmentNum++;
}
else
{
LogPrint ("Unexpected fragment ", fragmentNum, " instead ", it->second.nextFragmentNum, " of message ", msgID, ". Discarded");
m_IncompleteMessages.erase (it); // TODO: store unexpect fragment for a while
}
}
else
LogPrint ("First fragment of message ", msgID, " not found. Discarded");

7
TunnelEndpoint.h

@ -26,7 +26,12 @@ namespace tunnel @@ -26,7 +26,12 @@ namespace tunnel
private:
std::map<uint32_t, TunnelMessageBlock> m_IncompleteMessages;
struct TunnelMessageBlockEx: public TunnelMessageBlock
{
uint8_t nextFragmentNum;
};
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
size_t m_NumReceivedBytes;
};
}

23
TunnelPool.cpp

@ -10,8 +10,8 @@ namespace i2p @@ -10,8 +10,8 @@ namespace i2p
{
namespace tunnel
{
TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numTunnels):
m_LocalDestination (localDestination), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr)
TunnelPool::TunnelPool (i2p::data::LocalDestination& localDestination, int numHops, int numTunnels):
m_LocalDestination (localDestination), m_NumHops (numHops), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr)
{
}
@ -189,15 +189,18 @@ namespace tunnel @@ -189,15 +189,18 @@ namespace tunnel
if (inboundTunnel)
{
LogPrint ("Creating destination outbound tunnel...");
auto firstHop = i2p::data::netdb.GetRandomRouter (&i2p::context.GetRouterInfo ());
auto secondHop = i2p::data::netdb.GetRandomRouter (firstHop);
auto * tunnel = tunnels.CreateTunnel<OutboundTunnel> (
new TunnelConfig (std::vector<const i2p::data::RouterInfo *>
const i2p::data::RouterInfo * prevHop = &i2p::context.GetRouterInfo ();
std::vector<const i2p::data::RouterInfo *> hops;
for (int i = 0; i < m_NumHops; i++)
{
firstHop,
secondHop
},
inboundTunnel->GetTunnelConfig ()));
auto hop = i2p::data::netdb.GetRandomRouter (prevHop);
prevHop = hop;
hops.push_back (hop);
}
auto * tunnel = tunnels.CreateTunnel<OutboundTunnel> (
new TunnelConfig (hops, inboundTunnel->GetTunnelConfig ()));
tunnel->SetTunnelPool (this);
}
}

4
TunnelPool.h

@ -23,7 +23,7 @@ namespace tunnel @@ -23,7 +23,7 @@ namespace tunnel
{
public:
TunnelPool (i2p::data::LocalDestination& localDestination, int numTunnels = 5);
TunnelPool (i2p::data::LocalDestination& localDestination, int numHops, int numTunnels = 5);
~TunnelPool ();
const uint8_t * GetEncryptionPrivateKey () const { return m_LocalDestination.GetEncryptionPrivateKey (); };
@ -53,7 +53,7 @@ namespace tunnel @@ -53,7 +53,7 @@ namespace tunnel
private:
i2p::data::LocalDestination& m_LocalDestination;
int m_NumTunnels;
int m_NumHops, m_NumTunnels;
std::set<InboundTunnel *, TunnelCreationTimeCmp> m_InboundTunnels; // recent tunnel appears first
std::set<OutboundTunnel *, TunnelCreationTimeCmp> m_OutboundTunnels;
std::map<uint32_t, std::pair<OutboundTunnel *, InboundTunnel *> > m_Tests;

357
aes.cpp

@ -0,0 +1,357 @@ @@ -0,0 +1,357 @@
#include <stdlib.h>
#include "TunnelBase.h"
#include "aes.h"
namespace i2p
{
namespace crypto
{
#ifdef AESNI
ECBCryptoAESNI::ECBCryptoAESNI ()
{
m_KeySchedule = m_UnalignedBuffer;
uint8_t rem = ((uint64_t)m_KeySchedule) & 0x0f;
if (rem)
m_KeySchedule += (16 - rem);
}
#define KeyExpansion256(round0,round1) \
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
"movaps %%xmm1, %%xmm4 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm1 \n" \
"pxor %%xmm2, %%xmm1 \n" \
"movaps %%xmm1, "#round0"(%[sched]) \n" \
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
"movaps %%xmm3, %%xmm4 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pslldq $4, %%xmm4 \n" \
"pxor %%xmm4, %%xmm3 \n" \
"pxor %%xmm2, %%xmm3 \n" \
"movaps %%xmm3, "#round1"(%[sched]) \n"
void ECBCryptoAESNI::ExpandKey (const uint8_t * key)
{
__asm__
(
"movups (%[key]), %%xmm1 \n"
"movups 16(%[key]), %%xmm3 \n"
"movaps %%xmm1, (%[sched]) \n"
"movaps %%xmm3, 16(%[sched]) \n"
"aeskeygenassist $1, %%xmm3, %%xmm2 \n"
KeyExpansion256(32,48)
"aeskeygenassist $2, %%xmm3, %%xmm2 \n"
KeyExpansion256(64,80)
"aeskeygenassist $4, %%xmm3, %%xmm2 \n"
KeyExpansion256(96,112)
"aeskeygenassist $8, %%xmm3, %%xmm2 \n"
KeyExpansion256(128,144)
"aeskeygenassist $16, %%xmm3, %%xmm2 \n"
KeyExpansion256(160,176)
"aeskeygenassist $32, %%xmm3, %%xmm2 \n"
KeyExpansion256(192,208)
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
// key expansion final
"pshufd $0xff, %%xmm2, %%xmm2 \n"
"movaps %%xmm1, %%xmm4 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pslldq $4, %%xmm4 \n"
"pxor %%xmm4, %%xmm1 \n"
"pxor %%xmm2, %%xmm1 \n"
"movups %%xmm1, 224(%[sched]) \n"
: // output
: [key]"r"(key), [sched]"r"(m_KeySchedule) // input
: "%xmm1", "%xmm2", "%xmm3", "%xmm4" // clogged
);
}
#define EncryptAES256(sched) \
"pxor (%["#sched"]), %%xmm0 \n" \
"aesenc 16(%["#sched"]), %%xmm0 \n" \
"aesenc 32(%["#sched"]), %%xmm0 \n" \
"aesenc 48(%["#sched"]), %%xmm0 \n" \
"aesenc 64(%["#sched"]), %%xmm0 \n" \
"aesenc 80(%["#sched"]), %%xmm0 \n" \
"aesenc 96(%["#sched"]), %%xmm0 \n" \
"aesenc 112(%["#sched"]), %%xmm0 \n" \
"aesenc 128(%["#sched"]), %%xmm0 \n" \
"aesenc 144(%["#sched"]), %%xmm0 \n" \
"aesenc 160(%["#sched"]), %%xmm0 \n" \
"aesenc 176(%["#sched"]), %%xmm0 \n" \
"aesenc 192(%["#sched"]), %%xmm0 \n" \
"aesenc 208(%["#sched"]), %%xmm0 \n" \
"aesenclast 224(%["#sched"]), %%xmm0 \n"
void ECBEncryptionAESNI::Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
__asm__
(
"movups (%[in]), %%xmm0 \n"
EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(m_KeySchedule), [in]"r"(in), [out]"r"(out) : "%xmm0"
);
}
#define DecryptAES256(sched) \
"pxor 224(%["#sched"]), %%xmm0 \n" \
"aesdec 208(%["#sched"]), %%xmm0 \n" \
"aesdec 192(%["#sched"]), %%xmm0 \n" \
"aesdec 176(%["#sched"]), %%xmm0 \n" \
"aesdec 160(%["#sched"]), %%xmm0 \n" \
"aesdec 144(%["#sched"]), %%xmm0 \n" \
"aesdec 128(%["#sched"]), %%xmm0 \n" \
"aesdec 112(%["#sched"]), %%xmm0 \n" \
"aesdec 96(%["#sched"]), %%xmm0 \n" \
"aesdec 80(%["#sched"]), %%xmm0 \n" \
"aesdec 64(%["#sched"]), %%xmm0 \n" \
"aesdec 48(%["#sched"]), %%xmm0 \n" \
"aesdec 32(%["#sched"]), %%xmm0 \n" \
"aesdec 16(%["#sched"]), %%xmm0 \n" \
"aesdeclast (%["#sched"]), %%xmm0 \n"
void ECBDecryptionAESNI::Decrypt (const ChipherBlock * in, ChipherBlock * out)
{
__asm__
(
"movups (%[in]), %%xmm0 \n"
DecryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
: : [sched]"r"(m_KeySchedule), [in]"r"(in), [out]"r"(out) : "%xmm0"
);
}
#define CallAESIMC(offset) \
"movaps "#offset"(%[shed]), %%xmm0 \n" \
"aesimc %%xmm0, %%xmm0 \n" \
"movaps %%xmm0, "#offset"(%[shed]) \n"
void ECBDecryptionAESNI::SetKey (const uint8_t * key)
{
ExpandKey (key); // expand encryption key first
// then invert it using aesimc
__asm__
(
CallAESIMC(16)
CallAESIMC(32)
CallAESIMC(48)
CallAESIMC(64)
CallAESIMC(80)
CallAESIMC(96)
CallAESIMC(112)
CallAESIMC(128)
CallAESIMC(144)
CallAESIMC(160)
CallAESIMC(176)
CallAESIMC(192)
CallAESIMC(208)
: : [shed]"r"(m_KeySchedule) : "%xmm0"
);
}
#endif
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{
#ifdef AESNI
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"block_e: \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[out]) \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz block_e; \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{
m_LastBlock ^= in[i];
m_ECBEncryption.Encrypt (&m_LastBlock, &m_LastBlock);
out[i] = m_LastBlock;
}
#endif
}
void CBCEncryption::Encrypt (const uint8_t * in, std::size_t len, uint8_t * out)
{
// len/16
Encrypt (len >> 4, (const ChipherBlock *)in, (ChipherBlock *)out);
}
void CBCEncryption::Encrypt (const uint8_t * in, uint8_t * out)
{
#ifdef AESNI
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched)
"movups %%xmm0, (%[out]) \n"
"movups %%xmm0, (%[iv]) \n"
:
: [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory"
);
#else
Encrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
#endif
}
void CBCDecryption::Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{
#ifdef AESNI
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"block_d: \n"
"movups (%[in]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
"movaps %%xmm2, %%xmm1 \n"
"add $16, %[in] \n"
"add $16, %[out] \n"
"dec %[num] \n"
"jnz block_d; \n"
"movups %%xmm1, (%[iv]) \n"
:
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
#else
for (int i = 0; i < numBlocks; i++)
{
ChipherBlock tmp = in[i];
m_ECBDecryption.Decrypt (in + i, out + i);
out[i] ^= m_IV;
m_IV = tmp;
}
#endif
}
void CBCDecryption::Decrypt (const uint8_t * in, std::size_t len, uint8_t * out)
{
Decrypt (len >> 4, (const ChipherBlock *)in, (ChipherBlock *)out);
}
void CBCDecryption::Decrypt (const uint8_t * in, uint8_t * out)
{
#ifdef AESNI
__asm__
(
"movups (%[iv]), %%xmm1 \n"
"movups (%[in]), %%xmm0 \n"
"movups %%xmm0, (%[iv]) \n"
DecryptAES256(sched)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[out]) \n"
:
: [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
[in]"r"(in), [out]"r"(out)
: "%xmm0", "%xmm1", "memory"
);
#else
Decrypt (1, (const ChipherBlock *)in, (ChipherBlock *)out);
#endif
}
void TunnelEncryption::Encrypt (uint8_t * payload)
{
#ifdef AESNI
__asm__
(
// encrypt IV
"movups (%[payload]), %%xmm0 \n"
EncryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n"
// double IV encryption
EncryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n"
// encrypt data, IV is xmm1
"block_et: \n"
"add $16, %[payload] \n"
"movups (%[payload]), %%xmm0 \n"
"pxor %%xmm1, %%xmm0 \n"
EncryptAES256(sched_l)
"movaps %%xmm0, %%xmm1 \n"
"movups %%xmm0, (%[payload]) \n"
"dec %[num] \n"
"jnz block_et; \n"
:
: [sched_iv]"r"(m_IVEncryption.GetKeySchedule ()), [sched_l]"r"(m_LayerEncryption.GetKeySchedule ()),
[payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "cc", "memory"
);
#else
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
m_LayerEncryption.Encrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
m_IVEncryption.Encrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
#endif
}
void TunnelDecryption::Decrypt (uint8_t * payload)
{
#ifdef AESNI
__asm__
(
// decrypt IV
"movups (%[payload]), %%xmm0 \n"
DecryptAES256(sched_iv)
"movaps %%xmm0, %%xmm1 \n"
// double IV encryption
DecryptAES256(sched_iv)
"movups %%xmm0, (%[payload]) \n"
// decrypt data, IV is xmm1
"block_dt: \n"
"add $16, %[payload] \n"
"movups (%[payload]), %%xmm0 \n"
"movaps %%xmm0, %%xmm2 \n"
DecryptAES256(sched_l)
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[payload]) \n"
"movaps %%xmm2, %%xmm1 \n"
"dec %[num] \n"
"jnz block_dt; \n"
:
: [sched_iv]"r"(m_IVDecryption.GetKeySchedule ()), [sched_l]"r"(m_LayerDecryption.GetKeySchedule ()),
[payload]"r"(payload), [num]"r"(63) // 63 blocks = 1008 bytes
: "%xmm0", "%xmm1", "%xmm2", "cc", "memory"
);
#else
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // iv
m_LayerDecryption.Decrypt (payload + 16, i2p::tunnel::TUNNEL_DATA_ENCRYPTED_SIZE, payload + 16); // data
m_IVDecryption.Decrypt ((ChipherBlock *)payload, (ChipherBlock *)payload); // double iv
#endif
}
}
}

188
aes.h

@ -0,0 +1,188 @@ @@ -0,0 +1,188 @@
#ifndef AES_H__
#define AES_H__
#include <inttypes.h>
#include <cryptopp/modes.h>
#include <cryptopp/aes.h>
namespace i2p
{
namespace crypto
{
union ChipherBlock
{
uint8_t buf[16];
uint64_t ll[2];
void operator^=(const ChipherBlock& other) // XOR
{
ll[0] ^= other.ll[0];
ll[1] ^= other.ll[1];
}
};
#ifdef AESNI
class ECBCryptoAESNI
{
public:
ECBCryptoAESNI ();
uint8_t * GetKeySchedule () { return m_KeySchedule; };
protected:
void ExpandKey (const uint8_t * key);
protected:
uint8_t * m_KeySchedule; // start of 16 bytes boundary of m_UnalignedBuffer
uint8_t m_UnalignedBuffer[256]; // 14 rounds for AES-256, 240 + 16 bytes
};
class ECBEncryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const uint8_t * key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out);
};
class ECBDecryptionAESNI: public ECBCryptoAESNI
{
public:
void SetKey (const uint8_t * key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
};
typedef ECBEncryptionAESNI ECBEncryption;
typedef ECBDecryptionAESNI ECBDecryption;
#else // use crypto++
class ECBEncryption
{
public:
void SetKey (const uint8_t * key)
{
m_Encryption.SetKey (key, 32);
}
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
{
m_Encryption.ProcessData (out->buf, in->buf, 16);
}
private:
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption m_Encryption;
};
class ECBDecryption
{
public:
void SetKey (const uint8_t * key)
{
m_Decryption.SetKey (key, 32);
}
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
{
m_Decryption.ProcessData (out->buf, in->buf, 16);
}
private:
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption m_Decryption;
};
#endif
class CBCEncryption
{
public:
CBCEncryption () { memset (m_LastBlock.buf, 0, 16); };
void SetKey (const uint8_t * key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes
void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Encrypt (const uint8_t * in, uint8_t * out); // one block
private:
ChipherBlock m_LastBlock;
ECBEncryption m_ECBEncryption;
};
class CBCDecryption
{
public:
CBCDecryption () { memset (m_IV.buf, 0, 16); };
void SetKey (const uint8_t * key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes
void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out);
void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out);
void Decrypt (const uint8_t * in, uint8_t * out); // one block
private:
ChipherBlock m_IV;
ECBDecryption m_ECBDecryption;
};
class TunnelEncryption // with double IV encryption
{
public:
void SetKeys (const uint8_t * layerKey, const uint8_t * ivKey)
{
m_LayerEncryption.SetKey (layerKey);
m_IVEncryption.SetKey (ivKey);
}
void Encrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data)
private:
ECBEncryption m_IVEncryption;
#ifdef AESNI
ECBEncryption m_LayerEncryption;
#else
CBCEncryption m_LayerEncryption;
#endif
};
class TunnelDecryption // with double IV encryption
{
public:
void SetKeys (const uint8_t * layerKey, const uint8_t * ivKey)
{
m_LayerDecryption.SetKey (layerKey);
m_IVDecryption.SetKey (ivKey);
}
void Decrypt (uint8_t * payload); // 1024 bytes (16 IV + 1008 data)
private:
ECBDecryption m_IVDecryption;
#ifdef AESNI
ECBDecryption m_LayerDecryption;
#else
CBCDecryption m_LayerDecryption;
#endif
};
}
}
#endif

44
hmac.h

@ -18,38 +18,38 @@ namespace crypto @@ -18,38 +18,38 @@ namespace crypto
// digest is 16 bytes
// block size is 64 bytes
{
uint8_t buf[2048];
uint64_t buf[256];
// ikeypad
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ IPAD;
((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ IPAD;
((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ IPAD;
((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ IPAD;
((uint64_t *)buf)[4] = IPAD;
((uint64_t *)buf)[5] = IPAD;
((uint64_t *)buf)[6] = IPAD;
((uint64_t *)buf)[7] = IPAD;
buf[0] = ((uint64_t *)key)[0] ^ IPAD;
buf[1] = ((uint64_t *)key)[1] ^ IPAD;
buf[2] = ((uint64_t *)key)[2] ^ IPAD;
buf[3] = ((uint64_t *)key)[3] ^ IPAD;
buf[4] = IPAD;
buf[5] = IPAD;
buf[6] = IPAD;
buf[7] = IPAD;
// concatenate with msg
memcpy (buf + 64, msg, len);
memcpy (buf + 8, msg, len);
// calculate first hash
uint8_t hash[16]; // MD5
CryptoPP::Weak1::MD5().CalculateDigest (hash, buf, len + 64);
CryptoPP::Weak1::MD5().CalculateDigest (hash, (uint8_t *)buf, len + 64);
// okeypad
((uint64_t *)buf)[0] = ((uint64_t *)key)[0] ^ OPAD;
((uint64_t *)buf)[1] = ((uint64_t *)key)[1] ^ OPAD;
((uint64_t *)buf)[2] = ((uint64_t *)key)[2] ^ OPAD;
((uint64_t *)buf)[3] = ((uint64_t *)key)[3] ^ OPAD;
((uint64_t *)buf)[4] = OPAD;
((uint64_t *)buf)[5] = OPAD;
((uint64_t *)buf)[6] = OPAD;
((uint64_t *)buf)[7] = OPAD;
buf[0] = ((uint64_t *)key)[0] ^ OPAD;
buf[1] = ((uint64_t *)key)[1] ^ OPAD;
buf[2] = ((uint64_t *)key)[2] ^ OPAD;
buf[3] = ((uint64_t *)key)[3] ^ OPAD;
buf[4] = OPAD;
buf[5] = OPAD;
buf[6] = OPAD;
buf[7] = OPAD;
// copy first hash after okeypad
memcpy (buf + 64, hash, 16);
memcpy (buf + 8, hash, 16);
// fill next 16 bytes with zeros (first hash size assumed 32 bytes in I2P)
memset (buf + 80, 0, 16);
memset (buf + 10, 0, 16);
// calculate digest
CryptoPP::Weak1::MD5().CalculateDigest (digest, buf, 96);
CryptoPP::Weak1::MD5().CalculateDigest (digest, (uint8_t *)buf, 96);
}
}
}

2
i2p.cpp

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
#include <thread>
#include <stdlib.h>
#include "Daemon.h"
int main( int argc, char* argv[] )

Loading…
Cancel
Save