static int
readPadD (tr_handshake    * handshake,
          struct evbuffer * inbuf)
{
  const size_t needlen = handshake->pad_d_len;

  dbgmsg (handshake, "pad d: need %zu, got %zu",
          needlen, evbuffer_get_length (inbuf));
  if (evbuffer_get_length (inbuf) < needlen)
    return READ_LATER;

  tr_peerIoDrain (handshake->io, inbuf, needlen);

  tr_peerIoSetEncryption (handshake->io, handshake->crypto_select);

  setState (handshake, AWAITING_HANDSHAKE);
  return READ_NOW;
}
tr_handshake*
tr_handshakeNew (tr_peerIo           * io,
                 tr_encryption_mode    encryptionMode,
                 handshakeDoneCB       doneCB,
                 void                * doneUserData)
{
  tr_handshake * handshake;
  tr_session * session = tr_peerIoGetSession (io);

  handshake = tr_new0 (tr_handshake, 1);
  handshake->io = io;
  handshake->crypto = tr_peerIoGetCrypto (io);
  handshake->encryptionMode = encryptionMode;
  handshake->doneCB = doneCB;
  handshake->doneUserData = doneUserData;
  handshake->session = session;
  handshake->timeout_timer = evtimer_new (session->event_base, handshakeTimeout, handshake);
  tr_timerAdd (handshake->timeout_timer, HANDSHAKE_TIMEOUT_SEC, 0);

  tr_peerIoRef (io); /* balanced by the unref in tr_handshakeFree */
  tr_peerIoSetIOFuncs (handshake->io, canRead, NULL, gotError, handshake);
  tr_peerIoSetEncryption (io, PEER_ENCRYPTION_NONE);

  if (tr_peerIoIsIncoming (handshake->io))
    {
      setReadState (handshake, AWAITING_HANDSHAKE);
    }
  else if (encryptionMode != TR_CLEAR_PREFERRED)
    {
      sendYa (handshake);
    }
  else
    {
      uint8_t msg[HANDSHAKE_SIZE];
      buildHandshakeMessage (handshake, msg);

      handshake->haveSentBitTorrentHandshake = 1;
      setReadState (handshake, AWAITING_HANDSHAKE);
      tr_peerIoWriteBytes (handshake->io, msg, sizeof (msg), false);
    }

  return handshake;
}
/* 2 $A \leftarrow B$: Diffie Hellman $Y_B$, PadB */
static int readYb(tr_handshake * handshake, struct evbuffer * inbuf) {
    int isEncrypted;
    const uint8_t * secret;
    uint8_t yb[KEY_LEN];
    struct evbuffer * outbuf;
    size_t needlen = HANDSHAKE_NAME_LEN;

    (...)
    isEncrypted = memcmp(evbuffer_pullup(inbuf, HANDSHAKE_NAME_LEN),
                    HANDSHAKE_NAME, HANDSHAKE_NAME_LEN);
    (...)
    tr_peerIoSetEncryption(handshake->io, isEncrypted ? PEER_ENCRYPTION_RC4
                                                      : PEER_ENCRYPTION_NONE);

    if (!isEncrypted) {
        setState(handshake, AWAITING_HANDSHAKE); // Handshake não encriptado acaba aqui.
        return READ_NOW;
    }

    (...)
    /* compute the secret $S$*/
    evbuffer_remove(inbuf, yb, KEY_LEN);
    secret = tr_cryptoComputeSecret(handshake->crypto, yb);
    memcpy(handshake->mySecret, secret, KEY_LEN);
Beispiel #4
0
static int
readIA( tr_handshake *    handshake,
        struct evbuffer * inbuf )
{
    const size_t      needlen = handshake->ia_len;
    struct evbuffer * outbuf;
    uint32_t          crypto_select;

    dbgmsg( handshake, "reading IA... have %zu, need %zu",
            evbuffer_get_length( inbuf ), needlen );
    if( evbuffer_get_length( inbuf ) < needlen )
        return READ_LATER;

    /**
    ***  B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
    **/

    tr_cryptoEncryptInit( handshake->crypto );
    outbuf = evbuffer_new( );

    dbgmsg( handshake, "sending vc" );
    /* send VC */
    {
        uint8_t vc[VC_LENGTH];
        memset( vc, 0, VC_LENGTH );
        evbuffer_add( outbuf, vc, VC_LENGTH );
    }

    /* send crypto_select */
    crypto_select = getCryptoSelect( handshake, handshake->crypto_provide );
    if( crypto_select )
    {
        dbgmsg( handshake, "selecting crypto mode '%d'", (int)crypto_select );
        evbuffer_add_uint32( outbuf, crypto_select );
    }
    else
    {
        dbgmsg( handshake, "peer didn't offer an encryption mode we like." );
        evbuffer_free( outbuf );
        return tr_handshakeDone( handshake, FALSE );
    }

    dbgmsg( handshake, "sending pad d" );
    /* ENCRYPT(VC, crypto_provide, len(PadD), PadD
     * PadD is reserved for future extensions to the handshake...
     * standard practice at this time is for it to be zero-length */
    {
        const uint16_t len = 0;
        evbuffer_add_uint16( outbuf, len );
    }

    /* maybe de-encrypt our connection */
    if( crypto_select == CRYPTO_PROVIDE_PLAINTEXT )
    {
        tr_peerIoWriteBuf( handshake->io, outbuf, FALSE );
        tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_NONE );
    }

    dbgmsg( handshake, "sending handshake" );
    /* send our handshake */
    {
        uint8_t msg[HANDSHAKE_SIZE];
        buildHandshakeMessage( handshake, msg );

        evbuffer_add( outbuf, msg, sizeof( msg ) );
        handshake->haveSentBitTorrentHandshake = 1;
    }

    /* send it out */
    tr_peerIoWriteBuf( handshake->io, outbuf, FALSE );
    evbuffer_free( outbuf );

    /* now await the handshake */
    setState( handshake, AWAITING_PAYLOAD_STREAM );
    return READ_NOW;
}
Beispiel #5
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;
}
Beispiel #6
0
static int
readYb( tr_handshake * handshake, struct evbuffer * inbuf )
{
    int               isEncrypted;
    const uint8_t *   secret;
    uint8_t           yb[KEY_LEN];
    struct evbuffer * outbuf;
    size_t            needlen = HANDSHAKE_NAME_LEN;

    if( evbuffer_get_length( inbuf ) < needlen )
        return READ_LATER;

    isEncrypted = memcmp( evbuffer_pullup( inbuf, HANDSHAKE_NAME_LEN ), HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
    if( isEncrypted )
    {
        needlen = KEY_LEN;
        if( evbuffer_get_length( inbuf ) < needlen )
            return READ_LATER;
    }

    dbgmsg( handshake, "got a %s handshake",
           ( isEncrypted ? "encrypted" : "plaintext" ) );

    tr_peerIoSetEncryption( handshake->io, isEncrypted ? PEER_ENCRYPTION_RC4
                                                       : PEER_ENCRYPTION_NONE );
    if( !isEncrypted )
    {
        setState( handshake, AWAITING_HANDSHAKE );
        return READ_NOW;
    }

    handshake->haveReadAnythingFromPeer = TRUE;

    /* compute the secret */
    evbuffer_remove( inbuf, yb, KEY_LEN );
    secret = tr_cryptoComputeSecret( handshake->crypto, yb );
    memcpy( handshake->mySecret, secret, KEY_LEN );

    /* now send these: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S),
     * ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA) */
    outbuf = evbuffer_new( );

    /* HASH('req1', S) */
    {
        uint8_t req1[SHA_DIGEST_LENGTH];
        tr_sha1( req1, "req1", 4, secret, KEY_LEN, NULL );
        evbuffer_add( outbuf, req1, SHA_DIGEST_LENGTH );
    }

    /* HASH('req2', SKEY) xor HASH('req3', S) */
    {
        int     i;
        uint8_t req2[SHA_DIGEST_LENGTH];
        uint8_t req3[SHA_DIGEST_LENGTH];
        uint8_t buf[SHA_DIGEST_LENGTH];
        tr_sha1( req2, "req2", 4,
                 tr_cryptoGetTorrentHash( handshake->crypto ),
                 SHA_DIGEST_LENGTH, NULL );
        tr_sha1( req3, "req3", 4, secret, KEY_LEN, NULL );
        for( i = 0; i < SHA_DIGEST_LENGTH; ++i )
            buf[i] = req2[i] ^ req3[i];
        evbuffer_add( outbuf, buf, SHA_DIGEST_LENGTH );
    }

    /* ENCRYPT(VC, crypto_provide, len(PadC), PadC
     * PadC is reserved for future extensions to the handshake...
     * standard practice at this time is for it to be zero-length */
    {
        uint8_t vc[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 };

        tr_peerIoWriteBuf( handshake->io, outbuf, FALSE );
        tr_cryptoEncryptInit( handshake->crypto );
        tr_peerIoSetEncryption( handshake->io, PEER_ENCRYPTION_RC4 );

        evbuffer_add        ( outbuf, vc, VC_LENGTH );
        evbuffer_add_uint32 ( outbuf, getCryptoProvide( handshake ) );
        evbuffer_add_uint16 ( outbuf, 0 );
    }

    /* ENCRYPT len(IA)), ENCRYPT(IA) */
    {
        uint8_t msg[HANDSHAKE_SIZE];
        buildHandshakeMessage( handshake, msg );

        evbuffer_add_uint16 ( outbuf, sizeof( msg ) );
        evbuffer_add        ( outbuf, msg, sizeof( msg ) );

        handshake->haveSentBitTorrentHandshake = 1;
    }

    /* send it */
    tr_cryptoDecryptInit( handshake->crypto );
    setReadState( handshake, AWAITING_VC );
    tr_peerIoWriteBuf( handshake->io, outbuf, FALSE );

    /* cleanup */
    evbuffer_free( outbuf );
    return READ_LATER;
}