forked from premiere/premiere-libtorrent
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
|
||||
{
|
||||
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];
|
||||
|
@ -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,10 +396,14 @@ 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,
|
||||
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);
|
||||
|
@ -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,88 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
// Set the prime P and the generator, generate local public key
|
||||
DH_key_exchange::DH_key_exchange()
|
||||
namespace
|
||||
{
|
||||
m_DH = DH_new();
|
||||
if (m_DH == 0) throw std::bad_alloc();
|
||||
|
||||
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)
|
||||
{
|
||||
DH_free(m_DH);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
m_DH->length = 160l;
|
||||
|
||||
TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));
|
||||
|
||||
if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0)
|
||||
{
|
||||
DH_free(m_DH);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
// 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(m_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);
|
||||
}
|
||||
else
|
||||
BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value
|
||||
}
|
||||
|
||||
DH_key_exchange::~DH_key_exchange()
|
||||
{
|
||||
TORRENT_ASSERT(m_DH);
|
||||
DH_free(m_DH);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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();
|
||||
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();
|
||||
|
||||
if (secret_size != 96)
|
||||
{
|
||||
TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
|
||||
std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
|
||||
}
|
||||
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
|
||||
BN_free(bn_remote_pubkey);
|
||||
}
|
||||
|
||||
char const* DH_key_exchange::get_secret() const
|
||||
{
|
||||
return m_dh_secret;
|
||||
}
|
||||
|
||||
const unsigned char DH_key_exchange::m_dh_prime[96] = {
|
||||
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,
|
||||
|
@ -134,7 +55,102 @@ namespace libtorrent
|
|||
0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
|
||||
};
|
||||
|
||||
const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 };
|
||||
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;
|
||||
|
||||
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);
|
||||
m_dh = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_dh->length = 160l;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dh_key_exchange::~dh_key_exchange()
|
||||
{
|
||||
if (m_dh) DH_free(m_dh);
|
||||
}
|
||||
|
||||
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);
|
||||
BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
|
||||
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) return -1;
|
||||
|
||||
if (secret_size != 96)
|
||||
{
|
||||
TORRENT_ASSERT(secret_size < 96 && secret_size > 0);
|
||||
std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0);
|
||||
}
|
||||
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
|
||||
{
|
||||
return m_dh_secret;
|
||||
}
|
||||
|
||||
} // namespace libtorrent
|
||||
|
||||
|
|
Loading…
Reference in New Issue