Fix error detection in 'base64Decode()'

Fixed a bug in initialization of 'base64DecodeChars' variable.
Currently decoder do not fail on invalid Base64 strings.
Added test-case to verify the fix.

Also have made 'base64DecodeChars' to be computed at compile time.
And added a test case to encode/decode string with non-printable charactes.
This commit is contained in:
Alexey Novikov 2021-10-17 11:51:33 +04:00
parent 130284b850
commit 64a3b045c1
2 changed files with 27 additions and 8 deletions

View file

@ -4,6 +4,8 @@
#include <limits.h> #include <limits.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <numeric>
namespace nix { namespace nix {
/* ----------- tests for util.hh ------------------------------------------------*/ /* ----------- tests for util.hh ------------------------------------------------*/
@ -282,6 +284,17 @@ namespace nix {
ASSERT_EQ(decoded, s); ASSERT_EQ(decoded, s);
} }
TEST(base64Encode, encodeAndDecodeNonPrintable) {
char s[256];
std::iota(std::rbegin(s), std::rend(s), 0);
auto encoded = base64Encode(s);
auto decoded = base64Decode(encoded);
EXPECT_EQ(decoded.length(), 255);
ASSERT_EQ(decoded, s);
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* base64Decode * base64Decode
* --------------------------------------------------------------------------*/ * --------------------------------------------------------------------------*/
@ -294,6 +307,10 @@ namespace nix {
ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum"); ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum");
} }
TEST(base64Decode, decodeThrowsOnInvalidChar) {
ASSERT_THROW(base64Decode("cXVvZCBlcm_0IGRlbW9uc3RyYW5kdW0="), Error);
}
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
* toLower * toLower
* --------------------------------------------------------------------------*/ * --------------------------------------------------------------------------*/

View file

@ -1436,8 +1436,7 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in
} }
static char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static std::array<char, 256> base64DecodeChars;
string base64Encode(std::string_view s) string base64Encode(std::string_view s)
{ {
@ -1462,12 +1461,15 @@ string base64Encode(std::string_view s)
string base64Decode(std::string_view s) string base64Decode(std::string_view s)
{ {
static std::once_flag flag; constexpr char npos = -1;
std::call_once(flag, [](){ constexpr std::array<char, 256> base64DecodeChars = [&]() {
base64DecodeChars = { (char)-1 }; std::array<char, 256> result{};
for (auto& c : result)
c = npos;
for (int i = 0; i < 64; i++) for (int i = 0; i < 64; i++)
base64DecodeChars[(int) base64Chars[i]] = i; result[base64Chars[i]] = i;
}); return result;
}();
string res; string res;
unsigned int d = 0, bits = 0; unsigned int d = 0, bits = 0;
@ -1477,7 +1479,7 @@ string base64Decode(std::string_view s)
if (c == '\n') continue; if (c == '\n') continue;
char digit = base64DecodeChars[(unsigned char) c]; char digit = base64DecodeChars[(unsigned char) c];
if (digit == -1) if (digit == npos)
throw Error("invalid character in Base64 string: '%c'", c); throw Error("invalid character in Base64 string: '%c'", c);
bits += 6; bits += 6;