Browse Source

AEAD/ChaCha20/Poly1305 decryption and SessionCreate prcessing

pull/1194/head
orignal 7 years ago
parent
commit
5447259e1a
  1. 23
      libi2pd/Crypto.cpp
  2. 2
      libi2pd/Crypto.h
  3. 71
      libi2pd/NTCP2.cpp
  4. 7
      libi2pd/NTCP2.h
  5. 9
      tests/test-aeadchacha20poly1305.cpp

23
libi2pd/Crypto.cpp

@ -1062,9 +1062,9 @@ namespace crypto
// AEAD/ChaCha20/Poly1305 // AEAD/ChaCha20/Poly1305
size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len) bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt)
{ {
if (msgLen + 16 < len) return 0; if (encrypt && msgLen + 16 < len) return 0;
// generate one time poly key // generate one time poly key
uint8_t polyKey[64]; uint8_t polyKey[64];
memset(polyKey, 0, sizeof(polyKey)); memset(polyKey, 0, sizeof(polyKey));
@ -1072,6 +1072,7 @@ namespace crypto
// encrypt data // encrypt data
memcpy (buf, msg, msgLen); memcpy (buf, msg, msgLen);
chacha20 (buf, msgLen, nonce, key, 1); chacha20 (buf, msgLen, nonce, key, 1);
// create Poly1305 message // create Poly1305 message
std::vector<uint8_t> polyMsg(adLen + msgLen + 3*16); std::vector<uint8_t> polyMsg(adLen + msgLen + 3*16);
size_t offset = 0; size_t offset = 0;
@ -1084,7 +1085,7 @@ namespace crypto
rem = 16 - rem; rem = 16 - rem;
memcpy (polyMsg.data () + offset, padding, rem); offset += rem; memcpy (polyMsg.data () + offset, padding, rem); offset += rem;
} }
memcpy (polyMsg.data () + offset, buf, msgLen); offset += msgLen; // encrypted data memcpy (polyMsg.data () + offset, encrypt ? buf : msg, msgLen); offset += msgLen; // encrypted data
rem = msgLen & 0x0F; // %16 rem = msgLen & 0x0F; // %16
if (rem) if (rem)
{ {
@ -1095,9 +1096,19 @@ namespace crypto
htole64buf (polyMsg.data () + offset, adLen); offset += 8; htole64buf (polyMsg.data () + offset, adLen); offset += 8;
htole64buf (polyMsg.data () + offset, msgLen); offset += 8; htole64buf (polyMsg.data () + offset, msgLen); offset += 8;
// calculate Poly1305 tag and write in after encrypted data if (encrypt)
Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset); {
return msgLen + 16; // calculate Poly1305 tag and write in after encrypted data
Poly1305HMAC ((uint32_t *)(buf + msgLen), (uint32_t *)polyKey, polyMsg.data (), offset);
}
else
{
uint32_t tag[8];
// calculate Poly1305 tag
Poly1305HMAC (tag, (uint32_t *)polyKey, polyMsg.data (), offset);
if (memcmp (tag, msg + msgLen, 16)) return false; // compare with provided
}
return true;
} }
// init and terminate // init and terminate

2
libi2pd/Crypto.h

@ -255,7 +255,7 @@ namespace crypto
}; };
// AEAD/ChaCha20/Poly1305 // AEAD/ChaCha20/Poly1305
size_t AEADChaCha20Poly1305Encrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len); bool AEADChaCha20Poly1305 (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len, bool encrypt); // msgLen is len without tag
// init and terminate // init and terminate
void InitCrypto (bool precomputation); void InitCrypto (bool precomputation);

71
libi2pd/NTCP2.cpp

