예제 #1
0
static int
test_sha1 (void)
{
  uint8_t hash[SHA_DIGEST_LENGTH];

  tr_sha1 (hash, "test", 4, NULL);
  check (memcmp (hash, "\xa9\x4a\x8f\xe5\xcc\xb1\x9b\xa6\x1c\x4c\x08\x73\xd3\x91\xe9\x87\x98\x2f\xbb\xd3", SHA_DIGEST_LENGTH) == 0);

  tr_sha1 (hash, "1", 1, "22", 2, "333", 3, NULL);
  check (memcmp (hash, "\x1f\x74\x64\x8e\x50\xa6\xa6\x70\x8e\xc5\x4a\xb3\x27\xa1\x63\xd5\x53\x6b\x7c\xed", SHA_DIGEST_LENGTH) == 0);

  return 0;
}
예제 #2
0
tr_bool
tr_ssha1_matches( const char * source, const char * pass )
{
    char * salt;
    size_t saltlen;
    char * hashed;
    uint8_t buf[SHA_DIGEST_LENGTH];
    tr_bool result;

    /* extract the salt */
    saltlen = strlen( source ) - 2*SHA_DIGEST_LENGTH-1;
    salt = tr_malloc( saltlen );
    memcpy( salt, source + 2*SHA_DIGEST_LENGTH+1, saltlen );

    /* hash pass + salt */
    hashed = tr_malloc( 2*SHA_DIGEST_LENGTH + saltlen + 2 );
    tr_sha1( buf, pass, strlen( pass ), salt, saltlen, NULL );
    tr_sha1_to_hex( &hashed[1], buf );
    memcpy( hashed + 1+2*SHA_DIGEST_LENGTH, salt, saltlen );
    hashed[1+2*SHA_DIGEST_LENGTH + saltlen] = '\0';
    hashed[0] = '{';

    result = strcmp( source, hashed ) == 0 ? TRUE : FALSE;

    tr_free( hashed );
    tr_free( salt );

    return result;
}
예제 #3
0
char*
tr_ssha1( const void * plaintext )
{
    enum { saltval_len = 8,
           salter_len  = 64 };
    static const char * salter = "0123456789"
                                 "abcdefghijklmnopqrstuvwxyz"
                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                 "./";

    size_t i;
    unsigned char salt[saltval_len];
    uint8_t sha[SHA_DIGEST_LENGTH];
    char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2];

    tr_cryptoRandBuf( salt, saltval_len );
    for( i=0; i<saltval_len; ++i )
        salt[i] = salter[ salt[i] % salter_len ];

    tr_sha1( sha, plaintext, strlen( plaintext ), salt, saltval_len, NULL );
    tr_sha1_to_hex( &buf[1], sha );
    memcpy( &buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len );
    buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0';
    buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring
                     easier */

    return tr_strdup( &buf );
}
예제 #4
0
static int
readYa( tr_handshake *    handshake,
        struct evbuffer * inbuf )
{
    uint8_t        ya[KEY_LEN];
    uint8_t *      walk, outbuf[KEY_LEN + PadB_MAXLEN];
    const uint8_t *myKey, *secret;
    int            len;

    dbgmsg( handshake, "in readYa... need %d, have %zu",
            KEY_LEN, evbuffer_get_length( inbuf ) );
    if( evbuffer_get_length( inbuf ) < KEY_LEN )
        return READ_LATER;

    /* read the incoming peer's public key */
    evbuffer_remove( inbuf, ya, KEY_LEN );
    secret = tr_cryptoComputeSecret( handshake->crypto, ya );
    memcpy( handshake->mySecret, secret, KEY_LEN );
    tr_sha1( handshake->myReq1, "req1", 4, secret, KEY_LEN, NULL );

    dbgmsg( handshake, "sending B->A: Diffie Hellman Yb, PadB" );
    /* send our public key to the peer */
    walk = outbuf;
    myKey = tr_cryptoGetMyPublicKey( handshake->crypto, &len );
    memcpy( walk, myKey, len );
    walk += len;
    len = tr_cryptoRandInt( PadB_MAXLEN );
    tr_cryptoRandBuf( walk, len );
    walk += len;

    setReadState( handshake, AWAITING_PAD_A );
    tr_peerIoWriteBytes( handshake->io, outbuf, walk - outbuf, FALSE );
    return READ_NOW;
}
예제 #5
0
bool tr_dh_secret_derive(tr_dh_secret_t raw_handle, void const* prepend_data, size_t prepend_data_size, void const* append_data,
    size_t append_data_size, uint8_t* hash)
{
    TR_ASSERT(raw_handle != NULL);
    TR_ASSERT(hash != NULL);

    struct tr_dh_secret* handle = raw_handle;

    return tr_sha1(hash, prepend_data == NULL ? "" : prepend_data, prepend_data == NULL ? 0 : (int)prepend_data_size,
        handle->key, (int)handle->key_length, append_data, append_data == NULL ? 0 : (int)append_data_size, NULL);
}
예제 #6
0
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;
}
예제 #7
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;
}