source: branches/encryption/libtransmission/crypto.c @ 2938

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

make things a little less prolix - s/tr_encryption/tr_crypto/

  • Property svn:keywords set to Date Rev Author Id
File size: 6.0 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: crypto.c 2938 2007-08-29 12:24:34Z charles $
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 "crypto.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***
56**/
57
58#define KEY_LEN 96
59
60#define PRIME_LEN 96
61
62static const uint8_t dh_P[PRIME_LEN] =
63{
64    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
65    0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
66    0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
67    0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
68    0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
69    0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
70    0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
71    0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63,
72};
73
74static const uint8_t dh_G[] = { 2 };
75
76struct tr_crypto
77{
78    DH * dh;
79    RC4_KEY dec_key;
80    RC4_KEY enc_key;
81    uint8_t torrentHash[SHA_DIGEST_LENGTH];
82    unsigned int isIncoming       : 1;
83    unsigned int torrentHashIsSet : 1;
84    unsigned int mySecretIsSet    : 1;
85    uint8_t myPublicKey[KEY_LEN];
86    uint8_t mySecret[KEY_LEN];
87
88};
89
90/**
91***
92**/
93
94tr_crypto * 
95tr_cryptoNew( const uint8_t * torrentHash,
96              int             isIncoming )
97{
98    int len, offset;
99    tr_crypto * crypto;
100
101    crypto = tr_new0( tr_crypto, 1 );
102    crypto->isIncoming = isIncoming ? 1 : 0;
103    tr_cryptoSetTorrentHash( crypto, torrentHash );
104
105    crypto->dh = DH_new( );
106    crypto->dh->p = BN_bin2bn( dh_P, sizeof(dh_P), NULL );
107    crypto->dh->g = BN_bin2bn( dh_G, sizeof(dh_G), NULL );
108    DH_generate_key( crypto->dh );
109
110    // DH can generate key sizes that are smaller than the size of
111    // P with exponentially decreasing probability, in which case
112    // the msb's of myPublicKey need to be zeroed appropriately.
113    len = DH_size( crypto->dh );
114    offset = KEY_LEN - len;
115    assert( len <= KEY_LEN );
116    memset( crypto->myPublicKey, 0, offset );
117    BN_bn2bin( crypto->dh->pub_key, crypto->myPublicKey + offset );
118
119    return crypto;
120}
121
122void
123tr_cryptoFree( tr_crypto * crypto )
124{
125    assert( crypto != NULL );
126    assert( crypto->dh != NULL );
127
128    DH_free( crypto->dh );
129    tr_free( crypto );
130}
131
132/**
133***
134**/
135
136const uint8_t*
137tr_cryptoComputeSecret( tr_crypto      * crypto,
138                        const uint8_t  * peerPublicKey )
139{
140    int len, offset;
141    uint8_t secret[KEY_LEN];
142    BIGNUM * bn = BN_bin2bn( peerPublicKey, KEY_LEN, NULL );
143    assert( DH_size(crypto->dh) == KEY_LEN );
144
145    len = DH_compute_key( secret, bn, crypto->dh );
146    assert( len <= KEY_LEN );
147    offset = KEY_LEN - len;
148    memset( crypto->mySecret, 0, offset );
149    memcpy( crypto->mySecret + offset, secret, len );
150    crypto->mySecretIsSet = 1;
151   
152    BN_free( bn );
153
154    return crypto->mySecret;
155}
156
157const uint8_t*
158tr_cryptoGetMyPublicKey( const tr_crypto * crypto, int * setme_len )
159{
160    *setme_len = KEY_LEN;
161    return crypto->myPublicKey;
162}
163
164/**
165***
166**/
167
168static void
169initRC4( tr_crypto * crypto, RC4_KEY * setme, const char * key )
170{
171    SHA_CTX sha;
172    uint8_t buf[SHA_DIGEST_LENGTH];
173
174    assert( crypto->torrentHashIsSet );
175    assert( crypto->mySecretIsSet );
176
177    SHA1_Init( &sha );
178    SHA1_Update( &sha, key, 4 );
179    SHA1_Update( &sha, crypto->mySecret, KEY_LEN );
180    SHA1_Update( &sha, crypto->torrentHash, SHA_DIGEST_LENGTH );
181    SHA1_Final( buf, &sha );
182    RC4_set_key( setme, SHA_DIGEST_LENGTH, buf );
183}
184
185void
186tr_cryptoDecryptInit( tr_crypto * crypto )
187{
188    unsigned char discard[1024];
189    const char * txt = crypto->isIncoming ? "keyA" : "keyB";
190    initRC4( crypto, &crypto->dec_key, txt );
191    RC4( &crypto->dec_key, sizeof(discard), discard, discard );
192}
193
194void
195tr_cryptoDecrypt( tr_crypto  * crypto,
196                  size_t       buf_len,
197                  const void * buf_in,
198                  void       * buf_out )
199{
200    RC4( &crypto->dec_key, buf_len,
201         (const unsigned char*)buf_in,
202         (unsigned char*)buf_out );
203}
204
205void
206tr_cryptoEncryptInit( tr_crypto * crypto )
207{
208    unsigned char discard[1024];
209    const char * txt = crypto->isIncoming ? "keyB" : "keyA";
210    initRC4( crypto, &crypto->enc_key, txt );
211    RC4( &crypto->enc_key, sizeof(discard), discard, discard );
212}
213
214void
215tr_cryptoEncrypt( tr_crypto  * crypto,
216                  size_t       buf_len,
217                  const void * buf_in,
218                  void       * buf_out )
219{
220    RC4( &crypto->enc_key, buf_len,
221         (const unsigned char*)buf_in,
222         (unsigned char*)buf_out );
223}
224
225/**
226***
227**/
228
229void
230tr_cryptoSetTorrentHash( tr_crypto     * crypto,
231                         const uint8_t * hash )
232{
233    crypto->torrentHashIsSet = hash ? 1 : 0;
234
235    if( hash != NULL )
236        memcpy( crypto->torrentHash, hash, SHA_DIGEST_LENGTH );
237    else
238        memset( crypto->torrentHash, 0, SHA_DIGEST_LENGTH );
239}
240
241const uint8_t*
242tr_cryptoGetTorrentHash( const tr_crypto * crypto )
243{
244    assert( crypto->torrentHashIsSet );
245
246    return crypto->torrentHash;
247}
Note: See TracBrowser for help on using the repository browser.