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.
|
- 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.
|
- [[#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)
|
## 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)
|
std::vector<uint8_t> Base64Decode(const std::string& text)
|
||||||
{
|
{
|
||||||
auto inputSize = text.size();
|
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;
|
size_t sourceIndex = 0;
|
||||||
@ -406,6 +412,10 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
|||||||
while (sourceIndex + 4 < inputSize)
|
while (sourceIndex + 4 < inputSize)
|
||||||
{
|
{
|
||||||
int64_t result = Base64Decode(inputPtr + sourceIndex);
|
int64_t result = Base64Decode(inputPtr + sourceIndex);
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||||
|
}
|
||||||
Base64WriteThreeLowOrderBytes(destinationPtr, result);
|
Base64WriteThreeLowOrderBytes(destinationPtr, result);
|
||||||
destinationPtr += 3;
|
destinationPtr += 3;
|
||||||
sourceIndex += 4;
|
sourceIndex += 4;
|
||||||
@ -436,6 +446,11 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
|||||||
i0 |= i3;
|
i0 |= i3;
|
||||||
i0 |= i2;
|
i0 |= i2;
|
||||||
|
|
||||||
|
if (i0 < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||||
|
}
|
||||||
|
|
||||||
Base64WriteThreeLowOrderBytes(destinationPtr, i0);
|
Base64WriteThreeLowOrderBytes(destinationPtr, i0);
|
||||||
destinationPtr += 3;
|
destinationPtr += 3;
|
||||||
}
|
}
|
||||||
@ -446,6 +461,10 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
|||||||
i2 <<= 6;
|
i2 <<= 6;
|
||||||
|
|
||||||
i0 |= i2;
|
i0 |= i2;
|
||||||
|
if (i0 < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||||
|
}
|
||||||
|
|
||||||
destinationPtr[1] = static_cast<uint8_t>(i0 >> 8);
|
destinationPtr[1] = static_cast<uint8_t>(i0 >> 8);
|
||||||
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
||||||
@ -453,6 +472,11 @@ std::vector<uint8_t> Base64Decode(const std::string& text)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (i0 < 0)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unexpected character in Base64 encoded string");
|
||||||
|
}
|
||||||
|
|
||||||
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
destinationPtr[0] = static_cast<uint8_t>(i0 >> 16);
|
||||||
destinationPtr += 1;
|
destinationPtr += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,3 +125,49 @@ TEST(Base64, Roundtrip)
|
|||||||
EXPECT_EQ(Convert::Base64Decode(Convert::Base64Encode(data)), data);
|
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::Core::Context c);
|
||||||
EXPECT_NO_THROW(Azure::DateTime(2020, 11, 03, 15, 30, 44));
|
EXPECT_NO_THROW(Azure::DateTime(2020, 11, 03, 15, 30, 44));
|
||||||
EXPECT_NO_THROW(Azure::ETag e);
|
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::Cryptography::Md5Hash m);
|
||||||
EXPECT_NO_THROW(Azure::Core::Http::RawResponse r(
|
EXPECT_NO_THROW(Azure::Core::Http::RawResponse r(
|
||||||
1, 1, Azure::Core::Http::HttpStatusCode::Accepted, "phrase"));
|
1, 1, Azure::Core::Http::HttpStatusCode::Accepted, "phrase"));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user