feature to encrypt peer connections with a secret AES-256 key stored in .torrent file

This commit is contained in:
Arvid Norberg 2011-09-05 05:50:41 +00:00
parent 43c9e640ab
commit 92bcb9ebfd
17 changed files with 397 additions and 69 deletions

View File

@ -1,3 +1,4 @@
* feature to encrypt peer connections with a secret AES-256 key stored in .torrent file
* deprecated compact storage allocation
* close files in separate thread on systems where close() may block (Mac OS X for instance)
* don't create all directories up front when adding torrents

View File

@ -85,8 +85,10 @@ void print_usage()
" If this is not specified, the torrent file is\n"
" printed to the standard out, except on windows\n"
" where the filename defaults to a.torrent\n"
"-c add root certificate to the torrent, to make\n"
" it an SSL torrent\n"
"-c file add root certificate to the torrent, to verify\n"
" the HTTPS tracker\n"
"-e file add an AES-256 encryption key. This is used\n"
" to encrypt every peer connection\n"
, stderr);
}
@ -112,6 +114,7 @@ int main(int argc, char* argv[])
int piece_size = 0;
int flags = 0;
std::string root_cert;
std::string encryption_key;
std::string outfile;
std::string merklefile;
@ -167,6 +170,10 @@ int main(int argc, char* argv[])
++i;
root_cert = argv[i];
break;
case 'e':
++i;
encryption_key = argv[i];
break;
default:
print_usage();
return 1;
@ -207,15 +214,29 @@ int main(int argc, char* argv[])
if (!root_cert.empty())
{
FILE* cert = fopen(root_cert.c_str(), "rb");
if (cert)
std::vector<char> pem;
load_file(root_cert, pem, ec, 10000);
if (ec)
{
std::string pem;
pem.resize(5000);
int s = fread(&pem[0], 1, pem.size(), cert);
pem.resize(s);
t.set_root_cert(pem);
fclose(cert);
fprintf(stderr, "failed to load root certificate for tracker: %s\n", ec.message().c_str());
}
else
{
t.set_root_cert(std::string(&pem[0], pem.size()));
}
}
if (!encryption_key.empty())
{
std::vector<char> key;
load_file(encryption_key, key, ec, 32);
if (ec)
{
fprintf(stderr, "failed to load AES-256 encryption key: %s\n", ec.message().c_str());
}
else
{
t.set_encryption_key(std::string(&key[0], key.size()));
}
}

View File

@ -613,6 +613,12 @@ namespace libtorrent
torrent_map m_torrents;
std::map<std::string, boost::shared_ptr<torrent> > m_uuids;
// these are all the torrents using full AES-256 encryption of
// all peer connections. When receiving a handshake that's encrypred
// these are the torrents we need to try to decrypt it with to
// find the decryption key
std::set<boost::shared_ptr<torrent> > m_encrypted_torrents;
typedef std::list<boost::shared_ptr<torrent> > check_queue_t;
// this has all torrents that wants to be checked in it

View File

