@ -244,6 +244,119 @@ namespace transport
@@ -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,25 +481,10 @@ namespace transport
@@ -368,25 +481,10 @@ 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
{
if ( options [ 1 ] = = 2 )
LogPrint ( eLogDebug , " NTCP2: SessionRequest received " , bytes_transferred ) ;
uint16_t paddingLen = 0 ;
if ( m_Establisher - > ProcessSessionRequestMessage ( paddingLen ) )
{
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
@ -404,18 +502,9 @@ namespace transport
@@ -404,18 +502,9 @@ namespace transport
SendSessionCreated ( ) ;
}
else
{
LogPrint ( eLogWarning , " NTCP2: SessionRequest version mismatch " , ( int ) options [ 1 ] ) ;
Terminate ( ) ;
}
}
else
{
LogPrint ( eLogWarning , " NTCP2: SessionRequest AEAD verification failed " ) ;
Terminate ( ) ;
}
}
}
void NTCP2Session : : HandleSessionRequestPaddingReceived ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
@ -446,23 +535,9 @@ namespace transport
@@ -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 = 0 ;
if ( m_Establisher - > ProcessSessionCreatedMessage ( paddingLen ) )
{
uint16_t paddingLen = bufbe16toh ( payload + 2 ) ;
LogPrint ( eLogDebug , " NTCP2: padding length " , paddingLen ) ;
// TODO: check tsB
if ( paddingLen > 0 )
{
if ( paddingLen < = 287 - 64 ) // session created is 287 bytes max
@ -480,12 +555,9 @@ namespace transport
@@ -480,12 +555,9 @@ namespace transport
SendSessionConfirmed ( ) ;
}
else
{
LogPrint ( eLogWarning , " NTCP2: SessionCreated AEAD verification failed " ) ;
Terminate ( ) ;
}
}
}
void NTCP2Session : : HandleSessionCreatedPaddingReceived ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
@ -559,38 +631,16 @@ namespace transport
@@ -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
@@ -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 )
{
@ -647,18 +697,12 @@ namespace transport
@@ -647,18 +697,12 @@ namespace transport
ReceiveLength ( ) ;
}
else
{
LogPrint ( eLogWarning , " NTCP2: SessionConfirmed Part2 AEAD verification failed " ) ;
Terminate ( ) ;
}
}
else
{
LogPrint ( eLogWarning , " NTCP2: SessionConfirmed Part1 AEAD verification failed " ) ;
Terminate ( ) ;
}
}
}
void NTCP2Session : : ClientLogin ( )
{
@ -691,13 +735,21 @@ namespace transport
@@ -691,13 +735,21 @@ 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_NextRece ivedLen comes from the network in BigEndian
m_NextReceivedLen = be16toh ( m_NextReceivedLen ) ^ le16toh ( m_ReceiveIV . key ) ;
LogPrint ( eLogDebug , " NTCP2: received length " , m_NextReceivedLen ) ;
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 ( ) ;
}
}
}
void NTCP2Session : : Receive ( )