base64-decode.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*
  2. * This code originally came from here
  3. *
  4. * http://base64.sourceforge.net/b64.c
  5. *
  6. * with the following license:
  7. *
  8. * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
  9. *
  10. * Permission is hereby granted, free of charge, to any person
  11. * obtaining a copy of this software and associated
  12. * documentation files (the "Software"), to deal in the
  13. * Software without restriction, including without limitation
  14. * the rights to use, copy, modify, merge, publish, distribute,
  15. * sublicense, and/or sell copies of the Software, and to
  16. * permit persons to whom the Software is furnished to do so,
  17. * subject to the following conditions:
  18. *
  19. * The above copyright notice and this permission notice shall
  20. * be included in all copies or substantial portions of the
  21. * Software.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  24. * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  25. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  26. * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  27. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  28. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  29. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  30. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. *
  32. * VERSION HISTORY:
  33. * Bob Trower 08/04/01 -- Create Version 0.00.00B
  34. *
  35. * I cleaned it up quite a bit to match the (linux kernel) style of the rest
  36. * of libwebsockets; this version is under LGPL2.1 + SLE like the rest of lws
  37. * since he explicitly allows sublicensing, but I give the URL above so you can
  38. * get the original with Bob's super-liberal terms directly if you prefer.
  39. */
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include "core/private.h"
  43. static const char encode_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  44. "abcdefghijklmnopqrstuvwxyz0123456789+/";
  45. static const char encode_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  46. "abcdefghijklmnopqrstuvwxyz0123456789-_";
  47. static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
  48. "$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
  49. static int
  50. _lws_b64_encode_string(const char *encode, const char *in, int in_len,
  51. char *out, int out_size)
  52. {
  53. unsigned char triple[3];
  54. int i;
  55. int len;
  56. int line = 0;
  57. int done = 0;
  58. while (in_len) {
  59. len = 0;
  60. for (i = 0; i < 3; i++) {
  61. if (in_len) {
  62. triple[i] = *in++;
  63. len++;
  64. in_len--;
  65. } else
  66. triple[i] = 0;
  67. }
  68. if (done + 4 >= out_size)
  69. return -1;
  70. *out++ = encode[triple[0] >> 2];
  71. *out++ = encode[((triple[0] & 0x03) << 4) |
  72. ((triple[1] & 0xf0) >> 4)];
  73. *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
  74. ((triple[2] & 0xc0) >> 6)] : '=');
  75. *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
  76. done += 4;
  77. line += 4;
  78. }
  79. if (done + 1 >= out_size)
  80. return -1;
  81. *out++ = '\0';
  82. return done;
  83. }
  84. LWS_VISIBLE int
  85. lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
  86. {
  87. return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
  88. }
  89. LWS_VISIBLE int
  90. lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
  91. {
  92. return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
  93. }
  94. /*
  95. * returns length of decoded string in out, or -1 if out was too small
  96. * according to out_size
  97. *
  98. * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
  99. * the first NUL in the input.
  100. */
  101. static int
  102. _lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
  103. {
  104. int len, i, c = 0, done = 0;
  105. unsigned char v, quad[4];
  106. while (in_len && *in) {
  107. len = 0;
  108. for (i = 0; i < 4 && in_len && *in; i++) {
  109. v = 0;
  110. c = 0;
  111. while (in_len && *in && !v) {
  112. c = v = *in++;
  113. in_len--;
  114. /* support the url base64 variant too */
  115. if (v == '-')
  116. c = v = '+';
  117. if (v == '_')
  118. c = v = '/';
  119. v = (v < 43 || v > 122) ? 0 : decode[v - 43];
  120. if (v)
  121. v = (v == '$') ? 0 : v - 61;
  122. }
  123. if (c) {
  124. len++;
  125. if (v)
  126. quad[i] = v - 1;
  127. } else
  128. quad[i] = 0;
  129. }
  130. if (out_size < (done + len - 1))
  131. /* out buffer is too small */
  132. return -1;
  133. /*
  134. * "The '==' sequence indicates that the last group contained
  135. * only one byte, and '=' indicates that it contained two
  136. * bytes." (wikipedia)
  137. */
  138. if ((!in_len || !*in) && c == '=')
  139. len--;
  140. if (len >= 2)
  141. *out++ = quad[0] << 2 | quad[1] >> 4;
  142. if (len >= 3)
  143. *out++ = quad[1] << 4 | quad[2] >> 2;
  144. if (len >= 4)
  145. *out++ = ((quad[2] << 6) & 0xc0) | quad[3];
  146. done += len - 1;
  147. }
  148. if (done + 1 >= out_size)
  149. return -1;
  150. *out = '\0';
  151. return done;
  152. }
  153. LWS_VISIBLE int
  154. lws_b64_decode_string(const char *in, char *out, int out_size)
  155. {
  156. return _lws_b64_decode_string(in, -1, out, out_size);
  157. }
  158. LWS_VISIBLE int
  159. lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
  160. {
  161. return _lws_b64_decode_string(in, in_len, out, out_size);
  162. }
  163. #if 0
  164. int
  165. lws_b64_selftest(void)
  166. {
  167. char buf[64];
  168. unsigned int n, r = 0;
  169. unsigned int test;
  170. /* examples from https://en.wikipedia.org/wiki/Base64 */
  171. static const char * const plaintext[] = {
  172. "any carnal pleasure.",
  173. "any carnal pleasure",
  174. "any carnal pleasur",
  175. "any carnal pleasu",
  176. "any carnal pleas",
  177. "Admin:kloikloi"
  178. };
  179. static const char * const coded[] = {
  180. "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
  181. "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
  182. "YW55IGNhcm5hbCBwbGVhc3Vy",
  183. "YW55IGNhcm5hbCBwbGVhc3U=",
  184. "YW55IGNhcm5hbCBwbGVhcw==",
  185. "QWRtaW46a2xvaWtsb2k="
  186. };
  187. for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {
  188. buf[sizeof(buf) - 1] = '\0';
  189. n = lws_b64_encode_string(plaintext[test],
  190. strlen(plaintext[test]), buf, sizeof buf);
  191. if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
  192. lwsl_err("Failed lws_b64 encode selftest "
  193. "%d result '%s' %d\n", test, buf, n);
  194. r = -1;
  195. }
  196. buf[sizeof(buf) - 1] = '\0';
  197. n = lws_b64_decode_string(coded[test], buf, sizeof buf);
  198. if (n != strlen(plaintext[test]) ||
  199. strcmp(buf, plaintext[test])) {
  200. lwsl_err("Failed lws_b64 decode selftest "
  201. "%d result '%s' / '%s', %d / %d\n",
  202. test, buf, plaintext[test], n, strlen(plaintext[test]));
  203. r = -1;
  204. }
  205. }
  206. lwsl_notice("Base 64 selftests passed\n");
  207. return r;
  208. }
  209. #endif