source: trunk/libtransmission/crypto.c @ 10521

Last change on this file since 10521 was 10521, checked in by charles, 12 years ago

(trunk libT) "transmission.h" should *always* be #included before any other libtransmission header

  • Property svn:keywords set to Date Rev Author Id
File size: 10.2 KB
Line 
1/* * This file Copyright (C) 2007-2010 Mnemosyne LLC
2 *
3 * This file is licensed by the GPL version 2.  Works owned by the
4 * Transmission project are granted a special exemption to clause 2(b)
5 * so that the bulk of its code can remain under the MIT license.
6 * This exemption does not extend to derived works not owned by
7 * the Transmission project.
8 *
9 * $Id: crypto.c 10521 2010-04-23 16:36:16Z charles $
10 */
11
12#include <stdlib.h> /* for abs() */
13#include <limits.h> /* for INT_MAX */
14#include <sys/types.h> /* for event.h, as well as netinet/in.h on some platforms
15                         */
16#include <assert.h>
17#include <inttypes.h> /* uint8_t */
18#include <string.h> /* memcpy */
19#include <stdarg.h>
20
21#include <openssl/bn.h>
22#include <openssl/dh.h>
23#include <openssl/err.h>
24#include <openssl/rc4.h>
25#include <openssl/sha.h>
26#include <openssl/rand.h>
27
28#include <event.h>
29
30#include "transmission.h"
31#include "crypto.h"
32#include "utils.h"
33
34#define MY_NAME "tr_crypto"
35
36/**
37***
38**/
39
40void
41tr_sha1( uint8_t *    setme,
42         const void * content1,
43         int          content1_len,
44         ... )
45{
46    va_list vl;
47    SHA_CTX sha;
48
49    SHA1_Init( &sha );
50    SHA1_Update( &sha, content1, content1_len );
51
52    va_start( vl, content1_len );
53    for( ; ; )
54    {
55        const void * content = (const void*) va_arg( vl, const void* );
56        const int    content_len = content ? (int) va_arg( vl, int ) : -1;
57        if( content == NULL || content_len < 1 )
58            break;
59        SHA1_Update( &sha, content, content_len );
60    }
61    va_end( vl );
62    SHA1_Final( setme, &sha );
63}
64
65/**
66***
67**/
68
69#define KEY_LEN 96
70
71#define PRIME_LEN 96
72
73#define DH_PRIVKEY_LEN_MIN 16
74#define DH_PRIVKEY_LEN 20
75
76static const uint8_t dh_P[PRIME_LEN] =
77{
78    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
79    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
80    0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
81    0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
82    0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
83    0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
84    0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
85    0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63,
86};
87
88static const uint8_t dh_G[] = { 2 };
89
90/** @brief Holds state information for encrypted peer communications */
91struct tr_crypto
92{
93    RC4_KEY         dec_key;
94    RC4_KEY         enc_key;
95    uint8_t         torrentHash[SHA_DIGEST_LENGTH];
96    tr_bool         isIncoming;
97    tr_bool         torrentHashIsSet;
98    tr_bool         mySecretIsSet;
99    uint8_t         myPublicKey[KEY_LEN];
100    uint8_t         mySecret[KEY_LEN];
101    DH *            dh;
102};
103
104/**
105***
106**/
107
108#define logErrorFromSSL( ... ) \
109    do { \
110        if( tr_msgLoggingIsActive( TR_MSG_ERR ) ) { \
111            char buf[512]; \
112            ERR_error_string_n( ERR_get_error( ), buf, sizeof( buf ) ); \
113            tr_msg( __FILE__, __LINE__, TR_MSG_ERR, MY_NAME, "%s", buf ); \
114        } \
115    } while( 0 )
116
117static void
118ensureKeyExists( tr_crypto * crypto)
119{
120    if( crypto->dh == NULL )
121    {
122        int len, offset;
123        DH * dh = DH_new( );
124
125        dh->p = BN_bin2bn( dh_P, sizeof( dh_P ), NULL );
126        if( dh->p == NULL )
127            logErrorFromSSL( );
128
129        dh->g = BN_bin2bn( dh_G, sizeof( dh_G ), NULL );
130        if( dh->g == NULL )
131            logErrorFromSSL( );
132
133        /* private DH value: strong random BN of DH_PRIVKEY_LEN*8 bits */
134        dh->priv_key = BN_new( );
135        do {
136            if( BN_rand( dh->priv_key, DH_PRIVKEY_LEN * 8, -1, 0 ) != 1 )
137                logErrorFromSSL( );
138        } while ( BN_num_bits( dh->priv_key ) < DH_PRIVKEY_LEN_MIN * 8 );
139
140        if( !DH_generate_key( dh ) )
141            logErrorFromSSL( );
142
143        /* DH can generate key sizes that are smaller than the size of
144           P with exponentially decreasing probability, in which case
145           the msb's of myPublicKey need to be zeroed appropriately. */
146        len = BN_num_bytes( dh->pub_key );
147        offset = KEY_LEN - len;
148        assert( len <= KEY_LEN );
149        memset( crypto->myPublicKey, 0, offset );
150        BN_bn2bin( dh->pub_key, crypto->myPublicKey + offset );
151
152        crypto->dh = dh;
153    }
154}
155
156tr_crypto *
157tr_cryptoNew( const uint8_t * torrentHash,
158              int             isIncoming )
159{
160    tr_crypto * crypto;
161
162    crypto = tr_new0( tr_crypto, 1 );
163    crypto->isIncoming = isIncoming ? 1 : 0;
164    tr_cryptoSetTorrentHash( crypto, torrentHash );
165    crypto->dh = NULL;
166
167    return crypto;
168}
169
170void
171tr_cryptoFree( tr_crypto * crypto )
172{
173    if( crypto->dh != NULL )
174        DH_free( crypto->dh );
175    tr_free( crypto );
176}
177
178/**
179***
180**/
181
182const uint8_t*
183tr_cryptoComputeSecret( tr_crypto *     crypto,
184                        const uint8_t * peerPublicKey )
185{
186    int      len;
187    uint8_t  secret[KEY_LEN];
188    BIGNUM * bn = BN_bin2bn( peerPublicKey, KEY_LEN, NULL );
189    DH *     dh;
190
191    ensureKeyExists( crypto );
192    dh = crypto->dh;
193
194    assert( DH_size( dh ) == KEY_LEN );
195
196    len = DH_compute_key( secret, bn, dh );
197    if( len == -1 )
198        logErrorFromSSL( );
199    else {
200        int offset;
201        assert( len <= KEY_LEN );
202        offset = KEY_LEN - len;
203        memset( crypto->mySecret, 0, offset );
204        memcpy( crypto->mySecret + offset, secret, len );
205        crypto->mySecretIsSet = 1;
206    }
207
208    BN_free( bn );
209    return crypto->mySecret;
210}
211
212const uint8_t*
213tr_cryptoGetMyPublicKey( const tr_crypto * crypto,
214                         int *             setme_len )
215{
216    ensureKeyExists( (tr_crypto *) crypto );
217    *setme_len = KEY_LEN;
218    return crypto->myPublicKey;
219}
220
221/**
222***
223**/
224
225static void
226initRC4( tr_crypto *  crypto,
227         RC4_KEY *    setme,
228         const char * key )
229{
230    SHA_CTX sha;
231    uint8_t buf[SHA_DIGEST_LENGTH];
232
233    assert( crypto->torrentHashIsSet );
234    assert( crypto->mySecretIsSet );
235
236    if( SHA1_Init( &sha )
237        && SHA1_Update( &sha, key, 4 )
238        && SHA1_Update( &sha, crypto->mySecret, KEY_LEN )
239        && SHA1_Update( &sha, crypto->torrentHash, SHA_DIGEST_LENGTH )
240        && SHA1_Final( buf, &sha ) )
241    {
242        RC4_set_key( setme, SHA_DIGEST_LENGTH, buf );
243    }
244    else
245    {
246        logErrorFromSSL( );
247    }
248}
249
250void
251tr_cryptoDecryptInit( tr_crypto * crypto )
252{
253    unsigned char discard[1024];
254    const char *  txt = crypto->isIncoming ? "keyA" : "keyB";
255
256    initRC4( crypto, &crypto->dec_key, txt );
257    RC4( &crypto->dec_key, sizeof( discard ), discard, discard );
258}
259
260void
261tr_cryptoDecrypt( tr_crypto *  crypto,
262                  size_t       buf_len,
263                  const void * buf_in,
264                  void *       buf_out )
265{
266    RC4( &crypto->dec_key, buf_len,
267         (const unsigned char*)buf_in,
268         (unsigned char*)buf_out );
269}
270
271void
272tr_cryptoEncryptInit( tr_crypto * crypto )
273{
274    unsigned char discard[1024];
275    const char *  txt = crypto->isIncoming ? "keyB" : "keyA";
276
277    initRC4( crypto, &crypto->enc_key, txt );
278    RC4( &crypto->enc_key, sizeof( discard ), discard, discard );
279}
280
281void
282tr_cryptoEncrypt( tr_crypto *  crypto,
283                  size_t       buf_len,
284                  const void * buf_in,
285                  void *       buf_out )
286{
287    RC4( &crypto->enc_key, buf_len,
288         (const unsigned char*)buf_in,
289         (unsigned char*)buf_out );
290}
291
292/**
293***
294**/
295
296void
297tr_cryptoSetTorrentHash( tr_crypto *     crypto,
298                         const uint8_t * hash )
299{
300    crypto->torrentHashIsSet = hash ? 1 : 0;
301
302    if( hash )
303        memcpy( crypto->torrentHash, hash, SHA_DIGEST_LENGTH );
304    else
305        memset( crypto->torrentHash, 0, SHA_DIGEST_LENGTH );
306}
307
308const uint8_t*
309tr_cryptoGetTorrentHash( const tr_crypto * crypto )
310{
311    assert( crypto );
312    assert( crypto->torrentHashIsSet );
313
314    return crypto->torrentHash;
315}
316
317int
318tr_cryptoHasTorrentHash( const tr_crypto * crypto )
319{
320    assert( crypto );
321
322    return crypto->torrentHashIsSet ? 1 : 0;
323}
324
325int
326tr_cryptoRandInt( int upperBound )
327{
328    int noise;
329    int val;
330
331    assert( upperBound > 0 );
332
333    if( RAND_pseudo_bytes ( (unsigned char *) &noise, sizeof noise ) >= 0 )
334    {
335        val = abs( noise ) % upperBound;
336    }
337    else /* fall back to a weaker implementation... */
338    {
339        val = tr_cryptoWeakRandInt( upperBound );
340    }
341
342    return val;
343}
344
345int
346tr_cryptoWeakRandInt( int upperBound )
347{
348    static tr_bool init = FALSE;
349
350    assert( upperBound > 0 );
351
352    if( !init )
353    {
354        srand( tr_date( ) );
355        init = TRUE;
356    }
357
358    return rand( ) % upperBound;
359}
360
361void
362tr_cryptoRandBuf( void * buf, size_t len )
363{
364    if( RAND_pseudo_bytes ( (unsigned char*)buf, len ) != 1 )
365        logErrorFromSSL( );
366}
367
368/***
369****
370***/
371
372char*
373tr_ssha1( const void * plaintext )
374{
375    static const char * salter = "0123456789"
376                                 "abcdefghijklmnopqrstuvwxyz"
377                                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
378                                 "./";
379    const size_t salter_len = 64;
380    const size_t saltval_len = 8;
381
382    size_t i;
383    char salt[saltval_len];
384    uint8_t sha[SHA_DIGEST_LENGTH];
385    char buf[2*SHA_DIGEST_LENGTH + saltval_len + 2];
386
387    for( i=0; i<saltval_len; ++i )
388        salt[i] = salter[ tr_cryptoRandInt( salter_len ) ];
389
390    tr_sha1( sha, plaintext, strlen( plaintext ), salt, saltval_len, NULL );
391    tr_sha1_to_hex( &buf[1], sha );
392    memcpy( &buf[1+2*SHA_DIGEST_LENGTH], &salt, saltval_len );
393    buf[1+2*SHA_DIGEST_LENGTH + saltval_len] = '\0';
394    buf[0] = '{'; /* signal that this is a hash. this makes saving/restoring
395                     easier */
396
397    return tr_strdup( &buf );
398}
399
400tr_bool
401tr_ssha1_matches( const char * source, const char * pass )
402{
403    char * salt;
404    size_t saltlen;
405    char * hashed;
406    uint8_t buf[SHA_DIGEST_LENGTH];
407    tr_bool result;
408
409    /* extract the salt */
410    saltlen = strlen( source ) - 2*SHA_DIGEST_LENGTH-1;
411    salt = tr_malloc( saltlen );
412    memcpy( salt, source + 2*SHA_DIGEST_LENGTH+1, saltlen );
413
414    /* hash pass + salt */
415    hashed = tr_malloc( 2*SHA_DIGEST_LENGTH + saltlen + 2 );
416    tr_sha1( buf, pass, strlen( pass ), salt, saltlen, NULL );
417    tr_sha1_to_hex( &hashed[1], buf );
418    memcpy( hashed + 1+2*SHA_DIGEST_LENGTH, salt, saltlen );
419    hashed[1+2*SHA_DIGEST_LENGTH + saltlen] = '\0';
420    hashed[0] = '{';
421
422    result = strcmp( source, hashed ) == 0 ? TRUE : FALSE;
423
424    tr_free( hashed );
425    tr_free( salt );
426
427    return result;
428}
Note: See TracBrowser for help on using the repository browser.