removed exceptions from pe_crypto and improved error handling

This commit is contained in:
Arvid Norberg 2008-06-28 10:10:05 +00:00
parent 13766dc855
commit d132dd45e3
4 changed files with 107 additions and 76 deletions

View File

@ -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

View File

@ -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

View File

@ -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());

View File

@ -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