@ -2,6 +2,7 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
#include <stdlib.h> #include <stdlib.h>
#include <vector>
#include "Log.h" #include "Log.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Crypto.h" #include "Crypto.h"
@ -50,11 +51,11 @@ namespace transport
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ())); m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ()));
} }
bool NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived) void NTCP2Session::KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived)
{ {
static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes static const char protocolName[] = "Noise_XK_25519_ChaChaPoly_SHA256"; // 32 bytes
uint8_t h[64], ck[33]; uint8_t h[64];
memcpy (ck, protocolName, 32); memcpy (m_CK, protocolName, 32);
SHA256 ((const uint8_t *)protocolName, 32, h); SHA256 ((const uint8_t *)protocolName, 32, h);
// h = SHA256(h || rs) // h = SHA256(h || rs)
memcpy (h + 32, rs, 32); memcpy (h + 32, rs, 32);
@ -69,14 +70,43 @@ namespace transport
BN_CTX_free (ctx); BN_CTX_free (ctx);
// temp_key = HMAC-SHA256(ck, input_key_material) // temp_key = HMAC-SHA256(ck, input_key_material)
uint8_t tempKey[32]; unsigned int len; uint8_t tempKey[32]; unsigned int len;
HMAC(EVP_sha256(), ck, 32, inputKeyMaterial, 32, tempKey, &len); HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len);
// ck = HMAC-SHA256(temp_key, byte(0x01)) // ck = HMAC-SHA256(temp_key, byte(0x01))
inputKeyMaterial[0] = 1; inputKeyMaterial[0] = 1;
HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, ck, &len); HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len);
// derived = HMAC-SHA256(temp_key, ck || byte(0x02)) // derived = HMAC-SHA256(temp_key, ck || byte(0x02))
ck[32] = 2; m_CK[32] = 2;
HMAC(EVP_sha256(), tempKey, 32, ck, 33, derived, &len); HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
return true; }
void NTCP2Session::KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived)
{
uint8_t h[64];
memcpy (h, m_H, 32);
memcpy (h + 32, sessionRequest + 32, 32); // encrypted payload
SHA256 (h, 64, m_H);
int paddingLength = sessionRequestLen - 64;
if (paddingLength > 0)
{
std::vector<uint8_t> h1(paddingLength + 32);
memcpy (h1.data (), m_H, 32);
memcpy (h1.data () + 32, sessionRequest + 64, paddingLength);
SHA256 (h1.data (), paddingLength + 32, m_H);
}
// x25519 between remote pub and priv
uint8_t inputKeyMaterial[32];
BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::GetEd25519 ()->ScalarMul (pub, m_ExpandedPrivateKey, inputKeyMaterial, ctx);
BN_CTX_free (ctx);
// temp_key = HMAC-SHA256(ck, input_key_material)
uint8_t tempKey[32]; unsigned int len;
HMAC(EVP_sha256(), m_CK, 32, inputKeyMaterial, 32, tempKey, &len);
// ck = HMAC-SHA256(temp_key, byte(0x01))
inputKeyMaterial[0] = 1;
HMAC(EVP_sha256(), tempKey, 32, inputKeyMaterial, 1, m_CK, &len);
// derived = HMAC-SHA256(temp_key, ck || byte(0x02))
m_CK[32] = 2;
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len);
} }
void NTCP2Session::CreateEphemeralKey (uint8_t * pub) void NTCP2Session::CreateEphemeralKey (uint8_t * pub)
@ -93,7 +123,8 @@ namespace transport
{ {
// create buffer and fill padding // create buffer and fill padding
auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes auto paddingLength = rand () % (287 - 64); // message length doesn't exceed 287 bytes
m_SessionRequestBuffer = new uint8_t[paddingLength + 64]; m_SessionRequestBufferLen = paddingLength + 64;
m_SessionRequestBuffer = new uint8_t[m_SessionRequestBufferLen];
RAND_bytes (m_SessionRequestBuffer + 64, paddingLength); RAND_bytes (m_SessionRequestBuffer + 64, paddingLength);
// generate key pair (X) // generate key pair (X)
uint8_t x[32]; uint8_t x[32];
@ -119,9 +150,9 @@ namespace transport
// sign and encrypt options, use m_H as AD // sign and encrypt options, use m_H as AD
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero memset (nonce, 0, 12); // set nonce to zero
i2p::crypto::AEADChaCha20Poly1305Encrypt (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32); i2p::crypto::AEADChaCha20Poly1305 (options, 16, m_H, 32, key, nonce, m_SessionRequestBuffer + 32, 32, true); // encrypt
// send message // send message
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, paddingLength + 64), boost::asio::transfer_all (), boost::asio::async_write (m_Socket, boost::asio::buffer (m_SessionRequestBuffer, m_SessionRequestBufferLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
} }
@ -151,13 +182,29 @@ namespace transport
} }
else else
{ {
LogPrint (eLogWarning, "NTCP2: SessionCreated received ", bytes_transferred); LogPrint (eLogInfo, "NTCP2: SessionCreated received ", bytes_transferred);
uint8_t y[32]; uint8_t y[32];
// decrypt Y // decrypt Y
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ()); decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
decryption.SetIV (m_IV); decryption.SetIV (m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, y); decryption.Decrypt (m_SessionCreatedBuffer, 32, y);
// decryption key for next block
uint8_t key[32];
KeyDerivationFunction2 (y, m_SessionRequestBuffer, m_SessionRequestBufferLen, key);
// decrypt and verify MAC
uint8_t payload[8];
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 8, m_H, 32, key, nonce, payload, 8, false)) // decrypt
{
// TODO:
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated MAC verification failed ");
Terminate ();
}
} }
} }

7
libi2pd/NTCP2.h

@ -29,7 +29,9 @@ namespace transport
private: private:
bool KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest void KeyDerivationFunction1 (const uint8_t * rs, const uint8_t * pub, uint8_t * derived); // for SessionRequest
void KeyDerivationFunction2 (const uint8_t * pub, const uint8_t * sessionRequest, size_t sessionRequestLen, uint8_t * derived); // for SessionCreate
void CreateEphemeralKey (uint8_t * pub); void CreateEphemeralKey (uint8_t * pub);
void SendSessionRequest (); void SendSessionRequest ();
@ -43,8 +45,9 @@ namespace transport
bool m_IsEstablished, m_IsTerminated; bool m_IsEstablished, m_IsTerminated;
uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key uint8_t m_ExpandedPrivateKey[64]; // x25519 ephemeral key
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32]; uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/;
uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer; uint8_t * m_SessionRequestBuffer, * m_SessionCreatedBuffer;
size_t m_SessionRequestBufferLen;
}; };
class NTCP2Server class NTCP2Server

9
tests/test-aeadchacha20poly1305.cpp

@ -43,7 +43,12 @@ uint8_t encrypted[114] =
int main () int main ()
{ {
uint8_t buf[114+16]; uint8_t buf[114+16];
i2p::crypto::AEADChaCha20Poly1305Encrypt ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16); // test encryption
i2p::crypto::AEADChaCha20Poly1305 ((uint8_t *)text, 114, ad, 12, key, nonce, buf, 114 + 16, true);
assert (memcmp (buf, encrypted, 114) == 0); assert (memcmp (buf, encrypted, 114) == 0);
assert(memcmp (buf + 114, tag, 16) == 0); assert (memcmp (buf + 114, tag, 16) == 0);
// test decryption
uint8_t buf1[114];
assert (i2p::crypto::AEADChaCha20Poly1305 (buf, 114, ad, 12, key, nonce, buf1, 114, false));
assert (memcmp (buf1, text, 114) == 0);
} }

Loading…
Cancel
Save