Browse Source

send and receive data

pull/163/head
orignal 10 years ago
parent
commit
71dae29077
  1. 279
      Reseed.cpp
  2. 13
      Reseed.h

279
Reseed.cpp

@ -3,9 +3,11 @@
#include <sstream> #include <sstream>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <cryptopp/asn.h> #include <cryptopp/asn.h>
#include <cryptopp/base64.h> #include <cryptopp/base64.h>
#include <cryptopp/crc.h> #include <cryptopp/crc.h>
#include <cryptopp/hmac.h>
#include <cryptopp/zinflate.h> #include <cryptopp/zinflate.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Reseed.h" #include "Reseed.h"
@ -497,7 +499,30 @@ namespace data
LogPrint (eLogInfo, numCertificates, " certificates loaded"); LogPrint (eLogInfo, numCertificates, " certificates loaded");
} }
TlsSession::TlsSession (const std::string& address) std::string Reseeder::HttpsRequest (const std::string& address)
{
i2p::util::http::url u(address);
TlsSession session (u.host_, 443);
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 ());
return "";
}
TlsSession::TlsSession (const std::string& host, int port):
m_Seqn (0)
{
m_Site.connect(host, boost::lexical_cast<std::string>(port));
if (m_Site.good ())
{
Handshake ();
}
else
LogPrint (eLogError, "Can't connect to ", host, ":", port);
}
void TlsSession::Handshake ()
{ {
static uint8_t clientHello[] = static uint8_t clientHello[] =
{ {
@ -555,116 +580,108 @@ namespace data
// 12 bytes of verified data // 12 bytes of verified data
}; };
i2p::util::http::url u(address); CryptoPP::SHA256 finishedHash;
boost::asio::ip::tcp::iostream site; // send ClientHello
site.connect(u.host_, "443"); m_Site.write ((char *)clientHello, sizeof (clientHello));
if (site.good ()) finishedHash.Update (clientHello + 5, sizeof (clientHello) - 5);
{ // read ServerHello
CryptoPP::SHA256 finishedHash; uint8_t type;
// send ClientHello m_Site.read ((char *)&type, 1);
site.write ((char *)clientHello, sizeof (clientHello)); uint16_t version;
finishedHash.Update (clientHello + 5, sizeof (clientHello) - 5); m_Site.read ((char *)&version, 2);
// read ServerHello uint16_t length;
uint8_t type; m_Site.read ((char *)&length, 2);
site.read ((char *)&type, 1); length = be16toh (length);
uint16_t version; char * serverHello = new char[length];
site.read ((char *)&version, 2); m_Site.read (serverHello, length);
uint16_t length; finishedHash.Update ((uint8_t *)serverHello, length);
site.read ((char *)&length, 2); uint8_t serverRandom[32];
length = be16toh (length); if (serverHello[0] == 0x02) // handshake type server hello
char * serverHello = new char[length]; memcpy (serverRandom, serverHello + 6, 32);
site.read (serverHello, length); else
finishedHash.Update ((uint8_t *)serverHello, length); LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]);
uint8_t serverRandom[32]; delete[] serverHello;
if (serverHello[0] == 0x02) // handshake type server hello // read Certificate
memcpy (serverRandom, serverHello + 6, 32); m_Site.read ((char *)&type, 1);
else m_Site.read ((char *)&version, 2);
LogPrint (eLogError, "Unexpected handshake type ", (int)serverHello[0]); m_Site.read ((char *)&length, 2);
delete[] serverHello; length = be16toh (length);
// read Certificate char * certificate = new char[length];
site.read ((char *)&type, 1); m_Site.read (certificate, length);
site.read ((char *)&version, 2); finishedHash.Update ((uint8_t *)certificate, length);
site.read ((char *)&length, 2); CryptoPP::RSA::PublicKey publicKey;
length = be16toh (length); // 0 - handshake type
char * certificate = new char[length]; // 1 - 3 - handshake payload length
site.read (certificate, length); // 4 - 6 - length of array of certificates
finishedHash.Update ((uint8_t *)certificate, length); // 7 - 9 - length of certificate
CryptoPP::RSA::PublicKey publicKey; if (certificate[0] == 0x0B) // handshake type certificate
// 0 - handshake type publicKey = ExtractPublicKey ((uint8_t *)certificate + 10, length - 10);
// 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]);
delete[] certificate;
// read ServerHelloDone
site.read ((char *)&type, 1);
site.read ((char *)&version, 2);
site.read ((char *)&length, 2);
length = be16toh (length);
char * serverHelloDone = new char[length];
site.read (serverHelloDone, length);
finishedHash.Update ((uint8_t *)serverHelloDone, length);
if (serverHelloDone[0] != 0x0E) // handshake type hello done
LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]);
delete[] serverHelloDone;
// our turn now
// generate secret key
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey);
// encryptor.CiphertextLength (48);
uint8_t secret[48], encrypted[256];
secret[0] = clientKeyExchange[1]; secret[1] = clientKeyExchange[2]; // version
m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes
encryptor.Encrypt (rnd, secret, 48, encrypted);
// send ClientKeyExchange
site.write ((char *)clientKeyExchange, sizeof (clientKeyExchange));
site.write ((char *)encrypted, 256);
finishedHash.Update (clientKeyExchange + 5, sizeof (clientKeyExchange) - 5);
finishedHash.Update (encrypted, 256);
uint8_t masterSecret[48], random[64];
memcpy (random, clientHello + 11, 32);
memcpy (random + 32, serverRandom, 32);
// send ChangeCipherSpecs
site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs));
// calculate master secret
PRF (secret, "master secret", random, 64, 48, masterSecret);
// expand master secret
uint8_t keys[256]; // clientMACKey, serverMACKey, clientKey, serverKey
memcpy (random, serverRandom, 32);
memcpy (random + 32, clientHello + 11, 32);
PRF (masterSecret, "key expansion", random, 64, 256, keys);
memcpy (m_MacKey, keys, 32);
m_Encryption.SetKey (keys + 64);
m_Decryption.SetKey (keys + 96);
// send finished
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
finishedHash.Final (finishedHashDigest);
PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4);
uint8_t mac[32];
CalculateMAC (0x16, 0, finishedPayload, 16, mac);
Encrypt (finishedPayload, 16, mac, encryptedPayload);
site.write ((char *)finished, sizeof (finished));
site.write ((char *)encryptedPayload, 80);
// read ChangeCipherSpecs
uint8_t changeCipherSpecs1[6];
site.read ((char *)changeCipherSpecs1, 6);
// read finished
site.read ((char *)&type, 1);
site.read ((char *)&version, 2);
site.read ((char *)&length, 2);
length = be16toh (length);
char * finished1 = new char[length];
site.read (finished1, length);
delete[] finished1;
}
else else
LogPrint (eLogError, "Can't connect to ", address); LogPrint (eLogError, "Unexpected handshake type ", (int)certificate[0]);
delete[] certificate;
// 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);
finishedHash.Update ((uint8_t *)serverHelloDone, length);
if (serverHelloDone[0] != 0x0E) // handshake type hello done
LogPrint (eLogError, "Unexpected handshake type ", (int)serverHelloDone[0]);
delete[] serverHelloDone;
// our turn now
// generate secret key
CryptoPP::AutoSeededRandomPool rnd;
CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey);
// encryptor.CiphertextLength (48);
uint8_t secret[48], encrypted[256];
secret[0] = 3; secret[1] = 3; // version
m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes
encryptor.Encrypt (rnd, secret, 48, encrypted);
// send ClientKeyExchange
m_Site.write ((char *)clientKeyExchange, sizeof (clientKeyExchange));
m_Site.write ((char *)encrypted, 256);
finishedHash.Update (clientKeyExchange + 5, sizeof (clientKeyExchange) - 5);
finishedHash.Update (encrypted, 256);
uint8_t masterSecret[48], random[64];
memcpy (random, clientHello + 11, 32);
memcpy (random + 32, serverRandom, 32);
// send ChangeCipherSpecs
m_Site.write ((char *)changeCipherSpecs, sizeof (changeCipherSpecs));
// calculate master secret
PRF (secret, "master secret", random, 64, 48, masterSecret);
// expand master secret
uint8_t keys[256]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32)
memcpy (random, serverRandom, 32);
memcpy (random + 32, clientHello + 11, 32);
PRF (masterSecret, "key expansion", random, 64, 256, keys);
memcpy (m_MacKey, keys, 32);
m_Encryption.SetKey (keys + 64);
m_Decryption.SetKey (keys + 96);
// send finished
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
finishedHash.Final (finishedHashDigest);
PRF (masterSecret, "client finished", finishedHashDigest, 32, 12, finishedPayload + 4);
uint8_t mac[32];
CalculateMAC (0x16, finishedPayload, 16, mac);
Encrypt (finishedPayload, 16, mac, encryptedPayload);
m_Site.write ((char *)finished, sizeof (finished));
m_Site.write ((char *)encryptedPayload, 80);
// 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);
delete[] finished1;
} }
void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, void TlsSession::PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
@ -710,24 +727,24 @@ namespace data
return size; return size;
} }
size_t TlsSession::Decrypt (uint8_t * in, size_t len, uint8_t * out) size_t TlsSession::Decrypt (uint8_t * buf, size_t len)
{ {
m_Decryption.SetIV (in); m_Decryption.SetIV (buf);
m_Decryption.Decrypt (in + 16, len - 16, in + 16); m_Decryption.Decrypt (buf + 16, len - 16, buf + 16);
memcpy (out, in + 16, len - 48); // skip 32 bytes mac return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding
return len - 48 - in[len -1] - 1;
} }
void TlsSession::CalculateMAC (uint8_t type, uint64_t seqn, const uint8_t * buf, size_t len, uint8_t * mac) void TlsSession::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) uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2)
htobe64buf (header, seqn); htobe64buf (header, m_Seqn);
header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2
htobe16buf (header + 11, len); htobe16buf (header + 11, len);
CryptoPP::HMAC<CryptoPP::SHA256> hmac (m_MacKey, 32); CryptoPP::HMAC<CryptoPP::SHA256> hmac (m_MacKey, 32);
hmac.Update (header, 13); hmac.Update (header, 13);
hmac.Update (buf, len); hmac.Update (buf, len);
hmac.Final (mac); hmac.Final (mac);
m_Seqn++;
} }
CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len)
@ -773,6 +790,34 @@ namespace data
return ret; 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];
CalculateMAC (0x17, buf, len, mac);
size_t encryptedLen = Encrypt (buf, len, mac, out);
htobe16buf (out + 3, encryptedLen);
m_Site.write ((char *)out, encryptedLen + 5);
delete[] out;
}
std::string TlsSession::Receive ()
{
if (m_Site.eof ()) return "";
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 = Decrypt (buf, length);
std::string str ((char *)buf + 16, decryptedLen);
delete[] buf;
return str;
}
} }
} }

