base64-decode.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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 line = 0;
  56. int done = 0;
  57. while (in_len) {
  58. int len = 0;
  59. for (i = 0; i < 3; i++) {
  60. if (in_len) {
  61. triple[i] = *in++;
  62. len++;
  63. in_len--;
  64. } else
  65. triple[i] = 0;
  66. }
  67. if (done + 4 >= out_size)
  68. return -1;
  69. *out++ = encode[triple[0] >> 2];
  70. *out++ = encode[((triple[0] & 0x03) << 4) |
  71. ((triple[1] & 0xf0) >> 4)];
  72. *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
  73. ((triple[2] & 0xc0) >> 6)] : '=');
  74. *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
  75. done += 4;
  76. line += 4;
  77. }
  78. if (done + 1 >= out_size)
  79. return -1;
  80. *out++ = '\0';
  81. return done;
  82. }
  83. LWS_VISIBLE int
  84. lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
  85. {
  86. return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
  87. }
  88. LWS_VISIBLE int
  89. lws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
  90. {
  91. return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
  92. }
  93. /*
  94. * returns length of decoded string in out, or -1 if out was too small
  95. * according to out_size
  96. *
  97. * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
  98. * the first NUL in the input.
  99. */
  100. static int
  101. _lws_b64_decode_string(const char *in, int in_len, char *out, int out_size)
  102. {
  103. int len, i, c = 0, done = 0;
  104. unsigned char v, quad[4];
  105. while (in_len && *in) {
  106. len = 0;
  107. for (i = 0; i < 4 && in_len && *in; i++) {
  108. v = 0;
  109. c = 0;
  110. while (in_len && *in && !v) {
  111. c = v = *in++;
  112. in_len--;
  113. /* support the url base64 variant too */
  114. if (v == '-')
  115. c = v = '+';
  116. if (v == '_')
  117. c = v = '/';
  118. v = (v < 43 || v > 122) ? 0 : decode[v - 43];
  119. if (v)
  120. v = (v == '$') ? 0 : v - 61;
  121. }
  122. if (c) {
  123. len++;
  124. if (v)
  125. quad[i] = v - 1;
  126. } else
  127. quad[i] = 0;
  128. }
  129. if (out_size < (done + len - 1))
  130. /* out buffer is too small */
  131. return -1;
  132. /*
  133. * "The '==' sequence indicates that the last group contained
  134. * only one byte, and '=' indicates that it contained two
  135. * bytes." (wikipedia)
  136. */
  137. if ((!in_len || !*in) && c == '=')
  138. len--;
  139. if (len >= 2)
  140. *out++ = quad[0] << 2 | quad[1] >> 4;
  141. if (len >= 3)
  142. *out++ = quad[1] << 4 | quad[2] >> 2;
  143. if (len >= 4)
  144. *out++ = ((quad[2] << 6) & 0xc0) | quad[3];
  145. done += len - 1;
  146. }
  147. if (done + 1 >= out_size)
  148. return -1;
  149. *out = '\0';
  150. return done;
  151. }
  152. LWS_VISIBLE int
  153. lws_b64_decode_string(const char *in, char *out, int out_size)
  154. {
  155. return _lws_b64_decode_string(in, -1, out, out_size);
  156. }
  157. LWS_VISIBLE int
  158. lws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
  159. {
  160. return _lws_b64_decode_string(in, in_len, out, out_size);
  161. }
  162. #if 0
  163. int
  164. lws_b64_selftest(void)
  165. {
  166. char buf[64];
  167. unsigned int n, r = 0;
  168. unsigned int test;
  169. /* examples from https://en.wikipedia.org/wiki/Base64 */
  170. static const char * const plaintext[] = {
  171. "any carnal pleasure.",
  172. "any carnal pleasure",
  173. "any carnal pleasur",
  174. "any carnal pleasu",
  175. "any carnal pleas",
  176. "Admin:kloikloi"
  177. };
  178. static const char * const coded[] = {
  179. "YW55IGNhcm5hbCBwbGVhc3VyZS4=",
  180. "YW55IGNhcm5hbCBwbGVhc3VyZQ==",
  181. "YW55IGNhcm5hbCBwbGVhc3Vy",
  182. "YW55IGNhcm5hbCBwbGVhc3U=",
  183. "YW55IGNhcm5hbCBwbGVhcw==",
  184. "QWRtaW46a2xvaWtsb2k="
  185. };
  186. for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) {
  187. buf[sizeof(buf) - 1] = '\0';
  188. n = lws_b64_encode_string(plaintext[test],
  189. strlen(plaintext[test]), buf, sizeof buf);
  190. if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
  191. lwsl_err("Failed lws_b64 encode selftest "
  192. "%d result '%s' %d\n", test, buf, n);
  193. r = -1;
  194. }
  195. buf[sizeof(buf) - 1] = '\0';
  196. n = lws_b64_decode_string(coded[test], buf, sizeof buf);
  197. if (n != strlen(plaintext[test]) ||
  198. strcmp(buf, plaintext[test])) {
  199. lwsl_err("Failed lws_b64 decode selftest "
  200. "%d result '%s' / '%s', %d / %d\n",
  201. test, buf, plaintext[test], n, strlen(plaintext[test]));
  202. r = -1;
  203. }
  204. }
  205. lwsl_notice("Base 64 selftests passed\n");
  206. return r;
  207. }
  208. #endif