@ -298,7 +298,7 @@ public:
void append_send_buffer(char* buffer, int size, Destructor const& destructor)
{
#ifndef TORRENT_DISABLE_ENCRYPTION
if (m_enc_handler)
if (m_rc4_encrypted)
m_enc_handler->encrypt(buffer, size);
#endif
peer_connection::append_send_buffer(buffer, size, destructor, true);

View File

@ -90,6 +90,7 @@ namespace libtorrent
void add_node(std::pair<std::string, int> const& node);
void add_tracker(std::string const& url, int tier = 0);
void set_root_cert(std::string const& pem);
void set_encryption_key(std::string const& key);
void set_priv(bool p) { m_private = p; }
int num_pieces() const { return m_files.num_pieces(); }
@ -149,6 +150,11 @@ namespace libtorrent
// this is the root cert for SSL torrents
std::string m_root_cert;
// if this is an encrypted torrent, this is the
// symmetric encryption key every stream is
// encrypted by
std::string m_encryption_key;
// this is used when creating a torrent. If there's
// only one file there are cases where it's impossible
// to know if it should be written as a multifile torrent

View File

@ -41,6 +41,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <gcrypt.h>
#elif defined TORRENT_USE_OPENSSL
#include <openssl/rc4.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#else
// RC4 state from libtomcrypt
struct rc4 {
@ -197,6 +199,104 @@ namespace libtorrent
bool m_decrypt;
};
#ifdef TORRENT_USE_OPENSSL
struct aes256_handler : encryption_handler
{
aes256_handler() : m_enc_pos(0), m_dec_pos(0)
{
EVP_CIPHER_CTX_init(&m_enc);
EVP_CIPHER_CTX_init(&m_dec);
}
~aes256_handler()
{
EVP_CIPHER_CTX_cleanup(&m_enc);
EVP_CIPHER_CTX_cleanup(&m_dec);
}
void set_incoming_key(unsigned char const* in_key, int len)
{
const int nrounds = 5;
boost::uint8_t salt[8] = { 0xf1, 0x03, 0x46, 0xe2, 0xb1, 0xa8, 0x29, 0x63 };
boost::uint8_t key[32];
boost::uint8_t iv[32];
int i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, in_key, len, nrounds, key, iv);
TORRENT_ASSERT(len == 32);
EVP_EncryptInit_ex(&m_enc, EVP_aes_256_cbc(), NULL, key, iv);
// since we're using the AES as a stream cipher, both the encrypt and
// decrypt context will in fact only _encrypt_ stuff, so initializing
// this as encrypt is not a typo
EVP_EncryptInit_ex(&m_dec, EVP_aes_256_cbc(), NULL, key, iv);
m_enc_pos = 0;
m_dec_pos = 0;
std::memcpy(m_enc_state, iv, sizeof(m_enc_state));
std::memcpy(m_dec_state, iv, sizeof(m_enc_state));
}
void set_outgoing_key(unsigned char const* key, int len) { /* no-op */ }
void encrypt(char* pos, int len)
{
while (len > 0)
{
while (m_enc_pos < AES_BLOCK_SIZE && len > 0)
{
*pos ^= m_enc_state[m_enc_pos];
++m_enc_pos;
++pos;
--len;
}
if (m_enc_pos == AES_BLOCK_SIZE)
{
next_block(&m_enc, m_enc_state);
m_enc_pos = 0;
}
}
}
void decrypt(char* pos, int len)
{
while (len > 0)
{
while (m_dec_pos < AES_BLOCK_SIZE && len > 0)
{
*pos ^= m_dec_state[m_dec_pos];
++m_dec_pos;
++pos;
--len;
}
if (m_dec_pos == AES_BLOCK_SIZE)
{
next_block(&m_dec, m_dec_state);
m_dec_pos = 0;
}
}
}
private:
// we're turning the AES block-cipher into a stream cipher. This
// function will produce the next block in the sequence of
// block-sized buffers. We're using "Output feedback" (OFB) mode.
void next_block(EVP_CIPHER_CTX* ctx, boost::uint8_t* pad)
{
int outlen = AES_BLOCK_SIZE;
EVP_EncryptUpdate(ctx, pad, &outlen, pad, AES_BLOCK_SIZE);
TORRENT_ASSERT(outlen == AES_BLOCK_SIZE);
}
EVP_CIPHER_CTX m_enc;
EVP_CIPHER_CTX m_dec;
boost::uint8_t m_enc_state[AES_BLOCK_SIZE];
boost::uint8_t m_dec_state[AES_BLOCK_SIZE];
int m_enc_pos;
int m_dec_pos;
};
#endif // TORRENT_USE_OPENSSL
} // namespace libtorrent
#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED

View File

