Base64.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /*******************************************************************************
  2. * Copyright (c) 2018 Wind River Systems, Inc. All Rights Reserved.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v1.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * http://www.eclipse.org/legal/epl-v10.html
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Keith Holman - initial implementation and documentation
  15. *******************************************************************************/
  16. #include "Base64.h"
  17. #if defined(WIN32) || defined(WIN64)
  18. #pragma comment(lib, "crypt32.lib")
  19. #include <Windows.h>
  20. #include <WinCrypt.h>
  21. b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
  22. {
  23. b64_size_t ret = 0u;
  24. DWORD dw_out_len = (DWORD)out_len;
  25. if ( CryptStringToBinaryA( in, in_len, CRYPT_STRING_BASE64, out, &dw_out_len, NULL, NULL ) )
  26. ret = (b64_size_t)dw_out_len;
  27. return ret;
  28. }
  29. b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
  30. {
  31. b64_size_t ret = 0u;
  32. DWORD dw_out_len = (DWORD)out_len;
  33. if ( CryptBinaryToStringA( in, in_len, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, out, &dw_out_len ) )
  34. ret = (b64_size_t)dw_out_len;
  35. return ret;
  36. }
  37. #else /* if defined(WIN32) || defined(WIN64) */
  38. #if defined(OPENSSL)
  39. #include <openssl/bio.h>
  40. #include <openssl/evp.h>
  41. static b64_size_t Base64_encodeDecode(
  42. char *out, b64_size_t out_len, const char *in, b64_size_t in_len, int encode )
  43. {
  44. b64_size_t ret = 0u;
  45. if ( in_len > 0u )
  46. {
  47. int rv;
  48. BIO *bio, *b64, *b_in, *b_out;
  49. b64 = BIO_new(BIO_f_base64());
  50. bio = BIO_new(BIO_s_mem());
  51. b64 = BIO_push(b64, bio);
  52. BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); /* ignore new-lines */
  53. if ( encode )
  54. {
  55. b_in = bio;
  56. b_out = b64;
  57. }
  58. else
  59. {
  60. b_in = b64;
  61. b_out = bio;
  62. }
  63. rv = BIO_write(b_out, in, (int)in_len);
  64. BIO_flush(b_out); /* indicate end of encoding */
  65. if ( rv > 0 )
  66. {
  67. rv = BIO_read(b_in, out, (int)out_len);
  68. if ( rv > 0 )
  69. {
  70. ret = (b64_size_t)rv;
  71. if ( out_len > ret )
  72. out[ret] = '\0';
  73. }
  74. }
  75. BIO_free_all(b64); /* free all used memory */
  76. }
  77. return ret;
  78. }
  79. b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
  80. {
  81. return Base64_encodeDecode( (char*)out, out_len, in, in_len, 0 );
  82. }
  83. b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
  84. {
  85. return Base64_encodeDecode( out, out_len, (const char*)in, in_len, 1 );
  86. }
  87. #else /* if defined(OPENSSL) */
  88. b64_size_t Base64_decode( b64_data_t *out, b64_size_t out_len, const char *in, b64_size_t in_len )
  89. {
  90. #define NV 64
  91. static const unsigned char BASE64_DECODE_TABLE[] =
  92. {
  93. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 0-15 */
  94. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 16-31 */
  95. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, 62, NV, NV, NV, 63, /* 32-47 */
  96. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, NV, NV, NV, NV, NV, NV, /* 48-63 */
  97. NV, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 64-79 */
  98. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, NV, NV, NV, NV, NV, /* 80-95 */
  99. NV, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 96-111 */
  100. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, NV, NV, NV, NV, NV, /* 112-127 */
  101. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 128-143 */
  102. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 144-159 */
  103. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 160-175 */
  104. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 176-191 */
  105. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 192-207 */
  106. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 208-223 */
  107. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, /* 224-239 */
  108. NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV, NV /* 240-255 */
  109. };
  110. b64_size_t ret = 0u;
  111. b64_size_t out_count = 0u;
  112. /* in valid base64, length must be multiple of 4's: 0, 4, 8, 12, etc */
  113. while ( in_len > 3u && out_count < out_len )
  114. {
  115. int i;
  116. unsigned char c[4];
  117. for ( i = 0; i < 4; ++i, ++in )
  118. c[i] = BASE64_DECODE_TABLE[(int)(*in)];
  119. in_len -= 4u;
  120. /* first byte */
  121. *out = c[0] << 2;
  122. *out |= (c[1] & ~0xF) >> 4;
  123. ++out;
  124. ++out_count;
  125. if ( out_count < out_len )
  126. {
  127. /* second byte */
  128. *out = (c[1] & 0xF) << 4;
  129. if ( c[2] < NV )
  130. {
  131. *out |= (c[2] & ~0x3) >> 2;
  132. ++out;
  133. ++out_count;
  134. if ( out_count < out_len )
  135. {
  136. /* third byte */
  137. *out = (c[2] & 0x3) << 6;
  138. if ( c[3] < NV )
  139. {
  140. *out |= c[3];
  141. ++out;
  142. ++out_count;
  143. }
  144. else
  145. in_len = 0u;
  146. }
  147. }
  148. else
  149. in_len = 0u;
  150. }
  151. }
  152. if ( out_count <= out_len )
  153. {
  154. ret = out_count;
  155. if ( out_count < out_len )
  156. *out = '\0';
  157. }
  158. return ret;
  159. }
  160. b64_size_t Base64_encode( char *out, b64_size_t out_len, const b64_data_t *in, b64_size_t in_len )
  161. {
  162. static const char BASE64_ENCODE_TABLE[] =
  163. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  164. "abcdefghijklmnopqrstuvwxyz"
  165. "0123456789+/=";
  166. b64_size_t ret = 0u;
  167. b64_size_t out_count = 0u;
  168. while ( in_len > 0u && out_count < out_len )
  169. {
  170. int i;
  171. unsigned char c[] = { 0, 0, 64, 64 }; /* index of '=' char */
  172. /* first character */
  173. i = *in;
  174. c[0] = (i & ~0x3) >> 2;
  175. /* second character */
  176. c[1] = (i & 0x3) << 4;
  177. --in_len;
  178. if ( in_len > 0u )
  179. {
  180. ++in;
  181. i = *in;
  182. c[1] |= (i & ~0xF) >> 4;
  183. /* third character */
  184. c[2] = (i & 0xF) << 2;
  185. --in_len;
  186. if ( in_len > 0u )
  187. {
  188. ++in;
  189. i = *in;
  190. c[2] |= (i & ~0x3F) >> 6;
  191. /* fourth character */
  192. c[3] = (i & 0x3F);
  193. --in_len;
  194. ++in;
  195. }
  196. }
  197. /* encode the characters */
  198. out_count += 4u;
  199. for ( i = 0; i < 4 && out_count <= out_len; ++i, ++out )
  200. *out = BASE64_ENCODE_TABLE[c[i]];
  201. }
  202. if ( out_count <= out_len )
  203. {
  204. if ( out_count < out_len )
  205. *out = '\0';
  206. ret = out_count;
  207. }
  208. return ret;
  209. }
  210. #endif /* else if defined(OPENSSL) */
  211. #endif /* if else defined(WIN32) || defined(WIN64) */
  212. b64_size_t Base64_decodeLength( const char *in, b64_size_t in_len )
  213. {
  214. b64_size_t pad = 0u;
  215. if ( in && in_len > 1u )
  216. pad += ( in[in_len - 2u] == '=' ? 1u : 0u );
  217. if ( in && in_len > 0u )
  218. pad += ( in[in_len - 1u] == '=' ? 1u : 0u );
  219. return (in_len / 4u * 3u) - pad;
  220. }
  221. b64_size_t Base64_encodeLength( const b64_data_t *in, b64_size_t in_len )
  222. {
  223. return ((4u * in_len / 3u) + 3u) & ~0x3;
  224. }
  225. #if defined(BASE64_TEST)
  226. #include <stdio.h>
  227. #include <string.h>
  228. #define TEST_EXPECT(i,x) if (!(x)) {fprintf( stderr, "failed test: %s (for i == %d)\n", #x, i ); ++fails;}
  229. int main(int argc, char *argv[])
  230. {
  231. struct _td
  232. {
  233. const char *in;
  234. const char *out;
  235. };
  236. int i;
  237. unsigned int fails = 0u;
  238. struct _td test_data[] = {
  239. { "", "" },
  240. { "p", "cA==" },
  241. { "pa", "cGE=" },
  242. { "pah", "cGFo" },
  243. { "paho", "cGFobw==" },
  244. { "paho ", "cGFobyA=" },
  245. { "paho w", "cGFobyB3" },
  246. { "paho wi", "cGFobyB3aQ==" },
  247. { "paho wit", "cGFobyB3aXQ=" },
  248. { "paho with", "cGFobyB3aXRo" },
  249. { "paho with ", "cGFobyB3aXRoIA==" },
  250. { "paho with w", "cGFobyB3aXRoIHc=" },
  251. { "paho with we", "cGFobyB3aXRoIHdl" },
  252. { "paho with web", "cGFobyB3aXRoIHdlYg==" },
  253. { "paho with webs", "cGFobyB3aXRoIHdlYnM=" },
  254. { "paho with webso", "cGFobyB3aXRoIHdlYnNv" },
  255. { "paho with websoc", "cGFobyB3aXRoIHdlYnNvYw==" },
  256. { "paho with websock", "cGFobyB3aXRoIHdlYnNvY2s=" },
  257. { "paho with websocke", "cGFobyB3aXRoIHdlYnNvY2tl" },
  258. { "paho with websocket", "cGFobyB3aXRoIHdlYnNvY2tldA==" },
  259. { "paho with websockets", "cGFobyB3aXRoIHdlYnNvY2tldHM=" },
  260. { "paho with websockets.", "cGFobyB3aXRoIHdlYnNvY2tldHMu" },
  261. { "The quick brown fox jumps over the lazy dog",
  262. "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw==" },
  263. { "Man is distinguished, not only by his reason, but by this singular passion from\n"
  264. "other animals, which is a lust of the mind, that by a perseverance of delight\n"
  265. "in the continued and indefatigable generation of knowledge, exceeds the short\n"
  266. "vehemence of any carnal pleasure.",
  267. "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz"
  268. "IHNpbmd1bGFyIHBhc3Npb24gZnJvbQpvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg"
  269. "dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodAppbiB0aGUgY29udGlu"
  270. "dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo"
  271. "ZSBzaG9ydAp2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=" },
  272. { NULL, NULL }
  273. };
  274. /* decode tests */
  275. i = 0;
  276. while ( test_data[i].in != NULL )
  277. {
  278. int r;
  279. char out[512u];
  280. r = Base64_decode( out, sizeof(out), test_data[i].out, strlen(test_data[i].out) );
  281. TEST_EXPECT( i, r == strlen(test_data[i].in) && strncmp(out, test_data[i].in, strlen(test_data[i].in)) == 0 );
  282. ++i;
  283. }
  284. /* decode length tests */
  285. i = 0;
  286. while ( test_data[i].in != NULL )
  287. {
  288. TEST_EXPECT( i, Base64_decodeLength(test_data[i].out, strlen(test_data[i].out)) == strlen(test_data[i].in));
  289. ++i;
  290. }
  291. /* encode tests */
  292. i = 0;
  293. while ( test_data[i].in != NULL )
  294. {
  295. int r;
  296. char out[512u];
  297. r = Base64_encode( out, sizeof(out), test_data[i].in, strlen(test_data[i].in) );
  298. TEST_EXPECT( i, r == strlen(test_data[i].out) && strncmp(out, test_data[i].out, strlen(test_data[i].out)) == 0 );
  299. ++i;
  300. }
  301. /* encode length tests */
  302. i = 0;
  303. while ( test_data[i].in != NULL )
  304. {
  305. TEST_EXPECT( i, Base64_encodeLength(test_data[i].in, strlen(test_data[i].in)) == strlen(test_data[i].out) );
  306. ++i;
  307. }
  308. if ( fails )
  309. printf( "%u test failed!\n", fails );
  310. else
  311. printf( "all tests passed\n" );
  312. return fails;
  313. }
  314. #endif /* if defined(BASE64_TEST) */