From e9414894e22f6c0d62dd2cf4bbd09df59e23c1a0 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 29 Dec 2014 16:50:22 +0000 Subject: [PATCH] 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 --- ChangeLog | 4 + Jamfile | 28 ++-- docs/building.rst | 18 +-- include/libtorrent/config.hpp | 3 +- include/libtorrent/pe_crypto.hpp | 30 +--- src/pe_crypto.cpp | 270 +++++-------------------------- 6 files changed, 66 insertions(+), 287 deletions(-) diff --git a/ChangeLog b/ChangeLog index 82a084e64..4de5eb629 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ + * separate crypto library configuration and whether to support + bittorrent protocol 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. diff --git a/Jamfile b/Jamfile index acbe6d105..5e7dc5064 100755 --- a/Jamfile +++ b/Jamfile @@ -54,7 +54,7 @@ rule linking ( properties * ) local result ; # openssl libraries, if enabled - if openssl in $(properties) + if 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 gcrypt in $(properties) + if 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 += src/assert.cpp ; } - if openssl in $(properties) + if openssl in $(properties) { result += src/asio_ssl.cpp ; } - if tommath in $(properties) + if on in $(properties) { result += src/mpi.c ; + result += src/pe_crypto.cpp ; } - if off in $(properties) - || tommath in $(properties) + if built-in in $(properties) { result += src/sha1.cpp ; } - if ! off in $(properties) - { - result += src/pe_crypto.cpp ; - } - if ( darwin in $(properties) || gcc in $(properties) || clang in $(propertoes) @@ -406,12 +401,13 @@ feature dht : on off logging : composite propagated link-incompatible ; feature.compose off : TORRENT_DISABLE_DHT ; feature.compose logging : TORRENT_DHT_VERBOSE_LOGGING ; -feature encryption : tommath off openssl gcrypt : composite propagated link-incompatible ; -feature.compose openssl : TORRENT_USE_OPENSSL ; -feature.compose gcrypt : TORRENT_USE_GCRYPT ; -feature.compose tommath : TORRENT_USE_TOMMATH ; +feature encryption : on off : composite propagated link-incompatible ; feature.compose off : TORRENT_DISABLE_ENCRYPTION ; +feature crypto : built-in openssl gcrypt : composite ; +feature.compose openssl : TORRENT_USE_OPENSSL ; +feature.compose gcrypt : TORRENT_USE_GCRYPT ; + feature resolve-countries : on off : composite propagated link-incompatible ; feature.compose off : TORRENT_DISABLE_RESOLVE_COUNTRIES ; @@ -453,7 +449,7 @@ variant test_release on on source multi ; variant test_debug : debug - : openssl on on + : openssl on on logging on debug on full shared on on source multi diff --git a/docs/building.rst b/docs/building.rst index 83d13bfb8..293a7e91b 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -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()`` | diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index 054825a1c..842a5643a 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -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 diff --git a/include/libtorrent/pe_crypto.hpp b/include/libtorrent/pe_crypto.hpp index b9163b757..057cb34f7 100644 --- a/include/libtorrent/pe_crypto.hpp +++ b/include/libtorrent/pe_crypto.hpp @@ -37,11 +37,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" -#ifdef TORRENT_USE_GCRYPT -#include -#elif defined TORRENT_USE_OPENSSL -#include -#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 #include @@ -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& buf); void decrypt(std::vector& 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; diff --git a/src/pe_crypto.cpp b/src/pe_crypto.cpp index a12af2f6b..8be82f8b4 100644 --- a/src/pe_crypto.cpp +++ b/src/pe_crypto.cpp @@ -35,18 +35,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#if defined TORRENT_USE_GCRYPT -#include -#elif defined TORRENT_USE_OPENSSL -#include -#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& 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 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 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)