diff --git a/Reseed.cpp b/Reseed.cpp index c7347841..ad4ba10d 100644 --- a/Reseed.cpp +++ b/Reseed.cpp @@ -510,7 +510,7 @@ namespace data } TlsSession::TlsSession (const std::string& host, int port): - m_Seqn (0) + m_Cipher (nullptr) { m_Site.connect(host, boost::lexical_cast(port)); if (m_Site.good ()) @@ -521,6 +521,11 @@ namespace data LogPrint (eLogError, "Can't connect to ", host, ":", port); } + TlsSession::~TlsSession () + { + delete m_Cipher; + } + void TlsSession::Handshake () { static uint8_t clientHello[] = @@ -618,13 +623,14 @@ namespace data // generate secret key uint8_t secret[48]; secret[0] = 3; secret[1] = 3; // version - m_Rnd.GenerateBlock (secret + 2, 46); // 46 random bytes + CryptoPP::AutoSeededRandomPool rnd; + rnd.GenerateBlock (secret + 2, 46); // 46 random bytes // encrypt RSA CryptoPP::RSAES_PKCS1v15_Encryptor encryptor(publicKey); size_t encryptedLen = encryptor.CiphertextLength (48); // number of bytes for encrypted 48 bytes, usually 256 (2048 bits key) uint8_t * encrypted = new uint8_t[encryptedLen + 2]; // + 2 bytes for length htobe16buf (encrypted, encryptedLen); // first two bytes means length - encryptor.Encrypt (m_Rnd, secret, 48, encrypted + 2); + encryptor.Encrypt (rnd, secret, 48, encrypted + 2); // send ClientKeyExchange // 0x10 - handshake type "client key exchange" SendHandshakeMsg (0x10, encrypted, encryptedLen + 2); @@ -635,15 +641,12 @@ namespace data uint8_t masterSecret[48], random[64]; memcpy (random, clientHello + 11, 32); memcpy (random + 32, serverRandom, 32); - PRF (secret, "master secret", random, 64, 48, masterSecret); - // expand master secret - uint8_t keys[128]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32) + PRF (secret, "master secret", random, 64, 48, masterSecret); + // invert random for keys memcpy (random, serverRandom, 32); - memcpy (random + 32, clientHello + 11, 32); - PRF (masterSecret, "key expansion", random, 64, 128, keys); - memcpy (m_MacKey, keys, 32); - m_Encryption.SetKey (keys + 64); - m_Decryption.SetKey (keys + 96); + memcpy (random + 32, clientHello + 11, 32); + // create cipher + m_Cipher = new TlsCipher_AES_256_CBC_SHA256 (masterSecret, random); // send finished uint8_t finishedHashDigest[32], finishedPayload[40], encryptedPayload[80]; @@ -652,10 +655,10 @@ namespace data m_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_Cipher->CalculateMAC (0x16, finishedPayload, 16, mac); + size_t encryptedPayloadSize = m_Cipher->Encrypt (finishedPayload, 16, mac, encryptedPayload); m_Site.write ((char *)finished, sizeof (finished)); - m_Site.write ((char *)encryptedPayload, 80); + m_Site.write ((char *)encryptedPayload, encryptedPayloadSize); // read ChangeCipherSpecs uint8_t changeCipherSpecs1[6]; m_Site.read ((char *)changeCipherSpecs1, 6); @@ -709,45 +712,6 @@ namespace data } } - size_t TlsSession::Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) - { - size_t size = 0; - m_Rnd.GenerateBlock (out, 16); // iv - size += 16; - m_Encryption.SetIV (out); - memcpy (out + size, in, len); - size += len; - memcpy (out + size, mac, 32); - size += 32; - uint8_t paddingSize = len + 1; - paddingSize &= 0x0F; // %16 - if (paddingSize > 0) paddingSize = 16 - paddingSize; - memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size - size += paddingSize + 1; - m_Encryption.Encrypt (out + 16, size - 16, out + 16); - return size; - } - - size_t TlsSession::Decrypt (uint8_t * buf, size_t len) - { - m_Decryption.SetIV (buf); - m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); - return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding - } - - 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) - htobe64buf (header, m_Seqn); - header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 - htobe16buf (header + 11, len); - CryptoPP::HMAC hmac (m_MacKey, 32); - hmac.Update (header, 13); - hmac.Update (buf, len); - hmac.Final (mac); - m_Seqn++; - } - CryptoPP::RSA::PublicKey TlsSession::ExtractPublicKey (const uint8_t * certificate, size_t len) { CryptoPP::ByteQueue queue; @@ -797,8 +761,8 @@ namespace data 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 + 5); + m_Cipher->CalculateMAC (0x17, buf, len, mac); + size_t encryptedLen = m_Cipher->Encrypt (buf, len, mac, out + 5); htobe16buf (out + 3, encryptedLen); m_Site.write ((char *)out, encryptedLen + 5); delete[] out; @@ -814,11 +778,61 @@ namespace data length = be16toh (length); uint8_t * buf = new uint8_t[length]; m_Site.read ((char *)buf, length); - size_t decryptedLen = Decrypt (buf, length); + size_t decryptedLen = m_Cipher->Decrypt (buf, length); rs.write ((char *)buf + 16, decryptedLen); delete[] buf; return true; } + + TlsCipher_AES_256_CBC_SHA256::TlsCipher_AES_256_CBC_SHA256 (uint8_t * masterSecret, uint8_t * random): + m_Seqn (0) + { + uint8_t keys[128]; // clientMACKey(32), serverMACKey(32), clientKey(32), serverKey(32) + // expand master secret + TlsSession::PRF (masterSecret, "key expansion", random, 64, 128, keys); + memcpy (m_MacKey, keys, 32); + m_Encryption.SetKey (keys + 64); + m_Decryption.SetKey (keys + 96); + } + + void TlsCipher_AES_256_CBC_SHA256::CalculateMAC (uint8_t type, const uint8_t * buf, size_t len, uint8_t * mac) + { + uint8_t header[13]; // seqn (8) + type (1) + version (2) + length (2) + htobe64buf (header, m_Seqn); + header[8] = type; header[9] = 3; header[10] = 3; // 3,3 means TLS 1.2 + htobe16buf (header + 11, len); + CryptoPP::HMAC hmac (m_MacKey, 32); + hmac.Update (header, 13); + hmac.Update (buf, len); + hmac.Final (mac); + m_Seqn++; + } + + size_t TlsCipher_AES_256_CBC_SHA256::Encrypt (const uint8_t * in, size_t len, const uint8_t * mac, uint8_t * out) + { + size_t size = 0; + m_Rnd.GenerateBlock (out, 16); // iv + size += 16; + m_Encryption.SetIV (out); + memcpy (out + size, in, len); + size += len; + memcpy (out + size, mac, 32); + size += 32; + uint8_t paddingSize = len + 1; + paddingSize &= 0x0F; // %16 + if (paddingSize > 0) paddingSize = 16 - paddingSize; + memset (out + size, paddingSize, paddingSize + 1); // paddind and last byte are equal to padding size + size += paddingSize + 1; + m_Encryption.Encrypt (out + 16, size - 16, out + 16); + return size; + } + + size_t TlsCipher_AES_256_CBC_SHA256::Decrypt (uint8_t * buf, size_t len) + { + m_Decryption.SetIV (buf); + m_Decryption.Decrypt (buf + 16, len - 16, buf + 16); + return len - 48 - buf[len -1] - 1; // IV(16), mac(32) and padding + } } } diff --git a/Reseed.h b/Reseed.h index d43227a5..4b5347eb 100644 --- a/Reseed.h +++ b/Reseed.h @@ -47,34 +47,50 @@ namespace data std::map m_SigningKeys; }; + + class TlsCipher_AES_256_CBC_SHA256 + { + public: + + TlsCipher_AES_256_CBC_SHA256 (uint8_t * masterSecret, uint8_t * random); // master secret - 48 bytes, random - 64 bytes + + 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 Decrypt (uint8_t * buf, size_t len); // payload is buf + 16 + + private: + + uint64_t m_Seqn; + CryptoPP::AutoSeededRandomPool m_Rnd; + i2p::crypto::CBCEncryption m_Encryption; + i2p::crypto::CBCDecryption m_Decryption; + uint8_t m_MacKey[32]; // client + }; + + class TlsSession { public: TlsSession (const std::string& host, int port); + ~TlsSession (); void Send (const uint8_t * buf, size_t len); bool Receive (std::ostream& rs); + static void PRF (const uint8_t * secret, const char * label, const uint8_t * random, size_t randomLen, + size_t len, uint8_t * buf); + private: void Handshake (); void SendHandshakeMsg (uint8_t handshakeType, uint8_t * data, 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, - size_t len, uint8_t * buf); - 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 Decrypt (uint8_t * buf, size_t len); // pyaload is buf + 16 private: - uint64_t m_Seqn; boost::asio::ip::tcp::iostream m_Site; CryptoPP::SHA256 m_FinishedHash; - CryptoPP::AutoSeededRandomPool m_Rnd; - i2p::crypto::CBCEncryption m_Encryption; - i2p::crypto::CBCDecryption m_Decryption; - uint8_t m_MacKey[32]; // client + TlsCipher_AES_256_CBC_SHA256 * m_Cipher; }; } }