factor encryption handler a bit and add proposal for an authentication extension
This commit is contained in:
192
docs/auth.rst
Normal file
192
docs/auth.rst
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
===================================
|
||||||
|
BitTorrent authentication extension
|
||||||
|
===================================
|
||||||
|
|
||||||
|
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||||
|
:Version: Draft
|
||||||
|
|
||||||
|
.. contents:: Table of contents
|
||||||
|
:depth: 2
|
||||||
|
:backlinks: none
|
||||||
|
|
||||||
|
BitTorrent authentication extension
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
This extension indends to cover any combination of the following use cases:
|
||||||
|
|
||||||
|
1. Verifying that a torrent is published by a trusted source
|
||||||
|
2. Have a swarm be private and having peers authenticate peers they connect to
|
||||||
|
3. Allow peers, with prior knowledge about each other's public key, authenticate in order to set up trusted connections to known peers (i.e. "friends")
|
||||||
|
|
||||||
|
These building blocks could be used for building a web of trust, private
|
||||||
|
swarms and trusted sources for content.
|
||||||
|
|
||||||
|
torrent file extension
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
A .torrent file may have the following new fields (not inside the info-hash):
|
||||||
|
|
||||||
|
"publisher"
|
||||||
|
containing the RSA public key of the publisher of the torrent. Private counterpart
|
||||||
|
of this key that has the authority to allow new peers onto the swarm.
|
||||||
|
|
||||||
|
"signature"
|
||||||
|
The RSA signature of the ``info`` dictionary (specifically, the encrypted SHA-1
|
||||||
|
hash of the ``info`` dictionary).
|
||||||
|
|
||||||
|
These fields serve the purpose of satisfying use case (1), allowing downloaders to
|
||||||
|
verify that the torrent has a trusted source.
|
||||||
|
|
||||||
|
extension handshake
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
In order to satisfy use case (2), any peer supporting this extension MUST verify
|
||||||
|
that each peer on the swarm it connects to and receive an incoming connection from
|
||||||
|
is authenticated by the publisher's public key, if the torrent is *private*.
|
||||||
|
|
||||||
|
A torrent is private if the ``info`` dictionary contains an integer key ``private``
|
||||||
|
set to 1.
|
||||||
|
|
||||||
|
The extension handshake dictionary ("m") SHOULD contain a new extension key "lt_auth".
|
||||||
|
|
||||||
|
For private torrents, the extension handshake dictionary
|
||||||
|
MUST contain the certificate granting this peer access to the torrent. The
|
||||||
|
certificate is a dictionary ``cert`` containing the ``info-hash``,
|
||||||
|
``pubkey`` (the peer's public key), ``expiry`` (posix time of when cert expires).
|
||||||
|
The ``cert`` dictionary MAY be extended with more fields.
|
||||||
|
|
||||||
|
Next to the ``cert`` entry is a string ``sig`` being the signature
|
||||||
|
of the SHA-1 hash of the bencoded representation of the ``cert`` dictionary.
|
||||||
|
The signature is required for private torrents, but not required for non-private
|
||||||
|
torrents.
|
||||||
|
|
||||||
|
An example extension handshake for a private torrent could look like this::
|
||||||
|
|
||||||
|
{
|
||||||
|
"cert": {
|
||||||
|
"expiry": 1333242356,
|
||||||
|
"info-hash": f0fb0ed2d73a28aece3a9e4f91c91cf60e0ea0a6,
|
||||||
|
"pubkey":
|
||||||
|
79eaeecbfc91b129c34880e3113fc9545e7169fed95a7950a335cfcef3dd2989c
|
||||||
|
c80c69d9e66206cdb4e41eeae8b19234804cd55b3eb6dbee15a5362e3fa6eb33b
|
||||||
|
a61297dfc63426832623efdf54816474189ddf1baad1d08cb614ed130f9744671
|
||||||
|
a0c9bdf32747c284955ad9ae65db875f4f74f51e624710fe7c3db5ec8ce55f175
|
||||||
|
b49131cace810d6a61a9fcd0fa4e41e466e09c2a18629f4bebb8dbf4746648122
|
||||||
|
bfc8153e3e76ea16cae62e0e1608effa6bf2f1d1954d2e3ef2ca1db327f75a1aa
|
||||||
|
711ccad6a564821824a2708c20a9184a221554d1228fdaee39ba3ce4134847fab
|
||||||
|
91514d4ed720fabe8082e342dfce15ced93545bdc6
|
||||||
|
},
|
||||||
|
"m": {
|
||||||
|
"lt_auth": 8
|
||||||
|
}
|
||||||
|
"sig":
|
||||||
|
1767303857272cc9133253614712584a3c6be5f81cd777e9e6e99fbf23be27ca9
|
||||||
|
d96c3ad596521f90dd4fb2291d6c9a6108625cf58ca836c3e7f15595306cd9311
|
||||||
|
5c4736276cb4ee08b7f85a5eb26759bfb46b28f36cecfd73e71fac5cad8f22bb6
|
||||||
|
32d07ab4e530587d4fc4d21ae1c52aacbefa0a0dbabb9e24d6c552aaa464a8b94
|
||||||
|
97cc776e3b1b4051dbc9ef26952ab0e74188cbf1ea54f37309ef781d37b59ded7
|
||||||
|
e6ce09a9531cc9916ecbe1fb93369da47ab79457e9709576f737e3d89e3774731
|
||||||
|
d97ac8b1283dc46a382e4ddd5a155b17d6ded6683f508f111c5e974098315c509
|
||||||
|
77d533ddb52f42fa5019342496a217483b622c3a
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
This certificate would expire at ``Sat Mar 31 18:05:56 PDT 2012``. The values of ``sig``,
|
||||||
|
``info-hash`` and ``pubkey`` are binary strings, they are printed as hex in this example.
|
||||||
|
The RSA key size SHOULD be 2048 bits (256 bytes).
|
||||||
|
|
||||||
|
Whenconnecting to a peer, or accepting an incoming connection, for a private torrent,
|
||||||
|
the client MUST verify the validity of the incoming certificate. This is done by:
|
||||||
|
|
||||||
|
1. Verifying that the certificate has not expired.
|
||||||
|
2. Verifying that the ``info-hash`` matches the torrent the peers are connected over
|
||||||
|
3. Verifying that the signature ``sig``, is a valid signature made by the private counterpart of the public key of the publisher of the torrent (i.e. the ``publisher`` key in the torrent file)
|
||||||
|
|
||||||
|
If the certificate fails any one of those checks, the peer MUST be
|
||||||
|
disconnected without exchanging any more information. As an exception, before
|
||||||
|
disconnecting, the peer MAY send an ``lt_auto`` message saying the authentication
|
||||||
|
failed.
|
||||||
|
|
||||||
|
An example extension handshake for a non-private torrent could look like this::
|
||||||
|
|
||||||
|
{
|
||||||
|
"cert": {
|
||||||
|
"pubkey":
|
||||||
|
79eaeecbfc91b129c34880e3113fc9545e7169fed95a7950a335cfcef3dd2989c
|
||||||
|
c80c69d9e66206cdb4e41eeae8b19234804cd55b3eb6dbee15a5362e3fa6eb33b
|
||||||
|
a61297dfc63426832623efdf54816474189ddf1baad1d08cb614ed130f9744671
|
||||||
|
a0c9bdf32747c284955ad9ae65db875f4f74f51e624710fe7c3db5ec8ce55f175
|
||||||
|
b49131cace810d6a61a9fcd0fa4e41e466e09c2a18629f4bebb8dbf4746648122
|
||||||
|
bfc8153e3e76ea16cae62e0e1608effa6bf2f1d1954d2e3ef2ca1db327f75a1aa
|
||||||
|
711ccad6a564821824a2708c20a9184a221554d1228fdaee39ba3ce4134847fab
|
||||||
|
91514d4ed720fabe8082e342dfce15ced93545bdc6
|
||||||
|
},
|
||||||
|
"m": {
|
||||||
|
"lt_auth": 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that the only required field in the ``cert`` in this case is the ``pubkey``,
|
||||||
|
The assumption in this case is that the public key is recognized by the client
|
||||||
|
matched by a local directory of trusted peers. This is to support use case (3).
|
||||||
|
|
||||||
|
extension message
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The ``lt_auth`` extension message is used to protect against man-in-the-middle attacks,
|
||||||
|
and peers trying to assume someone else's identity. To do this, the entire connection
|
||||||
|
is encrypted with RC4 following this message. If the connection is already encrypted
|
||||||
|
with RC4, this overrides that encryption by resetting the encryption state.
|
||||||
|
|
||||||
|
It has the following format:
|
||||||
|
|
||||||
|
============= ============= ======================================================
|
||||||
|
size name description
|
||||||
|
============= ============= ======================================================
|
||||||
|
uint8_t type 0 = encrypt the connection with RC4 using the symmetric
|
||||||
|
key passed in this message.
|
||||||
|
1 = signature verification failed
|
||||||
|
2 = info-hash verification failed
|
||||||
|
3 = certificate expired
|
||||||
|
------------- ------------- ------------------------------------------------------
|
||||||
|
uint8_t[256] rc4_key If type is not 0, this field is not included.
|
||||||
|
The symmetric key the sender of this message will use
|
||||||
|
to encrypt every message following this one. The key
|
||||||
|
is encrypted with the recipient's public key. The
|
||||||
|
length of this field may vary, but for 2048 RSA keys
|
||||||
|
it ends up being 256 bytes.
|
||||||
|
============= ============= ======================================================
|
||||||
|
|
||||||
|
Note that this message is somewhat of a layer violation, since it reaches down and
|
||||||
|
starts encrypting the entire stream below itself. This is illustrated in the figure
|
||||||
|
below.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
+---------------------------+
|
||||||
|
| BitTorrent messages | -----+ lt_auth reaches down
|
||||||
|
+---------------------------+ | to the layer below
|
||||||
|
| (RC4 protocol encryption) | <----+
|
||||||
|
+-------------+-------------+
|
||||||
|
| TCP | uTP |
|
||||||
|
+----------+--+-----+-------+
|
||||||
|
|
||||||
|
applications
|
||||||
|
------------
|
||||||
|
|
||||||
|
This is a low level building block and not a complete system for authenticated or
|
||||||
|
private swarms. It does allow for peers to verify that a torrent comes from a
|
||||||
|
trusted source (assuming their public key is known in advance). It also allows
|
||||||
|
for publishers to limit access to content.
|
||||||
|
|
||||||
|
For privacy reasons, it is possible to apply this extension in a way that each peer
|
||||||
|
uses separate identities (key pairs) for every torrent it participates in.
|
||||||
|
|
||||||
|
Issues not covered by this extension are:
|
||||||
|
|
||||||
|
1. How the distribution of signed certificates are distributed to peers from
|
||||||
|
the signing authority (publisher), for use case (2).
|
||||||
|
2. How peers discover each other and and *pair* by recognizing each other's
|
||||||
|
public keys for future trusted connections, for use case (3).
|
||||||
|
3. How peers learn about the public keys of trusted publishers, for use case (1).
|
||||||
|
|
@@ -6,6 +6,7 @@ TARGETS = index \
|
|||||||
udp_tracker_protocol \
|
udp_tracker_protocol \
|
||||||
dht_rss \
|
dht_rss \
|
||||||
dht_store \
|
dht_store \
|
||||||
|
auth \
|
||||||
client_test \
|
client_test \
|
||||||
manual \
|
manual \
|
||||||
building \
|
building \
|
||||||
|
@@ -283,8 +283,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
// stream key (info hash of attached torrent)
|
// stream key (info hash of attached torrent)
|
||||||
// secret is the DH shared secret
|
// secret is the DH shared secret
|
||||||
// initializes m_RC4_handler
|
// initializes m_rc4_handler
|
||||||
void init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key);
|
void init_pe_rc4_handler(char const* secret, sha1_hash const& stream_key);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ public:
|
|||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
if (m_rc4_encrypted)
|
if (m_rc4_encrypted)
|
||||||
m_RC4_handler->encrypt(buffer, size);
|
m_rc4_handler->encrypt(buffer, size);
|
||||||
#endif
|
#endif
|
||||||
peer_connection::append_send_buffer(buffer, size, destructor, true);
|
peer_connection::append_send_buffer(buffer, size, destructor, true);
|
||||||
}
|
}
|
||||||
@@ -410,17 +410,17 @@ private:
|
|||||||
int m_sync_bytes_read;
|
int m_sync_bytes_read;
|
||||||
|
|
||||||
// initialized during write_pe1_2_dhkey, and destroyed on
|
// initialized during write_pe1_2_dhkey, and destroyed on
|
||||||
// creation of m_RC4_handler. Cannot reinitialize once
|
// creation of m_rc4_handler. Cannot reinitialize once
|
||||||
// initialized.
|
// 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
|
// if RC4 is negotiated, this is used for
|
||||||
// encryption/decryption during the entire session. Destroyed
|
// encryption/decryption during the entire session. Destroyed
|
||||||
// if plaintext is selected
|
// if plaintext is selected
|
||||||
boost::scoped_ptr<RC4_handler> m_RC4_handler;
|
boost::scoped_ptr<rc4_handler> m_rc4_handler;
|
||||||
|
|
||||||
// (outgoing only) synchronize verification constant with
|
// (outgoing only) synchronize verification constant with
|
||||||
// remote peer, this will hold RC4_decrypt(vc). Destroyed
|
// remote peer, this will hold rc4_decrypt(vc). Destroyed
|
||||||
// after the sync step.
|
// after the sync step.
|
||||||
boost::scoped_array<char> m_sync_vc;
|
boost::scoped_array<char> m_sync_vc;
|
||||||
|
|
||||||
|
@@ -85,33 +85,55 @@ namespace libtorrent
|
|||||||
sha1_hash m_xor_mask;
|
sha1_hash m_xor_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RC4_handler // Non copyable
|
class rc4_handler // Non copyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Input longkeys must be 20 bytes
|
// Input longkeys must be 20 bytes
|
||||||
RC4_handler(sha1_hash const& rc4_local_longkey,
|
rc4_handler()
|
||||||
sha1_hash const& rc4_remote_longkey)
|
: m_encrypt(false)
|
||||||
|
, m_decrypt(false)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_USE_GCRYPT
|
#ifdef TORRENT_USE_GCRYPT
|
||||||
gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
||||||
gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
||||||
gcry_cipher_setkey(m_rc4_incoming, &rc4_remote_longkey[0], 20);
|
|
||||||
gcry_cipher_setkey(m_rc4_outgoing, &rc4_local_longkey[0], 20);
|
|
||||||
#elif defined TORRENT_USE_OPENSSL
|
|
||||||
RC4_set_key(&m_local_key, 20, &rc4_local_longkey[0]);
|
|
||||||
RC4_set_key(&m_remote_key, 20, &rc4_remote_longkey[0]);
|
|
||||||
#else
|
|
||||||
rc4_init(&rc4_remote_longkey[0], 20, &m_rc4_incoming);
|
|
||||||
rc4_init(&rc4_local_longkey[0], 20, &m_rc4_outgoing);
|
|
||||||
#endif
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_incoming_key(unsigned char const* key, int len)
|
||||||
|
{
|
||||||
|
m_decrypt = true;
|
||||||
|
#ifdef TORRENT_USE_GCRYPT
|
||||||
|
gcry_cipher_close(m_rc4_incoming);
|
||||||
|
gcry_cipher_open(&m_rc4_incoming, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
||||||
|
gcry_cipher_setkey(m_rc4_incoming, key, len);
|
||||||
|
#elif defined TORRENT_USE_OPENSSL
|
||||||
|
RC4_set_key(&m_remote_key, len, key);
|
||||||
|
#else
|
||||||
|
rc4_init(key, len, &m_rc4_incoming);
|
||||||
|
#endif
|
||||||
|
// Discard first 1024 bytes
|
||||||
|
char buf[1024];
|
||||||
|
decrypt(buf, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_outgoing_key(unsigned char const* key, int len)
|
||||||
|
{
|
||||||
|
m_encrypt = true;
|
||||||
|
#ifdef TORRENT_USE_GCRYPT
|
||||||
|
gcry_cipher_close(m_rc4_outgoing);
|
||||||
|
gcry_cipher_open(&m_rc4_outgoing, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0);
|
||||||
|
gcry_cipher_setkey(m_rc4_outgoing, key, len);
|
||||||
|
#elif defined TORRENT_USE_OPENSSL
|
||||||
|
RC4_set_key(&m_local_key, len, key);
|
||||||
|
#else
|
||||||
|
rc4_init(key, len, &m_rc4_outgoing);
|
||||||
|
#endif
|
||||||
// Discard first 1024 bytes
|
// Discard first 1024 bytes
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
encrypt(buf, 1024);
|
encrypt(buf, 1024);
|
||||||
decrypt(buf, 1024);
|
}
|
||||||
};
|
|
||||||
|
|
||||||
~RC4_handler()
|
~rc4_handler()
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_USE_GCRYPT
|
#ifdef TORRENT_USE_GCRYPT
|
||||||
gcry_cipher_close(m_rc4_incoming);
|
gcry_cipher_close(m_rc4_incoming);
|
||||||
@@ -121,6 +143,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
void encrypt(char* pos, int len)
|
void encrypt(char* pos, int len)
|
||||||
{
|
{
|
||||||
|
if (!m_encrypt) return;
|
||||||
|
|
||||||
TORRENT_ASSERT(len >= 0);
|
TORRENT_ASSERT(len >= 0);
|
||||||
TORRENT_ASSERT(pos);
|
TORRENT_ASSERT(pos);
|
||||||
|
|
||||||
@@ -135,6 +159,8 @@ namespace libtorrent
|
|||||||
|
|
||||||
void decrypt(char* pos, int len)
|
void decrypt(char* pos, int len)
|
||||||
{
|
{
|
||||||
|
if (!m_decrypt) return;
|
||||||
|
|
||||||
TORRENT_ASSERT(len >= 0);
|
TORRENT_ASSERT(len >= 0);
|
||||||
TORRENT_ASSERT(pos);
|
TORRENT_ASSERT(pos);
|
||||||
|
|
||||||
@@ -158,6 +184,9 @@ namespace libtorrent
|
|||||||
rc4 m_rc4_incoming;
|
rc4 m_rc4_incoming;
|
||||||
rc4 m_rc4_outgoing;
|
rc4 m_rc4_outgoing;
|
||||||
#endif
|
#endif
|
||||||
|
// determines whether or not encryption and decryption is enabled
|
||||||
|
bool m_encrypt;
|
||||||
|
bool m_decrypt;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace libtorrent
|
} // namespace libtorrent
|
||||||
|
@@ -380,9 +380,9 @@ namespace libtorrent
|
|||||||
#ifndef TORRENT_DISABLE_ENCRYPTION
|
#ifndef TORRENT_DISABLE_ENCRYPTION
|
||||||
if (m_encrypted)
|
if (m_encrypted)
|
||||||
{
|
{
|
||||||
m_rc4_encrypted ?
|
p.flags |= m_rc4_encrypted
|
||||||
p.flags |= peer_info::rc4_encrypted :
|
? peer_info::rc4_encrypted
|
||||||
p.flags |= peer_info::plaintext_encrypted;
|
: peer_info::plaintext_encrypted;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -493,7 +493,7 @@ namespace libtorrent
|
|||||||
ptr += 20;
|
ptr += 20;
|
||||||
|
|
||||||
// Discard DH key exchange data, setup RC4 keys
|
// Discard DH key exchange data, setup RC4 keys
|
||||||
init_pe_RC4_handler(secret, info_hash);
|
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
|
// write the verification constant and crypto field
|
||||||
@@ -516,7 +516,7 @@ namespace libtorrent
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size);
|
write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size);
|
||||||
m_RC4_handler->encrypt(ptr, encrypt_size);
|
m_rc4_handler->encrypt(ptr, encrypt_size);
|
||||||
send_buffer(msg, sizeof(msg) - 512 + pad_size);
|
send_buffer(msg, sizeof(msg) - 512 + pad_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +536,7 @@ namespace libtorrent
|
|||||||
char msg[512 + 8 + 4 + 2];
|
char msg[512 + 8 + 4 + 2];
|
||||||
write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size);
|
write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size);
|
||||||
|
|
||||||
m_RC4_handler->encrypt(msg, buf_size);
|
m_rc4_handler->encrypt(msg, buf_size);
|
||||||
send_buffer(msg, buf_size);
|
send_buffer(msg, buf_size);
|
||||||
|
|
||||||
// encryption method has been negotiated
|
// encryption method has been negotiated
|
||||||
@@ -581,7 +581,7 @@ namespace libtorrent
|
|||||||
detail::write_uint16(handshake_len, write_buf); // len(IA)
|
detail::write_uint16(handshake_len, write_buf); // len(IA)
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_peer_connection::init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key)
|
void bt_peer_connection::init_pe_rc4_handler(char const* secret, sha1_hash const& stream_key)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
@@ -595,7 +595,7 @@ namespace libtorrent
|
|||||||
// outgoing connection : hash ('keyA',S,SKEY)
|
// outgoing connection : hash ('keyA',S,SKEY)
|
||||||
// incoming connection : hash ('keyB',S,SKEY)
|
// incoming connection : hash ('keyB',S,SKEY)
|
||||||
|
|
||||||
is_local() ? h.update(keyA, 4) : h.update(keyB, 4);
|
if (is_local()) h.update(keyA, 4); else h.update(keyB, 4);
|
||||||
h.update(secret, dh_key_len);
|
h.update(secret, dh_key_len);
|
||||||
h.update((char const*)stream_key.begin(), 20);
|
h.update((char const*)stream_key.begin(), 20);
|
||||||
const sha1_hash local_key = h.final();
|
const sha1_hash local_key = h.final();
|
||||||
@@ -606,14 +606,16 @@ namespace libtorrent
|
|||||||
// outgoing connection : hash ('keyB',S,SKEY)
|
// outgoing connection : hash ('keyB',S,SKEY)
|
||||||
// incoming connection : hash ('keyA',S,SKEY)
|
// incoming connection : hash ('keyA',S,SKEY)
|
||||||
|
|
||||||
is_local() ? h.update(keyB, 4) : h.update(keyA, 4);
|
if (is_local()) h.update(keyB, 4); else h.update(keyA, 4);
|
||||||
h.update(secret, dh_key_len);
|
h.update(secret, dh_key_len);
|
||||||
h.update((char const*)stream_key.begin(), 20);
|
h.update((char const*)stream_key.begin(), 20);
|
||||||
const sha1_hash remote_key = h.final();
|
const sha1_hash remote_key = h.final();
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_RC4_handler.get());
|
TORRENT_ASSERT(!m_rc4_handler.get());
|
||||||
m_RC4_handler.reset(new (std::nothrow) RC4_handler(local_key, remote_key));
|
m_rc4_handler.reset(new (std::nothrow) rc4_handler);
|
||||||
if (!m_RC4_handler)
|
m_rc4_handler->set_incoming_key(&remote_key[0], 20);
|
||||||
|
m_rc4_handler->set_outgoing_key(&local_key[0], 20);
|
||||||
|
if (!m_rc4_handler)
|
||||||
{
|
{
|
||||||
disconnect(errors::no_memory);
|
disconnect(errors::no_memory);
|
||||||
return;
|
return;
|
||||||
@@ -644,7 +646,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
void encrypt(char* buf, int len, void* userdata)
|
void encrypt(char* buf, int len, void* userdata)
|
||||||
{
|
{
|
||||||
RC4_handler* rc4 = (RC4_handler*)userdata;
|
rc4_handler* rc4 = (rc4_handler*)userdata;
|
||||||
rc4->encrypt(buf, len);
|
rc4->encrypt(buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,7 +661,7 @@ namespace libtorrent
|
|||||||
if (m_encrypted && m_rc4_encrypted)
|
if (m_encrypted && m_rc4_encrypted)
|
||||||
{
|
{
|
||||||
fun = encrypt;
|
fun = encrypt;
|
||||||
userdata = m_RC4_handler.get();
|
userdata = m_rc4_handler.get();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2322,8 +2324,8 @@ namespace libtorrent
|
|||||||
if (m_rc4_encrypted && m_encrypted)
|
if (m_rc4_encrypted && m_encrypted)
|
||||||
{
|
{
|
||||||
std::pair<buffer::interval, buffer::interval> wr_buf = wr_recv_buffers(bytes_transferred);
|
std::pair<buffer::interval, buffer::interval> wr_buf = wr_recv_buffers(bytes_transferred);
|
||||||
m_RC4_handler->decrypt(wr_buf.first.begin, wr_buf.first.left());
|
m_rc4_handler->decrypt(wr_buf.first.begin, wr_buf.first.left());
|
||||||
if (wr_buf.second.left()) m_RC4_handler->decrypt(wr_buf.second.begin, wr_buf.second.left());
|
if (wr_buf.second.left()) m_rc4_handler->decrypt(wr_buf.second.begin, wr_buf.second.left());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2507,7 +2509,7 @@ namespace libtorrent
|
|||||||
TORRENT_ASSERT(t);
|
TORRENT_ASSERT(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_pe_RC4_handler(m_dh_key_exchange->get_secret(), ti.info_hash());
|
init_pe_rc4_handler(m_dh_key_exchange->get_secret(), ti.info_hash());
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("*** stream key found, torrent located");
|
peer_log("*** stream key found, torrent located");
|
||||||
#endif
|
#endif
|
||||||
@@ -2515,7 +2517,7 @@ namespace libtorrent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_RC4_handler.get())
|
if (!m_rc4_handler.get())
|
||||||
{
|
{
|
||||||
disconnect(errors::invalid_info_hash, 1);
|
disconnect(errors::invalid_info_hash, 1);
|
||||||
return;
|
return;
|
||||||
@@ -2523,7 +2525,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
// verify constant
|
// verify constant
|
||||||
buffer::interval wr_recv_buf = wr_recv_buffer();
|
buffer::interval wr_recv_buf = wr_recv_buffer();
|
||||||
m_RC4_handler->decrypt(wr_recv_buf.begin + 20, 8);
|
m_rc4_handler->decrypt(wr_recv_buf.begin + 20, 8);
|
||||||
wr_recv_buf.begin += 28;
|
wr_recv_buf.begin += 28;
|
||||||
|
|
||||||
const char sh_vc[] = {0,0,0,0, 0,0,0,0};
|
const char sh_vc[] = {0,0,0,0, 0,0,0,0};
|
||||||
@@ -2568,7 +2570,7 @@ namespace libtorrent
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0);
|
std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0);
|
||||||
m_RC4_handler->decrypt(m_sync_vc.get(), 8);
|
m_rc4_handler->decrypt(m_sync_vc.get(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(m_sync_vc.get());
|
TORRENT_ASSERT(m_sync_vc.get());
|
||||||
@@ -2626,7 +2628,7 @@ namespace libtorrent
|
|||||||
if (!packet_finished()) return;
|
if (!packet_finished()) return;
|
||||||
|
|
||||||
buffer::interval wr_buf = wr_recv_buffer();
|
buffer::interval wr_buf = wr_recv_buffer();
|
||||||
m_RC4_handler->decrypt(wr_buf.begin, packet_size());
|
m_rc4_handler->decrypt(wr_buf.begin, packet_size());
|
||||||
|
|
||||||
recv_buffer = receive_buffer();
|
recv_buffer = receive_buffer();
|
||||||
|
|
||||||
@@ -2749,7 +2751,7 @@ namespace libtorrent
|
|||||||
int pad_size = is_local() ? packet_size() : packet_size() - 2;
|
int pad_size = is_local() ? packet_size() : packet_size() - 2;
|
||||||
|
|
||||||
buffer::interval wr_buf = wr_recv_buffer();
|
buffer::interval wr_buf = wr_recv_buffer();
|
||||||
m_RC4_handler->decrypt(wr_buf.begin, packet_size());
|
m_rc4_handler->decrypt(wr_buf.begin, packet_size());
|
||||||
|
|
||||||
recv_buffer = receive_buffer();
|
recv_buffer = receive_buffer();
|
||||||
|
|
||||||
@@ -2798,7 +2800,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
// ia is always rc4, so decrypt it
|
// ia is always rc4, so decrypt it
|
||||||
buffer::interval wr_buf = wr_recv_buffer();
|
buffer::interval wr_buf = wr_recv_buffer();
|
||||||
m_RC4_handler->decrypt(wr_buf.begin, packet_size());
|
m_rc4_handler->decrypt(wr_buf.begin, packet_size());
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("*** decrypted ia : %d bytes", packet_size());
|
peer_log("*** decrypted ia : %d bytes", packet_size());
|
||||||
@@ -2806,7 +2808,7 @@ namespace libtorrent
|
|||||||
|
|
||||||
if (!m_rc4_encrypted)
|
if (!m_rc4_encrypted)
|
||||||
{
|
{
|
||||||
m_RC4_handler.reset();
|
m_rc4_handler.reset();
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("*** destroyed rc4 keys");
|
peer_log("*** destroyed rc4 keys");
|
||||||
#endif
|
#endif
|
||||||
@@ -2830,14 +2832,14 @@ namespace libtorrent
|
|||||||
{
|
{
|
||||||
buffer::interval wr_buf = wr_recv_buffer();
|
buffer::interval wr_buf = wr_recv_buffer();
|
||||||
wr_buf.begin += packet_size();
|
wr_buf.begin += packet_size();
|
||||||
m_RC4_handler->decrypt(wr_buf.begin, wr_buf.left());
|
m_rc4_handler->decrypt(wr_buf.begin, wr_buf.left());
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("*** decrypted remaining %d bytes", wr_buf.left());
|
peer_log("*** decrypted remaining %d bytes", wr_buf.left());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else // !m_rc4_encrypted
|
else // !m_rc4_encrypted
|
||||||
{
|
{
|
||||||
m_RC4_handler.reset();
|
m_rc4_handler.reset();
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log("*** destroyed rc4 keys");
|
peer_log("*** destroyed rc4 keys");
|
||||||
#endif
|
#endif
|
||||||
@@ -3301,7 +3303,7 @@ namespace libtorrent
|
|||||||
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());
|
|| !is_local());
|
||||||
|
|
||||||
TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get());
|
TORRENT_ASSERT(!m_rc4_encrypted || m_rc4_handler.get());
|
||||||
#endif
|
#endif
|
||||||
if (!in_handshake())
|
if (!in_handshake())
|
||||||
{
|
{
|
||||||
|
@@ -156,8 +156,12 @@ int test_main()
|
|||||||
sha1_hash test1_key = hasher("test1_key",8).final();
|
sha1_hash test1_key = hasher("test1_key",8).final();
|
||||||
sha1_hash test2_key = hasher("test2_key",8).final();
|
sha1_hash test2_key = hasher("test2_key",8).final();
|
||||||
|
|
||||||
RC4_handler RC41(test2_key, test1_key);
|
rc4_handler rc41;
|
||||||
RC4_handler RC42(test1_key, test2_key);
|
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)
|
for (int rep = 0; rep < repcount; ++rep)
|
||||||
{
|
{
|
||||||
@@ -168,12 +172,12 @@ int test_main()
|
|||||||
std::fill(buf, buf + buf_len, 0);
|
std::fill(buf, buf + buf_len, 0);
|
||||||
std::fill(zero_buf, zero_buf + buf_len, 0);
|
std::fill(zero_buf, zero_buf + buf_len, 0);
|
||||||
|
|
||||||
RC41.encrypt(buf, buf_len);
|
rc41.encrypt(buf, buf_len);
|
||||||
RC42.decrypt(buf, buf_len);
|
rc42.decrypt(buf, buf_len);
|
||||||
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
|
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
|
||||||
|
|
||||||
RC42.encrypt(buf, buf_len);
|
rc42.encrypt(buf, buf_len);
|
||||||
RC41.decrypt(buf, buf_len);
|
rc41.decrypt(buf, buf_len);
|
||||||
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
|
TEST_CHECK(std::equal(buf, buf + buf_len, zero_buf));
|
||||||
|
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
|
Reference in New Issue
Block a user