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