Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This code originally came from here |
| 3 | * |
| 4 | * http://base64.sourceforge.net/b64.c |
| 5 | * |
| 6 | * with the following license: |
| 7 | * |
| 8 | * LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. |
| 9 | * |
| 10 | * Permission is hereby granted, free of charge, to any person |
| 11 | * obtaining a copy of this software and associated |
| 12 | * documentation files (the "Software"), to deal in the |
| 13 | * Software without restriction, including without limitation |
| 14 | * the rights to use, copy, modify, merge, publish, distribute, |
| 15 | * sublicense, and/or sell copies of the Software, and to |
| 16 | * permit persons to whom the Software is furnished to do so, |
| 17 | * subject to the following conditions: |
| 18 | * |
| 19 | * The above copyright notice and this permission notice shall |
| 20 | * be included in all copies or substantial portions of the |
| 21 | * Software. |
| 22 | * |
| 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
| 24 | * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
| 25 | * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR |
| 26 | * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS |
| 27 | * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| 28 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| 29 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| 30 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 31 | * |
| 32 | * VERSION HISTORY: |
| 33 | * Bob Trower 08/04/01 -- Create Version 0.00.00B |
| 34 | * |
| 35 | * I cleaned it up quite a bit to match the (linux kernel) style of the rest |
| 36 | * of libwebsockets; this version is under LGPL2 like the rest of libwebsockets |
| 37 | * since he explictly allows sublicensing, but I give the URL above so you can |
| 38 | * get the original with Bob's super-liberal terms directly if you prefer. |
| 39 | */ |
| 40 | |
| 41 | |
| 42 | #include <stdio.h> |
| 43 | #include <string.h> |
Joakim Soderberg | 4c53123 | 2013-02-06 15:26:58 +0900 | [diff] [blame] | 44 | #include "private-libwebsockets.h" |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 45 | |
| 46 | static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 47 | "abcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 48 | static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW" |
| 49 | "$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; |
| 50 | |
| 51 | int |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 52 | lws_b64_encode_string(const char *in, int in_len, char *out, int out_size) |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 53 | { |
| 54 | unsigned char triple[3]; |
| 55 | int i; |
| 56 | int len; |
| 57 | int line = 0; |
| 58 | int done = 0; |
| 59 | |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 60 | while (in_len) { |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 61 | len = 0; |
| 62 | for (i = 0; i < 3; i++) { |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 63 | if (in_len) { |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 64 | triple[i] = *in++; |
| 65 | len++; |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 66 | in_len--; |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 67 | } else |
| 68 | triple[i] = 0; |
| 69 | } |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 70 | if (!len) |
| 71 | continue; |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 72 | |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 73 | if (done + 4 >= out_size) |
| 74 | return -1; |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 75 | |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 76 | *out++ = encode[triple[0] >> 2]; |
| 77 | *out++ = encode[((triple[0] & 0x03) << 4) | |
| 78 | ((triple[1] & 0xf0) >> 4)]; |
| 79 | *out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) | |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 80 | ((triple[2] & 0xc0) >> 6)] : '='); |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 81 | *out++ = (len > 2 ? encode[triple[2] & 0x3f] : '='); |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 82 | |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 83 | done += 4; |
| 84 | line += 4; |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 85 | } |
| 86 | |
| 87 | if (done + 1 >= out_size) |
| 88 | return -1; |
| 89 | |
| 90 | *out++ = '\0'; |
| 91 | |
| 92 | return done; |
| 93 | } |
| 94 | |
| 95 | /* |
| 96 | * returns length of decoded string in out, or -1 if out was too small |
| 97 | * according to out_size |
| 98 | */ |
| 99 | |
| 100 | int |
| 101 | lws_b64_decode_string(const char *in, char *out, int out_size) |
| 102 | { |
| 103 | int len; |
| 104 | int i; |
| 105 | int done = 0; |
| 106 | unsigned char v; |
| 107 | unsigned char quad[4]; |
| 108 | |
| 109 | while (*in) { |
| 110 | |
| 111 | len = 0; |
| 112 | for (i = 0; i < 4 && *in; i++) { |
| 113 | |
| 114 | v = 0; |
| 115 | while (*in && !v) { |
| 116 | |
| 117 | v = *in++; |
| 118 | v = (v < 43 || v > 122) ? 0 : decode[v - 43]; |
| 119 | if (v) |
| 120 | v = (v == '$') ? 0 : v - 61; |
| 121 | if (*in) { |
| 122 | len++; |
| 123 | if (v) |
| 124 | quad[i] = v - 1; |
| 125 | } else |
| 126 | quad[i] = 0; |
| 127 | } |
| 128 | } |
| 129 | if (!len) |
| 130 | continue; |
| 131 | |
| 132 | if (out_size < (done + len - 1)) |
| 133 | /* out buffer is too small */ |
| 134 | return -1; |
| 135 | |
| 136 | if (len >= 2) |
| 137 | *out++ = quad[0] << 2 | quad[1] >> 4; |
| 138 | if (len >= 3) |
| 139 | *out++ = quad[1] << 4 | quad[2] >> 2; |
| 140 | if (len >= 4) |
| 141 | *out++ = ((quad[2] << 6) & 0xc0) | quad[3]; |
| 142 | |
| 143 | done += len - 1; |
| 144 | } |
| 145 | |
| 146 | if (done + 1 >= out_size) |
| 147 | return -1; |
| 148 | |
| 149 | *out++ = '\0'; |
| 150 | |
| 151 | return done; |
| 152 | } |
| 153 | |
| 154 | int |
| 155 | lws_b64_selftest(void) |
| 156 | { |
| 157 | char buf[64]; |
| 158 | int n; |
| 159 | int test; |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 160 | static const char * const plaintext[] = { |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 161 | "sanity check base 64" |
| 162 | }; |
Andy Green | 6ee372f | 2012-04-09 15:09:01 +0800 | [diff] [blame] | 163 | static const char * const coded[] = { |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 164 | "c2FuaXR5IGNoZWNrIGJhc2UgNjQ=" |
| 165 | }; |
| 166 | |
| 167 | for (test = 0; test < sizeof plaintext / sizeof(plaintext[0]); test++) { |
| 168 | |
| 169 | buf[sizeof(buf) - 1] = '\0'; |
Andy Green | 4739e5c | 2011-01-22 12:51:57 +0000 | [diff] [blame] | 170 | n = lws_b64_encode_string(plaintext[test], |
| 171 | strlen(plaintext[test]), buf, sizeof buf); |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 172 | if (n != strlen(coded[test]) || strcmp(buf, coded[test])) { |
Andy Green | 43db045 | 2013-01-10 19:50:35 +0800 | [diff] [blame] | 173 | lwsl_err("Failed lws_b64 encode selftest " |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 174 | "%d result '%s' %d\n", test, buf, n); |
| 175 | return -1; |
| 176 | } |
| 177 | |
| 178 | buf[sizeof(buf) - 1] = '\0'; |
| 179 | n = lws_b64_decode_string(coded[test], buf, sizeof buf); |
| 180 | if (n != strlen(plaintext[test]) || |
| 181 | strcmp(buf, plaintext[test])) { |
Andy Green | 43db045 | 2013-01-10 19:50:35 +0800 | [diff] [blame] | 182 | lwsl_err("Failed lws_b64 decode selftest " |
Andy Green | df73616 | 2011-01-18 15:39:02 +0000 | [diff] [blame] | 183 | "%d result '%s' %d\n", test, buf, n); |
| 184 | return -1; |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | return 0; |
| 189 | } |