From b245d45570036aeeabb66736ca1f7ef26675ab0b Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 28 Jan 2009 04:20:05 +0000 Subject: [PATCH] fixed encryption bug --- ChangeLog | 2 + include/libtorrent/bt_peer_connection.hpp | 22 ++++++++-- src/bt_peer_connection.cpp | 52 ++++++++++++++++++++++- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1503eb23b..146255615 100644 --- a/ChangeLog +++ b/ChangeLog @@ -50,6 +50,8 @@ release 0.14.2 * fixed race condition when saving DHT state * fixed bugs related to lexical_cast being locale dependent * added support for SunPro C++ compiler + * fixed bug where messeges sometimes could be encrypted in the + wrong order, for encrypted connections. release 0.14.1 diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index 5d3b9bc48..306d706e6 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -262,8 +262,8 @@ namespace libtorrent void write_pe3_sync(); void write_pe4_sync(int crypto_select); - void write_pe_vc_cryptofield(buffer::interval& write_buf, - int crypto_field, int pad_size); + void write_pe_vc_cryptofield(buffer::interval& write_buf + , int crypto_field, int pad_size); // stream key (info hash of attached torrent) // secret is the DH shared secret @@ -282,7 +282,14 @@ public: { #ifndef TORRENT_DISABLE_ENCRYPTION if (m_rc4_encrypted) + { + TORRENT_ASSERT(send_buffer_size() == m_encrypted_bytes); m_RC4_handler->encrypt(buffer, size); +#ifdef TORRENT_DEBUG + m_encrypted_bytes += size; + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size() + size); +#endif + } #endif peer_connection::append_send_buffer(buffer, size, destructor); } @@ -290,11 +297,13 @@ public: private: + void encrypt_pending_buffer(); + // Returns offset at which bytestream (src, src + src_size) // matches bytestream(target, target + target_size). // If no sync found, return -1 - int get_syncoffset(char const* src, int src_size, - char const* target, int target_size) const; + int get_syncoffset(char const* src, int src_size + , char const* target, int target_size) const; #endif enum state @@ -412,6 +421,11 @@ private: bool m_in_constructor; bool m_sent_handshake; + + // the number of bytes in the send buffer + // that have been encrypted (only used for + // encrypted connections) + int m_encrypted_bytes; #endif }; diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 6b712ba9b..4fdb91653 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -120,6 +120,7 @@ namespace libtorrent #ifdef TORRENT_DEBUG m_in_constructor = false; + m_encrypted_bytes = 0; #endif } @@ -167,6 +168,7 @@ namespace libtorrent #ifdef TORRENT_DEBUG m_in_constructor = false; + m_encrypted_bytes = 0; #endif } @@ -412,6 +414,10 @@ namespace libtorrent send_buf.begin); std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand); +#ifdef TORRENT_DEBUG + m_encrypted_bytes += send_buf.left(); + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); +#endif setup_send(); #ifdef TORRENT_VERBOSE_LOGGING @@ -496,6 +502,12 @@ namespace libtorrent write_pe_vc_cryptofield(send_buf, crypto_provide, pad_size); m_RC4_handler->encrypt(send_buf.end - encrypt_size, encrypt_size); +#ifdef TORRENT_DEBUG + const int packet_size = 20 + 20 + 8 + 4 + 2 + pad_size + 2; + TORRENT_ASSERT(send_buffer_size() - packet_size == m_encrypted_bytes); + m_encrypted_bytes += packet_size; + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); +#endif TORRENT_ASSERT(send_buf.begin == send_buf.end); setup_send(); @@ -519,6 +531,11 @@ namespace libtorrent write_pe_vc_cryptofield(send_buf, crypto_select, pad_size); m_RC4_handler->encrypt(send_buf.end - buf_size, buf_size); + TORRENT_ASSERT(send_buffer_size() - buf_size == m_encrypted_bytes); +#ifdef TORRENT_DEBUG + m_encrypted_bytes += buf_size; + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); +#endif setup_send(); // encryption method has been negotiated @@ -610,15 +627,25 @@ namespace libtorrent { TORRENT_ASSERT(buf); TORRENT_ASSERT(size > 0); + + encrypt_pending_buffer(); if (m_encrypted && m_rc4_encrypted) + { + TORRENT_ASSERT(send_buffer_size() == m_encrypted_bytes); m_RC4_handler->encrypt(const_cast(buf), size); +#ifdef TORRENT_DEBUG + m_encrypted_bytes += size; + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size() + size); +#endif + } peer_connection::send_buffer(buf, size, flags); } buffer::interval bt_peer_connection::allocate_send_buffer(int size) { + encrypt_pending_buffer(); if (m_encrypted && m_rc4_encrypted) { TORRENT_ASSERT(m_enc_send_buffer.left() == 0); @@ -632,16 +659,27 @@ namespace libtorrent } } - void bt_peer_connection::setup_send() + void bt_peer_connection::encrypt_pending_buffer() { if (m_encrypted && m_rc4_encrypted && m_enc_send_buffer.left()) { TORRENT_ASSERT(m_enc_send_buffer.begin); TORRENT_ASSERT(m_enc_send_buffer.end); + TORRENT_ASSERT(m_RC4_handler); + TORRENT_ASSERT(send_buffer_size() - m_enc_send_buffer.left() == m_encrypted_bytes); +#ifdef TORRENT_DEBUG + m_encrypted_bytes += m_enc_send_buffer.left(); + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); +#endif m_RC4_handler->encrypt(m_enc_send_buffer.begin, m_enc_send_buffer.left()); m_enc_send_buffer.end = m_enc_send_buffer.begin; } + } + + void bt_peer_connection::setup_send() + { + encrypt_pending_buffer(); peer_connection::setup_send(); } @@ -1560,6 +1598,8 @@ namespace libtorrent m_sent_bitfield = true; #endif + setup_send(); + if (num_lazy_pieces > 0) { for (int i = 0; i < num_lazy_pieces; ++i) @@ -1575,7 +1615,6 @@ namespace libtorrent if (m_supports_fast) send_allowed_set(); - setup_send(); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -2735,6 +2774,15 @@ namespace libtorrent std::remove_if(m_payloads.begin(), m_payloads.end(), range_below_zero) , m_payloads.end()); +#ifdef TORRENT_DEBUG + if (m_encrypted_bytes > 0) + { + m_encrypted_bytes -= bytes_transferred; + TORRENT_ASSERT(m_encrypted_bytes >= 0); + TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); + } +#endif + TORRENT_ASSERT(amount_payload <= (int)bytes_transferred); m_statistics.sent_bytes(amount_payload, bytes_transferred - amount_payload); }