@ -664,7 +664,11 @@ namespace libtorrent
void reset_recv_buffer(int packet_size);
void set_soft_packet_size(int size) { m_soft_packet_size = size; }
void attach_to_torrent(sha1_hash const& ih);
// if allow_encrypted is false, and the torrent 'ih' turns out
// to be an encrypted torrent (AES-256 encrypted) the peer will
// be disconnected. This is to prevent non-encrypted peers to
// attach to an encrypted torrent
void attach_to_torrent(sha1_hash const& ih, bool allow_encrypted);
bool verify_piece(peer_request const& p) const;

View File

@ -1324,6 +1324,12 @@ namespace libtorrent
// data into this torrent instead of replacing them
bool m_merge_resume_trackers:1;
// set to true if this torrent has been added to the session
// global list for encrypted torrents. When the torrent is
// paused it's removed and when it's started again, it's
// re-added
bool m_in_encrypted_list:1;
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
public:
// set to false until we've loaded resume data

View File

@ -333,8 +333,12 @@ namespace libtorrent
// ------- end deprecation -------
#endif
#ifdef TORRENT_USE_OPENSSL
std::string const& ssl_cert() const { return m_ssl_root_cert; }
std::string const& encryption_key() const { return m_aes_key; }
#endif
bool is_valid() const { return m_files.is_valid(); }
bool priv() const { return m_private; }
@ -450,6 +454,8 @@ namespace libtorrent
// pointing to the first byte of the first sha-1 hash
char const* m_piece_hashes;
// TODO: these strings could be lazy_entry* to save memory
// if a comment is found in the torrent file
// this will be set to that comment
std::string m_comment;
@ -458,11 +464,16 @@ namespace libtorrent
// to create the torrent file
std::string m_created_by;
#ifdef TORRENT_USE_OPENSSL
// for ssl-torrens, this contains the root
// certificate, in .pem format (i.e. ascii
// base64 encoded with head and tails)
std::string m_ssl_root_cert;
// used to encrypt the peer connections
std::string m_aes_key;
#endif
// the info section parsed. points into m_info_section
// parsed lazily
mutable lazy_entry m_info_dict;

View File

