diff --git a/src/Makefile.in b/src/Makefile.in index e941af99f..1145f0063 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -62,7 +62,6 @@ SRCS = \ common/crypto/hash.c \ common/debug.c \ common/encode.c \ - common/encode/base64.c \ common/error.c \ common/exec.c \ common/exit.c \ diff --git a/src/common/encode.c b/src/common/encode.c index e5b37a691..57e28837b 100644 --- a/src/common/encode.c +++ b/src/common/encode.c @@ -7,7 +7,6 @@ Binary to String Encode/Decode #include #include "common/encode.h" -#include "common/encode/base64.h" #include "common/debug.h" #include "common/error.h" @@ -17,7 +16,217 @@ Macro to handle invalid encode type errors #define ENCODE_TYPE_INVALID_ERROR(encodeType) \ THROW_FMT(AssertError, "invalid encode type %u", encodeType); +/*********************************************************************************************************************************** +Base64 encoding/decoding +***********************************************************************************************************************************/ +static const char encodeBase64Lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static void +encodeToStrBase64(const unsigned char *source, size_t sourceSize, char *destination) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM_P(UCHARDATA, source); + FUNCTION_TEST_PARAM(SIZE, sourceSize); + FUNCTION_TEST_PARAM_P(CHARDATA, destination); + FUNCTION_TEST_END(); + + ASSERT(source != NULL); + ASSERT(destination != NULL); + + unsigned int destinationIdx = 0; + + // Encode the string from three bytes to four characters + for (unsigned int sourceIdx = 0; sourceIdx < sourceSize; sourceIdx += 3) + { + // First encoded character is always used completely + destination[destinationIdx++] = encodeBase64Lookup[source[sourceIdx] >> 2]; + + // If there is only one byte to encode then the second encoded character is only partly used and the third and fourth + // encoded characters are padded. + if (sourceSize - sourceIdx == 1) + { + destination[destinationIdx++] = encodeBase64Lookup[(source[sourceIdx] & 0x03) << 4]; + destination[destinationIdx++] = 0x3d; + destination[destinationIdx++] = 0x3d; + } + // Else if more than one byte to encode + else + { + // If there is more than one byte to encode then the second encoded character is used completely + destination[destinationIdx++] = + encodeBase64Lookup[((source[sourceIdx] & 0x03) << 4) | ((source[sourceIdx + 1] & 0xf0) >> 4)]; + + // If there are only two bytes to encode then the third encoded character is only partly used and the fourth encoded + // character is padded. + if (sourceSize - sourceIdx == 2) + { + destination[destinationIdx++] = encodeBase64Lookup[(source[sourceIdx + 1] & 0x0f) << 2]; + destination[destinationIdx++] = 0x3d; + } + // Else the third and fourth encoded characters are used completely + else + { + destination[destinationIdx++] = + encodeBase64Lookup[((source[sourceIdx + 1] & 0x0f) << 2) | ((source[sourceIdx + 2] & 0xc0) >> 6)]; + destination[destinationIdx++] = encodeBase64Lookup[source[sourceIdx + 2] & 0x3f]; + } + } + } + + // Zero-terminate the string + destination[destinationIdx] = 0; + + FUNCTION_TEST_RETURN_VOID(); +} + /**********************************************************************************************************************************/ +static size_t +encodeToStrSizeBase64(size_t sourceSize) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(SIZE, sourceSize); + FUNCTION_TEST_END(); + + // Calculate how many groups of three are in the source + size_t encodeGroupTotal = sourceSize / 3; + + // Increase by one if there is a partial group + if (sourceSize % 3 != 0) + encodeGroupTotal++; + + // Four characters are needed to encode each group + FUNCTION_TEST_RETURN(encodeGroupTotal * 4); +} + +/**********************************************************************************************************************************/ +static const int decodeBase64Lookup[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, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -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, + -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, + -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, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static void +decodeToBinValidateBase64(const char *source) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRINGZ, source); + FUNCTION_TEST_END(); + + // Check for the correct length + size_t sourceSize = strlen(source); + + if (sourceSize % 4 != 0) + THROW_FMT(FormatError, "base64 size %zu is not evenly divisible by 4", sourceSize); + + // Check all characters + for (unsigned int sourceIdx = 0; sourceIdx < sourceSize; sourceIdx++) + { + // Check terminators + if (source[sourceIdx] == 0x3d) + { + // Make sure they are only in the last two positions + if (sourceIdx < sourceSize - 2) + THROW(FormatError, "base64 '=' character may only appear in last two positions"); + + // If second to last char is = then last char must also be + if (sourceIdx == sourceSize - 2 && source[sourceSize - 1] != 0x3d) + THROW(FormatError, "base64 last character must be '=' if second to last is"); + } + else + { + // Error on any invalid characters + if (decodeBase64Lookup[(int)source[sourceIdx]] == -1) + THROW_FMT(FormatError, "base64 invalid character found at position %u", sourceIdx); + } + } + + FUNCTION_TEST_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +static void +decodeToBinBase64(const char *source, unsigned char *destination) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRINGZ, source); + FUNCTION_TEST_PARAM_P(UCHARDATA, destination); + FUNCTION_TEST_END(); + + // Validate encoded string + decodeToBinValidateBase64(source); + + int destinationIdx = 0; + + // Decode the binary data from four characters to three bytes + for (unsigned int sourceIdx = 0; sourceIdx < strlen(source); sourceIdx += 4) + { + // Always decode the first character + destination[destinationIdx++] = + (unsigned char)(decodeBase64Lookup[(int)source[sourceIdx]] << 2 | decodeBase64Lookup[(int)source[sourceIdx + 1]] >> 4); + + // Second character is optional + if (source[sourceIdx + 2] != 0x3d) + { + destination[destinationIdx++] = (unsigned char) + (decodeBase64Lookup[(int)source[sourceIdx + 1]] << 4 | decodeBase64Lookup[(int)source[sourceIdx + 2]] >> 2); + } + + // Third character is optional + if (source[sourceIdx + 3] != 0x3d) + { + destination[destinationIdx++] = (unsigned char) + (((decodeBase64Lookup[(int)source[sourceIdx + 2]] << 6) & 0xc0) | decodeBase64Lookup[(int)source[sourceIdx + 3]]); + } + } + + FUNCTION_TEST_RETURN_VOID(); +} + +/**********************************************************************************************************************************/ +static size_t +decodeToBinSizeBase64(const char *source) +{ + FUNCTION_TEST_BEGIN(); + FUNCTION_TEST_PARAM(STRINGZ, source); + FUNCTION_TEST_END(); + + // Validate encoded string + decodeToBinValidateBase64(source); + + // Start with size calculated directly from source length + size_t sourceSize = strlen(source); + size_t destinationSize = sourceSize / 4 * 3; + + // Subtract last character if it is not present + if (source[sourceSize - 1] == 0x3d) + { + destinationSize--; + + // Subtract second to last character if it is not present + if (source[sourceSize - 2] == 0x3d) + destinationSize--; + } + + FUNCTION_TEST_RETURN(destinationSize); +} + +/*********************************************************************************************************************************** +Generic encoding/decoding +***********************************************************************************************************************************/ void encodeToStr(EncodeType encodeType, const unsigned char *source, size_t sourceSize, char *destination) { diff --git a/src/common/encode/base64.c b/src/common/encode/base64.c deleted file mode 100644 index bfe6e35fe..000000000 --- a/src/common/encode/base64.c +++ /dev/null @@ -1,216 +0,0 @@ -/*********************************************************************************************************************************** -Base64 Binary to String Encode/Decode -***********************************************************************************************************************************/ -#include "build.auto.h" - -#include - -#include "common/encode/base64.h" -#include "common/debug.h" -#include "common/error.h" - -/**********************************************************************************************************************************/ -static const char encodeBase64Lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -void -encodeToStrBase64(const unsigned char *source, size_t sourceSize, char *destination) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM_P(UCHARDATA, source); - FUNCTION_TEST_PARAM(SIZE, sourceSize); - FUNCTION_TEST_PARAM_P(CHARDATA, destination); - FUNCTION_TEST_END(); - - ASSERT(source != NULL); - ASSERT(destination != NULL); - - unsigned int destinationIdx = 0; - - // Encode the string from three bytes to four characters - for (unsigned int sourceIdx = 0; sourceIdx < sourceSize; sourceIdx += 3) - { - // First encoded character is always used completely - destination[destinationIdx++] = encodeBase64Lookup[source[sourceIdx] >> 2]; - - // If there is only one byte to encode then the second encoded character is only partly used and the third and fourth - // encoded characters are padded. - if (sourceSize - sourceIdx == 1) - { - destination[destinationIdx++] = encodeBase64Lookup[(source[sourceIdx] & 0x03) << 4]; - destination[destinationIdx++] = 0x3d; - destination[destinationIdx++] = 0x3d; - } - // Else if more than one byte to encode - else - { - // If there is more than one byte to encode then the second encoded character is used completely - destination[destinationIdx++] = - encodeBase64Lookup[((source[sourceIdx] & 0x03) << 4) | ((source[sourceIdx + 1] & 0xf0) >> 4)]; - - // If there are only two bytes to encode then the third encoded character is only partly used and the fourth encoded - // character is padded. - if (sourceSize - sourceIdx == 2) - { - destination[destinationIdx++] = encodeBase64Lookup[(source[sourceIdx + 1] & 0x0f) << 2]; - destination[destinationIdx++] = 0x3d; - } - // Else the third and fourth encoded characters are used completely - else - { - destination[destinationIdx++] = - encodeBase64Lookup[((source[sourceIdx + 1] & 0x0f) << 2) | ((source[sourceIdx + 2] & 0xc0) >> 6)]; - destination[destinationIdx++] = encodeBase64Lookup[source[sourceIdx + 2] & 0x3f]; - } - } - } - - // Zero-terminate the string - destination[destinationIdx] = 0; - - FUNCTION_TEST_RETURN_VOID(); -} - -/**********************************************************************************************************************************/ -size_t -encodeToStrSizeBase64(size_t sourceSize) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(SIZE, sourceSize); - FUNCTION_TEST_END(); - - // Calculate how many groups of three are in the source - size_t encodeGroupTotal = sourceSize / 3; - - // Increase by one if there is a partial group - if (sourceSize % 3 != 0) - encodeGroupTotal++; - - // Four characters are needed to encode each group - FUNCTION_TEST_RETURN(encodeGroupTotal * 4); -} - -/**********************************************************************************************************************************/ -static const int decodeBase64Lookup[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, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, - -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, - -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, - -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, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; - -void -decodeToBinBase64(const char *source, unsigned char *destination) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(STRINGZ, source); - FUNCTION_TEST_PARAM_P(UCHARDATA, destination); - FUNCTION_TEST_END(); - - // Validate encoded string - decodeToBinValidateBase64(source); - - int destinationIdx = 0; - - // Decode the binary data from four characters to three bytes - for (unsigned int sourceIdx = 0; sourceIdx < strlen(source); sourceIdx += 4) - { - // Always decode the first character - destination[destinationIdx++] = - (unsigned char)(decodeBase64Lookup[(int)source[sourceIdx]] << 2 | decodeBase64Lookup[(int)source[sourceIdx + 1]] >> 4); - - // Second character is optional - if (source[sourceIdx + 2] != 0x3d) - { - destination[destinationIdx++] = (unsigned char) - (decodeBase64Lookup[(int)source[sourceIdx + 1]] << 4 | decodeBase64Lookup[(int)source[sourceIdx + 2]] >> 2); - } - - // Third character is optional - if (source[sourceIdx + 3] != 0x3d) - { - destination[destinationIdx++] = (unsigned char) - (((decodeBase64Lookup[(int)source[sourceIdx + 2]] << 6) & 0xc0) | decodeBase64Lookup[(int)source[sourceIdx + 3]]); - } - } - - FUNCTION_TEST_RETURN_VOID(); -} - -/**********************************************************************************************************************************/ -size_t -decodeToBinSizeBase64(const char *source) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(STRINGZ, source); - FUNCTION_TEST_END(); - - // Validate encoded string - decodeToBinValidateBase64(source); - - // Start with size calculated directly from source length - size_t sourceSize = strlen(source); - size_t destinationSize = sourceSize / 4 * 3; - - // Subtract last character if it is not present - if (source[sourceSize - 1] == 0x3d) - { - destinationSize--; - - // Subtract second to last character if it is not present - if (source[sourceSize - 2] == 0x3d) - destinationSize--; - } - - FUNCTION_TEST_RETURN(destinationSize); -} - -/**********************************************************************************************************************************/ -void -decodeToBinValidateBase64(const char *source) -{ - FUNCTION_TEST_BEGIN(); - FUNCTION_TEST_PARAM(STRINGZ, source); - FUNCTION_TEST_END(); - - // Check for the correct length - size_t sourceSize = strlen(source); - - if (sourceSize % 4 != 0) - THROW_FMT(FormatError, "base64 size %zu is not evenly divisible by 4", sourceSize); - - // Check all characters - for (unsigned int sourceIdx = 0; sourceIdx < sourceSize; sourceIdx++) - { - // Check terminators - if (source[sourceIdx] == 0x3d) - { - // Make sure they are only in the last two positions - if (sourceIdx < sourceSize - 2) - THROW(FormatError, "base64 '=' character may only appear in last two positions"); - - // If second to last char is = then last char must also be - if (sourceIdx == sourceSize - 2 && source[sourceSize - 1] != 0x3d) - THROW(FormatError, "base64 last character must be '=' if second to last is"); - } - else - { - // Error on any invalid characters - if (decodeBase64Lookup[(int)source[sourceIdx]] == -1) - THROW_FMT(FormatError, "base64 invalid character found at position %u", sourceIdx); - } - } - - FUNCTION_TEST_RETURN_VOID(); -} diff --git a/src/common/encode/base64.h b/src/common/encode/base64.h deleted file mode 100644 index 78d7c0c3c..000000000 --- a/src/common/encode/base64.h +++ /dev/null @@ -1,27 +0,0 @@ -/*********************************************************************************************************************************** -Base64 Binary to String Encode/Decode - -The high-level functions in encode.c should be used in preference to these low-level functions. -***********************************************************************************************************************************/ -#ifndef COMMON_ENCODE_BASE64_H -#define COMMON_ENCODE_BASE64_H - -/*********************************************************************************************************************************** -Functions -***********************************************************************************************************************************/ -// Encode binary data to a printable string -void encodeToStrBase64(const unsigned char *source, size_t sourceSize, char *destination); - -// Size of the destination param required by encodeToStrBase64() minus space for the null terminator -size_t encodeToStrSizeBase64(size_t sourceSize); - -// Decode a string to binary data -void decodeToBinBase64(const char *source, unsigned char *destination); - -// Size of the destination param required by decodeToBinBase64() -size_t decodeToBinSizeBase64(const char *source); - -// Validate the encoded string -void decodeToBinValidateBase64(const char *source); - -#endif diff --git a/test/define.yaml b/test/define.yaml index fb3aeb649..5fc11efc7 100644 --- a/test/define.yaml +++ b/test/define.yaml @@ -119,7 +119,6 @@ unit: coverage: - common/encode - - common/encode/base64 # ---------------------------------------------------------------------------------------------------------------------------- - name: type-string