You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
6.7 KiB

  1. /** @file */
  2. /** @brief File description for doxygen missing. FIXME */
  3. // This file is under GNU General Public License 3.0
  4. // see LICENSE.txt
  5. #include <stdbool.h>
  6. #include <stdlib.h>
  7. #include <assert.h>
  8. #include <string.h>
  9. #include "platform.h"
  10. #include "base64.h"
  11. static char translate_char_to_bits(char input) {
  12. if (input >= 65 && input <= 90)
  13. return input - 65;
  14. if (input >= 97 && input <= 122)
  15. return input - 71; // 97 - 26
  16. if (input >= 48 && input <= 57)
  17. return input + 4; // 52 - 48
  18. if (input == '+')
  19. return 62;
  20. if (input == '/')
  21. return 63;
  22. if (input == ' ' || input == '\r' || input == '\n')
  23. return 127;
  24. return -1;
  25. }
  26. /**
  27. * @internal
  28. *
  29. * <!-- _is_whitespace() -->
  30. *
  31. * @brief TODO
  32. *
  33. * @param[in] in constchar
  34. *
  35. */
  36. static bool _is_whitespace(const char in) {
  37. switch (in) {
  38. case ' ':
  39. case '\r':
  40. case '\t':
  41. case '\n':
  42. return true;
  43. default:
  44. return false;
  45. }
  46. }
  47. /**
  48. * @internal
  49. *
  50. * <!-- subtract_whitespace() -->
  51. *
  52. * @brief TODO
  53. *
  54. * @param[in] *input constchar
  55. * @param[in] length int
  56. *
  57. */
  58. static size_t subtract_whitespace(const char* input, int length) {
  59. size_t actual_size = length;
  60. int i;
  61. const char* curr = input;
  62. for (i = 0; i < length; i++, curr++) {
  63. if (_is_whitespace(*curr))
  64. actual_size--;
  65. }
  66. return actual_size;
  67. }
  68. /**
  69. * @internal
  70. *
  71. * <!-- trim_end() -->
  72. *
  73. * @brief TODO
  74. *
  75. * @param[in] *input constchar
  76. * @param[in] *length int
  77. *
  78. */
  79. static void trim_end(const char* input, int* length) {
  80. const char* end = input + *length;
  81. int start_length = *length;
  82. int i;
  83. for (i = 0; i < start_length; i++) {
  84. if (!_is_whitespace(*(--end)))
  85. break;
  86. (*length) = (*length) - 1;
  87. }
  88. }
  89. /**
  90. * @internal
  91. *
  92. * <!-- next_char() -->
  93. *
  94. * @brief TODO
  95. *
  96. * @param[in] **input_ptr constchar
  97. * @param[in] *end constchar
  98. *
  99. */
  100. char next_char(const char** input_ptr, const char* end) {
  101. const char* input = *input_ptr;
  102. char this_ch = 0;
  103. while (input < end) {
  104. this_ch = *input++;
  105. if (!this_ch)
  106. return 0;
  107. if (_is_whitespace(this_ch))
  108. continue;
  109. break;
  110. }
  111. *input_ptr = input;
  112. return this_ch;
  113. }
  114. // 4 chars = 3 output bytes
  115. bloblist_t* base64_str_to_binary_blob(const char* input, int length) {
  116. if (length == 0)
  117. return NULL;
  118. trim_end(input, &length);
  119. void* blobby = NULL;
  120. const char* input_curr;
  121. input_curr = input;
  122. const char* input_end = input_curr + length;
  123. length = subtract_whitespace(input, length);
  124. size_t final_length = (length / 4) * 3;
  125. // padded -- FIXME: whitespace in between ==!!!!
  126. if (final_length && *(input_end - 1) == '=') {
  127. final_length -= 1;
  128. // if final length is now decreased by 1 and greater than 0,
  129. // we know there's a char at (input_end - 2).
  130. if (final_length && *(input_end - 2) == '=')
  131. final_length -=1;
  132. }
  133. else {
  134. // not padded
  135. int leftover = length % 4;
  136. switch (leftover) {
  137. case 0:
  138. break;
  139. case 2:
  140. final_length++;
  141. break;
  142. case 3:
  143. final_length+=2;
  144. break;
  145. default:
  146. return NULL;
  147. }
  148. }
  149. if (!final_length)
  150. goto pEp_error;
  151. blobby = calloc(final_length, 1);
  152. char* blobby_curr = (char*)blobby;
  153. // if the last 1 or 2 bytes are padded, we do those after
  154. size_t number_of_rounds = final_length / 3;
  155. unsigned int cycle;
  156. // full 3-byte rounds
  157. for (cycle = 0; cycle < number_of_rounds; cycle++) {
  158. char byte_array[] = {0,0,0};
  159. char in_val = next_char(&input_curr, input_end);
  160. if (in_val == 0)
  161. goto pEp_error; // can ALSO happen when input_curr == input_end,
  162. // which simply shouldn't happen, since we're
  163. // interating based on expected OUTPUT, not
  164. // input.
  165. char out_val = translate_char_to_bits(in_val);
  166. if (out_val > 63)
  167. goto pEp_error;
  168. byte_array[0] |= out_val << 2;
  169. in_val = next_char(&input_curr, input_end);
  170. if (in_val == 0)
  171. goto pEp_error;
  172. out_val = translate_char_to_bits(in_val);
  173. if (out_val > 63)
  174. goto pEp_error;
  175. byte_array[0] |= out_val >> 4;
  176. byte_array[1] = out_val << 4;
  177. in_val = next_char(&input_curr, input_end);
  178. if (in_val == 0)
  179. goto pEp_error;
  180. out_val = translate_char_to_bits(in_val);
  181. if (out_val > 63)
  182. goto pEp_error;
  183. byte_array[1] |= out_val >> 2;
  184. byte_array[2] = out_val << 6;
  185. in_val = next_char(&input_curr, input_end);
  186. if (in_val == 0)
  187. goto pEp_error;
  188. out_val = translate_char_to_bits(in_val);
  189. if (out_val > 63)
  190. goto pEp_error;
  191. byte_array[2] |= out_val;
  192. // Now write everything to the blob
  193. *blobby_curr++ = byte_array[0];
  194. *blobby_curr++ = byte_array[1];
  195. *blobby_curr++ = byte_array[2];
  196. }
  197. int last_bytes = final_length % 3;
  198. if (last_bytes != 0) {
  199. char byte_1 = 0;
  200. char byte_2 = 0;
  201. char in_val = next_char(&input_curr, input_end);
  202. if (in_val == 0)
  203. goto pEp_error;
  204. char out_val = translate_char_to_bits(in_val);
  205. if (out_val > 63)
  206. goto pEp_error;
  207. byte_1 = out_val << 2;
  208. in_val = next_char(&input_curr, input_end);
  209. if (in_val == 0)
  210. goto pEp_error;
  211. out_val = translate_char_to_bits(in_val);
  212. if (out_val > 63)
  213. goto pEp_error;
  214. byte_1 |= out_val >> 4;
  215. *blobby_curr++ = byte_1;
  216. if (last_bytes == 2) {
  217. byte_2 = out_val << 4;
  218. in_val = next_char(&input_curr, input_end);
  219. if (in_val == 0)
  220. goto pEp_error;
  221. out_val = translate_char_to_bits(in_val);
  222. if (out_val > 63)
  223. goto pEp_error;
  224. byte_2 |= out_val >> 2;
  225. *blobby_curr++ = byte_2;
  226. }
  227. }
  228. return new_bloblist((char*)blobby, final_length, NULL, NULL);
  229. pEp_error:
  230. free(blobby);
  231. return NULL;
  232. }