13
Reseed.h

@ -7,7 +7,7 @@
#include <map> #include <map>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include <cryptopp/rsa.h> #include <cryptopp/rsa.h>
#include <cryptopp/hmac.h> #include <boost/asio.hpp>
#include "Identity.h" #include "Identity.h"
#include "aes.h" #include "aes.h"
@ -51,19 +51,24 @@ namespace data
{ {
public: public:
TlsSession (const std::string& address); TlsSession (const std::string& host, int port);
void Send (const uint8_t * buf, size_t len);
std::string Receive ();
private: private:
void Handshake ();
CryptoPP::RSA::PublicKey ExtractPublicKey (const uint8_t * certificate, size_t len); 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, void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen,
size_t len, uint8_t * buf); size_t len, uint8_t * buf);
void CalculateMAC (uint8_t type, uint64_t seqn, const uint8_t * buf, size_t len, uint8_t * mac); void CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac);
size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out); size_t Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out);
size_t Decrypt (uint8_t * in, size_t len, uint8_t * out); size_t Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16
private: private:
uint64_t m_Seqn;
boost::asio::ip::tcp::iostream m_Site;
CryptoPP::AutoSeededRandomPool m_Rnd; CryptoPP::AutoSeededRandomPool m_Rnd;
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
i2p::crypto::CBCDecryption m_Decryption; i2p::crypto::CBCDecryption m_Decryption;

Loading…
Cancel
Save