Base64::Decode throws std::runtime_error on failure. (#3305)
* Throw an exception when base64 decode has bogus inputs Co-authored-by: Ahson Khan <ahkha@microsoft.com>
This commit is contained in:
parent
16b4670a8c
commit
60c075a64e
@ -15,6 +15,9 @@
|
||||
|
||||
- Fixed `Azure::DateTime::Parse()` validation if the result is going to exceed `9999-12-31T23:59:59.9999999` due to time zone, leap second, or fractional digits rounding up adjustments.
|
||||
- [[#3224]](https://github.com/Azure/azure-sdk-for-cpp/issues/3224) Fixed intermittent crash on macOS when logging is turned on.
|
||||
- The `Base64::Decode` API will throw a `std::runtime_error` exception if presented with invalid inputs.
|
||||
|
||||
### Other Changes
|
||||
|
||||
## 1.3.1 (2021-11-05)
|
||||
|
||||
|
||||
@ -382,9 +382,15 @@ static void Base64WriteThreeLowOrderBytes(std::vector<uint8_t>::iterator destina
|
||||
std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||
{
|
||||
auto inputSize = text.size();
|
||||
if (inputSize < 4)
|
||||
if (inputSize % 4 != 0)
|
||||
{
|
||||
return std::vector<uint8_t>(0);
|
||||
throw std::runtime_error("Unexpected end of Base64 encoded string.");
|
||||
}
|
||||
|
||||
// An empty input should result in an empty output.
|
||||
if (inputSize == 0)
|
||||
{
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
size_t sourceIndex = 0;
|
||||
@ -406,6 +412,10 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||
while (sourceIndex + 4 < inputSize)
|
||||
{
|
||||
int64_t result = Base64Decode(inputPtr + sourceIndex);
|
||||
if (result < 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||
}
|
||||
Base64WriteThreeLowOrderBytes(destinationPtr, result);
|
||||
destinationPtr += 3;
|
||||
sourceIndex += 4;
|
||||
@ -436,6 +446,11 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||
i0 |= i3;
|
||||
i0 |= i2;
|
||||
|
||||
if (i0 < 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||
}
|
||||
|
||||
Base64WriteThreeLowOrderBytes(destinationPtr, i0);
|
||||
destinationPtr += 3;
|
||||
}
|
||||
@ -446,6 +461,10 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||
i2 <<= 6;
|
||||
|
||||
i0 |= i2;
|
||||
if (i0 < 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||
}
|
||||
|
||||
destinationPtr[1] = static_cast<uint8_t>(i0 >> 8);
|
||||
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
||||
@ -453,6 +472,11 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i0 < 0)
|
||||
{
|
||||
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||
}
|
||||
|
||||
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
||||
destinationPtr += 1;
|
||||
}
|
||||
|
||||
@ -125,3 +125,49 @@ TEST(Base64, Roundtrip)
|
||||
EXPECT_EQ(Convert::Base64Decode(Convert::Base64Encode(data)), data);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Base64, ValidDecode)
|
||||
{
|
||||
// cspell::disable
|
||||
EXPECT_NO_THROW(Convert::Base64Decode(Convert::Base64Encode(std::vector<uint8_t>{})));
|
||||
EXPECT_NO_THROW(Convert::Base64Decode(""));
|
||||
EXPECT_NO_THROW(Convert::Base64Decode("aa=="));
|
||||
EXPECT_NO_THROW(Convert::Base64Decode("aaa="));
|
||||
// cspell::enable
|
||||
}
|
||||
|
||||
TEST(Base64, InvalidDecode)
|
||||
{
|
||||
// cspell::disable
|
||||
EXPECT_THROW(Convert::Base64Decode("a"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("aa"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("aaa"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("a==="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("===="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("@#!%"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ABCD%GA="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ABCDE^A="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ABCDEF&="), std::runtime_error);
|
||||
|
||||
EXPECT_THROW(Convert::Base64Decode("ABD%GA=="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ABDE^A=="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ABDEF&=="), std::runtime_error);
|
||||
|
||||
EXPECT_THROW(Convert::Base64Decode("AD%GA==="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ADE^A==="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ADEF&==="), std::runtime_error);
|
||||
|
||||
EXPECT_THROW(Convert::Base64Decode("ABCD===="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ADEF====="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("ADEF======"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("QQ======"), std::runtime_error);
|
||||
|
||||
EXPECT_THROW(Convert::Base64Decode("AB===CD="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("AB==CD=="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("AB=CD==="), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("AB====CD"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("AD=====EF"), std::runtime_error);
|
||||
EXPECT_THROW(Convert::Base64Decode("AD======EF"), std::runtime_error);
|
||||
|
||||
// cspell::enable
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ TEST(SimplifiedHeader, core)
|
||||
EXPECT_NO_THROW(Azure::Core::Context c);
|
||||
EXPECT_NO_THROW(Azure::DateTime(2020, 11, 03, 15, 30, 44));
|
||||
EXPECT_NO_THROW(Azure::ETag e);
|
||||
EXPECT_NO_THROW(Azure::Core::Convert::Base64Decode("foo"));
|
||||
EXPECT_NO_THROW(Azure::Core::Convert::Base64Decode("foo="));
|
||||
EXPECT_NO_THROW(Azure::Core::Cryptography::Md5Hash m);
|
||||
EXPECT_NO_THROW(Azure::Core::Http::RawResponse r(
|
||||
1, 1, Azure::Core::Http::HttpStatusCode::Accepted, "phrase"));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user