Example #1
0
static void
buildHandshakeMessage( tr_handshake * handshake, uint8_t * buf )
{
    uint8_t          * walk = buf;
    const uint8_t    * torrentHash = tr_cryptoGetTorrentHash( handshake->crypto );
    const tr_torrent * tor = tr_torrentFindFromHash( handshake->session, torrentHash );
    const uint8_t    * peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );

    memcpy( walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
    walk += HANDSHAKE_NAME_LEN;
    memset( walk, 0, HANDSHAKE_FLAGS_LEN );
    HANDSHAKE_SET_LTEP( walk );
    HANDSHAKE_SET_FASTEXT( walk );

    /* Note that this doesn't depend on whether the torrent is private.
     * We don't accept DHT peers for a private torrent,
     * but we participate in the DHT regardless. */
    if( tr_dhtEnabled( handshake->session ) )
        HANDSHAKE_SET_DHT( walk );

    walk += HANDSHAKE_FLAGS_LEN;
    memcpy( walk, torrentHash, SHA_DIGEST_LENGTH );
    walk += SHA_DIGEST_LENGTH;
    memcpy( walk, peer_id, PEER_ID_LEN );
    walk += PEER_ID_LEN;

    assert( strlen( ( const char* )peer_id ) == PEER_ID_LEN );
    assert( walk - buf == HANDSHAKE_SIZE );
}
Example #2
0
const uint8_t*
tr_peerIoGetTorrentHash( tr_peerIo * io )
{
    assert( tr_isPeerIo( io ) );
    assert( io->crypto );

    return tr_cryptoGetTorrentHash( io->crypto );
}
Example #3
0
static bool
buildHandshakeMessage (tr_handshake * handshake, uint8_t * buf)
{
  const unsigned char * peer_id = NULL;
  const uint8_t * torrentHash;
  tr_torrent * tor;
  bool success;

  if ((torrentHash = tr_cryptoGetTorrentHash (handshake->crypto)))
    if ((tor = tr_torrentFindFromHash (handshake->session, torrentHash)))
      peer_id = tr_torrentGetPeerId (tor);

  if (peer_id == NULL)
    {
      success = false;
    }
  else
    {
      uint8_t * walk = buf;

      memcpy (walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN);
      walk += HANDSHAKE_NAME_LEN;
      memset (walk, 0, HANDSHAKE_FLAGS_LEN);
      HANDSHAKE_SET_LTEP (walk);
      HANDSHAKE_SET_FASTEXT (walk);

      /* Note that this doesn't depend on whether the torrent is private.
       * We don't accept DHT peers for a private torrent,
       * but we participate in the DHT regardless. */
      if (tr_dhtEnabled (handshake->session))
        HANDSHAKE_SET_DHT (walk);

      walk += HANDSHAKE_FLAGS_LEN;
      memcpy (walk, torrentHash, SHA_DIGEST_LENGTH);
      walk += SHA_DIGEST_LENGTH;
      memcpy (walk, peer_id, PEER_ID_LEN);
      walk += PEER_ID_LEN;

      assert (walk - buf == HANDSHAKE_SIZE);
      success = true;
    }

  return success;
}
Example #4
0
static int
test_torrent_hash (void)
{
  tr_crypto a;
  uint8_t hash[SHA_DIGEST_LENGTH];
  int i;

  for (i = 0; i < SHA_DIGEST_LENGTH; ++i)
    hash[i] = i;

  tr_cryptoConstruct (&a, NULL, true);

  check (!tr_cryptoHasTorrentHash (&a));
  check (tr_cryptoGetTorrentHash (&a) == NULL);

  tr_cryptoSetTorrentHash (&a, hash);
  check (tr_cryptoHasTorrentHash (&a));
  check (tr_cryptoGetTorrentHash (&a) != NULL);
  check (memcmp (tr_cryptoGetTorrentHash (&a), hash, SHA_DIGEST_LENGTH) == 0);

  tr_cryptoDestruct (&a);

  for (i = 0; i < SHA_DIGEST_LENGTH; ++i)
    hash[i] = i + 1;

  tr_cryptoConstruct (&a, hash, false);

  check (tr_cryptoHasTorrentHash (&a));
  check (tr_cryptoGetTorrentHash (&a) != NULL);
  check (memcmp (tr_cryptoGetTorrentHash (&a), hash, SHA_DIGEST_LENGTH) == 0);

  tr_cryptoSetTorrentHash (&a, NULL);
  check (!tr_cryptoHasTorrentHash (&a));
  check (tr_cryptoGetTorrentHash (&a) == NULL);

  tr_cryptoDestruct (&a);

  return 0;
}
Example #5
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;
}