source: branches/1.5x/libtransmission/crypto.c @ 7664

Last change on this file since 7664 was 7664, checked in by charles, 13 years ago

(1.5x) updates from trunk: all of build system & libtransmission; bugfixes in daemon, cli, and gtk; sync tr_sessionInit() changes. NOTE: mac end needs to add request-list.[ch] to its libtransmissio rules

  • Property svn:keywords set to Date Rev Author Id
File size: 7.0 KB
Line 
1/*
2 * This file Copyright (C) 2007-2009 Charles Kerr <charles@transmissionbt.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: crypto.c 7664 2009-01-11 17:46:51Z charles $
11 */
12
13#include <stdlib.h> /* for abs() */
14#include <limits.h> /* for INT_MAX */
15#include <sys/types.h> /* for event.h, as well as netinet/in.h on some platforms
16                         */
17#include <assert.h>
18#include <inttypes.h> /* uint8_t */
19#include <string.h> /* memcpy */
20#include <stdarg.h>
21
22#include <openssl/bn.h>
23#include <openssl/dh.h>
24#include <openssl/rc4.h>
25#include <openssl/sha.h>
26#include <openssl/rand.h>
27
28#include <event.h>
29
30#include "crypto.h"
31#include "utils.h"
32
33/**
34***
35**/
36
37void
38tr_sha1( uint8_t *    setme,
39         const void * content1,
40         int          content1_len,
41         ... )
42{
43    va_list vl;
44    SHA_CTX sha;
45
46    SHA1_Init( &sha );
47    SHA1_Update( &sha, content1, content1_len );
48
49    va_start( vl, content1_len );
50    for( ; ; )
51    {
52        const void * content = (const void*) va_arg( vl, const void* );
53        const int    content_len = content ? (int) va_arg( vl, int ) : -1;
54        if( content == NULL || content_len < 1 )
55            break;
56        SHA1_Update( &sha, content, content_len );
57    }
58    va_end( vl );
59    SHA1_Final( setme, &sha );
60}
61
62/**
63***
64**/
65
66#define KEY_LEN 96
67
68#define PRIME_LEN 96
69
70static const uint8_t dh_P[PRIME_LEN] =
71{
72    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
73    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
74    0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
75    0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
76    0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
77    0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
78    0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
79    0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63,
80};
81
82static const uint8_t dh_G[] = { 2 };
83
84struct tr_crypto
85{
86    RC4_KEY         dec_key;
87    RC4_KEY         enc_key;
88    uint8_t         torrentHash[SHA_DIGEST_LENGTH];
89    tr_bool         isIncoming;
90    tr_bool         torrentHashIsSet;
91    tr_bool         mySecretIsSet;
92    uint8_t         myPublicKey[KEY_LEN];
93    uint8_t         mySecret[KEY_LEN];
94};
95
96/**
97***
98**/
99
100static DH*
101getSharedDH( void )
102{
103    static DH * dh = NULL;
104
105    if( dh == NULL )
106    {
107        dh = DH_new( );
108        dh->p = BN_bin2bn( dh_P, sizeof( dh_P ), NULL );
109        dh->g = BN_bin2bn( dh_G, sizeof( dh_G ), NULL );
110        DH_generate_key( dh );
111    }
112
113    return dh;
114}
115
116tr_crypto *
117tr_cryptoNew( const uint8_t * torrentHash,
118              int             isIncoming )
119{
120    int         len, offset;
121    tr_crypto * crypto;
122    DH *        dh = getSharedDH( );
123
124    crypto = tr_new0( tr_crypto, 1 );
125    crypto->isIncoming = isIncoming ? 1 : 0;
126    tr_cryptoSetTorrentHash( crypto, torrentHash );
127
128    /* DH can generate key sizes that are smaller than the size of
129       P with exponentially decreasing probability, in which case
130       the msb's of myPublicKey need to be zeroed appropriately. */
131    len = DH_size( dh );
132    offset = KEY_LEN - len;
133    assert( len <= KEY_LEN );
134    memset( crypto->myPublicKey, 0, offset );
135    BN_bn2bin( dh->pub_key, crypto->myPublicKey + offset );
136
137    return crypto;
138}
139
140void
141tr_cryptoFree( tr_crypto * crypto )
142{
143    tr_free( crypto );
144}
145
146/**
147***
148**/
149
150const uint8_t*
151tr_cryptoComputeSecret( tr_crypto *     crypto,
152                        const uint8_t * peerPublicKey )
153{
154    int      len, offset;
155    uint8_t  secret[KEY_LEN];
156    BIGNUM * bn = BN_bin2bn( peerPublicKey, KEY_LEN, NULL );
157    DH *     dh = getSharedDH( );
158
159    assert( DH_size( dh ) == KEY_LEN );
160
161    len = DH_compute_key( secret, bn, dh );
162    assert( len <= KEY_LEN );
163    offset = KEY_LEN - len;
164    memset( crypto->mySecret, 0, offset );
165    memcpy( crypto->mySecret + offset, secret, len );
166    crypto->mySecretIsSet = 1;
167
168    BN_free( bn );
169
170    return crypto->mySecret;
171}
172
173const uint8_t*
174tr_cryptoGetMyPublicKey( const tr_crypto * crypto,
175                         int *             setme_len )
176{
177    *setme_len = KEY_LEN;
178    return crypto->myPublicKey;
179}
180
181/**
182***
183**/
184
185static void
186initRC4( tr_crypto *  crypto,
187         RC4_KEY *    setme,
188         const char * key )
189{
190    SHA_CTX sha;
191    uint8_t buf[SHA_DIGEST_LENGTH];
192
193    assert( crypto->torrentHashIsSet );
194    assert( crypto->mySecretIsSet );
195
196    SHA1_Init( &sha );
197    SHA1_Update( &sha, key, 4 );
198    SHA1_Update( &sha, crypto->mySecret, KEY_LEN );
199    SHA1_Update( &sha, crypto->torrentHash, SHA_DIGEST_LENGTH );
200    SHA1_Final( buf, &sha );
201    RC4_set_key( setme, SHA_DIGEST_LENGTH, buf );
202}
203
204void
205tr_cryptoDecryptInit( tr_crypto * crypto )
206{
207    unsigned char discard[1024];
208    const char *  txt = crypto->isIncoming ? "keyA" : "keyB";
209
210    initRC4( crypto, &crypto->dec_key, txt );
211    RC4( &crypto->dec_key, sizeof( discard ), discard, discard );
212}
213
214void
215tr_cryptoDecrypt( tr_crypto *  crypto,
216                  size_t       buf_len,
217                  const void * buf_in,
218                  void *       buf_out )
219{
220    RC4( &crypto->dec_key, buf_len,
221         (const unsigned char*)buf_in,
222         (unsigned char*)buf_out );
223}
224
225void
226tr_cryptoEncryptInit( tr_crypto * crypto )
227{
228    unsigned char discard[1024];
229    const char *  txt = crypto->isIncoming ? "keyB" : "keyA";
230
231    initRC4( crypto, &crypto->enc_key, txt );
232    RC4( &crypto->enc_key, sizeof( discard ), discard, discard );
233}
234
235void
236tr_cryptoEncrypt( tr_crypto *  crypto,
237                  size_t       buf_len,
238                  const void * buf_in,
239                  void *       buf_out )
240{
241    RC4( &crypto->enc_key, buf_len,
242         (const unsigned char*)buf_in,
243         (unsigned char*)buf_out );
244}
245
246/**
247***
248**/
249
250void
251tr_cryptoSetTorrentHash( tr_crypto *     crypto,
252                         const uint8_t * hash )
253{
254    crypto->torrentHashIsSet = hash ? 1 : 0;
255
256    if( hash )
257        memcpy( crypto->torrentHash, hash, SHA_DIGEST_LENGTH );
258    else
259        memset( crypto->torrentHash, 0, SHA_DIGEST_LENGTH );
260}
261
262const uint8_t*
263tr_cryptoGetTorrentHash( const tr_crypto * crypto )
264{
265    assert( crypto );
266    assert( crypto->torrentHashIsSet );
267
268    return crypto->torrentHash;
269}
270
271int
272tr_cryptoHasTorrentHash( const tr_crypto * crypto )
273{
274    assert( crypto );
275
276    return crypto->torrentHashIsSet ? 1 : 0;
277}
278
279int
280tr_cryptoRandInt( int sup )
281{
282    int r;
283
284    RAND_pseudo_bytes ( (unsigned char *) &r, sizeof r );
285
286    return (int) ( sup * ( abs( r ) / ( INT_MAX + 1.0 ) ) );
287}
288
289int
290tr_cryptoWeakRandInt( int sup )
291{
292    static int init = 0;
293
294    assert( sup > 0 );
295
296    if( !init )
297    {
298        srand( tr_date( ) );
299        init = 1;
300    }
301
302    return rand( ) % sup;
303}
304
305void
306tr_cryptoRandBuf( unsigned char *buf,
307                  size_t         len )
308{
309    RAND_pseudo_bytes ( buf, len );
310}
311
Note: See TracBrowser for help on using the repository browser.