diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-08-31 13:02:13 +0200 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2023-08-24 16:40:05 +0200 |
commit | 14da50c14af04c6456e16c1b198bc0c226fcfb0e (patch) | |
tree | 645e26059ea425a80c9b639b50fdbe30a56808e1 /lib/base64.c | |
parent | 49b594ebef07a37fb709f0a699360d4598159173 (diff) |
Bytestring: implement bytestring literals and constants
Implement byte string literals on the format b"xxx" and b64"xxx"
which can be used as literals and in constants.
The format b"xxx" supports character data and octal and
hexadecimal data using C escapes (\n, \nn, \nnn, \xn and \xnn).
The format b64"xxx" supports base64 encoded strings (RFC1341).
Diffstat (limited to 'lib/base64.c')
-rw-r--r-- | lib/base64.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 00000000..d5f3ae9b --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,163 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README.base64 for more details. + */ + +#include "nest/bird.h" +#include "conf/conf.h" +#include "lib/resource.h" +#include "lib/base64.h" + +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +struct bytestring * base64_encode(linpool *pool, + const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char *pos; + struct bytestring *out; + const unsigned char *end, *in; + size_t olen; + int line_len; + + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + out = lp_alloc(pool, sizeof(struct bytestring) + olen); + if (out == NULL) + return NULL; + + end = src + len; + in = src; + pos = out->data; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + out->length = pos - out->data; + if (out_len) + *out_len = out->length; + return out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +struct bytestring * base64_decode_bs(linpool *pool, + const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + struct bytestring *out; + + memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = count / 4 * 3; + out = lp_alloc(pool, sizeof(struct bytestring) + olen); + if (out == NULL) + return NULL; + pos = out->data; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + //os_free(out); + return NULL; + } + break; + } + } + } + + out->length = pos - out->data; + if (out_len) + *out_len = out->length; + return out; +} |