#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.
This commit is contained in:
Mike Gelfand 2014-12-04 19:58:34 +00:00
parent 117ab3e8d2
commit 5c43b5c23c
13 changed files with 312 additions and 136 deletions

View File

@ -20,6 +20,7 @@
#include <curl/curl.h>
#include <libtransmission/transmission.h>
#include <libtransmission/crypto-utils.h>
#include <libtransmission/error.h>
#include <libtransmission/file.h>
#include <libtransmission/log.h>
@ -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<len; ++k) {
@ -1225,7 +1226,8 @@ printPieces (tr_variant * top)
tr_variant * torrent = tr_variantListChild (torrents, i);
if (tr_variantDictFindRaw (torrent, TR_KEY_pieces, &raw, &rawlen) &&
tr_variantDictFindInt (torrent, TR_KEY_pieceCount, &j)) {
printPiecesImpl (raw, rawlen, j);
assert (j >= 0);
printPiecesImpl (raw, rawlen, (size_t) j);
if (i+1<n)
printf ("\n");
}

View File

@ -183,6 +183,72 @@ test_random (void)
return 0;
}
static int
test_base64 (void)
{
size_t len;
char * in, * out;
int i;
out = tr_base64_encode_str ("YOYO!", &len);
check_int_eq (8, len);
check_streq ("WU9ZTyE=", out);
in = tr_base64_decode_str (out, &len);
check_int_eq (5, len);
check_streq ("YOYO!", in);
tr_free (in);
tr_free (out);
out = tr_base64_encode ("", 0, &len);
check_int_eq (0, len);
check_streq ("", out);
out = tr_base64_decode ("", 0, &len);
check_int_eq (0, len);
check_streq ("", out);
out = tr_base64_encode (NULL, 0, &len);
check_int_eq (0, len);
check (out == NULL);
out = tr_base64_decode (NULL, 0, &len);
check_int_eq (0, len);
check (out == NULL);
#define MAX_BUF_SIZE 1024
for (i = 1; i <= MAX_BUF_SIZE; ++i)
{
int j;
char buf[MAX_BUF_SIZE + 1];
for (j = 0; j < i; ++j)
buf[j] = tr_rand_int_weak (256);
out = tr_base64_encode (buf, j, &len);
check_int_eq ((j + 2) / 3 * 4, len);
in = tr_base64_decode (out, len, &len);
check_int_eq (j, len);
check (memcmp (in, buf, len) == 0);
tr_free (in);
tr_free (out);
for (j = 0; j < i; ++j)
buf[j] = 1 + tr_rand_int_weak (255);
buf[j] = '\0';
out = tr_base64_encode_str (buf, &len);
check_int_eq ((j + 2) / 3 * 4, len);
in = tr_base64_decode_str (out, &len);
check_int_eq (j, len);
check_streq (in, buf);
tr_free (in);
tr_free (out);
}
#undef MAX_BUF_SIZE
return 0;
}
int
main (void)
{
@ -190,7 +256,8 @@ main (void)
test_encrypt_decrypt,
test_sha1,
test_ssha1,
test_random };
test_random,
test_base64 };
return runTests (tests, NUM_TESTS (tests));
}

View File

@ -9,7 +9,9 @@
#include <assert.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/buffer.h>
#include <openssl/dh.h>
#include <openssl/err.h>
#include <openssl/evp.h>
@ -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;
}

View File

@ -10,7 +10,7 @@
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h> /* abs (), srand (), rand () */
#include <string.h> /* memmove (), memset () */
#include <string.h> /* 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);
}

View File

@ -13,7 +13,11 @@
#include <inttypes.h>
#include <stddef.h>
#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 */

View File

@ -14,6 +14,7 @@
#include <unistd.h>
#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);

View File

@ -15,6 +15,7 @@
#include <unistd.h> /* 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);

View File

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

View File

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

View File

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

View File

@ -812,82 +812,6 @@ tr_urlParse (const char * url_in,
return err;
}
#include <string.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
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;
}
/***
****
***/

View File

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

View File

@ -11,7 +11,7 @@
#include <QDir>
#include <libtransmission/transmission.h>
#include <libtransmission/utils.h> // tr_base64_encode()
#include <libtransmission/crypto-utils.h> // 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<const char*> (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<const char*> (b64), (int) len);
tr_free (b64);
}