1d4afb5ceSopenharmony_ci/*
2d4afb5ceSopenharmony_ci * This code originally came from here
3d4afb5ceSopenharmony_ci *
4d4afb5ceSopenharmony_ci * http://base64.sourceforge.net/b64.c
5d4afb5ceSopenharmony_ci *
6d4afb5ceSopenharmony_ci * already with MIT license, which is retained.
7d4afb5ceSopenharmony_ci *
8d4afb5ceSopenharmony_ci * LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
9d4afb5ceSopenharmony_ci *
10d4afb5ceSopenharmony_ci *                Permission is hereby granted, free of charge, to any person
11d4afb5ceSopenharmony_ci *                obtaining a copy of this software and associated
12d4afb5ceSopenharmony_ci *                documentation files (the "Software"), to deal in the
13d4afb5ceSopenharmony_ci *                Software without restriction, including without limitation
14d4afb5ceSopenharmony_ci *                the rights to use, copy, modify, merge, publish, distribute,
15d4afb5ceSopenharmony_ci *                sublicense, and/or sell copies of the Software, and to
16d4afb5ceSopenharmony_ci *                permit persons to whom the Software is furnished to do so,
17d4afb5ceSopenharmony_ci *                subject to the following conditions:
18d4afb5ceSopenharmony_ci *
19d4afb5ceSopenharmony_ci *                The above copyright notice and this permission notice shall
20d4afb5ceSopenharmony_ci *                be included in all copies or substantial portions of the
21d4afb5ceSopenharmony_ci *                Software.
22d4afb5ceSopenharmony_ci *
23d4afb5ceSopenharmony_ci *                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
24d4afb5ceSopenharmony_ci *                KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
25d4afb5ceSopenharmony_ci *                WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
26d4afb5ceSopenharmony_ci *                PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
27d4afb5ceSopenharmony_ci *                OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
28d4afb5ceSopenharmony_ci *                OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
29d4afb5ceSopenharmony_ci *                OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
30d4afb5ceSopenharmony_ci *                SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31d4afb5ceSopenharmony_ci *
32d4afb5ceSopenharmony_ci * VERSION HISTORY:
33d4afb5ceSopenharmony_ci *               Bob Trower 08/04/01 -- Create Version 0.00.00B
34d4afb5ceSopenharmony_ci *
35d4afb5ceSopenharmony_ci * I cleaned it up quite a bit to match the (linux kernel) style of the rest
36d4afb5ceSopenharmony_ci * of libwebsockets
37d4afb5ceSopenharmony_ci */
38d4afb5ceSopenharmony_ci
39d4afb5ceSopenharmony_ci#include "private-lib-core.h"
40d4afb5ceSopenharmony_ci
41d4afb5ceSopenharmony_ci#include <stdio.h>
42d4afb5ceSopenharmony_ci#include <string.h>
43d4afb5ceSopenharmony_ci
44d4afb5ceSopenharmony_cistatic const char encode_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
45d4afb5ceSopenharmony_ci			     "abcdefghijklmnopqrstuvwxyz0123456789+/";
46d4afb5ceSopenharmony_cistatic const char encode_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47d4afb5ceSopenharmony_ci			     "abcdefghijklmnopqrstuvwxyz0123456789-_";
48d4afb5ceSopenharmony_cistatic const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
49d4afb5ceSopenharmony_ci			     "$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
50d4afb5ceSopenharmony_ci
51d4afb5ceSopenharmony_cistatic int
52d4afb5ceSopenharmony_ci_lws_b64_encode_string(const char *encode, const char *in, int in_len,
53d4afb5ceSopenharmony_ci		       char *out, int out_size)
54d4afb5ceSopenharmony_ci{
55d4afb5ceSopenharmony_ci	unsigned char triple[3];
56d4afb5ceSopenharmony_ci	int i, done = 0;
57d4afb5ceSopenharmony_ci
58d4afb5ceSopenharmony_ci	while (in_len) {
59d4afb5ceSopenharmony_ci		int len = 0;
60d4afb5ceSopenharmony_ci		for (i = 0; i < 3; i++) {
61d4afb5ceSopenharmony_ci			if (in_len) {
62d4afb5ceSopenharmony_ci				triple[i] = (unsigned char)*in++;
63d4afb5ceSopenharmony_ci				len++;
64d4afb5ceSopenharmony_ci				in_len--;
65d4afb5ceSopenharmony_ci			} else
66d4afb5ceSopenharmony_ci				triple[i] = 0;
67d4afb5ceSopenharmony_ci		}
68d4afb5ceSopenharmony_ci
69d4afb5ceSopenharmony_ci		if (done + 4 >= out_size)
70d4afb5ceSopenharmony_ci			return -1;
71d4afb5ceSopenharmony_ci
72d4afb5ceSopenharmony_ci		*out++ = encode[triple[0] >> 2];
73d4afb5ceSopenharmony_ci		*out++ = encode[(((triple[0] & 0x03) << 4) & 0x30) |
74d4afb5ceSopenharmony_ci					     (((triple[1] & 0xf0) >> 4) & 0x0f)];
75d4afb5ceSopenharmony_ci		*out++ = (char)(len > 1 ? encode[(((triple[1] & 0x0f) << 2) & 0x3c) |
76d4afb5ceSopenharmony_ci					(((triple[2] & 0xc0) >> 6) & 3)] : '=');
77d4afb5ceSopenharmony_ci		*out++ = (char)(len > 2 ? encode[triple[2] & 0x3f] : '=');
78d4afb5ceSopenharmony_ci
79d4afb5ceSopenharmony_ci		done += 4;
80d4afb5ceSopenharmony_ci	}
81d4afb5ceSopenharmony_ci
82d4afb5ceSopenharmony_ci	if (done + 1 >= out_size)
83d4afb5ceSopenharmony_ci		return -1;
84d4afb5ceSopenharmony_ci
85d4afb5ceSopenharmony_ci	*out++ = '\0';
86d4afb5ceSopenharmony_ci
87d4afb5ceSopenharmony_ci	return done;
88d4afb5ceSopenharmony_ci}
89d4afb5ceSopenharmony_ci
90d4afb5ceSopenharmony_ciint
91d4afb5ceSopenharmony_cilws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
92d4afb5ceSopenharmony_ci{
93d4afb5ceSopenharmony_ci	return _lws_b64_encode_string(encode_orig, in, in_len, out, out_size);
94d4afb5ceSopenharmony_ci}
95d4afb5ceSopenharmony_ci
96d4afb5ceSopenharmony_ciint
97d4afb5ceSopenharmony_cilws_b64_encode_string_url(const char *in, int in_len, char *out, int out_size)
98d4afb5ceSopenharmony_ci{
99d4afb5ceSopenharmony_ci	return _lws_b64_encode_string(encode_url, in, in_len, out, out_size);
100d4afb5ceSopenharmony_ci}
101d4afb5ceSopenharmony_ci
102d4afb5ceSopenharmony_ci
103d4afb5ceSopenharmony_civoid
104d4afb5ceSopenharmony_cilws_b64_decode_state_init(struct lws_b64state *state)
105d4afb5ceSopenharmony_ci{
106d4afb5ceSopenharmony_ci	memset(state, 0, sizeof(*state));
107d4afb5ceSopenharmony_ci}
108d4afb5ceSopenharmony_ci
109d4afb5ceSopenharmony_ciint
110d4afb5ceSopenharmony_cilws_b64_decode_stateful(struct lws_b64state *s, const char *in, size_t *in_len,
111d4afb5ceSopenharmony_ci			uint8_t *out, size_t *out_size, int final)
112d4afb5ceSopenharmony_ci{
113d4afb5ceSopenharmony_ci	const char *orig_in = in, *end_in = in + *in_len;
114d4afb5ceSopenharmony_ci	uint8_t *orig_out = out, *end_out = out + *out_size;
115d4afb5ceSopenharmony_ci
116d4afb5ceSopenharmony_ci	while (in < end_in && *in && out + 3 <= end_out) {
117d4afb5ceSopenharmony_ci
118d4afb5ceSopenharmony_ci		for (; s->i < 4 && in < end_in && *in; s->i++) {
119d4afb5ceSopenharmony_ci			uint8_t v;
120d4afb5ceSopenharmony_ci
121d4afb5ceSopenharmony_ci			v = 0;
122d4afb5ceSopenharmony_ci			s->c = 0;
123d4afb5ceSopenharmony_ci			while (in < end_in && *in && !v) {
124d4afb5ceSopenharmony_ci				s->c = v = (unsigned char)*in++;
125d4afb5ceSopenharmony_ci				/* support the url base64 variant too */
126d4afb5ceSopenharmony_ci				if (v == '-')
127d4afb5ceSopenharmony_ci					s->c = v = '+';
128d4afb5ceSopenharmony_ci				if (v == '_')
129d4afb5ceSopenharmony_ci					s->c = v = '/';
130d4afb5ceSopenharmony_ci				v = (uint8_t)((v < 43 || v > 122) ? 0 : decode[v - 43]);
131d4afb5ceSopenharmony_ci				if (v)
132d4afb5ceSopenharmony_ci					v = (uint8_t)((v == '$') ? 0 : v - 61);
133d4afb5ceSopenharmony_ci			}
134d4afb5ceSopenharmony_ci			if (s->c) {
135d4afb5ceSopenharmony_ci				s->len++;
136d4afb5ceSopenharmony_ci				if (v)
137d4afb5ceSopenharmony_ci					s->quad[s->i] = (uint8_t)(v - 1);
138d4afb5ceSopenharmony_ci			} else
139d4afb5ceSopenharmony_ci				s->quad[s->i] = 0;
140d4afb5ceSopenharmony_ci		}
141d4afb5ceSopenharmony_ci
142d4afb5ceSopenharmony_ci		if (s->i != 4 && !final)
143d4afb5ceSopenharmony_ci			continue;
144d4afb5ceSopenharmony_ci
145d4afb5ceSopenharmony_ci		s->i = 0;
146d4afb5ceSopenharmony_ci
147d4afb5ceSopenharmony_ci		/*
148d4afb5ceSopenharmony_ci		 * "The '==' sequence indicates that the last group contained
149d4afb5ceSopenharmony_ci		 * only one byte, and '=' indicates that it contained two
150d4afb5ceSopenharmony_ci		 * bytes." (wikipedia)
151d4afb5ceSopenharmony_ci		 */
152d4afb5ceSopenharmony_ci
153d4afb5ceSopenharmony_ci		if ((in >= end_in || !*in) && s->c == '=')
154d4afb5ceSopenharmony_ci			s->len--;
155d4afb5ceSopenharmony_ci
156d4afb5ceSopenharmony_ci		if (s->len >= 2)
157d4afb5ceSopenharmony_ci			*out++ = (uint8_t)(s->quad[0] << 2 | s->quad[1] >> 4);
158d4afb5ceSopenharmony_ci		if (s->len >= 3)
159d4afb5ceSopenharmony_ci			*out++ = (uint8_t)(s->quad[1] << 4 | s->quad[2] >> 2);
160d4afb5ceSopenharmony_ci		if (s->len >= 4)
161d4afb5ceSopenharmony_ci			*out++ = (uint8_t)(((s->quad[2] << 6) & 0xc0) | s->quad[3]);
162d4afb5ceSopenharmony_ci
163d4afb5ceSopenharmony_ci		s->done += s->len - 1;
164d4afb5ceSopenharmony_ci		s->len = 0;
165d4afb5ceSopenharmony_ci	}
166d4afb5ceSopenharmony_ci
167d4afb5ceSopenharmony_ci	*out = '\0';
168d4afb5ceSopenharmony_ci	*in_len = (unsigned int)(in - orig_in);
169d4afb5ceSopenharmony_ci	*out_size = (unsigned int)(out - orig_out);
170d4afb5ceSopenharmony_ci
171d4afb5ceSopenharmony_ci	return 0;
172d4afb5ceSopenharmony_ci}
173d4afb5ceSopenharmony_ci
174d4afb5ceSopenharmony_ci
175d4afb5ceSopenharmony_ci/*
176d4afb5ceSopenharmony_ci * returns length of decoded string in out, or -1 if out was too small
177d4afb5ceSopenharmony_ci * according to out_size
178d4afb5ceSopenharmony_ci *
179d4afb5ceSopenharmony_ci * Only reads up to in_len chars, otherwise if in_len is -1 on entry reads until
180d4afb5ceSopenharmony_ci * the first NUL in the input.
181d4afb5ceSopenharmony_ci */
182d4afb5ceSopenharmony_ci
183d4afb5ceSopenharmony_cistatic size_t
184d4afb5ceSopenharmony_ci_lws_b64_decode_string(const char *in, int in_len, char *out, size_t out_size)
185d4afb5ceSopenharmony_ci{
186d4afb5ceSopenharmony_ci	struct lws_b64state state;
187d4afb5ceSopenharmony_ci	size_t il = (size_t)in_len, ol = out_size;
188d4afb5ceSopenharmony_ci
189d4afb5ceSopenharmony_ci	if (in_len == -1)
190d4afb5ceSopenharmony_ci		il = strlen(in);
191d4afb5ceSopenharmony_ci
192d4afb5ceSopenharmony_ci	lws_b64_decode_state_init(&state);
193d4afb5ceSopenharmony_ci	lws_b64_decode_stateful(&state, in, &il, (uint8_t *)out, &ol, 1);
194d4afb5ceSopenharmony_ci
195d4afb5ceSopenharmony_ci	if (!il)
196d4afb5ceSopenharmony_ci		return 0;
197d4afb5ceSopenharmony_ci
198d4afb5ceSopenharmony_ci	return ol;
199d4afb5ceSopenharmony_ci}
200d4afb5ceSopenharmony_ci
201d4afb5ceSopenharmony_ciint
202d4afb5ceSopenharmony_cilws_b64_decode_string(const char *in, char *out, int out_size)
203d4afb5ceSopenharmony_ci{
204d4afb5ceSopenharmony_ci	return (int)_lws_b64_decode_string(in, -1, out, (unsigned int)out_size);
205d4afb5ceSopenharmony_ci}
206d4afb5ceSopenharmony_ci
207d4afb5ceSopenharmony_ciint
208d4afb5ceSopenharmony_cilws_b64_decode_string_len(const char *in, int in_len, char *out, int out_size)
209d4afb5ceSopenharmony_ci{
210d4afb5ceSopenharmony_ci	return (int)_lws_b64_decode_string(in, in_len, out, (unsigned int)out_size);
211d4afb5ceSopenharmony_ci}
212d4afb5ceSopenharmony_ci
213d4afb5ceSopenharmony_ci#if 0
214d4afb5ceSopenharmony_cistatic const char * const plaintext[] = {
215d4afb5ceSopenharmony_ci	"any carnal pleasure.",
216d4afb5ceSopenharmony_ci	"any carnal pleasure",
217d4afb5ceSopenharmony_ci	"any carnal pleasur",
218d4afb5ceSopenharmony_ci	"any carnal pleasu",
219d4afb5ceSopenharmony_ci	"any carnal pleas",
220d4afb5ceSopenharmony_ci	"Admin:kloikloi"
221d4afb5ceSopenharmony_ci};
222d4afb5ceSopenharmony_cistatic const char * const coded[] = {
223d4afb5ceSopenharmony_ci	"YW55IGNhcm5hbCBwbGVhc3VyZS4=",
224d4afb5ceSopenharmony_ci	"YW55IGNhcm5hbCBwbGVhc3VyZQ==",
225d4afb5ceSopenharmony_ci	"YW55IGNhcm5hbCBwbGVhc3Vy",
226d4afb5ceSopenharmony_ci	"YW55IGNhcm5hbCBwbGVhc3U=",
227d4afb5ceSopenharmony_ci	"YW55IGNhcm5hbCBwbGVhcw==",
228d4afb5ceSopenharmony_ci	"QWRtaW46a2xvaWtsb2k="
229d4afb5ceSopenharmony_ci};
230d4afb5ceSopenharmony_ci
231d4afb5ceSopenharmony_ciint
232d4afb5ceSopenharmony_cilws_b64_selftest(void)
233d4afb5ceSopenharmony_ci{
234d4afb5ceSopenharmony_ci	char buf[64];
235d4afb5ceSopenharmony_ci	unsigned int n,  r = 0;
236d4afb5ceSopenharmony_ci	unsigned int test;
237d4afb5ceSopenharmony_ci
238d4afb5ceSopenharmony_ci	lwsl_notice("%s\n", __func__);
239d4afb5ceSopenharmony_ci
240d4afb5ceSopenharmony_ci	/* examples from https://en.wikipedia.org/wiki/Base64 */
241d4afb5ceSopenharmony_ci
242d4afb5ceSopenharmony_ci	for (test = 0; test < (int)LWS_ARRAY_SIZE(plaintext); test++) {
243d4afb5ceSopenharmony_ci
244d4afb5ceSopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
245d4afb5ceSopenharmony_ci		n = lws_b64_encode_string(plaintext[test],
246d4afb5ceSopenharmony_ci				      strlen(plaintext[test]), buf, sizeof buf);
247d4afb5ceSopenharmony_ci		if (n != strlen(coded[test]) || strcmp(buf, coded[test])) {
248d4afb5ceSopenharmony_ci			lwsl_err("Failed lws_b64 encode selftest "
249d4afb5ceSopenharmony_ci					   "%d result '%s' %d\n", test, buf, n);
250d4afb5ceSopenharmony_ci			r = -1;
251d4afb5ceSopenharmony_ci		}
252d4afb5ceSopenharmony_ci
253d4afb5ceSopenharmony_ci		buf[sizeof(buf) - 1] = '\0';
254d4afb5ceSopenharmony_ci		n = lws_b64_decode_string(coded[test], buf, sizeof buf);
255d4afb5ceSopenharmony_ci		if (n != strlen(plaintext[test]) ||
256d4afb5ceSopenharmony_ci		    strcmp(buf, plaintext[test])) {
257d4afb5ceSopenharmony_ci			lwsl_err("Failed lws_b64 decode selftest "
258d4afb5ceSopenharmony_ci				 "%d result '%s' / '%s', %d / %zu\n",
259d4afb5ceSopenharmony_ci				 test, buf, plaintext[test], n,
260d4afb5ceSopenharmony_ci				 strlen(plaintext[test]));
261d4afb5ceSopenharmony_ci			lwsl_hexdump_err(buf, n);
262d4afb5ceSopenharmony_ci			r = -1;
263d4afb5ceSopenharmony_ci		}
264d4afb5ceSopenharmony_ci	}
265d4afb5ceSopenharmony_ci
266d4afb5ceSopenharmony_ci	if (!r)
267d4afb5ceSopenharmony_ci		lwsl_notice("Base 64 selftests passed\n");
268d4afb5ceSopenharmony_ci	else
269d4afb5ceSopenharmony_ci		lwsl_notice("Base64 selftests failed\n");
270d4afb5ceSopenharmony_ci
271d4afb5ceSopenharmony_ci	return r;
272d4afb5ceSopenharmony_ci}
273d4afb5ceSopenharmony_ci#endif
274