From 07ea10f73837f297404f71ec41c1713ec80deba8 Mon Sep 17 00:00:00 2001 From: Dane Walton Date: Wed, 14 Sep 2022 12:19:26 -0500 Subject: [PATCH 1/3] merge base64url --- CHANGELOG.md | 2 + sdk/inc/azure/core/az_base64.h | 35 ++++++ sdk/src/azure/core/az_base64.c | 122 +++++++++++++++---- sdk/tests/core/test_az_base64.c | 207 ++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d2034ff99..c5e12a6c8b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Features Added +[[#2329](https://github.com/Azure/azure-sdk-for-c/pull/2329)] Add Base64 URL decoder. + ### Breaking Changes ### Bugs Fixed diff --git a/sdk/inc/azure/core/az_base64.h b/sdk/inc/azure/core/az_base64.h index 2710a0a10f..09ad08cbfd 100644 --- a/sdk/inc/azure/core/az_base64.h +++ b/sdk/inc/azure/core/az_base64.h @@ -84,6 +84,41 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* */ AZ_NODISCARD int32_t az_base64_get_max_decoded_size(int32_t source_base64_text_size); +/** + * @brief Decodes the span of UTF-8 encoded text represented as base 64 url into binary data. + * + * @param destination_bytes The output #az_span where the decoded binary data should be copied to as + * a result of the operation. + * @param[in] source_base64_url_text The input #az_span that contains the base 64 text to be + * decoded. + * @param[out] out_written A pointer to an `int32_t` that receives the number of bytes written into + * the destination #az_span. This can be used to slice the output for subsequent calls, if + * necessary. + * + * @return An #az_result value indicating the result of the operation. + * @retval #AZ_OK Success. + * @retval #AZ_ERROR_NOT_ENOUGH_SPACE The \p destination_bytes is not large enough to contain + * the decoded text. + * @retval #AZ_ERROR_UNEXPECTED_CHAR The input \p source_base64_url_text contains characters outside + * of the expected base 64 range or is incomplete (that is, has length % 4 == 1 characters). + * @retval #AZ_ERROR_UNEXPECTED_END The input \p source_base64_url_text is incomplete (that is, it + * is of a size which is length % 4 == 1 characters). + */ +AZ_NODISCARD az_result az_base64_url_decode( + az_span destination_bytes, + az_span source_base64_url_text, + int32_t* out_written); + +/** + * @brief Returns the maximum length of the result if you were to decode an #az_span of the + * specified length which contained base 64 url encoded text. + * + * @param source_base64_url_text_size The size of the span containing base 64 encoded text. + * + * @return The maximum length of the result. + */ +AZ_NODISCARD int32_t az_base64_url_get_max_decoded_size(int32_t source_base64_url_text_size); + #include #endif // _az_BASE64_H diff --git a/sdk/src/azure/core/az_base64.c b/sdk/src/azure/core/az_base64.c index 689c1d6c0b..7fc70285ad 100644 --- a/sdk/src/azure/core/az_base64.c +++ b/sdk/src/azure/core/az_base64.c @@ -12,6 +12,12 @@ #define _az_ENCODING_PAD '=' +typedef enum +{ + _az_base64_mode_standard, + _az_base64_mode_url +} _az_base64_mode; + static char const _az_base64_encode_array[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -370,17 +376,40 @@ AZ_NODISCARD int32_t az_base64_get_max_encoded_size(int32_t source_bytes_size) return (((source_bytes_size + 2) / 3) * 4); } -static AZ_NODISCARD int32_t _az_base64_decode(uint8_t* encoded_bytes) +static int32_t _get_base64_decoded_char(int32_t index, _az_base64_mode mode) +{ + if (mode == _az_base64_mode_url) + { + if (index == '+' || index == '/') + { + return -1; // can't use + or / with URL encoding + } + + if (index == '-') + { + index = '+'; // - becomes a + + } + else if (index == '_') + { + index = '/'; // _ becomes a / + } + } + + return _az_base64_decode_array[index]; +} + +static AZ_NODISCARD int32_t +_az_base64_decode_four_bytes(uint8_t* encoded_bytes, _az_base64_mode mode) { int32_t i0 = *encoded_bytes; int32_t i1 = *(encoded_bytes + 1); int32_t i2 = *(encoded_bytes + 2); int32_t i3 = *(encoded_bytes + 3); - i0 = _az_base64_decode_array[i0]; - i1 = _az_base64_decode_array[i1]; - i2 = _az_base64_decode_array[i2]; - i3 = _az_base64_decode_array[i3]; + i0 = _get_base64_decoded_char(i0, mode); + i1 = _get_base64_decoded_char(i1, mode); + i2 = _get_base64_decoded_char(i2, mode); + i3 = _get_base64_decoded_char(i3, mode); i0 <<= 18; i1 <<= 12; @@ -400,26 +429,18 @@ static void _az_base64_write_three_low_order_bytes(uint8_t* destination, int32_t *(destination + 2) = (uint8_t)(value); } -AZ_NODISCARD az_result -az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* out_written) +static az_result _az_base64_decode( + az_span destination_bytes, + az_span source_base64_url_text, + int32_t* out_written, + _az_base64_mode mode) { - _az_PRECONDITION_VALID_SPAN(destination_bytes, 1, false); - _az_PRECONDITION_VALID_SPAN(source_base64_text, 2, false); - _az_PRECONDITION_NOT_NULL(out_written); - - int32_t source_length = az_span_size(source_base64_text); - uint8_t* source_ptr = az_span_ptr(source_base64_text); + int32_t source_length = az_span_size(source_base64_url_text); + uint8_t* source_ptr = az_span_ptr(source_base64_url_text); int32_t destination_length = az_span_size(destination_bytes); uint8_t* destination_ptr = az_span_ptr(destination_bytes); - // The input must be non-empty and a minimum of two characters long. - // There can only be two assumed padding characters. - if (source_length == 0 || source_length % 4 == 1) - { - return AZ_ERROR_UNEXPECTED_END; - } - if (destination_length < az_base64_get_max_decoded_size(source_length) - 2) { return AZ_ERROR_NOT_ENOUGH_SPACE; @@ -430,7 +451,7 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* while (source_index < source_length - 4) { - int32_t result = _az_base64_decode(source_ptr + source_index); + int32_t result = _az_base64_decode_four_bytes(source_ptr + source_index, mode); if (result < 0) { return AZ_ERROR_UNEXPECTED_CHAR; @@ -441,6 +462,8 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* source_index += 4; } + // If using standard base64 decoding, there is a precondition guaranteeing size is divisible by 4. + // Otherwise with url encoding, we can assume padding characters. // If length is divisible by four, do nothing. Else, we assume up to two padding characters. int32_t source_length_mod_four = source_length % 4; int32_t i0 = *(source_ptr + source_index); @@ -450,8 +473,8 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* ? _az_ENCODING_PAD : *(source_ptr + source_index + 3); - i0 = _az_base64_decode_array[i0]; - i1 = _az_base64_decode_array[i1]; + i0 = _get_base64_decoded_char(i0, mode); + i1 = _get_base64_decoded_char(i1, mode); i0 <<= 18; i1 <<= 12; @@ -460,8 +483,8 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* if (i3 != _az_ENCODING_PAD) { - i2 = _az_base64_decode_array[i2]; - i3 = _az_base64_decode_array[i3]; + i2 = _get_base64_decoded_char(i2, mode); + i3 = _get_base64_decoded_char(i3, mode); i2 <<= 6; @@ -481,7 +504,7 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* } else if (i2 != _az_ENCODING_PAD) { - i2 = _az_base64_decode_array[i2]; + i2 = _get_base64_decoded_char(i2, mode); i2 <<= 6; @@ -517,8 +540,55 @@ az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* return AZ_OK; } +AZ_NODISCARD az_result +az_base64_decode(az_span destination_bytes, az_span source_base64_text, int32_t* out_written) +{ + _az_PRECONDITION_VALID_SPAN(destination_bytes, 1, false); + _az_PRECONDITION_VALID_SPAN(source_base64_text, 4, false); + _az_PRECONDITION_NOT_NULL(out_written); + + int32_t source_length = az_span_size(source_base64_text); + + // The input must be non-empty and a multiple of 4 to be valid. + if (source_length == 0 || source_length % 4 != 0) + { + return AZ_ERROR_UNEXPECTED_END; + } + + return _az_base64_decode( + destination_bytes, source_base64_text, out_written, _az_base64_mode_standard); +} + AZ_NODISCARD int32_t az_base64_get_max_decoded_size(int32_t source_base64_text_size) { _az_PRECONDITION(source_base64_text_size >= 0); return (source_base64_text_size / 4) * 3; } + +AZ_NODISCARD az_result az_base64_url_decode( + az_span destination_bytes, + az_span source_base64_url_text, + int32_t* out_written) +{ + _az_PRECONDITION_VALID_SPAN(destination_bytes, 1, false); + _az_PRECONDITION_VALID_SPAN(source_base64_url_text, 2, false); + _az_PRECONDITION_NOT_NULL(out_written); + + int32_t source_length = az_span_size(source_base64_url_text); + + // The input must be non-empty and a minimum of two characters long. + // There can only be two assumed padding characters. + if (source_length == 0 || source_length % 4 == 1) + { + return AZ_ERROR_UNEXPECTED_END; + } + + return _az_base64_decode( + destination_bytes, source_base64_url_text, out_written, _az_base64_mode_url); +} + +AZ_NODISCARD int32_t az_base64_url_get_max_decoded_size(int32_t source_base64_url_text_size) +{ + _az_PRECONDITION(source_base64_url_text_size >= 0); + return (source_base64_url_text_size / 4) * 3; +} diff --git a/sdk/tests/core/test_az_base64.c b/sdk/tests/core/test_az_base64.c index 78c9ebbc1d..2833183916 100644 --- a/sdk/tests/core/test_az_base64.c +++ b/sdk/tests/core/test_az_base64.c @@ -357,6 +357,209 @@ static void az_base64_decode_invalid_test(void** state) assert_int_equal(bytes_written, 0); } +static void _az_base64_url_decode_test_helper(az_span source, az_span expected) +{ + uint8_t destination_buffer[7]; + az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); + + int32_t bytes_written = 0; + assert_true(az_result_succeeded(az_base64_url_decode(destination, source, &bytes_written))); + assert_int_equal(bytes_written, az_span_size(expected)); + + assert_true(az_span_is_content_equal(az_span_slice(destination, 0, bytes_written), expected)); +} + +static void az_base64_url_decode_test(void** state) +{ + (void)state; + + az_span source = AZ_SPAN_FROM_STR("AA=="); + + uint8_t destination_buffer[1]; + az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); + + int32_t bytes_written = 0; + assert_true(az_result_succeeded(az_base64_url_decode(destination, source, &bytes_written))); + assert_int_equal(bytes_written, 1); + + uint8_t input_buffer[1] = { 0 }; + az_span expected = AZ_SPAN_FROM_BUFFER(input_buffer); + assert_true(az_span_is_content_equal(destination, expected)); + + uint8_t expected_buffer1[1] = { 1 }; + _az_base64_url_decode_test_helper(AZ_SPAN_FROM_STR("AQ"), AZ_SPAN_FROM_BUFFER(expected_buffer1)); + uint8_t expected_buffer2[2] = { 1, 2 }; + _az_base64_url_decode_test_helper(AZ_SPAN_FROM_STR("AQI"), AZ_SPAN_FROM_BUFFER(expected_buffer2)); + uint8_t expected_buffer3[3] = { 1, 2, 3 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("AQID"), AZ_SPAN_FROM_BUFFER(expected_buffer3)); + uint8_t expected_buffer4[4] = { 1, 2, 3, 4 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("AQIDBA"), AZ_SPAN_FROM_BUFFER(expected_buffer4)); + uint8_t expected_buffer5[5] = { 1, 2, 3, 4, 5 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("AQIDBAU"), AZ_SPAN_FROM_BUFFER(expected_buffer5)); + uint8_t expected_buffer6[6] = { 1, 2, 3, 4, 5, 6 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("AQIDBAUG"), AZ_SPAN_FROM_BUFFER(expected_buffer6)); + uint8_t expected_buffer7[7] = { 1, 2, 3, 4, 5, 6, 7 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("AQIDBAUGBw"), AZ_SPAN_FROM_BUFFER(expected_buffer7)); + uint8_t expected_buffer8[6] = { 0xF8, 0x01, 0x02, 0xFC, 0x03, 0x04 }; + _az_base64_url_decode_test_helper( + AZ_SPAN_FROM_STR("-AEC_AME"), AZ_SPAN_FROM_BUFFER(expected_buffer8)); +} + +static void az_base64_url_decode_destination_small_test(void** state) +{ + (void)state; + + uint8_t expected_buffer[10] = { 23, 51, 61, 250, 131, 184, 127, 228, 250, 66 }; + az_span source = AZ_SPAN_FROM_STR("FzM9-oO4f-T6Qg=="); + + uint8_t destination_buffer[10]; + az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); + + int32_t bytes_written = 0; + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 4), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 8), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 9), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 0); + + assert_true(az_result_succeeded(az_base64_url_decode(destination, source, &bytes_written))); + assert_int_equal(bytes_written, 10); + + assert_true(az_span_is_content_equal(destination, AZ_SPAN_FROM_BUFFER(expected_buffer))); + + source = AZ_SPAN_FROM_STR("AQI="); + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 1), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 10); + + source = AZ_SPAN_FROM_STR("AQID"); + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 2), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 10); + + source = AZ_SPAN_FROM_STR("AQIDBA=="); + assert_int_equal( + az_base64_url_decode(az_span_slice(destination, 0, 3), source, &bytes_written), + AZ_ERROR_NOT_ENOUGH_SPACE); + assert_int_equal(bytes_written, 10); +} + +static void az_base64_url_decode_source_small_test(void** state) +{ + (void)state; + + uint8_t destination_buffer[10]; + az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); + + int32_t bytes_written = 0; + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQIDB"), &bytes_written), + AZ_ERROR_UNEXPECTED_END); + assert_int_equal(bytes_written, 0); + + assert_int_equal(bytes_written, 0); +} + +static void az_base64_url_decode_invalid_test(void** state) +{ + (void)state; + + // Invalid Bytes: + // 0-44 + // 46 + // 58-64 + // 91-94 + // 96 + // 123-255 + + uint8_t destination_buffer[20]; + az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); + + int32_t bytes_written = 0; + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("A+++"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("A+=="), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("A!B="), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("A:BC"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQ+/"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQ=/"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQI/"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQIDB..."), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQIDBA.."), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQIDBA=|"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("AQIDBAU?"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("FzM9+oO4f+T6Qg==}}}}"), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_url_decode(destination, AZ_SPAN_FROM_STR("\\zM9+oO4f+T6Qg=="), &bytes_written), + AZ_ERROR_UNEXPECTED_CHAR); + assert_int_equal(bytes_written, 0); +} + int test_az_base64() { #ifndef AZ_NO_PRECONDITION_CHECKING @@ -375,6 +578,10 @@ int test_az_base64() cmocka_unit_test(az_base64_decode_destination_small_test), cmocka_unit_test(az_base64_decode_source_small_test), cmocka_unit_test(az_base64_decode_invalid_test), + cmocka_unit_test(az_base64_url_decode_test), + cmocka_unit_test(az_base64_url_decode_destination_small_test), + cmocka_unit_test(az_base64_url_decode_source_small_test), + cmocka_unit_test(az_base64_url_decode_invalid_test), }; return cmocka_run_group_tests_name("az_core_base64", tests, NULL, NULL); } From b6c406da5ee1c595fb0b5319582bc607d98db489 Mon Sep 17 00:00:00 2001 From: Dane Walton Date: Thu, 15 Sep 2022 15:30:16 -0500 Subject: [PATCH 2/3] remove array of base64 (#2338) --- sdk/src/azure/core/az_base64.c | 304 ++++----------------------------- 1 file changed, 37 insertions(+), 267 deletions(-) diff --git a/sdk/src/azure/core/az_base64.c b/sdk/src/azure/core/az_base64.c index 7fc70285ad..225581706a 100644 --- a/sdk/src/azure/core/az_base64.c +++ b/sdk/src/azure/core/az_base64.c @@ -21,266 +21,6 @@ typedef enum static char const _az_base64_encode_array[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static int8_t const _az_base64_decode_array[256] = { - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - 62, - -1, - -1, - -1, - 63, // 62 is placed at index 43 (for +), 63 at index 47 (for /) - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - -1, - -1, - -1, - -1, - -1, - -1, // 52-61 are placed at index 48-57 (for 0-9), 64 at index 61 (for =) - -1, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - -1, - -1, - -1, - -1, - -1, // 0-25 are placed at index 65-90 (for A-Z) - -1, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - -1, - -1, - -1, - -1, - -1, // 26-51 are placed at index 97-122 (for a-z) - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, // Bytes over 122 ('z') are invalid and cannot be decoded. Hence, padding the map with 255, - // which indicates invalid input - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, -}; - static AZ_NODISCARD int32_t _az_base64_encode(uint8_t* three_bytes) { int32_t i = (*three_bytes << 16) | (*(three_bytes + 1) << 8) | *(three_bytes + 2); @@ -376,26 +116,51 @@ AZ_NODISCARD int32_t az_base64_get_max_encoded_size(int32_t source_bytes_size) return (((source_bytes_size + 2) / 3) * 4); } -static int32_t _get_base64_decoded_char(int32_t index, _az_base64_mode mode) +static int32_t _get_base64_decoded_char(int32_t c, _az_base64_mode mode) { if (mode == _az_base64_mode_url) { - if (index == '+' || index == '/') + if (c == '+' || c == '/') { return -1; // can't use + or / with URL encoding } - if (index == '-') + if (c == '-') { - index = '+'; // - becomes a + + c = '+'; // - becomes a + } - else if (index == '_') + else if (c == '_') { - index = '/'; // _ becomes a / + c = '/'; // _ becomes a / } } - return _az_base64_decode_array[index]; + if (c >= 'A' && c <= 'Z') + { + return (c - 'A'); + } + + if (c >= 'a' && c <= 'z') + { + return 26 + (c - 'a'); + } + + if (c >= '0' && c <= '9') + { + return 52 + (c - '0'); + } + + if (c == '+') + { + return 62; + } + + if (c == '/') + { + return 63; + } + + return -1; } static AZ_NODISCARD int32_t @@ -411,6 +176,11 @@ _az_base64_decode_four_bytes(uint8_t* encoded_bytes, _az_base64_mode mode) i2 = _get_base64_decoded_char(i2, mode); i3 = _get_base64_decoded_char(i3, mode); + if (i0 == -1 || i1 == -1 || i2 == -1 || i3 == -1) + { + return -1; + } + i0 <<= 18; i1 <<= 12; i2 <<= 6; From c9eaaa37d5e603ed69e75cbf0dd82f42a339fb8d Mon Sep 17 00:00:00 2001 From: Dane Walton Date: Thu, 15 Sep 2022 15:50:29 -0500 Subject: [PATCH 3/3] take in main tests --- sdk/tests/core/test_az_base64.c | 49 ++++++++++----------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/sdk/tests/core/test_az_base64.c b/sdk/tests/core/test_az_base64.c index 2833183916..d4febed759 100644 --- a/sdk/tests/core/test_az_base64.c +++ b/sdk/tests/core/test_az_base64.c @@ -2,9 +2,7 @@ // SPDX-License-Identifier: MIT #include "az_test_definitions.h" -#include #include -#include #include #include @@ -14,23 +12,6 @@ #include -#ifndef AZ_NO_PRECONDITION_CHECKING -ENABLE_PRECONDITION_CHECK_TESTS() - -static void az_base64_decode_precondition_failed(void** state) -{ - (void)state; - uint8_t destination_buffer[10]; - az_span destination = AZ_SPAN_FROM_BUFFER(destination_buffer); - - int32_t bytes_written = 0; - - ASSERT_PRECONDITION_CHECKED(az_base64_decode(destination, AZ_SPAN_FROM_STR(""), &bytes_written)); - ASSERT_PRECONDITION_CHECKED(az_base64_decode(destination, AZ_SPAN_FROM_STR("A"), &bytes_written)); -} - -#endif // AZ_NO_PRECONDITION_CHECKING - static void az_base64_max_encode_test(void** state) { (void)state; @@ -184,19 +165,11 @@ static void az_base64_decode_test(void** state) uint8_t expected_buffer1[1] = { 1 }; _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQ=="), AZ_SPAN_FROM_BUFFER(expected_buffer1)); - uint8_t expected_buffer0[1] = { 1 }; - _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQ"), AZ_SPAN_FROM_BUFFER(expected_buffer0)); uint8_t expected_buffer2[2] = { 1, 2 }; _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQI="), AZ_SPAN_FROM_BUFFER(expected_buffer2)); uint8_t expected_buffer3[3] = { 1, 2, 3 }; _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQID"), AZ_SPAN_FROM_BUFFER(expected_buffer3)); uint8_t expected_buffer4[4] = { 1, 2, 3, 4 }; - // Can't have three short padding characters, so test later for "AQIDB" returns - // AZ_ERROR_UNEXPECTED_END Assume 2 padding - _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQIDBA"), AZ_SPAN_FROM_BUFFER(expected_buffer4)); - // Assume 1 padding - _az_base64_decode_test_helper(AZ_SPAN_FROM_STR("AQIDBA="), AZ_SPAN_FROM_BUFFER(expected_buffer4)); - // Assume 0 padding _az_base64_decode_test_helper( AZ_SPAN_FROM_STR("AQIDBA=="), AZ_SPAN_FROM_BUFFER(expected_buffer4)); uint8_t expected_buffer5[5] = { 1, 2, 3, 4, 5 }; @@ -273,6 +246,21 @@ static void az_base64_decode_source_small_test(void** state) az_base64_decode(destination, AZ_SPAN_FROM_STR("AQIDB"), &bytes_written), AZ_ERROR_UNEXPECTED_END); assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_decode(destination, AZ_SPAN_FROM_STR("AQIDBA"), &bytes_written), + AZ_ERROR_UNEXPECTED_END); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_decode(destination, AZ_SPAN_FROM_STR("AQIDBA="), &bytes_written), + AZ_ERROR_UNEXPECTED_END); + assert_int_equal(bytes_written, 0); + + assert_int_equal( + az_base64_decode(destination, AZ_SPAN_FROM_STR("AQIDBAU"), &bytes_written), + AZ_ERROR_UNEXPECTED_END); + assert_int_equal(bytes_written, 0); } static void az_base64_decode_invalid_test(void** state) @@ -562,14 +550,7 @@ static void az_base64_url_decode_invalid_test(void** state) int test_az_base64() { -#ifndef AZ_NO_PRECONDITION_CHECKING - SETUP_PRECONDITION_CHECK_TESTS(); -#endif // AZ_NO_PRECONDITION_CHECKING - const struct CMUnitTest tests[] = { -#ifndef AZ_NO_PRECONDITION_CHECKING - cmocka_unit_test(az_base64_decode_precondition_failed), -#endif // AZ_NO_PRECONDITION_CHECKING cmocka_unit_test(az_base64_max_encode_test), cmocka_unit_test(az_base64_max_decode_test), cmocka_unit_test(az_base64_encode_test),