added support for libgcrypt

This commit is contained in:
Arvid Norberg 2009-11-08 03:09:19 +00:00
parent e86ad4f0f7
commit e9e32235b4
7 changed files with 308 additions and 128 deletions

32
Jamfile
View File

@ -29,8 +29,7 @@ rule linking ( properties * )
local result ;
# openssl libraries, if enabled
if <openssl>sha-1 in $(properties)
|| <openssl>pe in $(properties)
if <encryption>openssl in $(properties)
{
# exclude gcc from a regular windows build to make mingw
# link against the regular unix library name
@ -55,6 +54,17 @@ rule linking ( properties * )
}
}
# gcrypt libraries, if enabled
if <encryption>gcrypt in $(properties)
{
# on mac os x, adding the /opt/local/include path
# would include openssl headers incompatible with
# the system library. Only add this include path
# if we're not using openssl (which we're most
# likely not if we're using libgcrypt)
result += <library>gcrypt <include>/opt/local/include ;
}
if <geoip>shared in $(properties)
{
result += <library>GeoIP ;
@ -161,16 +171,13 @@ rule building ( properties * )
result += <source>src/GeoIP.c ;
}
if <openssl>off in $(properties)
if <encryption>off in $(properties)
{
result += <source>src/sha1.cpp ;
}
else
{
if <openssl>pe in $(properties)
{
result += <source>src/pe_crypto.cpp ;
}
result += <source>src/pe_crypto.cpp ;
if <target-os>linux in $(properties)
{
@ -228,10 +235,10 @@ feature dht-support : on off logging : composite propagated link-incompatible ;
feature.compose <dht-support>off : <define>TORRENT_DISABLE_DHT ;
feature.compose <dht-support>logging : <define>TORRENT_DHT_VERBOSE_LOGGING ;
feature openssl : pe sha-1 off : composite propagated link-incompatible ;
feature.compose <openssl>pe : <define>TORRENT_USE_OPENSSL ;
feature.compose <openssl>sha-1 : <define>TORRENT_USE_OPENSSL <define>TORRENT_DISABLE_ENCRYPTION ;
feature.compose <openssl>off : <define>TORRENT_DISABLE_ENCRYPTION ;
feature encryption : 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>off : <define>TORRENT_DISABLE_ENCRYPTION ;
feature resolve-countries : on off : composite propagated link-incompatible ;
feature.compose <resolve-countries>off : <define>TORRENT_DISABLE_RESOLVE_COUNTRIES ;
@ -285,8 +292,9 @@ lib boost_system : : <target-os>darwin <name>boost_system-mt $(boost-library-sea
lib boost_system : : <name>boost_system ;
# openssl on linux/bsd/macos etc.
lib gcrypt : : <name>gcrypt <link>shared <search>/opt/local/lib ;
lib crypto : : <name>crypto <link>shared ;
lib ssl : : <name>ssl <link>shared ;
lib ssl : : <name>ssl <link>shared <use>crypto ;
# time functions used on linux require librt
lib librt : : <name>rt <link>shared ;

View File

@ -287,16 +287,14 @@ Build features:
| | * ``on`` - creates "upnp.log" with the messages |
| | sent to and received from UPnP devices. |
+--------------------------+----------------------------------------------------+
| ``openssl`` | * ``pe`` - turns on support for encrypted |
| | connections. requires openssl (libcrypto) |
| | * ``sha-1`` - openssl will be used instead of the |
| | public domain SHA-1 implementation shipped with |
| | libtorrent. ``libcrypto.a`` will be required for |
| | linking. Encryption support is still turned off. |
| ``encryption`` | * ``openssl`` - links against openssl and |
| | libcrypto to enable https and encrypted |
| | bittorrent connections. |
| | * ``gcrypt`` - links against libgcrypt to enable |
| | encrypted bittorrent connections. |
| | * ``off`` - turns off support for encrypted |
| | connections. openssl is not linked in. The |
| | shipped public domain SHA-1 implementation is |
| | used. |
| | connections. The shipped public domain SHA-1 |
| | implementation is used. |
+--------------------------+----------------------------------------------------+
| ``pool-allocators`` | * ``on`` - default, uses pool allocators for send |
| | buffers. |
@ -573,15 +571,6 @@ defines you can use to control the build.
| | UTF-16 before they are passed to the file |
| | operations. |
+----------------------------------------+-------------------------------------------------+
| ``LITTLE_ENDIAN`` | This will use the little endian version of the |
| | sha-1 code. If defined on a big-endian system |
| | the sha-1 hashes will be incorrect and fail. |
| | If it is not defined and ``__BIG_ENDIAN__`` |
| | isn't defined either (it is defined by Apple's |
| | GCC) both little-endian and big-endian versions |
| | will be built and the correct code will be |
| | chosen at run-time. |
+----------------------------------------+-------------------------------------------------+
| ``TORRENT_DISABLE_POOL_ALLOCATOR`` | Disables use of ``boost::pool<>``. |
+----------------------------------------+-------------------------------------------------+
| ``TORRENT_LINKING_SHARED`` | If this is defined when including the |
@ -608,10 +597,13 @@ defines you can use to control the build.
| | protocol traffic. |
+----------------------------------------+-------------------------------------------------+
| ``TORRENT_DISABLE_ENCRYPTION`` | This will disable any encryption support and |
| | the openssl dependency that comes with it. |
| | the dependencies of a crypto library. |
| | Encryption support is the peer connection |
| | encrypted supported by clients such as |
| | uTorrent, Azureus and KTorrent. |
| | If this is not defined, either |
| | ``TORRENT_USE_OPENSSL`` or |
| | ``TORRENT_USE_GCRYPT`` must be defined. |
+----------------------------------------+-------------------------------------------------+
| ``_UNICODE`` | On windows, this will cause the file IO |
| | use wide character API, to properly support |

View File

@ -33,6 +33,12 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_CONFIG_HPP_INCLUDED
#define TORRENT_CONFIG_HPP_INCLUDED
#if !defined TORRENT_USE_OPENSSL \
&& !defined TORRENT_USE_GCRYPT \
&& !defined TORRENT_DISABLE_ENCRYPTION
#error you need to either disable encryption or specify which library to use
#endif
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <stdio.h> // for snprintf

View File

@ -40,7 +40,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp"
#include "zlib.h"
#ifdef TORRENT_USE_OPENSSL
#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
extern "C"
{
#include <openssl/sha.h>
@ -87,35 +89,88 @@ namespace libtorrent
{
public:
hasher() { SHA1_Init(&m_context); }
hasher()
{
#ifdef TORRENT_USE_GCRYPT
gcry_md_open(&m_context, GCRY_MD_SHA1, 0);
#else
SHA1_Init(&m_context);
#endif
}
hasher(const char* data, int len)
{
SHA1_Init(&m_context);
TORRENT_ASSERT(data != 0);
TORRENT_ASSERT(len > 0);
#ifdef TORRENT_USE_GCRYPT
gcry_md_open(&m_context, GCRY_MD_SHA1, 0);
gcry_md_write(m_context, data, len);
#else
SHA1_Init(&m_context);
SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
#endif
}
#ifdef TORRENT_USE_GCRYPT
hasher(hasher const& h)
{
gcry_md_copy(&m_context, h.m_context);
}
hasher& operator=(hasher const& h)
{
gcry_md_close(m_context);
gcry_md_copy(&m_context, h.m_context);
return *this;
}
#endif
void update(std::string const& data) { update(&data[0], data.size()); }
void update(const char* data, int len)
{
TORRENT_ASSERT(data != 0);
TORRENT_ASSERT(len > 0);
#ifdef TORRENT_USE_GCRYPT
gcry_md_write(m_context, data, len);
#else
SHA1_Update(&m_context, reinterpret_cast<unsigned char const*>(data), len);
#endif
}
sha1_hash final()
{
sha1_hash digest;
#ifdef TORRENT_USE_GCRYPT
gcry_md_final(m_context);
digest.assign((const char*)gcry_md_read(m_context, 0));
#else
SHA1_Final(digest.begin(), &m_context);
#endif
return digest;
}
void reset() { SHA1_Init(&m_context); }
void reset()
{
#ifdef TORRENT_USE_GCRYPT
gcry_md_reset(m_context);
#else
SHA1_Init(&m_context);
#endif
}
#ifdef TORRENT_USE_GCRYPT
~hasher()
{
gcry_md_close(m_context);
}
#endif
private:
#ifdef TORRENT_USE_GCRYPT
gcry_md_hd_t m_context;
#else
SHA_CTX m_context;
#endif
};
}

View File

@ -35,9 +35,13 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED
#define TORRENT_PE_CRYPTO_HPP_INCLUDED
#include <openssl/dh.h>
#include <openssl/engine.h>
#ifdef TORRENT_USE_GCRYPT
#include <gcrypt.h>
#endif
#ifdef TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#endif
#include "libtorrent/peer_id.hpp" // For sha1_hash
#include "libtorrent/assert.hpp"
@ -48,31 +52,27 @@ namespace libtorrent
{
public:
dh_key_exchange();
~dh_key_exchange();
bool good() const { return m_dh; }
bool good() const { return true; }
// Get local public key, always 96 bytes
char const* get_local_key() const;
// read remote_pubkey, generate and store shared secret in
// m_dh_secret.
// m_dh_shared_secret.
int compute_secret(const char* remote_pubkey);
char const* get_secret() const { return m_dh_secret; }
char const* get_secret() const { return m_dh_shared_secret; }
sha1_hash const& get_hash_xor_mask() const { return m_xor_mask; }
private:
int get_local_key_size() const
{
TORRENT_ASSERT(m_dh);
return BN_num_bytes(m_dh->pub_key);
}
DH* m_dh;
int get_local_key_size() const
{ return sizeof(m_dh_local_key); }
char m_dh_local_key[96];
char m_dh_secret[96];
char m_dh_local_secret[96];
char m_dh_shared_secret[96];
sha1_hash m_xor_mask;
};
@ -80,13 +80,18 @@ namespace libtorrent
{
public:
// Input longkeys must be 20 bytes
RC4_handler(const sha1_hash& rc4_local_longkey,
const sha1_hash& rc4_remote_longkey)
RC4_handler(sha1_hash const& rc4_local_longkey,
sha1_hash const& rc4_remote_longkey)
{
RC4_set_key(&m_local_key, 20,
reinterpret_cast<unsigned char const*>(rc4_local_longkey.begin()));
RC4_set_key(&m_remote_key, 20,
reinterpret_cast<unsigned char const*>(rc4_remote_longkey.begin()));
#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);
gcry_cipher_setkey(m_rc4_incoming, &rc4_remote_longkey[0], 20);
gcry_cipher_setkey(m_rc4_outgoing, &rc4_local_longkey[0], 20);
#elif defined TORRENT_USE_OPENSSL
RC4_set_key(&m_local_key, 20, &rc4_local_longkey[0]);
RC4_set_key(&m_remote_key, 20, &rc4_remote_longkey[0]);
#endif
// Discard first 1024 bytes
char buf[1024];
@ -94,15 +99,24 @@ namespace libtorrent
decrypt(buf, 1024);
};
~RC4_handler() {};
~RC4_handler()
{
#ifdef TORRENT_USE_GCRYPT
gcry_cipher_close(m_rc4_incoming);
gcry_cipher_close(m_rc4_outgoing);
#endif
};
void encrypt(char* pos, int len)
{
TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos);
RC4(&m_local_key, len, reinterpret_cast<unsigned char const*>(pos),
reinterpret_cast<unsigned char*>(pos));
#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);
#endif
}
void decrypt(char* pos, int len)
@ -110,13 +124,21 @@ namespace libtorrent
TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos);
RC4(&m_remote_key, len, reinterpret_cast<unsigned char const*>(pos),
reinterpret_cast<unsigned char*>(pos));
#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);
#endif
}
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
#endif
};
} // namespace libtorrent

