diff --git a/libtransmission/crypto-utils-openssl.c b/libtransmission/crypto-utils-openssl.c index 187288875..e054ec495 100644 --- a/libtransmission/crypto-utils-openssl.c +++ b/libtransmission/crypto-utils-openssl.c @@ -16,6 +16,7 @@ #include "transmission.h" #include "crypto-utils.h" #include "log.h" +#include "utils.h" /*** **** @@ -131,6 +132,59 @@ tr_sha1_final (tr_sha1_ctx_t handle, **** ***/ +tr_rc4_ctx_t +tr_rc4_new (void) +{ + EVP_CIPHER_CTX * handle = EVP_CIPHER_CTX_new (); + + if (check_result (EVP_CipherInit_ex (handle, EVP_rc4 (), NULL, NULL, NULL, -1))) + return handle; + + EVP_CIPHER_CTX_free (handle); + return NULL; +} + +void +tr_rc4_free (tr_rc4_ctx_t handle) +{ + if (handle == NULL) + return; + + EVP_CIPHER_CTX_free (handle); +} + +void +tr_rc4_set_key (tr_rc4_ctx_t handle, + const uint8_t * key, + size_t key_length) +{ + assert (handle != NULL); + assert (key != NULL); + + if (!check_result (EVP_CIPHER_CTX_set_key_length (handle, key_length))) + return; + check_result (EVP_CipherInit_ex (handle, NULL, NULL, key, NULL, -1)); +} + +void +tr_rc4_process (tr_rc4_ctx_t handle, + const void * input, + void * output, + size_t length) +{ + int output_length; + + assert (handle != NULL); + assert (input != NULL); + assert (output != NULL); + + check_result (EVP_CipherUpdate (handle, output, &output_length, input, length)); +} + +/*** +**** +***/ + bool tr_rand_buffer (void * buffer, size_t length) diff --git a/libtransmission/crypto-utils.h b/libtransmission/crypto-utils.h index a839775c6..024728780 100644 --- a/libtransmission/crypto-utils.h +++ b/libtransmission/crypto-utils.h @@ -22,6 +22,8 @@ /** @brief Opaque SHA1 context type. */ typedef void * tr_sha1_ctx_t; + /** @brief Opaque RC4 context type. */ +typedef void * tr_rc4_ctx_t; /** * @brief Generate a SHA1 hash from one or more chunks of memory. @@ -48,6 +50,32 @@ bool tr_sha1_update (tr_sha1_ctx_t handle, */ bool tr_sha1_final (tr_sha1_ctx_t handle, uint8_t * hash); + +/** + * @brief Allocate and initialize new RC4 cipher context. + */ +tr_rc4_ctx_t tr_rc4_new (void); + +/** + * @brief Free RC4 cipher context. + */ +void tr_rc4_free (tr_rc4_ctx_t handle); + +/** + * @brief Set RC4 cipher key. + */ +void tr_rc4_set_key (tr_rc4_ctx_t handle, + const uint8_t * key, + size_t key_length); + +/** + * @brief Process memory block with RC4 cipher. + */ +void tr_rc4_process (tr_rc4_ctx_t handle, + const void * input, + void * output, + size_t length); + /** * @brief Returns a random number in the range of [0...upper_bound). */ diff --git a/libtransmission/crypto.c b/libtransmission/crypto.c index 31b8bf9b9..974bd3d54 100644 --- a/libtransmission/crypto.c +++ b/libtransmission/crypto.c @@ -9,12 +9,11 @@ #include #include -#include /* memcpy (), memset (), strcmp () */ +#include /* memcpy (), memmove (), memset (), strcmp () */ #include #include #include -#include #include "transmission.h" #include "crypto.h" @@ -118,6 +117,8 @@ tr_cryptoDestruct (tr_crypto * crypto) { if (crypto->dh != NULL) DH_free (crypto->dh); + tr_rc4_free (crypto->enc_key); + tr_rc4_free (crypto->dec_key); } /** @@ -171,21 +172,24 @@ tr_cryptoGetMyPublicKey (const tr_crypto * crypto, **/ static void -initRC4 (tr_crypto * crypto, - RC4_KEY * setme, - const char * key) +initRC4 (tr_crypto * crypto, + tr_rc4_ctx_t * setme, + const char * key) { uint8_t buf[SHA_DIGEST_LENGTH]; assert (crypto->torrentHashIsSet); assert (crypto->mySecretIsSet); + if (*setme == NULL) + *setme = tr_rc4_new (); + if (tr_sha1 (buf, key, 4, crypto->mySecret, KEY_LEN, crypto->torrentHash, SHA_DIGEST_LENGTH, NULL)) - RC4_set_key (setme, SHA_DIGEST_LENGTH, buf); + tr_rc4_set_key (*setme, buf, SHA_DIGEST_LENGTH); } void @@ -195,7 +199,7 @@ tr_cryptoDecryptInit (tr_crypto * crypto) const char * txt = crypto->isIncoming ? "keyA" : "keyB"; initRC4 (crypto, &crypto->dec_key, txt); - RC4 (&crypto->dec_key, sizeof (discard), discard, discard); + tr_rc4_process (crypto->dec_key, discard, discard, sizeof (discard)); } void @@ -204,9 +208,15 @@ tr_cryptoDecrypt (tr_crypto * crypto, const void * buf_in, void * buf_out) { - RC4 (&crypto->dec_key, buf_len, - (const unsigned char*)buf_in, - (unsigned char*)buf_out); + /* FIXME: someone calls this function with uninitialized key */ + if (crypto->dec_key == NULL) + { + if (buf_in != buf_out) + memmove (buf_out, buf_in, buf_len); + return; + } + + tr_rc4_process (crypto->dec_key, buf_in, buf_out, buf_len); } void @@ -216,7 +226,7 @@ tr_cryptoEncryptInit (tr_crypto * crypto) const char * txt = crypto->isIncoming ? "keyB" : "keyA"; initRC4 (crypto, &crypto->enc_key, txt); - RC4 (&crypto->enc_key, sizeof (discard), discard, discard); + tr_rc4_process (crypto->enc_key, discard, discard, sizeof (discard)); } void @@ -225,9 +235,15 @@ tr_cryptoEncrypt (tr_crypto * crypto, const void * buf_in, void * buf_out) { - RC4 (&crypto->enc_key, buf_len, - (const unsigned char*)buf_in, - (unsigned char*)buf_out); + /* FIXME: someone calls this function with uninitialized key */ + if (crypto->enc_key == NULL) + { + if (buf_in != buf_out) + memmove (buf_out, buf_in, buf_len); + return; + } + + tr_rc4_process (crypto->enc_key, buf_in, buf_out, buf_len); } /** diff --git a/libtransmission/crypto.h b/libtransmission/crypto.h index 985c90141..2a0baf554 100644 --- a/libtransmission/crypto.h +++ b/libtransmission/crypto.h @@ -16,6 +16,7 @@ #include +#include "crypto-utils.h" #include "utils.h" /* TR_GNUC_NULL_TERMINATED */ /** @@ -23,8 +24,7 @@ *** @{ **/ -#include /* RC4_KEY */ -#include /* DH */ +#include /* DH */ enum { @@ -34,8 +34,8 @@ enum /** @brief Holds state information for encrypted peer communications */ typedef struct { - RC4_KEY dec_key; - RC4_KEY enc_key; + tr_rc4_ctx_t dec_key; + tr_rc4_ctx_t enc_key; DH * dh; uint8_t myPublicKey[KEY_LEN]; uint8_t mySecret[KEY_LEN];