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