View File

@ -34,8 +34,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include <algorithm>
#include <openssl/dh.h>
#include <openssl/engine.h>
#if defined TORRENT_USE_GCRYPT
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/bn.h>
#include <openssl/rand.h>
#endif
#include "libtorrent/pe_crypto.hpp"
#include "libtorrent/hasher.hpp"
@ -55,69 +59,85 @@ namespace libtorrent
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
};
const unsigned char dh_generator[1] = { 2 };
}
// Set the prime P and the generator, generate local public key
dh_key_exchange::dh_key_exchange()
{
m_dh = DH_new();
if (m_dh == 0) return;
#ifdef TORRENT_USE_GCRYPT
// create local key
gcry_randomize(m_dh_local_secret, sizeof(m_dh_local_secret), GCRY_STRONG_RANDOM);
m_dh->p = BN_bin2bn(dh_prime, sizeof(dh_prime), 0);
m_dh->g = BN_bin2bn(dh_generator, sizeof(dh_generator), 0);
if (m_dh->p == 0 || m_dh->g == 0)
// 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)
{
DH_free(m_dh);
m_dh = 0;
return;
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);
}
m_dh->length = 160l;
get_out:
if (key) gcry_mpi_release(key);
if (prime) gcry_mpi_release(prime);
if (secret) gcry_mpi_release(secret);
TORRENT_ASSERT(sizeof(dh_prime) == DH_size(m_dh));
if (DH_generate_key(m_dh) == 0 || m_dh->pub_key == 0)
{
DH_free(m_dh);
m_dh = 0;
return;
}
#elif defined TORRENT_USE_OPENSSL
// create local key
RAND_bytes((unsigned char*)m_dh_local_secret, sizeof(m_dh_local_secret));
// DH can generate key sizes that are smaller than the size of
// P with exponentially decreasing probability, in which case
// the msb's of m_dh_local_key need to be zeroed
// appropriately.
int key_size = get_local_key_size();
int len_dh = sizeof(dh_prime); // must equal DH_size(m_DH)
if (key_size != len_dh)
{
TORRENT_ASSERT(key_size > 0 && key_size < len_dh);
BIGNUM* prime = 0;
BIGNUM* secret = 0;
BIGNUM* key = 0;
BN_CTX* ctx = 0;
int size;
int pad_zero_size = len_dh - key_size;
std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size) == 0)
{
DH_free(m_dh);
m_dh = 0;
return;
}
}
else
{
if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key) == 0)
{
DH_free(m_dh);
m_dh = 0;
return;
}
}
}
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;
dh_key_exchange::~dh_key_exchange()
{
if (m_dh) DH_free(m_dh);
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);
#else
#error you must define TORRENT_USE_OPENSSL or TORRENT_USE_GCRYPT
#endif
}
char const* dh_key_exchange::get_local_key() const
@ -130,29 +150,81 @@ namespace libtorrent
int dh_key_exchange::compute_secret(char const* remote_pubkey)
{
TORRENT_ASSERT(remote_pubkey);
BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
if (bn_remote_pubkey == 0) return -1;
char dh_secret[96];
int ret = 0;
#ifdef TORRENT_USE_GCRYPT
int secret_size = DH_compute_key((unsigned char*)dh_secret
, bn_remote_pubkey, m_dh);
if (secret_size < 0 || secret_size > 96) return -1;
gcry_mpi_t prime = 0;
gcry_mpi_t remote_key = 0;
gcry_mpi_t secret = 0;
size_t written;
gcry_error_t e;
if (secret_size != 96)
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);
// 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)
{
TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
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);
}
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
BN_free(bn_remote_pubkey);
get_out:
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);
#else
#error you must define TORRENT_USE_OPENSSL or TORRENT_USE_GCRYPT
#endif
// calculate the xor mask for the obfuscated hash
hasher h;
h.update("req3", 4);
h.update(m_dh_secret, 96);
h.update(m_dh_shared_secret, sizeof(m_dh_shared_secret));
m_xor_mask = h.final();
return 0;
return ret;
}
} // namespace libtorrent

View File

@ -92,7 +92,31 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/resource.h>
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION
#ifdef TORRENT_USE_GCRYPT
extern "C" {
GCRY_THREAD_OPTION_PTHREAD_IMPL;
}
namespace
{
// libgcrypt requires this to initialize the library
struct gcrypt_setup
{
gcrypt_setup()
{
gcry_check_version(0);
gcry_error_t e = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
if (e != 0) fprintf(stderr, "libcrypt ERROR: %s\n", gcry_strerror(e));
e = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
if (e != 0) fprintf(stderr, "initialization finished error: %s\n", gcry_strerror(e));
}
} gcrypt_global_constructor;
}
#endif // TORRENT_USE_GCRYPT
#ifdef TORRENT_USE_OPENSSL
#include <openssl/crypto.h>
@ -106,7 +130,8 @@ namespace
} openssl_global_destructor;
}
#endif
#endif // TORRENT_USE_OPENSSL
#ifdef TORRENT_WINDOWS
// for ERROR_SEM_TIMEOUT
#include <winerror.h>