removed exceptions from pe_crypto and improved error handling
This commit is contained in:
parent
13766dc855
commit
d132dd45e3
|
@ -389,7 +389,7 @@ private:
|
|||
// initialized during write_pe1_2_dhkey, and destroyed on
|
||||
// creation of m_RC4_handler. Cannot reinitialize once
|
||||
// initialized.
|
||||
boost::scoped_ptr<DH_key_exchange> m_DH_key_exchange;
|
||||
boost::scoped_ptr<DH_key_exchange> m_dh_key_exchange;
|
||||
|
||||
// if RC4 is negotiated, this is used for
|
||||
// encryption/decryption during the entire session. Destroyed
|
||||
|
|
|
@ -44,31 +44,30 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
class DH_key_exchange
|
||||
class dh_key_exchange
|
||||
{
|
||||
public:
|
||||
DH_key_exchange ();
|
||||
~DH_key_exchange ();
|
||||
dh_key_exchange();
|
||||
~dh_key_exchange();
|
||||
bool good() const { return m_dh; }
|
||||
|
||||
// Get local public key, always 96 bytes
|
||||
char const* get_local_key (void) const;
|
||||
char const* get_local_key() const;
|
||||
|
||||
// read remote_pubkey, generate and store shared secret in
|
||||
// m_dh_secret
|
||||
void compute_secret (const char* remote_pubkey);
|
||||
// m_dh_secret.
|
||||
int compute_secret(const char* remote_pubkey);
|
||||
|
||||
const char* get_secret (void) const;
|
||||
const char* get_secret() const;
|
||||
|
||||
private:
|
||||
int get_local_key_size () const
|
||||
int get_local_key_size() const
|
||||
{
|
||||
TORRENT_ASSERT(m_DH);
|
||||
return BN_num_bytes (m_DH->pub_key);
|
||||
TORRENT_ASSERT(m_dh);
|
||||
return BN_num_bytes(m_dh->pub_key);
|
||||
}
|
||||
|
||||
DH* m_DH;
|
||||
static const unsigned char m_dh_prime[96];
|
||||
static const unsigned char m_dh_generator[1];
|
||||
DH* m_dh;
|
||||
|
||||
char m_dh_local_key[96];
|
||||
char m_dh_secret[96];
|
||||
|
@ -78,24 +77,24 @@ namespace libtorrent
|
|||
{
|
||||
public:
|
||||
// Input longkeys must be 20 bytes
|
||||
RC4_handler (const sha1_hash& rc4_local_longkey,
|
||||
RC4_handler(const sha1_hash& rc4_local_longkey,
|
||||
const sha1_hash& rc4_remote_longkey)
|
||||
|
||||
{
|
||||
RC4_set_key (&m_local_key, 20,
|
||||
RC4_set_key(&m_local_key, 20,
|
||||
reinterpret_cast<unsigned char const*>(rc4_local_longkey.begin()));
|
||||
RC4_set_key (&m_remote_key, 20,
|
||||
RC4_set_key(&m_remote_key, 20,
|
||||
reinterpret_cast<unsigned char const*>(rc4_remote_longkey.begin()));
|
||||
|
||||
// Discard first 1024 bytes
|
||||
char buf[1024];
|
||||
encrypt (buf, 1024);
|
||||
decrypt (buf, 1024);
|
||||
encrypt(buf, 1024);
|
||||
decrypt(buf, 1024);
|
||||
};
|
||||
|
||||
~RC4_handler () {};
|
||||
~RC4_handler() {};
|
||||
|
||||
void encrypt (char* pos, int len)
|
||||
void encrypt(char* pos, int len)
|
||||
{
|
||||
TORRENT_ASSERT(len >= 0);
|
||||
TORRENT_ASSERT(pos);
|
||||
|
@ -104,7 +103,7 @@ namespace libtorrent
|
|||
reinterpret_cast<unsigned char*>(pos));
|
||||
}
|
||||
|
||||
void decrypt (char* pos, int len)
|
||||
void decrypt(char* pos, int len)
|
||||
{
|
||||
TORRENT_ASSERT(len >= 0);
|
||||
TORRENT_ASSERT(pos);
|
||||
|
@ -122,3 +121,4 @@ namespace libtorrent
|
|||
|
||||
#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
|
||||
#endif // TORRENT_DISABLE_ENCRYPTION
|
||||
|
||||
|
|
|
@ -192,6 +192,7 @@ namespace libtorrent
|
|||
if (out_enc_policy == pe_settings::forced)
|
||||
{
|
||||
write_pe1_2_dhkey();
|
||||
if (is_disconnecting()) return;
|
||||
|
||||
m_state = read_pe_dhkey;
|
||||
reset_recv_buffer(dh_key_len);
|
||||
|
@ -214,6 +215,7 @@ namespace libtorrent
|
|||
fast_reconnect(true);
|
||||
|
||||
write_pe1_2_dhkey();
|
||||
if (is_disconnecting()) return;
|
||||
m_state = read_pe_dhkey;
|
||||
reset_recv_buffer(dh_key_len);
|
||||
setup_receive();
|
||||
|
@ -372,7 +374,7 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(!m_encrypted);
|
||||
TORRENT_ASSERT(!m_rc4_encrypted);
|
||||
TORRENT_ASSERT(!m_DH_key_exchange.get());
|
||||
TORRENT_ASSERT(!m_dh_key_exchange.get());
|
||||
TORRENT_ASSERT(!m_sent_handshake);
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
|
@ -380,7 +382,12 @@ namespace libtorrent
|
|||
(*m_logger) << " initiating encrypted handshake\n";
|
||||
#endif
|
||||
|
||||
m_DH_key_exchange.reset(new DH_key_exchange);
|
||||
m_dh_key_exchange.reset(new (std::nothrow) dh_key_exchange);
|
||||
if (!m_dh_key_exchange || !m_dh_key_exchange->good())
|
||||
{
|
||||
disconnect("out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
int pad_size = std::rand() % 512;
|
||||
|
||||
|
@ -389,11 +396,15 @@ namespace libtorrent
|
|||
#endif
|
||||
|
||||
buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size);
|
||||
if (send_buf.begin == 0) return; // out of memory
|
||||
if (send_buf.begin == 0)
|
||||
{
|
||||
disconnect("out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
std::copy(m_DH_key_exchange->get_local_key(),
|
||||
m_DH_key_exchange->get_local_key() + dh_key_len,
|
||||
send_buf.begin);
|
||||
std::copy(m_dh_key_exchange->get_local_key(),
|
||||
m_dh_key_exchange->get_local_key() + dh_key_len,
|
||||
send_buf.begin);
|
||||
|
||||
std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand);
|
||||
setup_send();
|
||||
|
@ -417,7 +428,7 @@ namespace libtorrent
|
|||
|
||||
hasher h;
|
||||
sha1_hash const& info_hash = t->torrent_file().info_hash();
|
||||
char const* const secret = m_DH_key_exchange->get_secret();
|
||||
char const* const secret = m_dh_key_exchange->get_secret();
|
||||
|
||||
int pad_size = rand() % 512;
|
||||
|
||||
|
@ -452,7 +463,7 @@ namespace libtorrent
|
|||
|
||||
// Discard DH key exchange data, setup RC4 keys
|
||||
init_pe_RC4_handler(secret, info_hash);
|
||||
m_DH_key_exchange.reset(); // secret should be invalid at this point
|
||||
m_dh_key_exchange.reset(); // secret should be invalid at this point
|
||||
|
||||
// write the verification constant and crypto field
|
||||
TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2);
|
||||
|
@ -1752,13 +1763,17 @@ namespace libtorrent
|
|||
|
||||
if (!packet_finished()) return;
|
||||
|
||||
// write our dh public key. m_DH_key_exchange is
|
||||
// write our dh public key. m_dh_key_exchange is
|
||||
// initialized in write_pe1_2_dhkey()
|
||||
if (!is_local())
|
||||
write_pe1_2_dhkey();
|
||||
if (!is_local()) write_pe1_2_dhkey();
|
||||
if (is_disconnecting()) return;
|
||||
|
||||
// read dh key, generate shared secret
|
||||
m_DH_key_exchange->compute_secret (recv_buffer.begin); // TODO handle errors
|
||||
if (m_dh_key_exchange->compute_secret(recv_buffer.begin) == -1)
|
||||
{
|
||||
disconnect("out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << " received DH key\n";
|
||||
|
@ -1822,7 +1837,7 @@ namespace libtorrent
|
|||
|
||||
// compute synchash (hash('req1',S))
|
||||
h.update("req1", 4);
|
||||
h.update(m_DH_key_exchange->get_secret(), dh_key_len);
|
||||
h.update(m_dh_key_exchange->get_secret(), dh_key_len);
|
||||
|
||||
m_sync_hash.reset(new sha1_hash(h.final()));
|
||||
}
|
||||
|
@ -1895,7 +1910,7 @@ namespace libtorrent
|
|||
|
||||
h.reset();
|
||||
h.update("req3", 4);
|
||||
h.update(m_DH_key_exchange->get_secret(), dh_key_len);
|
||||
h.update(m_dh_key_exchange->get_secret(), dh_key_len);
|
||||
|
||||
obfs_hash = h.final();
|
||||
obfs_hash ^= skey_hash;
|
||||
|
@ -1912,7 +1927,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(t);
|
||||
}
|
||||
|
||||
init_pe_RC4_handler(m_DH_key_exchange->get_secret(), info_hash);
|
||||
init_pe_RC4_handler(m_dh_key_exchange->get_secret(), info_hash);
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << " stream key found, torrent located.\n";
|
||||
#endif
|
||||
|
@ -2641,7 +2656,7 @@ namespace libtorrent
|
|||
void bt_peer_connection::check_invariant() const
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get())
|
||||
TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get())
|
||||
|| !is_local());
|
||||
|
||||
TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get());
|
||||
|
|
|
@ -42,29 +42,46 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const unsigned char dh_prime[96] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
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()
|
||||
dh_key_exchange::dh_key_exchange()
|
||||
{
|
||||
m_DH = DH_new();
|
||||
if (m_DH == 0) throw std::bad_alloc();
|
||||
m_dh = DH_new();
|
||||
if (m_dh == 0) return;
|
||||
|
||||
m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL);
|
||||
m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL);
|
||||
if (m_DH->p == 0 || m_DH->g == 0)
|
||||
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)
|
||||
{
|
||||
DH_free(m_DH);
|
||||
throw std::bad_alloc();
|
||||
DH_free(m_dh);
|
||||
m_dh = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_DH->length = 160l;
|
||||
m_dh->length = 160l;
|
||||
|
||||
TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));
|
||||
TORRENT_ASSERT(sizeof(dh_prime) == DH_size(m_dh));
|
||||
|
||||
if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0)
|
||||
if (DH_generate_key(m_dh) == 0 || m_dh->pub_key == 0)
|
||||
{
|
||||
DH_free(m_DH);
|
||||
throw std::bad_alloc();
|
||||
DH_free(m_dh);
|
||||
m_dh = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// DH can generate key sizes that are smaller than the size of
|
||||
|
@ -72,42 +89,53 @@ namespace libtorrent
|
|||
// the msb's of m_dh_local_key need to be zeroed
|
||||
// appropriately.
|
||||
int key_size = get_local_key_size();
|
||||
int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH)
|
||||
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);
|
||||
|
||||
int pad_zero_size = len_dh - key_size;
|
||||
std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
|
||||
BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size);
|
||||
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
|
||||
BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value
|
||||
{
|
||||
if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key) == 0)
|
||||
{
|
||||
DH_free(m_dh);
|
||||
m_dh = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DH_key_exchange::~DH_key_exchange()
|
||||
dh_key_exchange::~dh_key_exchange()
|
||||
{
|
||||
TORRENT_ASSERT(m_DH);
|
||||
DH_free(m_DH);
|
||||
if (m_dh) DH_free(m_dh);
|
||||
}
|
||||
|
||||
char const* DH_key_exchange::get_local_key() const
|
||||
char const* dh_key_exchange::get_local_key() const
|
||||
{
|
||||
return m_dh_local_key;
|
||||
}
|
||||
|
||||
|
||||
// compute shared secret given remote public key
|
||||
void DH_key_exchange::compute_secret(char const* remote_pubkey)
|
||||
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) throw std::bad_alloc();
|
||||
if (bn_remote_pubkey == 0) return -1;
|
||||
char dh_secret[96];
|
||||
|
||||
int secret_size = DH_compute_key((unsigned char*)dh_secret
|
||||
, bn_remote_pubkey, m_DH);
|
||||
if (secret_size < 0 || secret_size > 96) throw std::bad_alloc();
|
||||
, bn_remote_pubkey, m_dh);
|
||||
if (secret_size < 0 || secret_size > 96) return -1;
|
||||
|
||||
if (secret_size != 96)
|
||||
{
|
||||
|
@ -116,26 +144,14 @@ namespace libtorrent
|
|||
}
|
||||
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
|
||||
BN_free(bn_remote_pubkey);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char const* DH_key_exchange::get_secret() const
|
||||
char const* dh_key_exchange::get_secret() const
|
||||
{
|
||||
return m_dh_secret;
|
||||
}
|
||||
|
||||
const unsigned char DH_key_exchange::m_dh_prime[96] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
|
||||
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
|
||||
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
|
||||
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
|
||||
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
|
||||
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_key_exchange::m_dh_generator[1] = { 2 };
|
||||
|
||||
} // namespace libtorrent
|
||||
|
||||
#endif // #ifndef TORRENT_DISABLE_ENCRYPTION
|
||||
|
|
Loading…
Reference in New Issue