diff --git a/base64.cpp b/base64.cpp index f5eac89b..cc0c7c21 100644 --- a/base64.cpp +++ b/base64.cpp @@ -33,35 +33,18 @@ namespace data } /* - * Reverse Substitution Table (built in run time) - */ - + * Reverse Substitution Table (built in run time) + */ static char iT64[256]; static int isFirstTime = 1; /* * Padding */ - static char P64 = '='; - /* - * - * ByteStreamToBase64 - * ------------------ - * - * Converts binary encoded data to BASE64 format. - * - */ - - size_t /* Number of bytes in the encoded buffer */ - ByteStreamToBase64 ( - const uint8_t * InBuffer, /* Input buffer, binary data */ - size_t InCount, /* Number of bytes in the input buffer */ - char * OutBuffer, /* output buffer */ - size_t len /* length of output buffer */ - ) + size_t ByteStreamToBase64(const uint8_t* InBuffer, size_t InCount, char* OutBuffer, size_t len) { unsigned char * ps; unsigned char * pd; @@ -124,23 +107,8 @@ namespace data return outCount; } - /* - * - * Base64ToByteStream - * ------------------ - * - * Converts BASE64 encoded data to binary format. If input buffer is - * not properly padded, buffer of negative length is returned - * - */ - size_t /* Number of output bytes */ - Base64ToByteStream ( - const char * InBuffer, /* BASE64 encoded buffer */ - size_t InCount, /* Number of input bytes */ - uint8_t * OutBuffer, /* output buffer length */ - size_t len /* length of output buffer */ - ) + size_t Base64ToByteStream(const char * InBuffer, size_t InCount, uint8_t* OutBuffer, size_t len) { unsigned char * ps; unsigned char * pd; @@ -154,7 +122,7 @@ namespace data if (isFirstTime) iT64Build(); n = InCount/4; m = InCount%4; - if (!m) + if(InCount && !m) outCount = 3*n; else { outCount = 0; @@ -165,7 +133,7 @@ namespace data while ( *ps-- == P64 ) outCount--; ps = (unsigned char *)InBuffer; - if (outCount > len) return -1; + if (outCount > len) return 0; pd = OutBuffer; auto endOfOutBuffer = OutBuffer + outCount; for ( i = 0; i < n; i++ ){ @@ -198,7 +166,6 @@ namespace data * * */ - static void iT64Build() { int i; @@ -238,6 +205,9 @@ namespace data size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen) { + if(!len) + return 0; // No data given + size_t ret = 0, pos = 1; int bits = 8, tmp = inBuf[0]; while (ret < outLen && (bits > 0 || pos < len)) diff --git a/base64.h b/base64.h index 027d62ba..3c1ecb76 100644 --- a/base64.h +++ b/base64.h @@ -9,12 +9,53 @@ namespace i2p namespace data { + + /* + * Base64 encodes an array of bytes. + * @return the number of characters written to the output buffer + * @param InBuffer array of input bytes to be encoded + * @param InCount length of the input array + * @param OutBuffer array to store output characters + * @param len length of the output buffer + * @note zero is returned when the output buffer is too small + */ size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); + + /** + * Decodes base 64 encoded data to an array of bytes. + * @return the number of bytes written to the output buffer + * @param InBuffer array of input characters to be decoded + * @param InCount length of the input array + * @param OutBuffer array to store output bytes + * @param len length of the output buffer + * @todo Do not return a negative value on failure, size_t could be unsigned. + * @note zero is returned when the output buffer is too small + */ size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); + const char * GetBase64SubstitutionTable (); + /** + * Decodes base 32 encoded data to an array of bytes. + * @return the number of bytes written to the output buffer + * @param inBuf array of input characters to be decoded + * @param len length of the input buffer + * @param outBuf array to store output bytes + * @param outLen length of the output array + * @note zero is returned when the output buffer is too small + */ size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); - size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); + + /** + * Base 32 encodes an array of bytes. + * @return the number of bytes written to the output buffer + * @param inBuf array of input bytes to be encoded + * @param len length of the input buffer + * @param outBuf array to store output characters + * @param outLen length of the output array + * @note zero is returned when the output buffer is too small + */ + size_t ByteStreamToBase32 (const uint8_t * inBuf, size_t len, char * outBuf, size_t outLen); } } diff --git a/filelist.mk b/filelist.mk index f2aae727..5602970c 100644 --- a/filelist.mk +++ b/filelist.mk @@ -25,4 +25,4 @@ LIB_SRC := $(COMMON_SRC) \ api.cpp TESTS_SRC := $(COMMON_SRC) \ - tests/Utility.cpp tests/Identity.cpp + tests/Utility.cpp tests/Identity.cpp tests/Data.cpp diff --git a/tests/Data.cpp b/tests/Data.cpp new file mode 100644 index 00000000..9e14ebfe --- /dev/null +++ b/tests/Data.cpp @@ -0,0 +1,117 @@ +#define BOOST_TEST_DYN_LINK + +#include +#include "../Identity.h" + +BOOST_AUTO_TEST_SUITE(DataTests) + +using namespace i2p::data; + +BOOST_AUTO_TEST_CASE(Base64EncodeEmpty) +{ + BOOST_CHECK_EQUAL(ByteStreamToBase64(nullptr, 0, nullptr, 0), 0); +} + +BOOST_AUTO_TEST_CASE(Base64DecodeEmpty) +{ + BOOST_CHECK_EQUAL(Base64ToByteStream(nullptr, 0, nullptr, 0), 0); +} + +BOOST_AUTO_TEST_CASE(Base64Encode) +{ + const uint8_t input[] = { + 0x53, 0xd3, 0x60, 0xfa, 0xf9, 0x58, 0xd0, 0x5e, 0x41, 0xa9, 0x6c, + 0xf1, 0x9f, 0xc4, 0xe, 0x23, 0x9b, 0xca, 0xb1, 0x61, 0xa7, 0x33, 0xcf, + 0x1f, 0x30 + }; + const char* output = "U9Ng-vlY0F5BqWzxn8QOI5vKsWGnM88fMA=="; + char result[36]; + const size_t size = ByteStreamToBase64(input, 25, result, 36); + + BOOST_CHECK_EQUAL_COLLECTIONS(result, result + 36, output, output + 36); + BOOST_CHECK_EQUAL(size, 36); +} + +BOOST_AUTO_TEST_CASE(Base64Decode) +{ + const char* input = "U9Ng-vlY0F5BqWzxn8QOI5vKsWGnM88fMA=="; + const uint8_t output[] = { + 0x53, 0xd3, 0x60, 0xfa, 0xf9, 0x58, 0xd0, 0x5e, 0x41, 0xa9, 0x6c, + 0xf1, 0x9f, 0xc4, 0xe, 0x23, 0x9b, 0xca, 0xb1, 0x61, 0xa7, 0x33, 0xcf, + 0x1f, 0x30 + }; + uint8_t result[25]; + const size_t size = Base64ToByteStream(input, 36, result, 25); + + BOOST_CHECK_EQUAL_COLLECTIONS(result, result + 25, output, output + 25); + BOOST_CHECK_EQUAL(size, 25); +} + +BOOST_AUTO_TEST_CASE(Base64EncodeBufferTooSmall) +{ + const uint8_t input[] = {0x53, 0xd3}; + char result[3]; + BOOST_CHECK_EQUAL(ByteStreamToBase64(input, 2, result, 3), 0); +} + +BOOST_AUTO_TEST_CASE(Base64DecodeBufferTooSmall) +{ + const char* input = "U9M="; + uint8_t result[1]; + BOOST_CHECK_EQUAL(Base64ToByteStream(input, 4, result, 1), 0); +} + +BOOST_AUTO_TEST_CASE(Base32EncodeEmpty) +{ + BOOST_CHECK_EQUAL(ByteStreamToBase32(nullptr, 0, nullptr, 0), 0); +} + +BOOST_AUTO_TEST_CASE(Base32DecodeEmpty) +{ + BOOST_CHECK_EQUAL(Base32ToByteStream(nullptr, 0, nullptr, 0), 0); +} + +BOOST_AUTO_TEST_CASE(Base32Encode) +{ + const uint8_t input[] = { + 0x53, 0xd3, 0x60, 0xfa, 0xf9, 0x58, 0xd0, 0x5e, 0x41, 0xa9, 0x6c, + 0xf1, 0x9f, 0xc4, 0xe, 0x23, 0x9b, 0xca, 0xb1, 0x61, 0xa7, 0x33, 0xcf, + 0x1f, 0x30 + }; + const char* output = "kpjwb6xzldif4qnjntyz7raoeon4vmlbu4z46hzq"; + char result[40]; + const size_t size = ByteStreamToBase32(input, 25, result, 40); + + BOOST_CHECK_EQUAL_COLLECTIONS(result, result + 40, output, output + 40); + BOOST_CHECK_EQUAL(size, 40); +} + +BOOST_AUTO_TEST_CASE(Base32Decode) +{ + const char* input = "kpjwb6xzldif4qnjntyz7raoeon4vmlbu4z46hzq"; + const uint8_t output[] = { + 0x53, 0xd3, 0x60, 0xfa, 0xf9, 0x58, 0xd0, 0x5e, 0x41, 0xa9, 0x6c, + 0xf1, 0x9f, 0xc4, 0xe, 0x23, 0x9b, 0xca, 0xb1, 0x61, 0xa7, 0x33, 0xcf, + 0x1f, 0x30 + }; + uint8_t result[25]; + const size_t size = Base32ToByteStream(input, 40, result, 25); + BOOST_CHECK_EQUAL_COLLECTIONS(result, result + 25, output, output + 25); + BOOST_CHECK_EQUAL(size, 25); +} + +BOOST_AUTO_TEST_CASE(Base32EncodeBufferTooSmall) +{ + const uint8_t input[] = {0x53, 0xd3}; + char result[3]; + BOOST_CHECK_EQUAL(ByteStreamToBase64(input, 2, result, 3), 0); +} + +BOOST_AUTO_TEST_CASE(Base32DecodeBufferTooSmall) +{ + const char* input = "kpjq"; + uint8_t result[1]; + BOOST_CHECK_EQUAL(Base64ToByteStream(input, 4, result, 1), 0); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/Identity.cpp b/tests/Identity.cpp index 597a2ba0..d74369a9 100644 --- a/tests/Identity.cpp +++ b/tests/Identity.cpp @@ -8,5 +8,4 @@ BOOST_AUTO_TEST_SUITE(IdentityTests) - BOOST_AUTO_TEST_SUITE_END() diff --git a/util.cpp b/util.cpp index e9a9b5e9..39312acb 100644 --- a/util.cpp +++ b/util.cpp @@ -562,7 +562,7 @@ namespace net { return fallback; } - int GetMTUWindowsIpv6(sockaddr_in inputAddress, int fallback) + int GetMTUWindowsIpv6(sockaddr_in6 inputAddress, int fallback) { ULONG outBufLen = 0; PIP_ADAPTER_ADDRESSES pAddresses = nullptr; @@ -645,7 +645,7 @@ namespace net { return GetMTUWindowsIpv6(inputAddress, fallback); } else { LogPrint(eLogError, "GetMTU() has failed: address family is not supported"); - return result; + return fallback; } }