From 1ebab1e3b74e4c9c435e4806402e0a4503d0f59c Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Thu, 8 Jun 2017 11:22:14 +0200 Subject: [PATCH] base64 encoder/decoder: Add parameter to control linefeed handling openssl is very strict about if the input data of the decoder contains linefeeds or not. Therefore make it a parameter and default to "one line" base64 output/input. Add unit test cases. --- src/stringfunc.cpp | 12 ++++++++---- src/stringfunc.hxx | 4 ++-- test/stringfunc.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/stringfunc.cpp b/src/stringfunc.cpp index 3813a1c..3c8ce1a 100644 --- a/src/stringfunc.cpp +++ b/src/stringfunc.cpp @@ -712,9 +712,10 @@ static std::string _convert_BIO_to_string(BIO *input) * Data size limit is 2GB on 32 bit (LONG_MAX) * * @param input String to encode + * @param one_line Encode all data as one line, no wrapping with line feeds * @return base64 encoded string */ -std::string base64_encode(const std::string &input) +std::string base64_encode(const std::string &input, bool one_line) { // check for empty buffer if (input.empty()) @@ -727,7 +728,8 @@ std::string base64_encode(const std::string &input) // setup encoder. Note: BIO_free_all frees both BIOs. BIO_Ptr base64_encoder(BIO_new(BIO_f_base64()), BIO_free_all); BIO *encoder_bio = base64_encoder.get(); - BIO_set_flags(encoder_bio, BIO_FLAGS_BASE64_NO_NL); + if (one_line) + BIO_set_flags(encoder_bio, BIO_FLAGS_BASE64_NO_NL); // chain output buffer and encoder together BIO *encoded_result = BIO_new(BIO_s_mem()); @@ -752,9 +754,10 @@ std::string base64_encode(const std::string &input) * @brief base64 decode a string using OpenSSL base64 functions * * @param input String to decode + * @param one_line Expect all base64 data in one line. Input with line feeds will fail. * @return base64 decoded string */ -std::string base64_decode(const std::string &input) +std::string base64_decode(const std::string &input, bool one_line) { // check for empty buffer if (input.empty()) @@ -767,7 +770,8 @@ std::string base64_decode(const std::string &input) // setup encoder. Note: BIO_free_all frees both BIOs. BIO_Ptr base64_decoder(BIO_new(BIO_f_base64()), BIO_free_all); BIO *bio_base64 = base64_decoder.get(); - BIO_set_flags(bio_base64, BIO_FLAGS_BASE64_NO_NL); + if (one_line) + BIO_set_flags(bio_base64, BIO_FLAGS_BASE64_NO_NL); // chain input buffer and decoder together BIO *bio_input = BIO_new_mem_buf((void*)input.c_str(), input.size()); diff --git a/src/stringfunc.hxx b/src/stringfunc.hxx index 3a5d038..01d2882 100644 --- a/src/stringfunc.hxx +++ b/src/stringfunc.hxx @@ -267,8 +267,8 @@ std::string to_string(const T& v) */ std::string shorten_stl_types(const std::string &input); -std::string base64_encode(const std::string &input); -std::string base64_decode(const std::string &input); +std::string base64_encode(const std::string &input, bool one_line=true); +std::string base64_decode(const std::string &input, bool one_line=true); } // eo namespace I2n diff --git a/test/stringfunc.cpp b/test/stringfunc.cpp index 604f446..38c8e71 100644 --- a/test/stringfunc.cpp +++ b/test/stringfunc.cpp @@ -882,6 +882,21 @@ BOOST_AUTO_TEST_CASE(base64_large_string_with_zero) BOOST_CHECK_EQUAL(large_binary_data, decoded); } +BOOST_AUTO_TEST_CASE(base64_large_string_with_zero_encode_linefeeds) +{ + // 10 MB data + int data_size = 1024 * 1024 * 10; + + string large_binary_data(data_size, 0); + BOOST_CHECK_EQUAL(data_size, large_binary_data.size()); + + const bool one_line_mode = false; + string encoded = base64_encode(large_binary_data, one_line_mode); + + string decoded = base64_decode(encoded, one_line_mode); + BOOST_CHECK_EQUAL(large_binary_data, decoded); +} + BOOST_AUTO_TEST_CASE(base64_decode_garbage) { std::string data = "Hello World, this is unencoded data"; @@ -891,4 +906,28 @@ BOOST_AUTO_TEST_CASE(base64_decode_garbage) BOOST_CHECK_EQUAL(0, decoded.size()); } +BOOST_AUTO_TEST_CASE(base64_encode_with_linefeeds) +{ + const string data = string("Hello World\n") + + "Hello World\n" + + "Hello World\n" + + "Hello World\n" + + "Hello World\n" + + "Hello World\n" + + "Hello World\n"; + + const string encoded = base64_encode(data, false); + + const std::string expected = string("SGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQK\n") + + "SGVsbG8gV29ybGQKSGVsbG8gV29ybGQKSGVsbG8gV29ybGQK\n"; + BOOST_CHECK_EQUAL(expected, encoded); + + // decode and compare + BOOST_CHECK_EQUAL(data, base64_decode(encoded, false)); + + // expected empty string when switching on single line base64 mode + // (openssl is very strict about this) + BOOST_CHECK_EQUAL("", base64_decode(encoded, true)); +} + BOOST_AUTO_TEST_SUITE_END() -- 1.7.1