@ -40,7 +40,7 @@ namespace transport
delete [ ] m_SessionConfirmedBuffer ;
delete [ ] m_SessionConfirmedBuffer ;
}
}
void NTCP2Establisher : : MixKey ( const uint8_t * inputKeyMaterial , uint8_t * derived )
void NTCP2Establisher : : MixKey ( const uint8_t * inputKeyMaterial )
{
{
// 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 ;
@ -50,7 +50,16 @@ namespace transport
HMAC ( EVP_sha256 ( ) , tempKey , 32 , one , 1 , m_CK , & len ) ;
HMAC ( EVP_sha256 ( ) , tempKey , 32 , one , 1 , m_CK , & len ) ;
// derived = HMAC-SHA256(temp_key, ck || byte(0x02))
// derived = HMAC-SHA256(temp_key, ck || byte(0x02))
m_CK [ 32 ] = 2 ;
m_CK [ 32 ] = 2 ;
HMAC ( EVP_sha256 ( ) , tempKey , 32 , m_CK , 33 , derived , & len ) ;
HMAC ( EVP_sha256 ( ) , tempKey , 32 , m_CK , 33 , m_K , & len ) ;
}
void NTCP2Establisher : : MixHash ( const uint8_t * buf , size_t len )
{
SHA256_CTX ctx ;
SHA256_Init ( & ctx ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , buf , len ) ;
SHA256_Final ( m_H , & ctx ) ;
}
}
void NTCP2Establisher : : KeyDerivationFunction1 ( const uint8_t * pub , i2p : : crypto : : X25519Keys & priv , const uint8_t * rs , const uint8_t * epub )
void NTCP2Establisher : : KeyDerivationFunction1 ( const uint8_t * pub , i2p : : crypto : : X25519Keys & priv , const uint8_t * rs , const uint8_t * epub )
@ -73,14 +82,11 @@ namespace transport
SHA256_Update ( & ctx , rs , 32 ) ;
SHA256_Update ( & ctx , rs , 32 ) ;
SHA256_Final ( m_H , & ctx ) ;
SHA256_Final ( m_H , & ctx ) ;
// h = SHA256(h || epub)
// h = SHA256(h || epub)
SHA256_Init ( & ctx ) ;
MixHash ( epub , 32 ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , epub , 32 ) ;
SHA256_Final ( m_H , & ctx ) ;
// x25519 between pub and priv
// x25519 between pub and priv
uint8_t inputKeyMaterial [ 32 ] ;
uint8_t inputKeyMaterial [ 32 ] ;
priv . Agree ( pub , inputKeyMaterial ) ;
priv . Agree ( pub , inputKeyMaterial ) ;
MixKey ( inputKeyMaterial , m_K ) ;
MixKey ( inputKeyMaterial ) ;
}
}
void NTCP2Establisher : : KDF1Alice ( )
void NTCP2Establisher : : KDF1Alice ( )
@ -95,30 +101,18 @@ namespace transport
void NTCP2Establisher : : KeyDerivationFunction2 ( const uint8_t * sessionRequest , size_t sessionRequestLen , const uint8_t * epub )
void NTCP2Establisher : : KeyDerivationFunction2 ( const uint8_t * sessionRequest , size_t sessionRequestLen , const uint8_t * epub )
{
{
SHA256_CTX ctx ;
MixHash ( sessionRequest + 32 , 32 ) ; // encrypted payload
SHA256_Init ( & ctx ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , sessionRequest + 32 , 32 ) ; // encrypted payload
SHA256_Final ( m_H , & ctx ) ;
int paddingLength = sessionRequestLen - 64 ;
int paddingLength = sessionRequestLen - 64 ;
if ( paddingLength > 0 )
if ( paddingLength > 0 )
{
MixHash ( sessionRequest + 64 , paddingLength ) ;
SHA256_Init ( & ctx ) ;
MixHash ( epub , 32 ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , sessionRequest + 64 , paddingLength ) ;
SHA256_Final ( m_H , & ctx ) ;
}
SHA256_Init ( & ctx ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , epub , 32 ) ;
SHA256_Final ( m_H , & ctx ) ;
// x25519 between remote pub and ephemaral priv
// x25519 between remote pub and ephemaral priv
uint8_t inputKeyMaterial [ 32 ] ;
uint8_t inputKeyMaterial [ 32 ] ;
m_EphemeralKeys . Agree ( GetRemotePub ( ) , inputKeyMaterial ) ;
m_EphemeralKeys . Agree ( GetRemotePub ( ) , inputKeyMaterial ) ;
MixKey ( inputKeyMaterial , m_K ) ;
MixKey ( inputKeyMaterial ) ;
}
}
void NTCP2Establisher : : KDF2Alice ( )
void NTCP2Establisher : : KDF2Alice ( )
@ -135,14 +129,14 @@ namespace transport
{
{
uint8_t inputKeyMaterial [ 32 ] ;
uint8_t inputKeyMaterial [ 32 ] ;
i2p : : context . GetStaticKeys ( ) . Agree ( GetRemotePub ( ) , inputKeyMaterial ) ;
i2p : : context . GetStaticKeys ( ) . Agree ( GetRemotePub ( ) , inputKeyMaterial ) ;
MixKey ( inputKeyMaterial , m_K ) ;
MixKey ( inputKeyMaterial ) ;
}
}
void NTCP2Establisher : : KDF3Bob ( )
void NTCP2Establisher : : KDF3Bob ( )
{
{
uint8_t inputKeyMaterial [ 32 ] ;
uint8_t inputKeyMaterial [ 32 ] ;
m_EphemeralKeys . Agree ( m_RemoteStaticKey , inputKeyMaterial ) ;
m_EphemeralKeys . Agree ( m_RemoteStaticKey , inputKeyMaterial ) ;
MixKey ( inputKeyMaterial , m_K ) ;
MixKey ( inputKeyMaterial ) ;
}
}
void NTCP2Establisher : : CreateEphemeralKey ( )
void NTCP2Establisher : : CreateEphemeralKey ( )
@ -170,8 +164,17 @@ namespace transport
memset ( options , 0 , 16 ) ;
memset ( options , 0 , 16 ) ;
options [ 1 ] = 2 ; // ver
options [ 1 ] = 2 ; // ver
htobe16buf ( options + 2 , paddingLength ) ; // padLen
htobe16buf ( options + 2 , paddingLength ) ; // padLen
m3p2Len = i2p : : context . GetRouterInfo ( ) . GetBufferLen ( ) + 20 ; // (RI header + RI + MAC for now) TODO: implement options
// m3p2Len
auto bufLen = i2p : : context . GetRouterInfo ( ) . GetBufferLen ( ) ;
m3p2Len = bufLen + 4 + 16 ; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf ( options + 4 , m3p2Len ) ;
htobe16buf ( options + 4 , m3p2Len ) ;
// fill m3p2 payload (RouterInfo block)
m_SessionConfirmedBuffer = new uint8_t [ m3p2Len + 48 ] ; // m3p1 is 48 bytes
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48 ;
m3p2 [ 0 ] = eNTCP2BlkRouterInfo ; // block
htobe16buf ( m3p2 + 1 , bufLen + 1 ) ; // flag + RI
m3p2 [ 3 ] = 0 ; // flag
memcpy ( m3p2 + 4 , i2p : : context . GetRouterInfo ( ) . GetBuffer ( ) , bufLen ) ; // TODO: own RI should be protected by mutex
// 2 bytes reserved
// 2 bytes reserved
htobe32buf ( options + 8 , i2p : : util : : GetSecondsSinceEpoch ( ) ) ; // tsA
htobe32buf ( options + 8 , i2p : : util : : GetSecondsSinceEpoch ( ) ) ; // tsA
// 4 bytes reserved
// 4 bytes reserved
@ -208,23 +211,12 @@ namespace transport
void NTCP2Establisher : : CreateSessionConfirmedMessagePart1 ( const uint8_t * nonce )
void NTCP2Establisher : : CreateSessionConfirmedMessagePart1 ( const uint8_t * nonce )
{
{
// update AD
// update AD
SHA256_CTX ctx ;
MixHash ( m_SessionCreatedBuffer + 32 , 32 ) ; // encrypted payload
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 ;
int paddingLength = m_SessionCreatedBufferLen - 64 ;
if ( paddingLength > 0 )
if ( paddingLength > 0 )
{
MixHash ( m_SessionCreatedBuffer + 64 , paddingLength ) ;
SHA256_CTX ctx1 ;
SHA256_Init ( & ctx1 ) ;
SHA256_Update ( & ctx1 , m_H , 32 ) ;
SHA256_Update ( & ctx1 , m_SessionCreatedBuffer + 64 , paddingLength ) ;
SHA256_Final ( m_H , & ctx1 ) ;
}
// part1 48 bytes
// part1 48 bytes
m_SessionConfirmedBuffer = new uint8_t [ m3p2Len + 48 ] ;
i2p : : crypto : : AEADChaCha20Poly1305 ( i2p : : context . GetNTCP2StaticPublicKey ( ) , 32 , m_H , 32 , m_K , nonce , m_SessionConfirmedBuffer , 48 , true ) ; // encrypt
i2p : : crypto : : AEADChaCha20Poly1305 ( i2p : : context . GetNTCP2StaticPublicKey ( ) , 32 , m_H , 32 , m_K , nonce , m_SessionConfirmedBuffer , 48 , true ) ; // encrypt
}
}
@ -232,24 +224,13 @@ namespace transport
{
{
// part 2
// part 2
// update AD again
// update AD again
SHA256_CTX ctx ;
MixHash ( m_SessionConfirmedBuffer , 48 ) ;
SHA256_Init ( & ctx ) ;
// encrypt m3p2, it must be filled in SessionRequest
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , m_SessionConfirmedBuffer , 48 ) ;
SHA256_Final ( m_H , & ctx ) ;
// fill and encrypt
uint8_t * buf = m_SessionConfirmedBuffer + 48 ;
buf [ 0 ] = eNTCP2BlkRouterInfo ; // block
htobe16buf ( buf + 1 , i2p : : context . GetRouterInfo ( ) . GetBufferLen ( ) + 1 ) ; // flag + RI
buf [ 3 ] = 0 ; // flag
memcpy ( buf + 4 , i2p : : context . GetRouterInfo ( ) . GetBuffer ( ) , i2p : : context . GetRouterInfo ( ) . GetBufferLen ( ) ) ;
KDF3Alice ( ) ;
KDF3Alice ( ) ;
i2p : : crypto : : AEADChaCha20Poly1305 ( buf , m3p2Len - 16 , m_H , 32 , m_K , nonce , buf , m3p2Len , true ) ; // encrypt
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48 ;
i2p : : crypto : : AEADChaCha20Poly1305 ( m3p2 , m3p2Len - 16 , m_H , 32 , m_K , nonce , m3p2 , m3p2Len , true ) ; // encrypt
// update h again
// update h again
SHA256_Init ( & ctx ) ;
MixHash ( m3p2 , m3p2Len ) ; //h = SHA256(h || ciphertext)
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , buf , m3p2Len ) ;
SHA256_Final ( m_H , & ctx ) ; //h = SHA256(h || ciphertext)
}
}
bool NTCP2Establisher : : ProcessSessionRequestMessage ( uint16_t & paddingLen )
bool NTCP2Establisher : : ProcessSessionRequestMessage ( uint16_t & paddingLen )
@ -339,21 +320,11 @@ namespace transport
bool NTCP2Establisher : : ProcessSessionConfirmedMessagePart1 ( const uint8_t * nonce )
bool NTCP2Establisher : : ProcessSessionConfirmedMessagePart1 ( const uint8_t * nonce )
{
{
// update AD
// update AD
SHA256_CTX ctx ;
MixHash ( m_SessionCreatedBuffer + 32 , 32 ) ; // encrypted payload
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 ;
int paddingLength = m_SessionCreatedBufferLen - 64 ;
if ( paddingLength > 0 )
if ( paddingLength > 0 )
{
MixHash ( m_SessionCreatedBuffer + 64 , paddingLength ) ;
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
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 " ) ;
LogPrint ( eLogWarning , " NTCP2: SessionConfirmed Part1 AEAD verification failed " ) ;
@ -365,11 +336,7 @@ namespace transport
bool NTCP2Establisher : : ProcessSessionConfirmedMessagePart2 ( const uint8_t * nonce , uint8_t * m3p2Buf )
bool NTCP2Establisher : : ProcessSessionConfirmedMessagePart2 ( const uint8_t * nonce , uint8_t * m3p2Buf )
{
{
// update AD again
// update AD again
SHA256_CTX ctx ;
MixHash ( m_SessionConfirmedBuffer , 48 ) ;
SHA256_Init ( & ctx ) ;
SHA256_Update ( & ctx , m_H , 32 ) ;
SHA256_Update ( & ctx , m_SessionConfirmedBuffer , 48 ) ;
SHA256_Final ( m_H , & ctx ) ;
KDF3Bob ( ) ;
KDF3Bob ( ) ;
if ( i2p : : crypto : : AEADChaCha20Poly1305 ( m_SessionConfirmedBuffer + 48 , m3p2Len - 16 , m_H , 32 , m_K , nonce , m3p2Buf , m3p2Len - 16 , false ) ) // decrypt
if ( i2p : : crypto : : AEADChaCha20Poly1305 ( m_SessionConfirmedBuffer + 48 , m3p2Len - 16 , m_H , 32 , m_K , nonce , m3p2Buf , m3p2Len - 16 , false ) ) // decrypt
@ -728,8 +695,7 @@ namespace transport
SendTerminationAndTerminate ( eNTCP2IncorrectSParameter ) ;
SendTerminationAndTerminate ( eNTCP2IncorrectSParameter ) ;
return ;
return ;
}
}
i2p : : data : : netdb . PostI2NPMsg ( CreateI2NPMessage ( eI2NPDummyMsg , buf . data ( ) + 3 , size ) ) ; // TODO: should insert ri and not parse it twice
i2p : : data : : netdb . AddRouterInfo ( buf . data ( ) + 4 , size - 1 ) ; // TODO: should insert ri and not parse it twice
// TODO: process options
// TODO: process options
// ready to communicate
// ready to communicate
@ -894,7 +860,7 @@ namespace transport
case eNTCP2BlkRouterInfo :
case eNTCP2BlkRouterInfo :
{
{
LogPrint ( eLogDebug , " NTCP2: RouterInfo flag= " , ( int ) frame [ offset ] ) ;
LogPrint ( eLogDebug , " NTCP2: RouterInfo flag= " , ( int ) frame [ offset ] ) ;
i2p : : data : : netdb . AddRouterInfo ( frame + offset + 1 , size - 1 ) ;
i2p : : data : : netdb . PostI2NPMsg ( CreateI2NPMessage ( eI2NPDummyMsg , frame + offset , size ) ) ;
break ;
break ;
}
}
case eNTCP2BlkI2NPMessage :
case eNTCP2BlkI2NPMessage :
@ -1041,7 +1007,7 @@ namespace transport
void NTCP2Session : : SendTermination ( NTCP2TerminationReason reason )
void NTCP2Session : : SendTermination ( NTCP2TerminationReason reason )
{
{
if ( ! IsEstablished ( ) ) return ;
if ( ! m_SendKey | | ! m_SendSipKey ) return ;
uint8_t payload [ 12 ] = { eNTCP2BlkTermination , 0 , 9 } ;
uint8_t payload [ 12 ] = { eNTCP2BlkTermination , 0 , 9 } ;
htobe64buf ( payload + 3 , m_ReceiveSequenceNumber ) ;
htobe64buf ( payload + 3 , m_ReceiveSequenceNumber ) ;
payload [ 11 ] = ( uint8_t ) reason ;
payload [ 11 ] = ( uint8_t ) reason ;