static int readCryptoSelect( tr_handshake * handshake, struct evbuffer * inbuf ) { uint32_t crypto_select; uint16_t pad_d_len; const size_t needlen = sizeof( uint32_t ) + sizeof( uint16_t ); if( evbuffer_get_length( inbuf ) < needlen ) return READ_LATER; tr_peerIoReadUint32( handshake->io, inbuf, &crypto_select ); handshake->crypto_select = crypto_select; dbgmsg( handshake, "crypto select is %d", (int)crypto_select ); if( !( crypto_select & getCryptoProvide( handshake ) ) ) { dbgmsg( handshake, "peer selected an encryption option we didn't provide" ); return tr_handshakeDone( handshake, FALSE ); } tr_peerIoReadUint16( handshake->io, inbuf, &pad_d_len ); dbgmsg( handshake, "pad_d_len is %d", (int)pad_d_len ); if( pad_d_len > 512 ) { dbgmsg( handshake, "encryption handshake: pad_d_len is too long" ); return tr_handshakeDone( handshake, FALSE ); } handshake->pad_d_len = pad_d_len; setState( handshake, AWAITING_PAD_D ); return READ_NOW; }
static int readPadC( tr_handshake * handshake, struct evbuffer * inbuf ) { uint16_t ia_len; const size_t needlen = handshake->pad_c_len + sizeof( uint16_t ); if( evbuffer_get_length( inbuf ) < needlen ) return READ_LATER; evbuffer_drain( inbuf, handshake->pad_c_len ); tr_peerIoReadUint16( handshake->io, inbuf, &ia_len ); dbgmsg( handshake, "ia_len is %d", (int)ia_len ); handshake->ia_len = ia_len; setState( handshake, AWAITING_IA ); return READ_NOW; }
static int readPadC (tr_handshake * handshake, struct evbuffer * inbuf) { char * padc; uint16_t ia_len; const size_t needlen = handshake->pad_c_len + sizeof (uint16_t); if (evbuffer_get_length (inbuf) < needlen) return READ_LATER; /* read the throwaway padc */ padc = tr_new (char, handshake->pad_c_len); tr_peerIoReadBytes (handshake->io, inbuf, padc, handshake->pad_c_len); tr_free (padc); /* read ia_len */ tr_peerIoReadUint16 (handshake->io, inbuf, &ia_len); dbgmsg (handshake, "ia_len is %d", (int)ia_len); handshake->ia_len = ia_len; setState (handshake, AWAITING_IA); return READ_NOW; }
static int readCryptoProvide( tr_handshake * handshake, struct evbuffer * inbuf ) { /* HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC)) */ int i; uint8_t vc_in[VC_LENGTH]; uint8_t req2[SHA_DIGEST_LENGTH]; uint8_t req3[SHA_DIGEST_LENGTH]; uint8_t obfuscatedTorrentHash[SHA_DIGEST_LENGTH]; uint16_t padc_len = 0; uint32_t crypto_provide = 0; const size_t needlen = SHA_DIGEST_LENGTH /* HASH('req1',s) */ + SHA_DIGEST_LENGTH /* HASH('req2', SKEY) xor HASH('req3', S) */ + VC_LENGTH + sizeof( crypto_provide ) + sizeof( padc_len ); tr_torrent * tor = NULL; if( evbuffer_get_length( inbuf ) < needlen ) return READ_LATER; /* TODO: confirm they sent HASH('req1',S) here? */ evbuffer_drain( inbuf, SHA_DIGEST_LENGTH ); /* This next piece is HASH('req2', SKEY) xor HASH('req3', S) ... * we can get the first half of that (the obufscatedTorrentHash) * by building the latter and xor'ing it with what the peer sent us */ dbgmsg( handshake, "reading obfuscated torrent hash..." ); evbuffer_remove( inbuf, req2, SHA_DIGEST_LENGTH ); tr_sha1( req3, "req3", 4, handshake->mySecret, KEY_LEN, NULL ); for( i = 0; i < SHA_DIGEST_LENGTH; ++i ) obfuscatedTorrentHash[i] = req2[i] ^ req3[i]; if(( tor = tr_torrentFindFromObfuscatedHash( handshake->session, obfuscatedTorrentHash ))) { const tr_bool clientIsSeed = tr_torrentIsSeed( tor ); const tr_bool peerIsSeed = tr_peerMgrPeerIsSeed( tor, tr_peerIoGetAddress( handshake->io, NULL ) ); dbgmsg( handshake, "got INCOMING connection's encrypted handshake for torrent [%s]", tr_torrentName( tor ) ); tr_peerIoSetTorrentHash( handshake->io, tor->info.hash ); if( clientIsSeed && peerIsSeed ) { dbgmsg( handshake, "another seed tried to reconnect to us!" ); return tr_handshakeDone( handshake, FALSE ); } } else { dbgmsg( handshake, "can't find that torrent..." ); return tr_handshakeDone( handshake, FALSE ); } /* next part: ENCRYPT(VC, crypto_provide, len(PadC), */ tr_cryptoDecryptInit( handshake->crypto ); tr_peerIoReadBytes( handshake->io, inbuf, vc_in, VC_LENGTH ); tr_peerIoReadUint32( handshake->io, inbuf, &crypto_provide ); handshake->crypto_provide = crypto_provide; dbgmsg( handshake, "crypto_provide is %d", (int)crypto_provide ); tr_peerIoReadUint16( handshake->io, inbuf, &padc_len ); dbgmsg( handshake, "padc is %d", (int)padc_len ); handshake->pad_c_len = padc_len; setState( handshake, AWAITING_PAD_C ); return READ_NOW; }