separate the configuration of crypto library and whether protocol encryption is enabled or not. make protocol encryption always use the built-in rc4 and tommath code. SHA-1 hashing is done by the crypto library

This commit is contained in:
Arvid Norberg 2014-12-29 16:50:22 +00:00
parent ae47823970
commit e9414894e2
6 changed files with 66 additions and 287 deletions

View File

@ -1,3 +1,7 @@
* separate crypto library configuration <crypto> and whether to support
bittorrent protocol encryption <encryption>
* simplify bittorrent protocol encryption by just using internal RC4
implementation.
* optimize copying torrent_info and file_storage objects
* cancel non-critical DNS lookups when shutting down, to cut down on
shutdown delay.

28
Jamfile
View File

@ -54,7 +54,7 @@ rule linking ( properties * )
local result ;
# openssl libraries, if enabled
if <encryption>openssl in $(properties)
if <crypto>openssl in $(properties)
{
# exclude gcc from a regular windows build to make mingw
# link against the regular unix library name
@ -94,7 +94,7 @@ rule linking ( properties * )
}
# gcrypt libraries, if enabled
if <encryption>gcrypt in $(properties)
if <crypto>gcrypt in $(properties)
{
# on mac os x, adding the /opt/local/include path
# would include openssl headers incompatible with
@ -254,27 +254,22 @@ rule building ( properties * )
result += <source>src/assert.cpp ;
}
if <encryption>openssl in $(properties)
if <crypto>openssl in $(properties)
{
result += <source>src/asio_ssl.cpp ;
}
if <encryption>tommath in $(properties)
if <encryption>on in $(properties)
{
result += <source>src/mpi.c ;
result += <source>src/pe_crypto.cpp ;
}
if <encryption>off in $(properties)
|| <encryption>tommath in $(properties)
if <crypo>built-in in $(properties)
{
result += <source>src/sha1.cpp ;
}
if ! <encryption>off in $(properties)
{
result += <source>src/pe_crypto.cpp ;
}
if ( <toolset>darwin in $(properties)
|| <toolset>gcc in $(properties)
|| <toolset>clang in $(propertoes)
@ -406,12 +401,13 @@ feature dht : on off logging : composite propagated link-incompatible ;
feature.compose <dht>off : <define>TORRENT_DISABLE_DHT ;
feature.compose <dht>logging : <define>TORRENT_DHT_VERBOSE_LOGGING ;
feature encryption : tommath off openssl gcrypt : composite propagated link-incompatible ;
feature.compose <encryption>openssl : <define>TORRENT_USE_OPENSSL ;
feature.compose <encryption>gcrypt : <define>TORRENT_USE_GCRYPT ;
feature.compose <encryption>tommath : <define>TORRENT_USE_TOMMATH ;
feature encryption : on off : composite propagated link-incompatible ;
feature.compose <encryption>off : <define>TORRENT_DISABLE_ENCRYPTION ;
feature crypto : built-in openssl gcrypt : composite ;
feature.compose <crypto>openssl : <define>TORRENT_USE_OPENSSL ;
feature.compose <crypto>gcrypt : <define>TORRENT_USE_GCRYPT ;
feature resolve-countries : on off : composite propagated link-incompatible ;
feature.compose <resolve-countries>off : <define>TORRENT_DISABLE_RESOLVE_COUNTRIES ;
@ -453,7 +449,7 @@ variant test_release
<export-extra>on <debug-iterators>on <boost>source <threading>multi
;
variant test_debug : debug
: <encryption>openssl <logging>on <disk-stats>on
: <crypto>openssl <logging>on <disk-stats>on
<dht>logging <request-log>on <allocator>debug <debug-iterators>on
<invariant-checks>full <boost-link>shared
<export-extra>on <debug-iterators>on <boost>source <threading>multi

View File

@ -283,19 +283,19 @@ Build features:
| | * ``on`` - creates "upnp.log" with the messages |
| | sent to and received from UPnP devices. |
+--------------------------+----------------------------------------------------+
| ``encryption`` | * ``openssl`` - links against openssl and |
| | libcrypto to enable https and encrypted |
| | bittorrent connections. |
| | * ``gcrypt`` - links against libgcrypt to enable |
| | encrypted bittorrent connections. |
| | * ``tommath`` - uses a shipped version of |
| | libtommath and a custom rc4 implementation |
| | (based on libtomcrypt). This is the default |
| | option. |
| ``encryption`` | * ``on`` - encrypted bittorrent connections |
| | enabled. (Message Stream encryption). |
| | * ``off`` - turns off support for encrypted |
| | connections. The shipped public domain SHA-1 |
| | implementation is used. |
+--------------------------+----------------------------------------------------+
| ``crypto`` | * ``built-in`` - (default) uses built-in SHA-1 |
| | implementation. |
| | * ``openssl`` - links against openssl and |
| | libcrypto to use for SHA-1 hashing. |
| | * ``gcrypt`` - links against libgcrypt to use for |
| | SHA-1 hashing. |
+--------------------------+----------------------------------------------------+
| ``allocator`` | * ``pool`` - default, uses pool allocators for |
| | send buffers. |
| | * ``system`` - uses ``malloc()`` and ``free()`` |

View File

@ -162,7 +162,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_USE_PURGABLE_CONTROL 1
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
# ifdef TORRENT_USE_OPENSSL
// on OSX, use the built-in common crypto for built-in
# if !defined TORRENT_USE_OPENSSL && !defined TORRENT_USE_GCRYPT
# define TORRENT_USE_COMMONCRYPTO 1
# endif // TORRENT_USE_OPENSSL
#endif // MAC_OS_X_VERSION_MIN_REQUIRED

View File

@ -37,11 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp"
#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
int x, y;
@ -50,7 +45,6 @@ struct rc4 {
void TORRENT_EXTRA_EXPORT rc4_init(const unsigned char* in, unsigned long len, rc4 *state);
unsigned long TORRENT_EXTRA_EXPORT rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state);
#endif
#include <boost/asio/buffer.hpp>
#include <list>
@ -131,24 +125,11 @@ namespace libtorrent
rc4_handler()
: m_encrypt(false)
, m_decrypt(false)
{
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
#endif
};
{}
void set_incoming_key(unsigned char const* key, int len);
void set_outgoing_key(unsigned char const* key, int len);
~rc4_handler()
{
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_close(m_rc4_incoming);
gcry_cipher_close(m_rc4_outgoing);
#endif
};
int encrypt(std::vector<boost::asio::mutable_buffer>& buf);
void decrypt(std::vector<boost::asio::mutable_buffer>& buf
, int& consume
@ -156,16 +137,9 @@ namespace libtorrent
, int& packet_size);
private:
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_hd_t m_rc4_incoming;
gcry_cipher_hd_t m_rc4_outgoing;
#elif defined TORRENT_USE_OPENSSL
RC4_KEY m_local_key; // Key to encrypt outgoing data
RC4_KEY m_remote_key; // Key to decrypt incoming data
#else
rc4 m_rc4_incoming;
rc4 m_rc4_outgoing;
#endif
// determines whether or not encryption and decryption is enabled
bool m_encrypt;
bool m_decrypt;

View File

@ -35,18 +35,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/cstdint.hpp>
#include <algorithm>
#if defined TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/bn.h>
#include "libtorrent/random.hpp"
#elif defined TORRENT_USE_TOMMATH
extern "C" {
#include "libtorrent/tommath.h"
}
#include "libtorrent/random.hpp"
#endif
#include "libtorrent/random.hpp"
#include "libtorrent/pe_crypto.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp"
@ -67,238 +60,81 @@ namespace libtorrent
};
}
struct mp_bigint
{
mp_bigint()
{ mp_init(&v); }
mp_int* operator&() { return &v; }
~mp_bigint() { mp_clear(&v); }
private:
// non-copyable
mp_bigint(mp_bigint const&);
mp_bigint const& operator=(mp_bigint const&);
mp_int v;
};
// Set the prime P and the generator, generate local public key
dh_key_exchange::dh_key_exchange()
{
#ifdef TORRENT_USE_GCRYPT
// create local key
gcry_randomize(m_dh_local_secret, sizeof(m_dh_local_secret), GCRY_STRONG_RANDOM);
// build gcrypt big ints from the prime and the secret
gcry_mpi_t prime = 0;
gcry_mpi_t secret = 0;
gcry_mpi_t key = 0;
gcry_error_t e;
e = gcry_mpi_scan(&prime, GCRYMPI_FMT_USG, dh_prime, sizeof(dh_prime), 0);
if (e) goto get_out;
e = gcry_mpi_scan(&secret, GCRYMPI_FMT_USG, m_dh_local_secret, sizeof(m_dh_local_secret), 0);
if (e) goto get_out;
key = gcry_mpi_new(8);
// generator is 2
gcry_mpi_set_ui(key, 2);
// key = (2 ^ secret) % prime
gcry_mpi_powm(key, key, secret, prime);
// key is now our local key
size_t written;
gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*)m_dh_local_key
, sizeof(m_dh_local_key), &written, key);
if (written < 96)
{
memmove(m_dh_local_key + (sizeof(m_dh_local_key) - written), m_dh_local_key, written);
memset(m_dh_local_key, 0, sizeof(m_dh_local_key) - written);
}
get_out:
if (key) gcry_mpi_release(key);
if (prime) gcry_mpi_release(prime);
if (secret) gcry_mpi_release(secret);
#elif defined TORRENT_USE_OPENSSL
// create local key
for (int i = 0; i < sizeof(m_dh_local_secret); ++i)
m_dh_local_secret[i] = random() & 0xff;
BIGNUM* prime = 0;
BIGNUM* secret = 0;
BIGNUM* key = 0;
BN_CTX* ctx = 0;
int size;
prime = BN_bin2bn(dh_prime, sizeof(dh_prime), 0);
if (prime == 0) goto get_out;
secret = BN_bin2bn((unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret), 0);
if (secret == 0) goto get_out;
key = BN_new();
if (key == 0) goto get_out;
// generator is 2
BN_set_word(key, 2);
ctx = BN_CTX_new();
if (ctx == 0) goto get_out;
BN_mod_exp(key, key, secret, prime, ctx);
BN_CTX_free(ctx);
// print key to m_dh_local_key
size = BN_num_bytes(key);
memset(m_dh_local_key, 0, sizeof(m_dh_local_key) - size);
BN_bn2bin(key, (unsigned char*)m_dh_local_key + sizeof(m_dh_local_key) - size);
get_out:
if (key) BN_free(key);
if (secret) BN_free(secret);
if (prime) BN_free(prime);
#elif defined TORRENT_USE_TOMMATH
// create local key
for (int i = 0; i < int(sizeof(m_dh_local_secret)); ++i)
m_dh_local_secret[i] = random() & 0xff;
mp_int prime;
mp_int secret;
mp_int key;
int e;
int size;
mp_bigint prime;
mp_bigint secret;
mp_bigint key;
mp_init(&prime);
mp_init(&secret);
mp_init(&key);
e = mp_read_unsigned_bin(&prime, dh_prime, sizeof(dh_prime));
if (e) goto get_out;
e = mp_read_unsigned_bin(&secret, (unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret));
if (e) goto get_out;
if (mp_read_unsigned_bin(&prime, dh_prime, sizeof(dh_prime)))
return;
if (mp_read_unsigned_bin(&secret, (unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret)))
return;
// generator is 2
mp_set_int(&key, 2);
// key = (2 ^ secret) % prime
e = mp_exptmod(&key, &secret, &prime, &key);
if (e) goto get_out;
if (mp_exptmod(&key, &secret, &prime, &key))
return;
// key is now our local key
size = mp_unsigned_bin_size(&key);
int size = mp_unsigned_bin_size(&key);
memset(m_dh_local_key, 0, sizeof(m_dh_local_key) - size);
mp_to_unsigned_bin(&key, (unsigned char*)m_dh_local_key + sizeof(m_dh_local_key) - size);
get_out:
mp_clear(&key);
mp_clear(&prime);
mp_clear(&secret);
#else
#error you must define which bigint library to use
#endif
}
char const* dh_key_exchange::get_local_key() const
{
return m_dh_local_key;
}
}
// compute shared secret given remote public key
int dh_key_exchange::compute_secret(char const* remote_pubkey)
{
TORRENT_ASSERT(remote_pubkey);
int ret = 0;
#ifdef TORRENT_USE_GCRYPT
mp_bigint prime;
mp_bigint secret;
mp_bigint remote_key;
gcry_mpi_t prime = 0;
gcry_mpi_t remote_key = 0;
gcry_mpi_t secret = 0;
size_t written;
gcry_error_t e;
if (mp_read_unsigned_bin(&prime, dh_prime, sizeof(dh_prime)))
return -1;
if (mp_read_unsigned_bin(&secret, (unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret)))
return -1;
if (mp_read_unsigned_bin(&remote_key, (unsigned char*)remote_pubkey, 96))
return -1;
e = gcry_mpi_scan(&prime, GCRYMPI_FMT_USG, dh_prime, sizeof(dh_prime), 0);
if (e != 0) { ret = 1; goto get_out; }
e = gcry_mpi_scan(&remote_key, GCRYMPI_FMT_USG, remote_pubkey, 96, 0);
if (e != 0) { ret = 1; goto get_out; }
e = gcry_mpi_scan(&secret, GCRYMPI_FMT_USG, (unsigned char const*)m_dh_local_secret
, sizeof(m_dh_local_secret), 0);
if (e != 0) { ret = 1; goto get_out; }
gcry_mpi_powm(remote_key, remote_key, secret, prime);
if (mp_exptmod(&remote_key, &secret, &prime, &remote_key))
return -1;
// remote_key is now the shared secret
e = gcry_mpi_print(GCRYMPI_FMT_USG, (unsigned char*)m_dh_shared_secret
, sizeof(m_dh_shared_secret), &written, remote_key);
if (e != 0) { ret = 1; goto get_out; }
if (written < 96)
{
memmove(m_dh_shared_secret, m_dh_shared_secret
+ (sizeof(m_dh_shared_secret) - written), written);
memset(m_dh_shared_secret, 0, sizeof(m_dh_shared_secret) - written);
}
get_out:
// TODO: 3 clean this up using destructors instead
if (prime) gcry_mpi_release(prime);
if (remote_key) gcry_mpi_release(remote_key);
if (secret) gcry_mpi_release(secret);
#elif defined TORRENT_USE_OPENSSL
BIGNUM* prime = 0;
BIGNUM* secret = 0;
BIGNUM* remote_key = 0;
BN_CTX* ctx = 0;
int size;
prime = BN_bin2bn(dh_prime, sizeof(dh_prime), 0);
if (prime == 0) { ret = 1; goto get_out; }
secret = BN_bin2bn((unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret), 0);
if (secret == 0) { ret = 1; goto get_out; }
remote_key = BN_bin2bn((unsigned char*)remote_pubkey, 96, 0);
if (remote_key == 0) { ret = 1; goto get_out; }
ctx = BN_CTX_new();
if (ctx == 0) { ret = 1; goto get_out; }
BN_mod_exp(remote_key, remote_key, secret, prime, ctx);
BN_CTX_free(ctx);
// remote_key is now the shared secret
size = BN_num_bytes(remote_key);
memset(m_dh_shared_secret, 0, sizeof(m_dh_shared_secret) - size);
BN_bn2bin(remote_key, (unsigned char*)m_dh_shared_secret + sizeof(m_dh_shared_secret) - size);
get_out:
BN_free(remote_key);
BN_free(secret);
BN_free(prime);
#elif defined TORRENT_USE_TOMMATH
mp_int prime;
mp_int secret;
mp_int remote_key;
int size;
int e;
mp_init(&prime);
mp_init(&secret);
mp_init(&remote_key);
e = mp_read_unsigned_bin(&prime, dh_prime, sizeof(dh_prime));
if (e) { ret = 1; goto get_out; }
e = mp_read_unsigned_bin(&secret, (unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret));
if (e) { ret = 1; goto get_out; }
e = mp_read_unsigned_bin(&remote_key, (unsigned char*)remote_pubkey, 96);
if (e) { ret = 1; goto get_out; }
e = mp_exptmod(&remote_key, &secret, &prime, &remote_key);
if (e) goto get_out;
// remote_key is now the shared secret
size = mp_unsigned_bin_size(&remote_key);
int size = mp_unsigned_bin_size(&remote_key);
memset(m_dh_shared_secret, 0, sizeof(m_dh_shared_secret) - size);
mp_to_unsigned_bin(&remote_key, (unsigned char*)m_dh_shared_secret + sizeof(m_dh_shared_secret) - size);
get_out:
mp_clear(&remote_key);
mp_clear(&secret);
mp_clear(&prime);
#else
#error you must define which bigint library to use
#endif
// calculate the xor mask for the obfuscated hash
hasher h;
h.update("req3", 4);
h.update(m_dh_shared_secret, sizeof(m_dh_shared_secret));
m_xor_mask = h.final();
return ret;
return 0;
}
int encryption_handler::encrypt(std::vector<asio::mutable_buffer>& iovec)
@ -431,15 +267,7 @@ get_out:
void rc4_handler::set_incoming_key(unsigned char const* key, int len)
{
m_decrypt = true;
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_close(m_rc4_incoming);
gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
gcry_cipher_setkey(m_rc4_incoming, key, len);
#elif defined TORRENT_USE_OPENSSL
RC4_set_key(&m_remote_key, len, key);
#else
rc4_init(key, len, &m_rc4_incoming);
#endif
// Discard first 1024 bytes
char buf[1024];
std::vector<boost::asio::mutable_buffer> vec(1, boost::asio::mutable_buffer(buf, 1024));
@ -452,15 +280,7 @@ get_out:
void rc4_handler::set_outgoing_key(unsigned char const* key, int len)
{
m_encrypt = true;
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_close(m_rc4_outgoing);
gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
gcry_cipher_setkey(m_rc4_outgoing, key, len);
#elif defined TORRENT_USE_OPENSSL
RC4_set_key(&m_local_key, len, key);
#else
rc4_init(key, len, &m_rc4_outgoing);
#endif
// Discard first 1024 bytes
char buf[1024];
std::vector<boost::asio::mutable_buffer> vec(1, boost::asio::mutable_buffer(buf, 1024));
@ -483,13 +303,7 @@ get_out:
TORRENT_ASSERT(pos);
bytes_processed += len;
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_encrypt(m_rc4_outgoing, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
RC4(&m_local_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
rc4_encrypt((unsigned char*)pos, len, &m_rc4_outgoing);
#endif
}
buf.clear();
return bytes_processed;
@ -513,13 +327,7 @@ get_out:
TORRENT_ASSERT(pos);
bytes_processed += len;
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_decrypt(m_rc4_incoming, pos, len, 0, 0);
#elif defined TORRENT_USE_OPENSSL
RC4(&m_remote_key, len, (const unsigned char*)pos, (unsigned char*)pos);
#else
rc4_encrypt((unsigned char*)pos, len, &m_rc4_incoming);
#endif
}
buf.clear();
produce = bytes_processed;
@ -527,8 +335,6 @@ get_out:
} // namespace libtorrent
#if !defined TORRENT_USE_OPENSSL && !defined TORRENT_USE_GCRYPT
// All this code is based on libTomCrypt (http://www.libtomcrypt.com/)
// this library is public domain and has been specially
// tailored for libtorrent by Arvid Norberg
@ -591,7 +397,5 @@ unsigned long rc4_encrypt(unsigned char *out, unsigned long outlen, rc4 *state)
return n;
}
#endif
#endif // #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)