source: branches/encryption/libtransmission/encryption.c @ 2936

Last change on this file since 2936 was 2936, checked in by charles, 15 years ago

not ready for use yet -- this is a periodic checkin so I don't lose my changes. Outgoing connections work for plaintext, encrypted, and encrypted connections that prefer plaintext. Incoming connections don't work yet. Handshakes aren't wired in to the rest of the peer code yet.

  • Property svn:keywords set to Date Rev Author Id
File size: 6.7 KB
Line 
1/*
2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.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:$
11 */
12
13#include <assert.h>
14#include <inttypes.h> /* uint8_t */
15#include <string.h> /* memcpy */
16#include <stdarg.h>
17
18#include <openssl/bn.h>
19#include <openssl/dh.h>
20#include <openssl/rc4.h>
21#include <openssl/sha.h>
22
23#include <event.h>
24#include "encryption.h"
25#include "utils.h"
26
27/**
28***
29**/
30
31void
32tr_sha1( uint8_t    * setme,
33         const void * content1,
34         int          content1_len,
35         ... )
36{
37    va_list vl;
38    SHA_CTX sha;
39
40    SHA1_Init( &sha );
41    SHA1_Update( &sha, content1, content1_len );
42
43    va_start( vl, content1_len );
44    for( ;; ) {
45        const void * content = (const void*) va_arg( vl, const void* );
46        const int content_len = content ? (int) va_arg( vl, int ) : -1;
47        if( content==NULL || content_len<1 )
48            break;
49        SHA1_Update( &sha, content, content_len );
50    }
51    SHA1_Final( setme, &sha );
52 
53
54}
55
56void
57tr_sha1_buf( struct evbuffer  * outbuf,
58             const void       * content1,
59             int                content1_len,
60             ... )
61{
62    uint8_t shabuf[SHA_DIGEST_LENGTH];
63    va_list vl;
64    SHA_CTX sha;
65
66    SHA1_Init( &sha );
67    SHA1_Update( &sha, content1, content1_len );
68
69    va_start( vl, content1_len );
70    for( ;; ) {
71        const void * content = (const void*) va_arg( vl, const void* );
72        const int content_len = content ? (int) va_arg( vl, int ) : -1;
73        if( content==NULL || content_len<1 )
74            break;
75        SHA1_Update( &sha, content, content_len );
76    }
77    SHA1_Final( shabuf, &sha );
78
79    evbuffer_add( outbuf, shabuf, SHA_DIGEST_LENGTH );
80}
81
82/**
83***
84**/
85
86#define KEY_LEN 96
87
88#define PRIME_LEN 96
89
90static const uint8_t dh_P[PRIME_LEN] =
91{
92    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
93    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
94    0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
95    0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
96    0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
97    0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
98    0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
99    0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63,
100};
101
102static const uint8_t dh_G[] = { 2 };
103
104struct tr_encryption
105{
106    DH * dh;
107    RC4_KEY dec_key;
108    RC4_KEY enc_key;
109    uint8_t torrentHash[SHA_DIGEST_LENGTH];
110    unsigned int isIncoming       : 1;
111    unsigned int torrentHashIsSet : 1;
112    unsigned int mySecretIsSet    : 1;
113    uint8_t myPublicKey[KEY_LEN];
114    uint8_t mySecret[KEY_LEN];
115
116};
117
118/**
119***
120**/
121
122tr_encryption * 
123tr_encryptionNew( const uint8_t * torrentHash,
124                  int             isIncoming )
125{
126    int len, offset;
127    tr_encryption * e;
128
129    e = tr_new0( tr_encryption, 1 );
130    e->isIncoming = isIncoming ? 1 : 0;
131    tr_encryptionSetTorrentHash( e, torrentHash );
132
133    e->dh = DH_new( );
134    e->dh->p = BN_bin2bn( dh_P, sizeof(dh_P), NULL );
135    e->dh->g = BN_bin2bn( dh_G, sizeof(dh_G), NULL );
136    DH_generate_key( e->dh );
137
138    // DH can generate key sizes that are smaller than the size of
139    // P with exponentially decreasing probability, in which case
140    // the msb's of myPublicKey need to be zeroed appropriately.
141    len = DH_size( e->dh );
142    offset = KEY_LEN - len;
143    assert( len <= KEY_LEN );
144    memset( e->myPublicKey, 0, offset );
145    BN_bn2bin( e->dh->pub_key, e->myPublicKey + offset );
146
147    return e;
148}
149
150void
151tr_encryptionFree( tr_encryption * e )
152{
153    assert( e != NULL );
154    assert( e->dh != NULL );
155
156    DH_free( e->dh );
157    tr_free( e );
158}
159
160/**
161***
162**/
163
164const uint8_t*
165tr_encryptionComputeSecret( tr_encryption * e,
166                            const uint8_t * peerPublicKey )
167{
168    int len, offset;
169    uint8_t secret[KEY_LEN];
170    BIGNUM * bn = BN_bin2bn( peerPublicKey, KEY_LEN, NULL );
171    assert( DH_size(e->dh) == KEY_LEN );
172
173    len = DH_compute_key( secret, bn, e->dh );
174    assert( len <= KEY_LEN );
175    offset = KEY_LEN - len;
176    memset( e->mySecret, 0, offset );
177    memcpy( e->mySecret + offset, secret, len );
178    e->mySecretIsSet = 1;
179   
180    BN_free( bn );
181
182    return e->mySecret;
183}
184
185const uint8_t*
186tr_encryptionGetMyPublicKey( const tr_encryption * e, int * setme_len )
187{
188    *setme_len = KEY_LEN;
189    return e->myPublicKey;
190}
191
192/**
193***
194**/
195
196static void
197initRC4( tr_encryption * e, RC4_KEY * setme, const char * key )
198{
199    SHA_CTX sha;
200    uint8_t buf[SHA_DIGEST_LENGTH];
201
202    assert( e->torrentHashIsSet );
203    assert( e->mySecretIsSet );
204
205    SHA1_Init( &sha );
206    SHA1_Update( &sha, key, 4 );
207    SHA1_Update( &sha, e->mySecret, KEY_LEN );
208    SHA1_Update( &sha, e->torrentHash, SHA_DIGEST_LENGTH );
209    SHA1_Final( buf, &sha );
210    RC4_set_key( setme, SHA_DIGEST_LENGTH, buf );
211}
212
213void
214tr_encryptionDecryptInit( tr_encryption * encryption )
215{
216    unsigned char discard[1024];
217    const char * txt = encryption->isIncoming ? "keyA" : "keyB";
218    initRC4( encryption, &encryption->dec_key, txt );
219    RC4( &encryption->dec_key, sizeof(discard), discard, discard );
220}
221
222void
223tr_encryptionDecrypt( tr_encryption * encryption,
224                      size_t          buf_len,
225                      const void    * buf_in,
226                      void          * buf_out )
227{
228    RC4( &encryption->dec_key, buf_len,
229         (const unsigned char*)buf_in,
230         (unsigned char*)buf_out );
231}
232
233void
234tr_encryptionEncryptInit( tr_encryption * encryption )
235{
236    unsigned char discard[1024];
237    const char * txt = encryption->isIncoming ? "keyB" : "keyA";
238    initRC4( encryption, &encryption->enc_key, txt );
239    RC4( &encryption->enc_key, sizeof(discard), discard, discard );
240}
241
242void
243tr_encryptionEncrypt( tr_encryption * encryption,
244                      size_t          buf_len,
245                      const void    * buf_in,
246                      void          * buf_out )
247{
248    RC4( &encryption->enc_key, buf_len,
249         (const unsigned char*)buf_in,
250         (unsigned char*)buf_out );
251}
252
253/**
254***
255**/
256
257void
258tr_encryptionSetTorrentHash( tr_encryption * e,
259                             const uint8_t * hash )
260{
261    e->torrentHashIsSet = hash ? 1 : 0;
262
263    if( hash != NULL )
264        memcpy( e->torrentHash, hash, SHA_DIGEST_LENGTH );
265    else
266        memset( e->torrentHash, 0, SHA_DIGEST_LENGTH );
267}
268
269const uint8_t*
270tr_encryptionGetTorrentHash( const tr_encryption * e )
271{
272    assert( e->torrentHashIsSet );
273
274    return e->torrentHash;
275}
Note: See TracBrowser for help on using the repository browser.