mirror of
				https://github.com/PurpleI2P/i2pd.git
				synced 2025-11-04 08:30:46 +00:00 
			
		
		
		
	AEAD/ChaCha20/Poly1305 decryption and SessionCreate prcessing
This commit is contained in:
		
							parent
							
								
									ee0ae0b74b
								
							
						
					
					
						commit
						5447259e1a
					
				
					 5 changed files with 90 additions and 24 deletions
				
			
		| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 ();
 | 
				
			||||||
 | 
								}	
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue