base64 encoder/decoder: Add parameter to control linefeed handling
authorThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 8 Jun 2017 09:22:14 +0000 (11:22 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Thu, 8 Jun 2017 09:22:14 +0000 (11:22 +0200)
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
src/stringfunc.hxx
test/stringfunc.cpp

index 3813a1c..3c8ce1a 100644 (file)
@@ -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());
index 3a5d038..01d2882 100644 (file)
@@ -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
 
index 604f446..38c8e71 100644 (file)
@@ -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()