static int readVC( tr_handshake * handshake, struct evbuffer * inbuf ) { const uint8_t key[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 }; const int key_len = VC_LENGTH; uint8_t tmp[VC_LENGTH]; /* note: this works w/o having to `unwind' the buffer if * we read too much, but it is pretty brute-force. * it would be nice to make this cleaner. */ for( ; ; ) { if( evbuffer_get_length( inbuf ) < VC_LENGTH ) { dbgmsg( handshake, "not enough bytes... returning read_more" ); return READ_LATER; } memcpy( tmp, evbuffer_pullup( inbuf, key_len ), key_len ); tr_cryptoDecryptInit( handshake->crypto ); tr_cryptoDecrypt( handshake->crypto, key_len, tmp, tmp ); if( !memcmp( tmp, key, key_len ) ) break; evbuffer_drain( inbuf, 1 ); } dbgmsg( handshake, "got it!" ); evbuffer_drain( inbuf, key_len ); setState( handshake, AWAITING_CRYPTO_SELECT ); return READ_NOW; }
void tr_peerIoReadBytes( tr_peerIo * io, struct evbuffer * inbuf, void * bytes, size_t byteCount ) { assert( tr_isPeerIo( io ) ); /* FIXME(libevent2): use evbuffer_get_length() */ assert( EVBUFFER_LENGTH( inbuf ) >= byteCount ); switch( io->encryptionMode ) { case PEER_ENCRYPTION_NONE: evbuffer_remove( inbuf, bytes, byteCount ); break; case PEER_ENCRYPTION_RC4: /* FIXME(libevent2): loop through calls to evbuffer_get_contiguous_space() + evbuffer_drain() */ tr_cryptoDecrypt( io->crypto, byteCount, EVBUFFER_DATA(inbuf), bytes ); evbuffer_drain(inbuf, byteCount ); break; default: assert( 0 ); } }
static int test_encrypt_decrypt (void) { tr_crypto a, b; uint8_t hash[SHA_DIGEST_LENGTH]; const char test1[] = { "test1" }; char buf11[sizeof (test1)], buf12[sizeof (test1)]; const char test2[] = { "@#)C$@)#(*%bvkdjfhwbc039bc4603756VB3)" }; char buf21[sizeof (test2)], buf22[sizeof (test2)]; int i; for (i = 0; i < SHA_DIGEST_LENGTH; ++i) hash[i] = i; tr_cryptoConstruct (&a, hash, false); tr_cryptoConstruct (&b, hash, true); tr_cryptoComputeSecret (&a, tr_cryptoGetMyPublicKey (&b, &i)); tr_cryptoComputeSecret (&b, tr_cryptoGetMyPublicKey (&a, &i)); tr_cryptoEncryptInit (&a); tr_cryptoEncrypt (&a, sizeof (test1), test1, buf11); tr_cryptoDecryptInit (&b); tr_cryptoDecrypt (&b, sizeof (test1), buf11, buf12); check_streq (test1, buf12); tr_cryptoEncryptInit (&b); tr_cryptoEncrypt (&b, sizeof (test2), test2, buf21); tr_cryptoDecryptInit (&a); tr_cryptoDecrypt (&a, sizeof (test2), buf21, buf22); check_streq (test2, buf22); tr_cryptoDestruct (&b); tr_cryptoDestruct (&a); return 0; }
static int readHandshake( tr_handshake * handshake, struct evbuffer * inbuf ) { uint8_t pstrlen; uint8_t * pstr; uint8_t reserved[HANDSHAKE_FLAGS_LEN]; uint8_t hash[SHA_DIGEST_LENGTH]; dbgmsg( handshake, "payload: need %d, got %zu", INCOMING_HANDSHAKE_LEN, evbuffer_get_length( inbuf ) ); if( evbuffer_get_length( inbuf ) < INCOMING_HANDSHAKE_LEN ) return READ_LATER; handshake->haveReadAnythingFromPeer = TRUE; pstrlen = evbuffer_pullup( inbuf, 1 )[0]; /* peek, don't read. We may be handing inbuf to AWAITING_YA */ if( pstrlen == 19 ) /* unencrypted */ { tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_NONE ); if( handshake->encryptionMode == TR_ENCRYPTION_REQUIRED ) { dbgmsg( handshake, "peer is unencrypted, and we're disallowing that" ); return tr_handshakeDone( handshake, FALSE ); } } else /* encrypted or corrupt */ { tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_RC4 ); if( tr_peerIoIsIncoming( handshake->io ) ) { dbgmsg( handshake, "I think peer is sending us an encrypted handshake..." ); setState( handshake, AWAITING_YA ); return READ_NOW; } tr_cryptoDecrypt( handshake->crypto, 1, &pstrlen, &pstrlen ); if( pstrlen != 19 ) { dbgmsg( handshake, "I think peer has sent us a corrupt handshake..." ); return tr_handshakeDone( handshake, FALSE ); } } evbuffer_drain( inbuf, 1 ); /* pstr (BitTorrent) */ pstr = tr_new( uint8_t, pstrlen + 1 ); tr_peerIoReadBytes( handshake->io, inbuf, pstr, pstrlen ); pstr[pstrlen] = '\0'; if( strcmp( (char*)pstr, "BitTorrent protocol" ) ) { tr_free( pstr ); return tr_handshakeDone( handshake, FALSE ); } tr_free( pstr ); /* reserved bytes */ tr_peerIoReadBytes( handshake->io, inbuf, reserved, sizeof( reserved ) ); /** *** Extensions **/ tr_peerIoEnableLTEP( handshake->io, HANDSHAKE_HAS_LTEP( reserved ) ); tr_peerIoEnableFEXT( handshake->io, HANDSHAKE_HAS_FASTEXT( reserved ) ); tr_peerIoEnableDHT( handshake->io, HANDSHAKE_HAS_DHT( reserved ) ); /* torrent hash */ tr_peerIoReadBytes( handshake->io, inbuf, hash, sizeof( hash ) ); if( tr_peerIoIsIncoming( handshake->io ) ) { if( !tr_torrentExists( handshake->session, hash ) ) { dbgmsg( handshake, "peer is trying to connect to us for a torrent we don't have." ); return tr_handshakeDone( handshake, FALSE ); } else { assert( !tr_peerIoHasTorrentHash( handshake->io ) ); tr_peerIoSetTorrentHash( handshake->io, hash ); } } else /* outgoing */ { assert( tr_peerIoHasTorrentHash( handshake->io ) ); if( memcmp( hash, tr_peerIoGetTorrentHash( handshake->io ), SHA_DIGEST_LENGTH ) ) { dbgmsg( handshake, "peer returned the wrong hash. wtf?" ); return tr_handshakeDone( handshake, FALSE ); } } /** *** If it's an incoming message, we need to send a response handshake **/ if( !handshake->haveSentBitTorrentHandshake ) { uint8_t msg[HANDSHAKE_SIZE]; buildHandshakeMessage( handshake, msg ); tr_peerIoWriteBytes( handshake->io, msg, sizeof( msg ), FALSE ); handshake->haveSentBitTorrentHandshake = 1; } setReadState( handshake, AWAITING_PEER_ID ); return READ_NOW; }