codecs.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include <assert.h>
  2. #include <errno.h>
  3. #include <limits.h>
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "core.h"
  9. #include "utils.h"
  10. /* Derived from original code by CodesInChaos */
  11. char *
  12. sodium_bin2hex(char *const hex, const size_t hex_maxlen,
  13. const unsigned char *const bin, const size_t bin_len)
  14. {
  15. size_t i = (size_t) 0U;
  16. unsigned int x;
  17. int b;
  18. int c;
  19. if (bin_len >= SIZE_MAX / 2 || hex_maxlen <= bin_len * 2U) {
  20. sodium_misuse(); /* LCOV_EXCL_LINE */
  21. }
  22. while (i < bin_len) {
  23. c = bin[i] & 0xf;
  24. b = bin[i] >> 4;
  25. x = (unsigned char) (87U + c + (((c - 10U) >> 8) & ~38U)) << 8 |
  26. (unsigned char) (87U + b + (((b - 10U) >> 8) & ~38U));
  27. hex[i * 2U] = (char) x;
  28. x >>= 8;
  29. hex[i * 2U + 1U] = (char) x;
  30. i++;
  31. }
  32. hex[i * 2U] = 0U;
  33. return hex;
  34. }
  35. int
  36. sodium_hex2bin(unsigned char *const bin, const size_t bin_maxlen,
  37. const char *const hex, const size_t hex_len,
  38. const char *const ignore, size_t *const bin_len,
  39. const char **const hex_end)
  40. {
  41. size_t bin_pos = (size_t) 0U;
  42. size_t hex_pos = (size_t) 0U;
  43. int ret = 0;
  44. unsigned char c;
  45. unsigned char c_acc = 0U;
  46. unsigned char c_alpha0, c_alpha;
  47. unsigned char c_num0, c_num;
  48. unsigned char c_val;
  49. unsigned char state = 0U;
  50. while (hex_pos < hex_len) {
  51. c = (unsigned char) hex[hex_pos];
  52. c_num = c ^ 48U;
  53. c_num0 = (c_num - 10U) >> 8;
  54. c_alpha = (c & ~32U) - 55U;
  55. c_alpha0 = ((c_alpha - 10U) ^ (c_alpha - 16U)) >> 8;
  56. if ((c_num0 | c_alpha0) == 0U) {
  57. if (ignore != NULL && state == 0U && strchr(ignore, c) != NULL) {
  58. hex_pos++;
  59. continue;
  60. }
  61. break;
  62. }
  63. c_val = (c_num0 & c_num) | (c_alpha0 & c_alpha);
  64. if (bin_pos >= bin_maxlen) {
  65. ret = -1;
  66. errno = ERANGE;
  67. break;
  68. }
  69. if (state == 0U) {
  70. c_acc = c_val * 16U;
  71. } else {
  72. bin[bin_pos++] = c_acc | c_val;
  73. }
  74. state = ~state;
  75. hex_pos++;
  76. }
  77. if (state != 0U) {
  78. hex_pos--;
  79. errno = EINVAL;
  80. ret = -1;
  81. }
  82. if (ret != 0) {
  83. bin_pos = (size_t) 0U;
  84. }
  85. if (hex_end != NULL) {
  86. *hex_end = &hex[hex_pos];
  87. } else if (hex_pos != hex_len) {
  88. errno = EINVAL;
  89. ret = -1;
  90. }
  91. if (bin_len != NULL) {
  92. *bin_len = bin_pos;
  93. }
  94. return ret;
  95. }
  96. /*
  97. * Some macros for constant-time comparisons. These work over values in
  98. * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
  99. *
  100. * Original code by Thomas Pornin.
  101. */
  102. #define EQ(x, y) \
  103. ((((0U - ((unsigned int) (x) ^ (unsigned int) (y))) >> 8) & 0xFF) ^ 0xFF)
  104. #define GT(x, y) ((((unsigned int) (y) - (unsigned int) (x)) >> 8) & 0xFF)
  105. #define GE(x, y) (GT(y, x) ^ 0xFF)
  106. #define LT(x, y) GT(y, x)
  107. #define LE(x, y) GE(y, x)
  108. static int
  109. b64_byte_to_char(unsigned int x)
  110. {
  111. return (LT(x, 26) & (x + 'A')) |
  112. (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
  113. (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '+') |
  114. (EQ(x, 63) & '/');
  115. }
  116. static unsigned int
  117. b64_char_to_byte(int c)
  118. {
  119. const unsigned int x =
  120. (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
  121. (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
  122. (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
  123. (EQ(c, '/') & 63);
  124. return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
  125. }
  126. static int
  127. b64_byte_to_urlsafe_char(unsigned int x)
  128. {
  129. return (LT(x, 26) & (x + 'A')) |
  130. (GE(x, 26) & LT(x, 52) & (x + ('a' - 26))) |
  131. (GE(x, 52) & LT(x, 62) & (x + ('0' - 52))) | (EQ(x, 62) & '-') |
  132. (EQ(x, 63) & '_');
  133. }
  134. static unsigned int
  135. b64_urlsafe_char_to_byte(int c)
  136. {
  137. const unsigned x =
  138. (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
  139. (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
  140. (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '-') & 62) |
  141. (EQ(c, '_') & 63);
  142. return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
  143. }
  144. #define VARIANT_NO_PADDING_MASK 0x2U
  145. #define VARIANT_URLSAFE_MASK 0x4U
  146. static void
  147. sodium_base64_check_variant(const int variant)
  148. {
  149. if ((((unsigned int) variant) & ~ 0x6U) != 0x1U) {
  150. sodium_misuse();
  151. }
  152. }
  153. size_t
  154. sodium_base64_encoded_len(const size_t bin_len, const int variant)
  155. {
  156. sodium_base64_check_variant(variant);
  157. return sodium_base64_ENCODED_LEN(bin_len, variant);
  158. }
  159. char *
  160. sodium_bin2base64(char * const b64, const size_t b64_maxlen,
  161. const unsigned char * const bin, const size_t bin_len,
  162. const int variant)
  163. {
  164. size_t acc_len = (size_t) 0;
  165. size_t b64_len;
  166. size_t b64_pos = (size_t) 0;
  167. size_t bin_pos = (size_t) 0;
  168. size_t nibbles;
  169. size_t remainder;
  170. unsigned int acc = 0U;
  171. sodium_base64_check_variant(variant);
  172. nibbles = bin_len / 3;
  173. remainder = bin_len - 3 * nibbles;
  174. b64_len = nibbles * 4;
  175. if (remainder != 0) {
  176. if ((((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) {
  177. b64_len += 4;
  178. } else {
  179. b64_len += 2 + (remainder >> 1);
  180. }
  181. }
  182. if (b64_maxlen <= b64_len) {
  183. sodium_misuse();
  184. }
  185. if ((((unsigned int) variant) & VARIANT_URLSAFE_MASK) != 0U) {
  186. while (bin_pos < bin_len) {
  187. acc = (acc << 8) + bin[bin_pos++];
  188. acc_len += 8;
  189. while (acc_len >= 6) {
  190. acc_len -= 6;
  191. b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc >> acc_len) & 0x3F);
  192. }
  193. }
  194. if (acc_len > 0) {
  195. b64[b64_pos++] = (char) b64_byte_to_urlsafe_char((acc << (6 - acc_len)) & 0x3F);
  196. }
  197. } else {
  198. while (bin_pos < bin_len) {
  199. acc = (acc << 8) + bin[bin_pos++];
  200. acc_len += 8;
  201. while (acc_len >= 6) {
  202. acc_len -= 6;
  203. b64[b64_pos++] = (char) b64_byte_to_char((acc >> acc_len) & 0x3F);
  204. }
  205. }
  206. if (acc_len > 0) {
  207. b64[b64_pos++] = (char) b64_byte_to_char((acc << (6 - acc_len)) & 0x3F);
  208. }
  209. }
  210. assert(b64_pos <= b64_len);
  211. while (b64_pos < b64_len) {
  212. b64[b64_pos++] = '=';
  213. }
  214. do {
  215. b64[b64_pos++] = 0U;
  216. } while (b64_pos < b64_maxlen);
  217. return b64;
  218. }
  219. static int
  220. _sodium_base642bin_skip_padding(const char * const b64, const size_t b64_len,
  221. size_t * const b64_pos_p,
  222. const char * const ignore, size_t padding_len)
  223. {
  224. int c;
  225. while (padding_len > 0) {
  226. if (*b64_pos_p >= b64_len) {
  227. errno = ERANGE;
  228. return -1;
  229. }
  230. c = b64[*b64_pos_p];
  231. if (c == '=') {
  232. padding_len--;
  233. } else if (ignore == NULL || strchr(ignore, c) == NULL) {
  234. errno = EINVAL;
  235. return -1;
  236. }
  237. (*b64_pos_p)++;
  238. }
  239. return 0;
  240. }
  241. int
  242. sodium_base642bin(unsigned char * const bin, const size_t bin_maxlen,
  243. const char * const b64, const size_t b64_len,
  244. const char * const ignore, size_t * const bin_len,
  245. const char ** const b64_end, const int variant)
  246. {
  247. size_t acc_len = (size_t) 0;
  248. size_t b64_pos = (size_t) 0;
  249. size_t bin_pos = (size_t) 0;
  250. int is_urlsafe;
  251. int ret = 0;
  252. unsigned int acc = 0U;
  253. unsigned int d;
  254. char c;
  255. sodium_base64_check_variant(variant);
  256. is_urlsafe = ((unsigned int) variant) & VARIANT_URLSAFE_MASK;
  257. while (b64_pos < b64_len) {
  258. c = b64[b64_pos];
  259. if (is_urlsafe) {
  260. d = b64_urlsafe_char_to_byte(c);
  261. } else {
  262. d = b64_char_to_byte(c);
  263. }
  264. if (d == 0xFF) {
  265. if (ignore != NULL && strchr(ignore, c) != NULL) {
  266. b64_pos++;
  267. continue;
  268. }
  269. break;
  270. }
  271. acc = (acc << 6) + d;
  272. acc_len += 6;
  273. if (acc_len >= 8) {
  274. acc_len -= 8;
  275. if (bin_pos >= bin_maxlen) {
  276. errno = ERANGE;
  277. ret = -1;
  278. break;
  279. }
  280. bin[bin_pos++] = (acc >> acc_len) & 0xFF;
  281. }
  282. b64_pos++;
  283. }
  284. if (acc_len > 4U || (acc & ((1U << acc_len) - 1U)) != 0U) {
  285. ret = -1;
  286. } else if (ret == 0 &&
  287. (((unsigned int) variant) & VARIANT_NO_PADDING_MASK) == 0U) {
  288. ret = _sodium_base642bin_skip_padding(b64, b64_len, &b64_pos, ignore,
  289. acc_len / 2);
  290. }
  291. if (ret != 0) {
  292. bin_pos = (size_t) 0U;
  293. } else if (ignore != NULL) {
  294. while (b64_pos < b64_len && strchr(ignore, b64[b64_pos]) != NULL) {
  295. b64_pos++;
  296. }
  297. }
  298. if (b64_end != NULL) {
  299. *b64_end = &b64[b64_pos];
  300. } else if (b64_pos != b64_len) {
  301. errno = EINVAL;
  302. ret = -1;
  303. }
  304. if (bin_len != NULL) {
  305. *bin_len = bin_pos;
  306. }
  307. return ret;
  308. }