summaryrefslogtreecommitdiffstats
path: root/src/crypto/base64/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/base64/base64.c')
-rw-r--r--src/crypto/base64/base64.c474
1 files changed, 474 insertions, 0 deletions
diff --git a/src/crypto/base64/base64.c b/src/crypto/base64/base64.c
new file mode 100644
index 0000000..12a52cf
--- /dev/null
+++ b/src/crypto/base64/base64.c
@@ -0,0 +1,474 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/base64.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+
+static const unsigned char data_bin2ascii[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f])
+
+/* 64 char lines
+ * pad input with 0
+ * left over chars are set to =
+ * 1 byte => xx==
+ * 2 bytes => xxx=
+ * 3 bytes => xxxx
+ */
+#define BIN_PER_LINE (64/4*3)
+#define CHUNKS_PER_LINE (64/4)
+#define CHAR_PER_LINE (64+1)
+
+/* 0xF0 is a EOLN
+ * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
+ * 0xF2 is EOF
+ * 0xE0 is ignore at start of line.
+ * 0xFF is error */
+
+#define B64_EOLN 0xF0
+#define B64_CR 0xF1
+#define B64_EOF 0xF2
+#define B64_WS 0xE0
+#define B64_ERROR 0xFF
+#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3)
+
+static const uint8_t data_ascii2bin[128] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF,
+ 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
+ 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+static uint8_t conv_ascii2bin(uint8_t a) {
+ if (a >= 128) {
+ return 0xFF;
+ }
+ return data_ascii2bin[a];
+}
+
+void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) {
+ ctx->length = 48;
+ ctx->num = 0;
+ ctx->line_num = 0;
+}
+
+void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len) {
+ unsigned i, j;
+ unsigned total = 0;
+
+ *out_len = 0;
+ if (in_len == 0) {
+ return;
+ }
+
+ assert(ctx->length <= sizeof(ctx->enc_data));
+
+ if (ctx->num + in_len < ctx->length) {
+ memcpy(&ctx->enc_data[ctx->num], in, in_len);
+ ctx->num += in_len;
+ return;
+ }
+ if (ctx->num != 0) {
+ i = ctx->length - ctx->num;
+ memcpy(&ctx->enc_data[ctx->num], in, i);
+ in += i;
+ in_len -= i;
+ j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length);
+ ctx->num = 0;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total = j + 1;
+ }
+ while (in_len >= ctx->length) {
+ j = EVP_EncodeBlock(out, in, ctx->length);
+ in += ctx->length;
+ in_len -= ctx->length;
+ out += j;
+ *(out++) = '\n';
+ *out = '\0';
+ total += j + 1;
+ }
+ if (in_len != 0) {
+ memcpy(&ctx->enc_data[0], in, in_len);
+ }
+ ctx->num = in_len;
+ *out_len = total;
+}
+
+void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) {
+ unsigned ret = 0;
+
+ if (ctx->num != 0) {
+ ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num);
+ out[ret++] = '\n';
+ out[ret] = '\0';
+ ctx->num = 0;
+ }
+ *out_len = ret;
+}
+
+size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
+ uint32_t l;
+ size_t remaining = src_len, ret = 0;
+
+ while (remaining) {
+ if (remaining >= 3) {
+ l = (((uint32_t)src[0]) << 16L) | (((uint32_t)src[1]) << 8L) | src[2];
+ *(dst++) = conv_bin2ascii(l >> 18L);
+ *(dst++) = conv_bin2ascii(l >> 12L);
+ *(dst++) = conv_bin2ascii(l >> 6L);
+ *(dst++) = conv_bin2ascii(l);
+ remaining -= 3;
+ } else {
+ l = ((uint32_t)src[0]) << 16L;
+ if (remaining == 2) {
+ l |= ((uint32_t)src[1] << 8L);
+ }
+
+ *(dst++) = conv_bin2ascii(l >> 18L);
+ *(dst++) = conv_bin2ascii(l >> 12L);
+ *(dst++) = (remaining == 1) ? '=' : conv_bin2ascii(l >> 6L);
+ *(dst++) = '=';
+ remaining = 0;
+ }
+ ret += 4;
+ src += 3;
+ }
+
+ *dst = '\0';
+ return ret;
+}
+
+int EVP_DecodedLength(size_t *out_len, size_t len) {
+ if (len % 4 != 0) {
+ return 0;
+ }
+ *out_len = (len / 4) * 3;
+ return 1;
+}
+
+int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out,
+ const uint8_t *in, size_t in_len) {
+ uint8_t a, b, c, d;
+ size_t pad_len = 0, len = 0, max_len, i;
+ uint32_t l;
+
+ if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) {
+ return 0;
+ }
+
+ for (i = 0; i < in_len; i += 4) {
+ a = conv_ascii2bin(*(in++));
+ b = conv_ascii2bin(*(in++));
+ if (i + 4 == in_len && in[1] == '=') {
+ if (in[0] == '=') {
+ pad_len = 2;
+ } else {
+ pad_len = 1;
+ }
+ }
+ if (pad_len < 2) {
+ c = conv_ascii2bin(*(in++));
+ } else {
+ c = 0;
+ }
+ if (pad_len < 1) {
+ d = conv_ascii2bin(*(in++));
+ } else {
+ d = 0;
+ }
+ if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) {
+ return 0;
+ }
+ l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) |
+ (((uint32_t)c) << 6L) | (((uint32_t)d)));
+ *(out++) = (uint8_t)(l >> 16L) & 0xff;
+ if (pad_len < 2) {
+ *(out++) = (uint8_t)(l >> 8L) & 0xff;
+ }
+ if (pad_len < 1) {
+ *(out++) = (uint8_t)(l) & 0xff;
+ }
+ len += 3 - pad_len;
+ }
+ *out_len = len;
+ return 1;
+}
+
+void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) {
+ ctx->length = 30;
+ ctx->num = 0;
+ ctx->line_num = 0;
+ ctx->expect_nl = 0;
+}
+
+int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len,
+ const uint8_t *in, size_t in_len) {
+ int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl;
+ uint8_t *d;
+ unsigned i, n, ln, ret = 0;
+
+ n = ctx->num;
+ d = ctx->enc_data;
+ ln = ctx->line_num;
+ exp_nl = ctx->expect_nl;
+
+ /* last line of input. */
+ if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) {
+ rv = 0;
+ goto end;
+ }
+
+ /* We parse the input data */
+ for (i = 0; i < in_len; i++) {
+ /* If the current line is > 80 characters, scream alot */
+ if (ln >= 80) {
+ rv = -1;
+ goto end;
+ }
+
+ /* Get char and put it into the buffer */
+ tmp = *(in++);
+ v = conv_ascii2bin(tmp);
+ /* only save the good data :-) */
+ if (!B64_NOT_BASE64(v)) {
+ assert(n < sizeof(ctx->enc_data));
+ d[n++] = tmp;
+ ln++;
+ } else if (v == B64_ERROR) {
+ rv = -1;
+ goto end;
+ }
+
+ /* have we seen a '=' which is 'definitly' the last
+ * input line. seof will point to the character that
+ * holds it. and eof will hold how many characters to
+ * chop off. */
+ if (tmp == '=') {
+ if (seof == -1) {
+ seof = n;
+ }
+ eof++;
+ if (eof > 2) {
+ /* There are, at most, two equals signs at the end of base64 data. */
+ rv = -1;
+ goto end;
+ }
+ }
+
+ if (v == B64_CR) {
+ ln = 0;
+ if (exp_nl) {
+ continue;
+ }
+ }
+
+ /* eoln */
+ if (v == B64_EOLN) {
+ ln = 0;
+ if (exp_nl) {
+ exp_nl = 0;
+ continue;
+ }
+ }
+ exp_nl = 0;
+
+ /* If we are at the end of input and it looks like a
+ * line, process it. */
+ if ((i + 1) == in_len && (((n & 3) == 0) || eof)) {
+ v = B64_EOF;
+ /* In case things were given us in really small
+ records (so two '=' were given in separate
+ updates), eof may contain the incorrect number
+ of ending bytes to skip, so let's redo the count */
+ eof = 0;
+ if (d[n - 1] == '=') {
+ eof++;
+ }
+ if (d[n - 2] == '=') {
+ eof++;
+ }
+ /* There will never be more than two '=' */
+ }
+
+ if ((v == B64_EOF && (n & 3) == 0) || n >= 64) {
+ /* This is needed to work correctly on 64 byte input
+ * lines. We process the line and then need to
+ * accept the '\n' */
+ if (v != B64_EOF && n >= 64) {
+ exp_nl = 1;
+ }
+ if (n > 0) {
+ /* TODO(davidben): Switch this to EVP_DecodeBase64. */
+ v = EVP_DecodeBlock(out, d, n);
+ n = 0;
+ if (v < 0) {
+ rv = 0;
+ goto end;
+ }
+ ret += (v - eof);
+ } else {
+ eof = 1;
+ v = 0;
+ }
+
+ /* This is the case where we have had a short
+ * but valid input line */
+ if (v < (int)ctx->length && eof) {
+ rv = 0;
+ goto end;
+ } else {
+ ctx->length = v;
+ }
+
+ if (seof >= 0) {
+ rv = 0;
+ goto end;
+ }
+ out += v;
+ }
+ }
+ rv = 1;
+
+end:
+ *out_len = ret;
+ ctx->num = n;
+ ctx->line_num = ln;
+ ctx->expect_nl = exp_nl;
+ return rv;
+}
+
+int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) {
+ int i;
+
+ *outl = 0;
+ if (ctx->num != 0) {
+ /* TODO(davidben): Switch this to EVP_DecodeBase64. */
+ i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num);
+ if (i < 0) {
+ return -1;
+ }
+ ctx->num = 0;
+ *outl = i;
+ return 1;
+ } else {
+ return 1;
+ }
+}
+
+int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) {
+ size_t dst_len;
+
+ /* trim white space from the start of the line. */
+ while (conv_ascii2bin(*src) == B64_WS && src_len > 0) {
+ src++;
+ src_len--;
+ }
+
+ /* strip off stuff at the end of the line
+ * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */
+ while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) {
+ src_len--;
+ }
+
+ if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) {
+ return -1;
+ }
+ if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) {
+ return -1;
+ }
+
+ /* EVP_DecodeBlock does not take padding into account, so put the
+ * NULs back in... so the caller can strip them back out. */
+ while (dst_len % 3 != 0) {
+ dst[dst_len++] = '\0';
+ }
+ assert(dst_len <= INT_MAX);
+
+ return dst_len;
+}
+
+int EVP_EncodedLength(size_t *out_len, size_t len) {
+ if (len + 2 < len) {
+ return 0;
+ }
+ len += 2;
+ len /= 3;
+ if (((len << 2) >> 2) != len) {
+ return 0;
+ }
+ len <<= 2;
+ if (len + 1 < len) {
+ return 0;
+ }
+ len++;
+ *out_len = len;
+ return 1;
+}