[388] | 1 | // Copyright (c) Microsoft. All rights reserved.
|
---|
| 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
---|
| 3 |
|
---|
| 4 | #include <stdlib.h>
|
---|
| 5 | #include "azure_c_shared_utility/gballoc.h"
|
---|
| 6 | #include <stddef.h>
|
---|
| 7 | #include <stdint.h>
|
---|
| 8 | #include "azure_c_shared_utility/azure_base64.h"
|
---|
| 9 | #include "azure_c_shared_utility/xlogging.h"
|
---|
| 10 |
|
---|
| 11 |
|
---|
| 12 | #define splitInt(intVal, bytePos) (char)((intVal >> (bytePos << 3)) & 0xFF)
|
---|
| 13 | #define joinChars(a, b, c, d) (uint32_t)((uint32_t)a + ((uint32_t)b << 8) + ((uint32_t)c << 16) + ((uint32_t)d << 24))
|
---|
| 14 |
|
---|
| 15 | static char base64char(unsigned char val)
|
---|
| 16 | {
|
---|
| 17 | char result;
|
---|
| 18 |
|
---|
| 19 | if (val < 26)
|
---|
| 20 | {
|
---|
| 21 | result = 'A' + (char)val;
|
---|
| 22 | }
|
---|
| 23 | else if (val < 52)
|
---|
| 24 | {
|
---|
| 25 | result = 'a' + ((char)val - 26);
|
---|
| 26 | }
|
---|
| 27 | else if (val < 62)
|
---|
| 28 | {
|
---|
| 29 | result = '0' + ((char)val - 52);
|
---|
| 30 | }
|
---|
| 31 | else if (val == 62)
|
---|
| 32 | {
|
---|
| 33 | result = '+';
|
---|
| 34 | }
|
---|
| 35 | else
|
---|
| 36 | {
|
---|
| 37 | result = '/';
|
---|
| 38 | }
|
---|
| 39 |
|
---|
| 40 | return result;
|
---|
| 41 | }
|
---|
| 42 |
|
---|
| 43 | static char base64b16(unsigned char val)
|
---|
| 44 | {
|
---|
| 45 | const uint32_t base64b16values[4] = {
|
---|
| 46 | joinChars('A', 'E', 'I', 'M'),
|
---|
| 47 | joinChars('Q', 'U', 'Y', 'c'),
|
---|
| 48 | joinChars('g', 'k', 'o', 's'),
|
---|
| 49 | joinChars('w', '0', '4', '8')
|
---|
| 50 | };
|
---|
| 51 | return splitInt(base64b16values[val >> 2], (val & 0x03));
|
---|
| 52 | }
|
---|
| 53 |
|
---|
| 54 | static char base64b8(unsigned char val)
|
---|
| 55 | {
|
---|
| 56 | const uint32_t base64b8values = joinChars('A', 'Q', 'g', 'w');
|
---|
| 57 | return splitInt(base64b8values, val);
|
---|
| 58 | }
|
---|
| 59 |
|
---|
| 60 | static int base64toValue(char base64character, unsigned char* value)
|
---|
| 61 | {
|
---|
| 62 | int result = 0;
|
---|
| 63 | if (('A' <= base64character) && (base64character <= 'Z'))
|
---|
| 64 | {
|
---|
| 65 | *value = base64character - 'A';
|
---|
| 66 | }
|
---|
| 67 | else if (('a' <= base64character) && (base64character <= 'z'))
|
---|
| 68 | {
|
---|
| 69 | *value = ('Z' - 'A') + 1 + (base64character - 'a');
|
---|
| 70 | }
|
---|
| 71 | else if (('0' <= base64character) && (base64character <= '9'))
|
---|
| 72 | {
|
---|
| 73 | *value = ('Z' - 'A') + 1 + ('z' - 'a') + 1 + (base64character - '0');
|
---|
| 74 | }
|
---|
| 75 | else if ('+' == base64character)
|
---|
| 76 | {
|
---|
| 77 | *value = 62;
|
---|
| 78 | }
|
---|
| 79 | else if ('/' == base64character)
|
---|
| 80 | {
|
---|
| 81 | *value = 63;
|
---|
| 82 | }
|
---|
| 83 | else
|
---|
| 84 | {
|
---|
| 85 | *value = 0;
|
---|
| 86 | result = -1;
|
---|
| 87 | }
|
---|
| 88 | return result;
|
---|
| 89 | }
|
---|
| 90 |
|
---|
| 91 | static size_t numberOfBase64Characters(const char* encodedString)
|
---|
| 92 | {
|
---|
| 93 | size_t length = 0;
|
---|
| 94 | unsigned char junkChar;
|
---|
| 95 | while (base64toValue(encodedString[length],&junkChar) != -1)
|
---|
| 96 | {
|
---|
| 97 | length++;
|
---|
| 98 | }
|
---|
| 99 | return length;
|
---|
| 100 | }
|
---|
| 101 |
|
---|
| 102 | /*returns the count of original bytes before being base64 encoded*/
|
---|
| 103 | /*notice NO validation of the content of encodedString. Its length is validated to be a multiple of 4.*/
|
---|
| 104 | static size_t Base64decode_len(const char *encodedString)
|
---|
| 105 | {
|
---|
| 106 | size_t result;
|
---|
| 107 | size_t sourceLength = strlen(encodedString);
|
---|
| 108 |
|
---|
| 109 | if (sourceLength == 0)
|
---|
| 110 | {
|
---|
| 111 | result = 0;
|
---|
| 112 | }
|
---|
| 113 | else
|
---|
| 114 | {
|
---|
| 115 | result = sourceLength / 4 * 3;
|
---|
| 116 | if (encodedString[sourceLength - 1] == '=')
|
---|
| 117 | {
|
---|
| 118 | if (encodedString[sourceLength - 2] == '=')
|
---|
| 119 | {
|
---|
| 120 | result --;
|
---|
| 121 | }
|
---|
| 122 | result--;
|
---|
| 123 | }
|
---|
| 124 | }
|
---|
| 125 | return result;
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | static void Base64decode(unsigned char *decodedString, const char *base64String)
|
---|
| 129 | {
|
---|
| 130 |
|
---|
| 131 | size_t numberOfEncodedChars;
|
---|
| 132 | size_t indexOfFirstEncodedChar;
|
---|
| 133 | size_t decodedIndex;
|
---|
| 134 |
|
---|
| 135 | //
|
---|
| 136 | // We can only operate on individual bytes. If we attempt to work
|
---|
| 137 | // on anything larger we could get an alignment fault on some
|
---|
| 138 | // architectures
|
---|
| 139 | //
|
---|
| 140 |
|
---|
| 141 | numberOfEncodedChars = numberOfBase64Characters(base64String);
|
---|
| 142 | indexOfFirstEncodedChar = 0;
|
---|
| 143 | decodedIndex = 0;
|
---|
| 144 | while (numberOfEncodedChars >= 4)
|
---|
| 145 | {
|
---|
| 146 | unsigned char c1;
|
---|
| 147 | unsigned char c2;
|
---|
| 148 | unsigned char c3;
|
---|
| 149 | unsigned char c4;
|
---|
| 150 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
|
---|
| 151 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
|
---|
| 152 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3);
|
---|
| 153 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 3], &c4);
|
---|
| 154 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
|
---|
| 155 | decodedIndex++;
|
---|
| 156 | decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2);
|
---|
| 157 | decodedIndex++;
|
---|
| 158 | decodedString[decodedIndex] = ((c3 & 0x03) << 6) | c4;
|
---|
| 159 | decodedIndex++;
|
---|
| 160 | numberOfEncodedChars -= 4;
|
---|
| 161 | indexOfFirstEncodedChar += 4;
|
---|
| 162 |
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | if (numberOfEncodedChars == 2)
|
---|
| 166 | {
|
---|
| 167 | unsigned char c1;
|
---|
| 168 | unsigned char c2;
|
---|
| 169 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
|
---|
| 170 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
|
---|
| 171 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
|
---|
| 172 | }
|
---|
| 173 | else if (numberOfEncodedChars == 3)
|
---|
| 174 | {
|
---|
| 175 | unsigned char c1;
|
---|
| 176 | unsigned char c2;
|
---|
| 177 | unsigned char c3;
|
---|
| 178 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1);
|
---|
| 179 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2);
|
---|
| 180 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3);
|
---|
| 181 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4);
|
---|
| 182 | decodedIndex++;
|
---|
| 183 | decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2);
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 |
|
---|
| 187 | BUFFER_HANDLE Azure_Base64_Decode(const char* source)
|
---|
| 188 | {
|
---|
| 189 | BUFFER_HANDLE result;
|
---|
| 190 | /*Codes_SRS_BASE64_06_008: [If source is NULL then Azure_Base64_Decode shall return NULL.]*/
|
---|
| 191 | if (source == NULL)
|
---|
| 192 | {
|
---|
| 193 | LogError("invalid parameter const char* source=%p", source);
|
---|
| 194 | result = NULL;
|
---|
| 195 | }
|
---|
| 196 | else
|
---|
| 197 | {
|
---|
| 198 | if ((strlen(source) % 4) != 0)
|
---|
| 199 | {
|
---|
| 200 | /*Codes_SRS_BASE64_06_011: [If the source string has an invalid length for a base 64 encoded string then Azure_Base64_Decode shall return NULL.]*/
|
---|
| 201 | LogError("Invalid length Base64 string!");
|
---|
| 202 | result = NULL;
|
---|
| 203 | }
|
---|
| 204 | else
|
---|
| 205 | {
|
---|
| 206 | if ((result = BUFFER_new()) == NULL)
|
---|
| 207 | {
|
---|
| 208 | /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Azure_Base64_Decode shall return NULL.]*/
|
---|
| 209 | LogError("Could not create a buffer to decoding.");
|
---|
| 210 | }
|
---|
| 211 | else
|
---|
| 212 | {
|
---|
| 213 | size_t sizeOfOutputBuffer = Base64decode_len(source);
|
---|
| 214 | /*Codes_SRS_BASE64_06_009: [If the string pointed to by source is zero length then the handle returned shall refer to a zero length buffer.]*/
|
---|
| 215 | if (sizeOfOutputBuffer > 0)
|
---|
| 216 | {
|
---|
| 217 | if (BUFFER_pre_build(result, sizeOfOutputBuffer) != 0)
|
---|
| 218 | {
|
---|
| 219 | /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Azure_Base64_Decode shall return NULL.]*/
|
---|
| 220 | LogError("Could not prebuild a buffer for base 64 decoding.");
|
---|
| 221 | BUFFER_delete(result);
|
---|
| 222 | result = NULL;
|
---|
| 223 | }
|
---|
| 224 | else
|
---|
| 225 | {
|
---|
| 226 | Base64decode(BUFFER_u_char(result), source);
|
---|
| 227 | }
|
---|
| 228 | }
|
---|
| 229 | }
|
---|
| 230 | }
|
---|
| 231 | }
|
---|
| 232 | return result;
|
---|
| 233 | }
|
---|
| 234 |
|
---|
| 235 |
|
---|
| 236 | static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size)
|
---|
| 237 | {
|
---|
| 238 | STRING_HANDLE result;
|
---|
| 239 | size_t neededSize = 0;
|
---|
| 240 | char* encoded;
|
---|
| 241 | size_t currentPosition = 0;
|
---|
| 242 | neededSize += (size == 0) ? (0) : ((((size - 1) / 3) + 1) * 4);
|
---|
| 243 | neededSize += 1; /*+1 because \0 at the end of the string*/
|
---|
| 244 | /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Base64_Encode shall return NULL.]*/
|
---|
| 245 | encoded = (char*)malloc(neededSize);
|
---|
| 246 | if (encoded == NULL)
|
---|
| 247 | {
|
---|
| 248 | result = NULL;
|
---|
| 249 | LogError("Base64_Encode:: Allocation failed.");
|
---|
| 250 | }
|
---|
| 251 | else
|
---|
| 252 | {
|
---|
| 253 | /*b0 b1(+1) b2(+2)
|
---|
| 254 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
---|
| 255 | |----c1---| |----c2---| |----c3---| |----c4---|
|
---|
| 256 | */
|
---|
| 257 |
|
---|
| 258 | size_t destinationPosition = 0;
|
---|
| 259 | while (size - currentPosition >= 3)
|
---|
| 260 | {
|
---|
| 261 | char c1 = base64char(source[currentPosition] >> 2);
|
---|
| 262 | char c2 = base64char(
|
---|
| 263 | ((source[currentPosition] & 3) << 4) |
|
---|
| 264 | (source[currentPosition + 1] >> 4)
|
---|
| 265 | );
|
---|
| 266 | char c3 = base64char(
|
---|
| 267 | ((source[currentPosition + 1] & 0x0F) << 2) |
|
---|
| 268 | ((source[currentPosition + 2] >> 6) & 3)
|
---|
| 269 | );
|
---|
| 270 | char c4 = base64char(
|
---|
| 271 | source[currentPosition + 2] & 0x3F
|
---|
| 272 | );
|
---|
| 273 | currentPosition += 3;
|
---|
| 274 | encoded[destinationPosition++] = c1;
|
---|
| 275 | encoded[destinationPosition++] = c2;
|
---|
| 276 | encoded[destinationPosition++] = c3;
|
---|
| 277 | encoded[destinationPosition++] = c4;
|
---|
| 278 |
|
---|
| 279 | }
|
---|
| 280 | if (size - currentPosition == 2)
|
---|
| 281 | {
|
---|
| 282 | char c1 = base64char(source[currentPosition] >> 2);
|
---|
| 283 | char c2 = base64char(
|
---|
| 284 | ((source[currentPosition] & 0x03) << 4) |
|
---|
| 285 | (source[currentPosition + 1] >> 4)
|
---|
| 286 | );
|
---|
| 287 | char c3 = base64b16(source[currentPosition + 1] & 0x0F);
|
---|
| 288 | encoded[destinationPosition++] = c1;
|
---|
| 289 | encoded[destinationPosition++] = c2;
|
---|
| 290 | encoded[destinationPosition++] = c3;
|
---|
| 291 | encoded[destinationPosition++] = '=';
|
---|
| 292 | }
|
---|
| 293 | else if (size - currentPosition == 1)
|
---|
| 294 | {
|
---|
| 295 | char c1 = base64char(source[currentPosition] >> 2);
|
---|
| 296 | char c2 = base64b8(source[currentPosition] & 0x03);
|
---|
| 297 | encoded[destinationPosition++] = c1;
|
---|
| 298 | encoded[destinationPosition++] = c2;
|
---|
| 299 | encoded[destinationPosition++] = '=';
|
---|
| 300 | encoded[destinationPosition++] = '=';
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 | /*null terminating the string*/
|
---|
| 304 | encoded[destinationPosition] = '\0';
|
---|
| 305 | /*Codes_SRS_BASE64_06_007: [Otherwise Base64_Encode shall return a pointer to STRING, that string contains the base 64 encoding of input.]*/
|
---|
| 306 | result = STRING_new_with_memory(encoded);
|
---|
| 307 | if (result == NULL)
|
---|
| 308 | {
|
---|
| 309 | free(encoded);
|
---|
| 310 | LogError("Base64_Encode:: Allocation failed for return value.");
|
---|
| 311 | }
|
---|
| 312 | }
|
---|
| 313 | return result;
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | STRING_HANDLE Azure_Base64_Encode_Bytes(const unsigned char* source, size_t size)
|
---|
| 317 | {
|
---|
| 318 | STRING_HANDLE result;
|
---|
| 319 | /*Codes_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */
|
---|
| 320 | if (source == NULL)
|
---|
| 321 | {
|
---|
| 322 | result = NULL;
|
---|
| 323 | }
|
---|
| 324 | /*Codes_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.] */
|
---|
| 325 | else if (size == 0)
|
---|
| 326 | {
|
---|
| 327 | result = STRING_new(); /*empty string*/
|
---|
| 328 | }
|
---|
| 329 | else
|
---|
| 330 | {
|
---|
| 331 | result = Base64_Encode_Internal(source, size);
|
---|
| 332 | }
|
---|
| 333 | return result;
|
---|
| 334 | }
|
---|
| 335 |
|
---|
| 336 | STRING_HANDLE Azure_Base64_Encode(BUFFER_HANDLE input)
|
---|
| 337 | {
|
---|
| 338 | STRING_HANDLE result;
|
---|
| 339 | /*the following will happen*/
|
---|
| 340 | /*1. the "data" of the binary shall be "eaten" 3 characters at a time and produce 4 base64 encoded characters for as long as there are more than 3 characters still to process*/
|
---|
| 341 | /*2. the remaining characters (1 or 2) shall be encoded.*/
|
---|
| 342 | /*there's a level of assumption that 'a' corresponds to 0b000000 and that '_' corresponds to 0b111111*/
|
---|
| 343 | /*the encoding will use the optional [=] or [==] at the end of the encoded string, so that other less standard aware libraries can do their work*/
|
---|
| 344 | /*these are the bits of the 3 normal bytes to be encoded*/
|
---|
| 345 |
|
---|
| 346 | /*Codes_SRS_BASE64_06_001: [If input is NULL then Base64_Encode shall return NULL.]*/
|
---|
| 347 | if (input == NULL)
|
---|
| 348 | {
|
---|
| 349 | result = NULL;
|
---|
| 350 | LogError("Base64_Encode:: NULL input");
|
---|
| 351 | }
|
---|
| 352 | else
|
---|
| 353 | {
|
---|
| 354 | size_t inputSize;
|
---|
| 355 | const unsigned char* inputBinary;
|
---|
| 356 | if ((BUFFER_content(input, &inputBinary) != 0) ||
|
---|
| 357 | (BUFFER_size(input, &inputSize) != 0))
|
---|
| 358 | {
|
---|
| 359 | result = NULL;
|
---|
| 360 | LogError("Base64_Encode:: BUFFER_routines failure.");
|
---|
| 361 | }
|
---|
| 362 | else
|
---|
| 363 | {
|
---|
| 364 | result = Base64_Encode_Internal(inputBinary, inputSize);
|
---|
| 365 | }
|
---|
| 366 | }
|
---|
| 367 | return result;
|
---|
| 368 | }
|
---|