From 5c43b5c23c9e35965b12a5a409dfeab8103ca1dc Mon Sep 17 00:00:00 2001 From: Mike Gelfand Date: Thu, 4 Dec 2014 19:58:34 +0000 Subject: [PATCH] #4400, #5462: Move BASE64 helpers to crypto-utils On a way to factoring out OpenSSL support to a standalone file to ease addition of other crypto libraries support in the future, move helpers providing BASE64 encoding and decoding to crypto-utils.{c,h}. OpenSSL- related functionality is moved to crypto-utils-openssl.c. Add new functions to be implemented by crypto backends: * tr_base64_encode_impl - encode from binary to BASE64, * tr_base64_decode_impl - decode from BASE64 to binary. Change `tr_base64_encode` and `tr_base64_decode` functions to expect non-negative input data length which is considered real and never adjusted. To process null-terminated strings (which was achieved before by passing 0 or -1 as input data length), add new `tr_base64_encode_str` and `tr_base64_decode_str` functions which do not accept input data length as an argument but calculate it on their own. --- daemon/remote.c | 8 ++- libtransmission/crypto-test.c | 69 ++++++++++++++++++- libtransmission/crypto-utils-openssl.c | 91 ++++++++++++++++++++++++++ libtransmission/crypto-utils.c | 76 ++++++++++++++++++++- libtransmission/crypto-utils.h | 56 +++++++++++++++- libtransmission/libtransmission-test.c | 5 +- libtransmission/rename-test.c | 5 +- libtransmission/rpc-server.c | 4 +- libtransmission/rpcimpl.c | 5 +- libtransmission/utils-test.c | 23 ------- libtransmission/utils.c | 76 --------------------- libtransmission/utils.h | 16 ----- qt/add-data.cc | 14 ++-- 13 files changed, 312 insertions(+), 136 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 4f8cfffc3..91b5b6912 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -1191,9 +1192,9 @@ printPeers (tr_variant * top) } static void -printPiecesImpl (const uint8_t * raw, size_t rawlen, int64_t j) +printPiecesImpl (const uint8_t * raw, size_t rawlen, size_t j) { - int i, k, len; + size_t i, k, len; char * str = tr_base64_decode (raw, rawlen, &len); printf (" "); for (i=k=0; k= 0); + printPiecesImpl (raw, rawlen, (size_t) j); if (i+1 +#include #include +#include #include #include #include @@ -301,3 +303,92 @@ tr_rand_buffer (void * buffer, return check_result (RAND_bytes (buffer, (int) length)); } + +/*** +**** +***/ + +void * +tr_base64_encode_impl (const void * input, + size_t input_length, + size_t * output_length) +{ + char * ret = NULL; + int ret_length = 0; + BIO * bmem; + BIO * b64; + + assert (input != NULL); + assert (input_length > 0); + + bmem = BIO_new (BIO_s_mem ()); + b64 = BIO_new (BIO_f_base64 ()); + + BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); + b64 = BIO_push (b64, bmem); + + if (check_result_eq (BIO_write (b64, input, input_length), (int) input_length) && + check_result (BIO_flush (b64))) + { + BUF_MEM * bptr; + + BIO_get_mem_ptr (b64, &bptr); + ret = tr_strndup (bptr->data, bptr->length); + ret_length = bptr->length; + } + + BIO_free_all (b64); + + if (output_length != NULL) + *output_length = (size_t) ret_length; + + return ret; +} + +void * +tr_base64_decode_impl (const void * input, + size_t input_length, + size_t * output_length) +{ + char * ret; + int ret_length; + int i; + + assert (input != NULL); + assert (input_length > 0); + + ret = tr_new (char, input_length + 1); + + /* try two times, without and with BIO_FLAGS_BASE64_NO_NL flag */ + for (i = 0; i < 2; ++i) + { + BIO * bmem = BIO_new_mem_buf ((void *) input, (int) input_length); + BIO * b64 = BIO_new (BIO_f_base64 ()); + + BIO_set_flags (b64, i == 1 ? BIO_FLAGS_BASE64_NO_NL : 0); + bmem = BIO_push (b64, bmem); + + ret_length = BIO_read (bmem, ret, (int) input_length); + if (ret_length < 0 && i == 1) + log_error (); + + BIO_free_all (bmem); + + /* < 0 - fatal error, > 0 - success*/ + if (ret_length != 0) + break; + } + + if (ret_length < 0) + { + tr_free (ret); + return NULL; + } + + ret[ret_length] = '\0'; + + if (output_length != NULL) + *output_length = (size_t) ret_length; + + return ret; +} diff --git a/libtransmission/crypto-utils.c b/libtransmission/crypto-utils.c index a11cdee53..b91c268cb 100644 --- a/libtransmission/crypto-utils.c +++ b/libtransmission/crypto-utils.c @@ -10,7 +10,7 @@ #include #include #include /* abs (), srand (), rand () */ -#include /* memmove (), memset () */ +#include /* memmove (), memset (), strlen () */ #include "transmission.h" #include "crypto-utils.h" @@ -115,3 +115,77 @@ tr_rand_int_weak (int upper_bound) return rand () % upper_bound; } + +/*** +**** +***/ + +void * +tr_base64_encode (const void * input, + size_t input_length, + size_t * output_length) +{ + char * ret; + + if (input != NULL) + { + if (input_length != 0) + { + if ((ret = tr_base64_encode_impl (input, input_length, output_length)) != NULL) + return ret; + } + else + ret = tr_strdup (""); + } + else + { + ret = NULL; + } + + if (output_length != NULL) + *output_length = 0; + + return ret; +} + +void * +tr_base64_encode_str (const char * input, + size_t * output_length) +{ + return tr_base64_encode (input, input == NULL ? 0 : strlen (input), output_length); +} + +void * +tr_base64_decode (const void * input, + size_t input_length, + size_t * output_length) +{ + char * ret; + + if (input != NULL) + { + if (input_length != 0) + { + if ((ret = tr_base64_decode_impl (input, input_length, output_length)) != NULL) + return ret; + } + else + ret = tr_strdup (""); + } + else + { + ret = NULL; + } + + if (output_length != NULL) + *output_length = 0; + + return ret; +} + +void * +tr_base64_decode_str (const char * input, + size_t * output_length) +{ + return tr_base64_decode (input, input == NULL ? 0 : strlen (input), output_length); +} diff --git a/libtransmission/crypto-utils.h b/libtransmission/crypto-utils.h index 3091443b6..de8e34075 100644 --- a/libtransmission/crypto-utils.h +++ b/libtransmission/crypto-utils.h @@ -13,7 +13,11 @@ #include #include -#include "utils.h" /* TR_GNUC_NULL_TERMINATED */ +#include "utils.h" /* TR_GNUC_MALLOC, TR_GNUC_NULL_TERMINATED */ + +#ifdef __cplusplus +extern "C" { +#endif /** *** @addtogroup utils Utilities @@ -150,6 +154,56 @@ int tr_rand_int_weak (int upper_bound); bool tr_rand_buffer (void * buffer, size_t length); +/** + * @brief Translate a block of bytes into base64. + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_encode (const void * input, + size_t input_length, + size_t * output_length) TR_GNUC_MALLOC; + +/** + * @brief Translate null-terminated string into base64. + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_encode_str (const char * input, + size_t * output_length) TR_GNUC_MALLOC; + +/** + * @brief Translate a block of bytes into base64 (internal, do not use). + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_encode_impl (const void * input, + size_t input_length, + size_t * output_length) TR_GNUC_MALLOC; + +/** + * @brief Translate a block of bytes from base64 into raw form. + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_decode (const void * input, + size_t input_length, + size_t * output_length) TR_GNUC_MALLOC; + +/** + * @brief Translate null-terminated string from base64 into raw form. + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_decode_str (const char * input, + size_t * output_length) TR_GNUC_MALLOC; + +/** + * @brief Translate null-terminated string from base64 into raw form (internal, do not use). + * @return a newly-allocated null-terminated string that can be freed with tr_free () + */ +void * tr_base64_decode_impl (const void * input, + size_t input_length, + size_t * output_length) TR_GNUC_MALLOC; + /** @} */ +#ifdef __cplusplus +} +#endif + #endif /* TR_CRYPTO_UTILS_H */ diff --git a/libtransmission/libtransmission-test.c b/libtransmission/libtransmission-test.c index 032f3e2e2..83ceadbfd 100644 --- a/libtransmission/libtransmission-test.c +++ b/libtransmission/libtransmission-test.c @@ -14,6 +14,7 @@ #include #include "transmission.h" +#include "crypto-utils.h" #include "error.h" #include "file.h" #include "platform.h" /* TR_PATH_DELIMETER */ @@ -310,7 +311,7 @@ tr_torrent * libttest_zero_torrent_init (tr_session * session) { int err; - int metainfo_len; + size_t metainfo_len; char * metainfo; const char * metainfo_base64; tr_torrent * tor; @@ -342,7 +343,7 @@ libttest_zero_torrent_init (tr_session * session) "OnByaXZhdGVpMGVlZQ=="; /* create the torrent ctor */ - metainfo = tr_base64_decode (metainfo_base64, -1, &metainfo_len); + metainfo = tr_base64_decode_str (metainfo_base64, &metainfo_len); assert (metainfo != NULL); assert (metainfo_len > 0); assert (session != NULL); diff --git a/libtransmission/rename-test.c b/libtransmission/rename-test.c index a48fcac75..aad099689 100644 --- a/libtransmission/rename-test.c +++ b/libtransmission/rename-test.c @@ -15,6 +15,7 @@ #include /* sync() */ #include "transmission.h" +#include "crypto-utils.h" #include "file.h" #include "resume.h" #include "torrent.h" /* tr_isTorrent() */ @@ -101,12 +102,12 @@ static tr_torrent * create_torrent_from_base64_metainfo (tr_ctor * ctor, const char * metainfo_base64) { int err; - int metainfo_len; + size_t metainfo_len; char * metainfo; tr_torrent * tor; /* create the torrent ctor */ - metainfo = tr_base64_decode (metainfo_base64, -1, &metainfo_len); + metainfo = tr_base64_decode_str (metainfo_base64, &metainfo_len); assert (metainfo != NULL); assert (metainfo_len > 0); tr_ctorSetMetainfo (ctor, (uint8_t*)metainfo, metainfo_len); diff --git a/libtransmission/rpc-server.c b/libtransmission/rpc-server.c index 367819493..505408ace 100644 --- a/libtransmission/rpc-server.c +++ b/libtransmission/rpc-server.c @@ -611,8 +611,8 @@ handle_request (struct evhttp_request * req, void * arg) auth = evhttp_find_header (req->input_headers, "Authorization"); if (auth && !evutil_ascii_strncasecmp (auth, "basic ", 6)) { - int plen; - char * p = tr_base64_decode (auth + 6, 0, &plen); + size_t plen; + char * p = tr_base64_decode_str (auth + 6, &plen); if (p && plen && ((pass = strchr (p, ':')))) { user = p; diff --git a/libtransmission/rpcimpl.c b/libtransmission/rpcimpl.c index fab0a207f..33621e93f 100644 --- a/libtransmission/rpcimpl.c +++ b/libtransmission/rpcimpl.c @@ -19,6 +19,7 @@ #include "transmission.h" #include "completion.h" +#include "crypto-utils.h" #include "error.h" #include "fdlimit.h" #include "file.h" @@ -1796,8 +1797,8 @@ torrentAdd (tr_session * session, if (fname == NULL) { - int len; - char * metainfo = tr_base64_decode (metainfo_base64, -1, &len); + size_t len; + char * metainfo = tr_base64_decode_str (metainfo_base64, &len); tr_ctorSetMetainfo (ctor, (uint8_t*)metainfo, len); tr_free (metainfo); } diff --git a/libtransmission/utils-test.c b/libtransmission/utils-test.c index 2ff9b8b7f..d9fb93091 100644 --- a/libtransmission/utils-test.c +++ b/libtransmission/utils-test.c @@ -36,28 +36,6 @@ #include "libtransmission-test.h" -static int -test_base64 (void) -{ - int len; - char *in, *out; - - /* base64 */ - out = tr_base64_encode ("YOYO!", -1, &len); - check_streq ("WU9ZTyE=", out); - check_int_eq (8, len); - in = tr_base64_decode (out, -1, &len); - check_streq ("YOYO!", in); - check_int_eq (5, len); - tr_free (in); - tr_free (out); - out = tr_base64_encode (NULL, 0, &len); - check (out == NULL); - check_int_eq (0, len); - - return 0; -} - static int test_strip_positional_args (void) { @@ -518,7 +496,6 @@ int main (void) { const testFunc tests[] = { test_array, - test_base64, test_buildpath, test_hex, test_lowerbound, diff --git a/libtransmission/utils.c b/libtransmission/utils.c index 4c0792d3e..d1f98729a 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -812,82 +812,6 @@ tr_urlParse (const char * url_in, return err; } -#include -#include -#include -#include -#include -#include - -char * -tr_base64_encode (const void * input, int length, int * setme_len) -{ - int retlen = 0; - char * ret = NULL; - - if (input != NULL) - { - BIO * b64; - BIO * bmem; - BUF_MEM * bptr; - - if (length < 1) - length = (int)strlen (input); - - bmem = BIO_new (BIO_s_mem ()); - b64 = BIO_new (BIO_f_base64 ()); - BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); - b64 = BIO_push (b64, bmem); - BIO_write (b64, input, length); - (void) BIO_flush (b64); - BIO_get_mem_ptr (b64, &bptr); - ret = tr_strndup (bptr->data, bptr->length); - retlen = bptr->length; - BIO_free_all (b64); - } - - if (setme_len) - *setme_len = retlen; - - return ret; -} - -char * -tr_base64_decode (const void * input, - int length, - int * setme_len) -{ - char * ret; - BIO * b64; - BIO * bmem; - int retlen; - - if (length < 1) - length = strlen (input); - - ret = tr_new0 (char, length); - b64 = BIO_new (BIO_f_base64 ()); - bmem = BIO_new_mem_buf ((unsigned char*)input, length); - bmem = BIO_push (b64, bmem); - retlen = BIO_read (bmem, ret, length); - if (!retlen) - { - /* try again, but with the BIO_FLAGS_BASE64_NO_NL flag */ - BIO_free_all (bmem); - b64 = BIO_new (BIO_f_base64 ()); - BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL); - bmem = BIO_new_mem_buf ((unsigned char*)input, length); - bmem = BIO_push (b64, bmem); - retlen = BIO_read (bmem, ret, length); - } - - if (setme_len) - *setme_len = retlen; - - BIO_free_all (bmem); - return ret; -} - /*** **** ***/ diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 8cda66f8c..3e6f2d88f 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -287,22 +287,6 @@ char* tr_strdup_printf (const char * fmt, ...) TR_GNUC_PRINTF (1, 2) char * tr_strdup_vprintf (const char * fmt, va_list args) TR_GNUC_MALLOC; -/** - * @brief Translate a block of bytes into base64 - * @return a newly-allocated string that can be freed with tr_free () - */ -char* tr_base64_encode (const void * input, - int inlen, - int * outlen) TR_GNUC_MALLOC; - -/** - * @brief Translate a block of bytes from base64 into raw form - * @return a newly-allocated string that can be freed with tr_free () - */ -char* tr_base64_decode (const void * input, - int inlen, - int * outlen) TR_GNUC_MALLOC; - /** @brief Portability wrapper for strlcpy () that uses the system implementation if available */ size_t tr_strlcpy (char * dst, const void * src, size_t siz); diff --git a/qt/add-data.cc b/qt/add-data.cc index 3ce5b36ef..b9f4979ad 100644 --- a/qt/add-data.cc +++ b/qt/add-data.cc @@ -11,7 +11,7 @@ #include #include -#include // tr_base64_encode() +#include // tr_base64_encode() #include "add-data.h" #include "utils.h" @@ -46,11 +46,11 @@ AddData :: set (const QString& key) } else { - int len; - char * raw = tr_base64_decode (key.toUtf8().constData(), key.toUtf8().size(), &len); + size_t len; + void * raw = tr_base64_decode (key.toUtf8().constData(), key.toUtf8().size(), &len); if (raw) { - metainfo.append (raw, len); + metainfo.append (static_cast (raw), (int) len); tr_free (raw); type = METAINFO; } @@ -70,9 +70,9 @@ AddData :: toBase64 () const if (!metainfo.isEmpty ()) { - int len = 0; - char * b64 = tr_base64_encode (metainfo.constData(), metainfo.size(), &len); - ret = QByteArray (b64, len); + size_t len; + void * b64 = tr_base64_encode (metainfo.constData(), metainfo.size(), &len); + ret = QByteArray (static_cast (b64), (int) len); tr_free (b64); } -- 2.40.0