@ -37,6 +37,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/limits.hpp>
#include <boost/bind.hpp>
#ifdef TORRENT_USE_OPENSSL
#include <memory> // autp_ptr
#endif
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/identify_client.hpp"
@ -127,6 +131,21 @@ namespace libtorrent
m_in_constructor = false;
#endif
memset(m_reserved_bits, 0, sizeof(m_reserved_bits));
#ifdef TORRENT_USE_OPENSSL
boost::shared_ptr<torrent> t = tor.lock();
std::string const key = t->torrent_file().encryption_key();
if (key.size() == 32)
{
m_enc_handler.reset(new aes256_handler);
m_enc_handler->set_incoming_key((const unsigned char*)key.c_str(), key.size());
m_encrypted = true;
m_rc4_encrypted = true;
#ifdef TORRENT_VERBOSE_LOGGING
peer_log("*** encrypted torrent. enabling AES-256 encryption");
#endif
}
#endif
}
bt_peer_connection::bt_peer_connection(
@ -198,7 +217,19 @@ namespace libtorrent
{
#ifndef TORRENT_DISABLE_ENCRYPTION
pe_settings::enc_policy const& out_enc_policy = m_ses.get_pe_settings().out_enc_policy;
pe_settings::enc_policy out_enc_policy = m_ses.get_pe_settings().out_enc_policy;
#ifdef TORRENT_USE_OPENSSL
// if this torrent is using AES-256 encryption, don't
// also enable the normal encryption
boost::shared_ptr<torrent> t = associated_torrent().lock();
std::string const key = t->torrent_file().encryption_key();
if (key.size() == 32) out_enc_policy = pe_settings::disabled;
#endif
#ifdef TORRENT_VERBOSE_LOGGING
char const* policy_name[] = {"forced", "enabled", "disabled"};
peer_log("*** outgoing encryption policy: %s", policy_name[out_enc_policy]);
#endif
if (out_enc_policy == pe_settings::forced)
{
@ -2532,6 +2563,13 @@ namespace libtorrent
for (i = m_ses.m_torrents.begin(); i != m_ses.m_torrents.end(); ++i)
{
torrent const& ti = *i->second;
#ifdef TORRENT_USE_OPENSSL
// don't consider encrypted torrents (since that would
// open up a hole to connecting to them without the key)
if (ti.torrent_file().encryption_key().size() == 32) continue;
#endif
sha1_hash const& skey_hash = ti.obfuscated_hash();
sha1_hash obfs_hash = m_dh_key_exchange->get_hash_xor_mask();
obfs_hash ^= skey_hash;
@ -2541,7 +2579,7 @@ namespace libtorrent
{
if (!t)
{
attach_to_torrent(ti.info_hash());
attach_to_torrent(ti.info_hash(), false);
if (is_disconnecting()) return;
t = associated_torrent().lock();
@ -2889,52 +2927,102 @@ namespace libtorrent
recv_buffer = receive_buffer();
int packet_size = recv_buffer[0];
const char protocol_string[] = "BitTorrent protocol";
const char protocol_string[] = "\x13" "BitTorrent protocol";
if (packet_size != 19 ||
!std::equal(recv_buffer.begin + 1, recv_buffer.begin + 19, protocol_string))
memcmp(recv_buffer.begin, protocol_string, 20) != 0)
{
#ifndef TORRENT_DISABLE_ENCRYPTION
if (!is_local() && m_ses.get_pe_settings().in_enc_policy == pe_settings::disabled)
{
disconnect(errors::no_incoming_encrypted);
return;
}
#ifdef TORRENT_VERBOSE_LOGGING
peer_log("*** unrecognized protocol header");
#endif
// Don't attempt to perform an encrypted handshake
// within an encrypted connection
if (!m_encrypted && !is_local())
bool found_encrypted_torrent = false;
#ifdef TORRENT_USE_OPENSSL
if (!is_local())
{
std::auto_ptr<encryption_handler> handler(new aes256_handler);
boost::uint8_t temp_pad[20];
for (std::set<boost::shared_ptr<torrent> >::iterator i = m_ses.m_encrypted_torrents.begin()
, end(m_ses.m_encrypted_torrents.end()); i != end; ++i)
{
boost::shared_ptr<torrent> t = *i;
std::string const key = t->torrent_file().encryption_key();
TORRENT_ASSERT(key.size() == 32);
handler->set_incoming_key((const unsigned char*)key.c_str(), key.size());
std::memcpy(temp_pad, recv_buffer.begin, 20);
handler->decrypt((char*)temp_pad, 20);
if (memcmp(temp_pad, protocol_string, 20) != 0) continue;
// we found the key that could decrypt it
m_rc4_encrypted = true;
m_encrypted = true;
m_enc_handler.reset(handler.release());
found_encrypted_torrent = true;
#ifdef TORRENT_VERBOSE_LOGGING
peer_log("*** found encrypted torrent");
#endif
TORRENT_ASSERT(recv_buffer.left() == 20);
// handler->decrypt((char*)recv_buffer.begin + 20, recv_buffer.left() - 20);
break;
}
}
#endif
if (!found_encrypted_torrent)
{
if (!is_local()
&& m_ses.get_pe_settings().in_enc_policy == pe_settings::disabled)
{
disconnect(errors::no_incoming_encrypted);
return;
}
// Don't attempt to perform an encrypted handshake
// within an encrypted connection. For local connections,
// we're expected to already have passed the encrypted
// handshake by this point
if (m_encrypted || is_local())
{
disconnect(errors::invalid_info_hash, 1);
return;
}
#ifdef TORRENT_VERBOSE_LOGGING
peer_log("*** attempting encrypted connection");
#endif
m_state = read_pe_dhkey;
cut_receive_buffer(0, dh_key_len);
TORRENT_ASSERT(!packet_finished());
return;
return;
}
TORRENT_ASSERT((!is_local() && m_encrypted) || is_local());
#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
#else
disconnect(errors::invalid_info_hash, 1);
return;
#endif // TORRENT_DISABLE_ENCRYPTION
}
#ifndef TORRENT_DISABLE_ENCRYPTION
TORRENT_ASSERT(m_state != read_pe_dhkey);
if (!is_local() &&
(m_ses.get_pe_settings().in_enc_policy == pe_settings::forced) &&
!m_encrypted)
else
{
disconnect(errors::no_incoming_regular);
return;
}
#ifndef TORRENT_DISABLE_ENCRYPTION
TORRENT_ASSERT(m_state != read_pe_dhkey);
if (!is_local() &&
(m_ses.get_pe_settings().in_enc_policy == pe_settings::forced) &&
!m_encrypted)
{
disconnect(errors::no_incoming_regular);
return;
}
#endif
#ifdef TORRENT_VERBOSE_LOGGING
peer_log("<== BitTorrent protocol");
peer_log("<== BitTorrent protocol");
#endif
}
m_state = read_info_hash;
reset_recv_buffer(28);
@ -2990,7 +3078,7 @@ namespace libtorrent
std::copy(recv_buffer.begin + 8, recv_buffer.begin + 28
, (char*)info_hash.begin());
attach_to_torrent(info_hash);
attach_to_torrent(info_hash, m_encrypted && m_rc4_encrypted);
if (is_disconnecting()) return;
}
else

View File

@ -301,6 +301,9 @@ namespace libtorrent
if (!m_root_cert.empty())
info["ssl-cert"] = m_root_cert;
if (!m_encryption_key.empty())
info["encryption-key"] = m_encryption_key;
if (m_private) info["private"] = 1;
if (!m_multifile)

View File

@ -1115,7 +1115,7 @@ namespace libtorrent
&& t->to_req(piece_block(p.piece, p.start / t->block_size())) == p;
}
void peer_connection::attach_to_torrent(sha1_hash const& ih)
void peer_connection::attach_to_torrent(sha1_hash const& ih, bool allow_encrypted)
{
INVARIANT_CHECK;
@ -1148,6 +1148,14 @@ namespace libtorrent
return;
}
#ifdef TORRENT_USE_OPENSSL
if (t->torrent_file().encryption_key().size() == 32 && !allow_encrypted)
{
disconnect(errors::invalid_info_hash, 2);
return;
}
#endif
if (t->is_paused() && (!t->is_auto_managed()
|| !m_ses.m_settings.incoming_starts_queued_torrents))
{

View File

@ -412,6 +412,7 @@ namespace libtorrent
, m_magnet_link(false)
, m_apply_ip_filter(p.apply_ip_filter)
, m_merge_resume_trackers(p.merge_resume_trackers)
, m_in_encrypted_list(false)
{
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
m_resume_data_loaded = false;
@ -1367,6 +1368,14 @@ namespace libtorrent
}
#endif
#ifdef TORRENT_USE_OPENSSL
if (m_torrent_file->encryption_key().size() == 32 && !m_in_encrypted_list)
{
m_ses.m_encrypted_torrents.insert(shared_from_this());
m_in_encrypted_list = true;
}
#endif
m_file_priority.resize(m_torrent_file->num_files(), 1);
m_file_progress.resize(m_torrent_file->num_files(), 0);
@ -3192,6 +3201,14 @@ namespace libtorrent
if (m_abort) return;
#ifdef TORRENT_USE_OPENSSL
if (m_torrent_file->is_valid() && m_torrent_file->encryption_key().size() == 32 && m_in_encrypted_list)
{
m_ses.m_encrypted_torrents.erase(shared_from_this());
m_in_encrypted_list = false;
}
#endif
m_abort = true;
// if the torrent is paused, it doesn't need
// to announce with even=stopped again.
@ -6410,6 +6427,14 @@ namespace libtorrent
TORRENT_ASSERT(m_ses.is_network_thread());
if (!is_paused()) return;
#ifdef TORRENT_USE_OPENSSL
if (m_torrent_file->is_valid() && m_torrent_file->encryption_key().size() == 32 && m_in_encrypted_list)
{
m_ses.m_encrypted_torrents.erase(shared_from_this());
m_in_encrypted_list = false;
}
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
@ -6560,6 +6585,14 @@ namespace libtorrent
TORRENT_ASSERT(m_ses.is_network_thread());
if (is_paused()) return;
#ifdef TORRENT_USE_OPENSSL
if (m_torrent_file->is_valid() && m_torrent_file->encryption_key().size() == 32 && !m_in_encrypted_list)
{
m_ses.m_encrypted_torrents.insert(shared_from_this());
m_in_encrypted_list = true;
}
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)

View File

@ -467,6 +467,10 @@ namespace libtorrent
, m_piece_hashes(t.m_piece_hashes)
, m_comment(t.m_comment)
, m_created_by(t.m_created_by)
#ifdef TORRENT_USE_OPENSSL
, m_ssl_root_cert(t.m_ssl_root_cert)
, m_aes_key(t.m_aes_key)
#endif
, m_creation_date(t.m_creation_date)
, m_info_hash(t.m_info_hash)
, m_merkle_first_leaf(t.m_merkle_first_leaf)
@ -933,8 +937,12 @@ namespace libtorrent
m_private = info.dict_find_int_value("private", 0);
#ifdef TORRENT_USE_OPENSSL
m_ssl_root_cert = info.dict_find_string_value("ssl-cert");
m_aes_key = info.dict_find_string_value("encryption-key");
#endif
return true;
}

View File

@ -203,7 +203,7 @@ boost::intrusive_ptr<T> clone_ptr(boost::intrusive_ptr<T> const& ptr)
}
boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_size
, int num_pieces, bool add_tracker)
, int num_pieces, bool add_tracker, bool encrypted_torrent)
{
char const* tracker_url = "http://non-existent-name.com/announce";
// excercise the path when encountering invalid urls
@ -243,7 +243,17 @@ boost::intrusive_ptr<torrent_info> create_torrent(std::ostream* file, int piece_
std::vector<char> tmp;
std::back_insert_iterator<std::vector<char> > out(tmp);
bencode(out, t.generate());
entry tor = t.generate();
if (encrypted_torrent)
{
std::string key;
key.resize(32);
std::generate(key.begin(), key.end(), &std::rand);
tor["info"]["encryption-key"] = key;
}
bencode(out, tor);
error_code ec;
return boost::intrusive_ptr<torrent_info>(new torrent_info(
&tmp[0], tmp.size(), ec));
@ -254,7 +264,7 @@ setup_transfer(session* ses1, session* ses2, session* ses3
, bool clear_files, bool use_metadata_transfer, bool connect_peers
, std::string suffix, int piece_size
, boost::intrusive_ptr<torrent_info>* torrent, bool super_seeding
, add_torrent_params const* p, bool stop_lsd)
, add_torrent_params const* p, bool stop_lsd, bool encrypted_torrent)
{
assert(ses1);
assert(ses2);
@ -298,7 +308,7 @@ setup_transfer(session* ses1, session* ses2, session* ses3
error_code ec;
create_directory("./tmp1" + suffix, ec);
std::ofstream file(("./tmp1" + suffix + "/temporary").c_str());
t = ::create_torrent(&file, piece_size, 19, true);
t = ::create_torrent(&file, piece_size, 19, true, encrypted_torrent);
file.close();
if (clear_files)
{

View File

@ -53,7 +53,7 @@ void wait_for_listen(libtorrent::session& ses, char const* name);
void test_sleep(int millisec);
boost::intrusive_ptr<libtorrent::torrent_info> create_torrent(std::ostream* file = 0
, int piece_size = 16 * 1024, int num_pieces = 13, bool add_tracker = true);
, int piece_size = 16 * 1024, int num_pieces = 13, bool add_tracker = true, bool encrypted = false);
boost::tuple<libtorrent::torrent_handle
, libtorrent::torrent_handle
@ -62,7 +62,7 @@ setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2
, libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true
, bool connect = true, std::string suffix = "", int piece_size = 16 * 1024
, boost::intrusive_ptr<libtorrent::torrent_info>* torrent = 0, bool super_seeding = false
, libtorrent::add_torrent_params const* p = 0, bool stop_lsd = true);
, libtorrent::add_torrent_params const* p = 0, bool stop_lsd = true, bool encrypted_torrent = false);
int start_web_server(bool ssl = false, bool chunked = false);
void stop_web_server();

View File

@ -74,7 +74,7 @@ void display_pe_settings(libtorrent::pe_settings s)
void test_transfer(libtorrent::pe_settings::enc_policy policy,
libtorrent::pe_settings::enc_level level = libtorrent::pe_settings::both,
bool pref_rc4 = false)
bool pref_rc4 = false, bool encrypted_torrent = false)
{
using namespace libtorrent;
using std::cerr;
@ -106,7 +106,8 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy,
torrent_handle tor2;
using boost::tuples::ignore;
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, true, false, true, "_pe");
boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, true, false, true
, "_pe", 16 * 1024, 0, false, 0, true, encrypted_torrent);
std::cerr << "waiting for transfer to complete\n";
@ -131,6 +132,32 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy,
remove_all("./tmp3_pe", ec);
}
void test_enc_handler(libtorrent::encryption_handler* a, libtorrent::encryption_handler* b)
{
int repcount = 128;
for (int rep = 0; rep < repcount; ++rep)
{
std::size_t buf_len = rand() % (512 * 1024);
char* buf = new char[buf_len];
char* cmp_buf = new char[buf_len];
std::generate(buf, buf + buf_len, &std::rand);
std::memcpy(cmp_buf, buf, buf_len);
a->encrypt(buf, buf_len);
TEST_CHECK(!std::equal(buf, buf + buf_len, cmp_buf));
b->decrypt(buf, buf_len);
TEST_CHECK(std::equal(buf, buf + buf_len, cmp_buf));
b->encrypt(buf, buf_len);
TEST_CHECK(!std::equal(buf, buf + buf_len, cmp_buf));
a->decrypt(buf, buf_len);
TEST_CHECK(std::equal(buf, buf + buf_len, cmp_buf));
delete[] buf;
delete[] cmp_buf;
}
}
int test_main()
{
@ -156,35 +183,31 @@ int test_main()
sha1_hash test1_key = hasher("test1_key",8).final();
sha1_hash test2_key = hasher("test2_key",8).final();
fprintf(stderr, "testing RC4 handler\n");
rc4_handler rc41;
rc41.set_incoming_key(&test2_key[0], 20);
rc41.set_outgoing_key(&test1_key[0], 20);
rc4_handler rc42;
rc42.set_incoming_key(&test1_key[0], 20);
rc42.set_outgoing_key(&test2_key[0], 20);
for (int rep = 0; rep < repcount; ++rep)
{
std::size_t buf_len = rand() % (512 * 1024);
char* buf = new char[buf_len];
char* zero_buf = new char[buf_len];
std::fill(buf, buf + buf_len, 0);
std::fill(zero_buf, zero_buf + buf_len, 0);
rc41.encrypt(buf, buf_len);
rc42.decrypt(buf, buf_len);
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
rc42.encrypt(buf, buf_len);
rc41.decrypt(buf, buf_len);
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
delete[] buf;
delete[] zero_buf;
}
test_enc_handler(&rc41, &rc42);
#ifdef TORRENT_USE_OPENSSL
fprintf(stderr, "testing AES-256 handler\n");
char key1[32];
std::generate(key1, key1 + 32, &std::rand);
aes256_handler aes1;
aes1.set_incoming_key((const unsigned char*)key1, 32);
aes256_handler aes2;
aes2.set_incoming_key((const unsigned char*)key1, 32);
test_enc_handler(&aes1, &aes2);
#endif
test_transfer(pe_settings::enabled, pe_settings::both, false, true);
test_transfer(pe_settings::enabled, pe_settings::both, true, true);
return 0;
test_transfer(pe_settings::disabled);
test_transfer(pe_settings::forced, pe_settings::plaintext);