diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp
index b54a83ef..325af961 100644
--- a/libi2pd/NTCP2.cpp
+++ b/libi2pd/NTCP2.cpp
@@ -244,6 +244,119 @@ namespace transport
 		SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext)
 	}	
 
+	bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
+	{
+		// decrypt X
+		i2p::crypto::CBCDecryption decryption;
+		decryption.SetKey (i2p::context.GetIdentHash ());
+		decryption.SetIV (i2p::context.GetNTCP2IV ());
+		decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
+		decryption.GetIV (m_IV); // save IV for SessionCreated	
+		// decryption key for next block
+		KDF1Bob ();
+		// verify MAC and decrypt options block (32 bytes), use m_H as AD
+		uint8_t nonce[12], options[16];
+		memset (nonce, 0, 12); // set nonce to zero
+		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt
+		{
+			if (options[1] == 2)
+			{
+				paddingLen = bufbe16toh (options + 2);
+				m_SessionRequestBufferLen = paddingLen + 64;
+				m3p2Len = bufbe16toh (options + 4);
+				// TODO: check tsA
+			}
+			else
+			{
+				LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
+				return false;
+			}
+		}
+		else
+		{
+			LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
+			return false;
+		}	
+		return true;	
+	}
+
+	bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen)
+	{
+		m_SessionCreatedBufferLen = 64;
+		// decrypt Y
+		i2p::crypto::CBCDecryption decryption;
+		decryption.SetKey (m_RemoteIdentHash);
+		decryption.SetIV (m_IV);
+		decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
+		// decryption key for next block (m_K)
+		KDF2Alice ();
+		// decrypt and verify MAC
+		uint8_t payload[16];
+		uint8_t nonce[12];
+		memset (nonce, 0, 12); // set nonce to zero
+		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt
+		{		
+			paddingLen = bufbe16toh(payload + 2);
+			// TODO: check tsB
+		}
+		else
+		{	
+			LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
+			return false;
+		}	
+		return true;
+	}
+
+	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce)
+	{
+		// update AD
+		SHA256_CTX ctx;
+		SHA256_Init (&ctx);
+		SHA256_Update (&ctx, m_H, 32);
+		SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32);	// encrypted payload
+		SHA256_Final (m_H, &ctx);
+
+		int paddingLength = m_SessionCreatedBufferLen - 64;
+		if (paddingLength > 0)
+		{
+			SHA256_CTX ctx1;
+			SHA256_Init (&ctx1);
+			SHA256_Update (&ctx1, m_H, 32);			
+			SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength);			
+			SHA256_Final (m_H, &ctx1);
+		}	
+		if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S
+		{
+			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
+			return false;
+		}
+		return true;
+	}
+
+	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf)
+	{
+		// update AD again
+		SHA256_CTX ctx;
+		SHA256_Init (&ctx);
+		SHA256_Update (&ctx, m_H, 32);			
+		SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48);			
+		SHA256_Final (m_H, &ctx);		
+
+		KDF3Bob (); 
+		if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
+		{
+			// caclulate new h again for KDF data
+			memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext
+			SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext);
+		}
+		else
+		{
+			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
+			return false;
+		}
+		return true;
+	}
+
 	NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
 		TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), 
 		m_Server (server), m_Socket (m_Server.GetService ()), 
@@ -368,52 +481,28 @@ namespace transport
 		}
 		else
 		{
-			// decrypt X
-			i2p::crypto::CBCDecryption decryption;
-			decryption.SetKey (i2p::context.GetIdentHash ());
-			decryption.SetIV (i2p::context.GetNTCP2IV ());
-			decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ());
-			decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated	
-			// decryption key for next block
-			m_Establisher->KDF1Bob ();
-			// verify MAC and decrypt options block (32 bytes), use m_H as AD
-			uint8_t nonce[12], options[16];
-			memset (nonce, 0, 12); // set nonce to zero
-			if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt
+			LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
+			uint16_t paddingLen = 0;
+			if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
 			{
-				if (options[1] == 2)
+				if (paddingLen > 0)
 				{
-					uint16_t paddingLen = bufbe16toh (options + 2);
-					m_Establisher->m_SessionRequestBufferLen = paddingLen + 64;
-					m_Establisher->m3p2Len = bufbe16toh (options + 4);
-					// TODO: check tsA
-					if (paddingLen > 0)
+					if (paddingLen <= 287 - 64) // session request is 287 bytes max
 					{
-						if (paddingLen <= 287 - 64) // session request is 287 bytes max
-						{
-							boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
-								std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
-						}
-						else
-						{
-							LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen,  " is too long");
-							Terminate ();
-						}
+						boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
+							std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 					}
 					else
-						SendSessionCreated ();
+					{
+						LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen,  " is too long");
+						Terminate ();
+					}
 				}
 				else
