summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2021-06-08 11:28:14 +0200
committerJo-Philipp Wich <jo@mein.io>2021-06-08 11:28:58 +0200
commit234a4f63a6cfd1b942507b19af6d457f66972290 (patch)
treebc47ad8443cf8d5ce45d0f006cc40621e86ae50c
parent856a0c05fbbde4363634e7f8d5de7ed66d0e0cdc (diff)
lib: implement b64enc() and b64dec() functions
The new functions allow encoding and decoding base64 values respectively. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--README.md28
-rw-r--r--lib.c268
2 files changed, 295 insertions, 1 deletions
diff --git a/README.md b/README.md
index 0d98fd1..524f0c0 100644
--- a/README.md
+++ b/README.md
@@ -1226,3 +1226,31 @@ max("1", "abc"); // "abc"
max("def", "abc", "ghi"); // "ghi"
max(true, false); // true
```
+
+#### 6.62. `b64dec(str)`
+
+Decodes the given base64 encoded string and returns the decoded result, any
+whitespace in the input string is ignored.
+
+If non-whitespace, non-base64 characters are encountered, if invalid padding
+or trailing garbage is found, the function returns `null`.
+
+If a non-string argument is given, the function returns `null`.
+
+```javascript
+b64dec("VGhpcyBpcyBhIHRlc3Q="); // "This is a test"
+b64dec(123); // null
+b64dec("XXX"); // null
+```
+
+#### 6.63. `b64enc(str)`
+
+Encodes the given string into base64 and returns the resulting encoded
+string.
+
+If a non-string argument is given, the function returns `null`.
+
+```javascript
+b64enc("This is a test"); // "VGhpcyBpcyBhIHRlc3Q="
+b64enc(123); // null
+```
diff --git a/lib.c b/lib.c
index e95edd8..8044fde 100644
--- a/lib.c
+++ b/lib.c
@@ -2609,6 +2609,270 @@ uc_max(uc_vm *vm, size_t nargs)
return uc_min_max(vm, nargs, TK_GT);
}
+
+/* -------------------------------------------------------------------------
+ * The following base64 encoding and decoding routines are taken from
+ * https://git.openwrt.org/?p=project/libubox.git;a=blob;f=base64.c
+ * and modified for use in ucode.
+ *
+ * Original copyright and license statements below.
+ */
+
+/*
+ * base64 - libubox base64 functions
+ *
+ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $OpenBSD: base64.c,v 1.7 2013/12/31 02:32:56 tedu Exp $ */
+
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+static uc_value_t *
+uc_b64dec(uc_vm *vm, size_t nargs)
+{
+ enum { BYTE1, BYTE2, BYTE3, BYTE4 } state;
+ uc_value_t *str = uc_get_arg(0);
+ uc_stringbuf_t *buf;
+ const char *src;
+ unsigned int ch;
+ uint8_t val;
+ size_t off;
+
+ if (ucv_type(str) != UC_STRING)
+ return NULL;
+
+ buf = ucv_stringbuf_new();
+ src = ucv_string_get(str);
+ off = printbuf_length(buf);
+
+ state = BYTE1;
+
+ /* memset the last expected output char to pre-grow the output buffer */
+ printbuf_memset(buf, off + (ucv_string_length(str) / 4) * 3, 0, 1);
+
+ while ((ch = (unsigned char)*src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == '=')
+ break;
+
+ if (ch >= 'A' && ch <= 'Z')
+ val = ch - 'A';
+ else if (ch >= 'a' && ch <= 'z')
+ val = ch - 'a' + 26;
+ else if (ch >= '0' && ch <= '9')
+ val = ch - '0' + 52;
+ else if (ch == '+')
+ val = 62;
+ else if (ch == '/')
+ val = 63;
+ else
+ goto err;
+
+ switch (state) {
+ case BYTE1:
+ buf->buf[off] = val << 2;
+ state = BYTE2;
+ break;
+
+ case BYTE2:
+ buf->buf[off++] |= val >> 4;
+ buf->buf[off] = (val & 0x0f) << 4;
+ state = BYTE3;
+ break;
+
+ case BYTE3:
+ buf->buf[off++] |= val >> 2;
+ buf->buf[off] = (val & 0x03) << 6;
+ state = BYTE4;
+ break;
+
+ case BYTE4:
+ buf->buf[off++] |= val;
+ state = BYTE1;
+ break;
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == '=') { /* We got a pad char. */
+ ch = (unsigned char)*src++; /* Skip it, get next. */
+ switch (state) {
+ case BYTE1: /* Invalid = in first position */
+ case BYTE2: /* Invalid = in second position */
+ goto err;
+
+ case BYTE3: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for (; ch != '\0'; ch = (unsigned char)*src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != '=')
+ goto err;
+ ch = (unsigned char)*src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case BYTE4: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for (; ch != '\0'; ch = (unsigned char)*src++)
+ if (!isspace(ch))
+ goto err;
+
+ /*
+ * Now make sure for cases BYTE3 and BYTE4 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (buf->buf[off] != 0)
+ goto err;
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != BYTE1)
+ goto err;
+ }
+
+ /* Truncate buffer length to actual output length */
+ buf->bpos = off;
+
+ return ucv_stringbuf_finish(buf);
+
+err:
+ printbuf_free(buf);
+
+ return NULL;
+}
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static uc_value_t *
+uc_b64enc(uc_vm *vm, size_t nargs)
+{
+ uc_value_t *str = uc_get_arg(0);
+ unsigned char input[3] = {0};
+ uc_stringbuf_t *buf;
+ const char *src;
+ char output[4];
+ size_t len, i;
+
+ if (ucv_type(str) != UC_STRING)
+ return NULL;
+
+ buf = ucv_stringbuf_new();
+ src = ucv_string_get(str);
+ len = ucv_string_length(str);
+
+ while (2 < len) {
+ input[0] = (unsigned char)*src++;
+ input[1] = (unsigned char)*src++;
+ input[2] = (unsigned char)*src++;
+ len -= 3;
+
+ output[0] = Base64[input[0] >> 2];
+ output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
+ output[2] = Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
+ output[3] = Base64[input[2] & 0x3f];
+
+ ucv_stringbuf_addstr(buf, output, sizeof(output));
+ }
+
+ /* Now we worry about padding. */
+ if (0 != len) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < len; i++)
+ input[i] = *src++;
+
+ output[0] = Base64[input[0] >> 2];
+ output[1] = Base64[((input[0] & 0x03) << 4) + (input[1] >> 4)];
+ output[2] = (len == 1) ? '=' : Base64[((input[1] & 0x0f) << 2) + (input[2] >> 6)];
+ output[3] = '=';
+
+ ucv_stringbuf_addstr(buf, output, sizeof(output));
+ }
+
+ return ucv_stringbuf_finish(buf);
+}
+
+/* End of base64 code.
+ * -------------------------------------------------------------------------
+ */
+
+
static const uc_cfunction_list functions[] = {
{ "chr", uc_chr },
{ "die", uc_die },
@@ -2664,7 +2928,9 @@ static const uc_cfunction_list functions[] = {
{ "wildcard", uc_wildcard },
{ "sourcepath", uc_sourcepath },
{ "min", uc_min },
- { "max", uc_max }
+ { "max", uc_max },
+ { "b64dec", uc_b64dec },
+ { "b64enc", uc_b64enc }
};