• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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