-				{
-					LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
-					Terminate ();
-				}
-			}
-			else
-			{
-				LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
-				Terminate ();
+					SendSessionCreated ();
 			}	
+			else
+				Terminate ();
 		}
 	}
 
@@ -446,23 +535,9 @@ namespace transport
 		else
 		{
 			LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
-			m_Establisher->m_SessionCreatedBufferLen = 64;
-			// decrypt Y
-			i2p::crypto::CBCDecryption decryption;
-			decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
-			decryption.SetIV (m_Establisher->m_IV);
-			decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
-			// decryption key for next block (m_K)
-			m_Establisher->KDF2Alice ();
-			// decrypt and verify MAC
-			uint8_t payload[16];
-			uint8_t nonce[12];
-			memset (nonce, 0, 12); // set nonce to zero
-			if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt
-			{		
-				uint16_t paddingLen = bufbe16toh(payload + 2);
-				LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen);
-				// TODO: check tsB
+			uint16_t paddingLen = 0;
+			if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
+			{
 				if (paddingLen > 0)
 				{
 					if (paddingLen <= 287 - 64) // session created is 287 bytes max
@@ -480,10 +555,7 @@ namespace transport
 					SendSessionConfirmed ();
 			}
 			else
-			{	
-				LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
 				Terminate ();
-			}	
 		}
 	}
 
@@ -559,38 +631,16 @@ namespace transport
 		else
 		{
 			LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
-			// update AD
-			uint8_t h[80];
-			memcpy (h, m_Establisher->GetH (), 32);
-			memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload
-			SHA256 (h, 64, h); 
-			int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64;
-			if (paddingLength > 0)
-			{
-				SHA256_CTX ctx;
-				SHA256_Init (&ctx);
-				SHA256_Update (&ctx, h, 32);			
-				SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength);			
-				SHA256_Final (h, &ctx);
-			}	
 			// part 1
 			uint8_t nonce[12];
 			CreateNonce (1, nonce);
-			if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S
+			if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
 			{
 				// part 2
-				// update AD again
-				memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48);
-				SHA256 (h, 80, m_Establisher->m_H); 	
-
 				std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
-				m_Establisher->KDF3Bob (); 
 				memset (nonce, 0, 12); // set nonce to 0 again
-				if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt
+				if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ()))
 				{
-					// caclulate new h again for KDF data
-					memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext
-					SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext);
 					KeyDerivationFunctionDataPhase ();
 					// Bob data phase keys
 					m_SendKey = m_Kba;
@@ -599,7 +649,7 @@ namespace transport
 					m_ReceiveSipKey = m_Sipkeysab;
 					memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
 					memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
-
+					// payload
 					// process RI
 					if (buf[0] != eNTCP2BlkRouterInfo)
 					{
@@ -644,19 +694,13 @@ namespace transport
 					SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
 					m_Server.AddNTCP2Session (shared_from_this ());
 					Established ();
-					ReceiveLength ();		
-				}	
+					ReceiveLength ();
+				}
 				else
-				{
-					LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
 					Terminate ();
-				}		
 			}
 			else
-			{	
-				LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
 				Terminate ();
-			}	
 		}
 	}
 
@@ -691,12 +735,20 @@ namespace transport
 		else
 		{
 			i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey);
-			// m_NextRecivedLen comes from the network in BigEndian
+			// m_NextReceivedLen comes from the network in BigEndian
 			m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
 			LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen);
-			if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
-			m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
-			Receive ();
+			if (m_NextReceivedLen >= 16)
+			{	
+				if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
+				m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
+				Receive ();
+			}
+			else
+			{
+				LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short");
+				Terminate ();
+			}	
 		}
 	}
 
diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h
index 3e202dc5..1f5700be 100644
--- a/libi2pd/NTCP2.h
+++ b/libi2pd/NTCP2.h
@@ -91,6 +91,11 @@ namespace transport
 		void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
 		void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
 
+		bool ProcessSessionRequestMessage (uint16_t& paddingLen);
+		bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
+		bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
+		bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
+
 		BN_CTX * m_Ctx;
 		uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519
 		uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/;