Home | History | Annotate | Line # | Download | only in utils
      1 /*
      2  * Base64 encoding/decoding (RFC1341)
      3  * Copyright (c) 2005-2019, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 #include <stdint.h>
     11 
     12 #include "utils/common.h"
     13 #include "os.h"
     14 #include "base64.h"
     15 
     16 static const char base64_table[65] =
     17 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     18 static const char base64_url_table[65] =
     19 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
     20 
     21 
     22 #define BASE64_PAD BIT(0)
     23 #define BASE64_LF BIT(1)
     24 
     25 
     26 static char * base64_gen_encode(const unsigned char *src, size_t len,
     27 				size_t *out_len, const char *table, int add_pad)
     28 {
     29 	char *out, *pos;
     30 	const unsigned char *end, *in;
     31 	size_t olen;
     32 	int line_len;
     33 
     34 	if (len >= SIZE_MAX / 4)
     35 		return NULL;
     36 	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
     37 	if (add_pad & BASE64_LF)
     38 		olen += olen / 72; /* line feeds */
     39 	olen++; /* nul termination */
     40 	if (olen < len)
     41 		return NULL; /* integer overflow */
     42 	out = os_malloc(olen);
     43 	if (out == NULL)
     44 		return NULL;
     45 
     46 	end = src + len;
     47 	in = src;
     48 	pos = out;
     49 	line_len = 0;
     50 	while (end - in >= 3) {
     51 		*pos++ = table[(in[0] >> 2) & 0x3f];
     52 		*pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f];
     53 		*pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f];
     54 		*pos++ = table[in[2] & 0x3f];
     55 		in += 3;
     56 		line_len += 4;
     57 		if ((add_pad & BASE64_LF) && line_len >= 72) {
     58 			*pos++ = '\n';
     59 			line_len = 0;
     60 		}
     61 	}
     62 
     63 	if (end - in) {
     64 		*pos++ = table[(in[0] >> 2) & 0x3f];
     65 		if (end - in == 1) {
     66 			*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
     67 			if (add_pad & BASE64_PAD)
     68 				*pos++ = '=';
     69 		} else {
     70 			*pos++ = table[(((in[0] & 0x03) << 4) |
     71 					(in[1] >> 4)) & 0x3f];
     72 			*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
     73 		}
     74 		if (add_pad & BASE64_PAD)
     75 			*pos++ = '=';
     76 		line_len += 4;
     77 	}
     78 
     79 	if ((add_pad & BASE64_LF) && line_len)
     80 		*pos++ = '\n';
     81 
     82 	*pos = '\0';
     83 	if (out_len)
     84 		*out_len = pos - out;
     85 	return out;
     86 }
     87 
     88 
     89 static unsigned char * base64_gen_decode(const char *src, size_t len,
     90 					 size_t *out_len, const char *table)
     91 {
     92 	unsigned char dtable[256], *out, *pos, block[4], tmp;
     93 	size_t i, count, olen;
     94 	int pad = 0;
     95 	size_t extra_pad;
     96 
     97 	os_memset(dtable, 0x80, 256);
     98 	for (i = 0; i < sizeof(base64_table) - 1; i++)
     99 		dtable[(unsigned char) table[i]] = (unsigned char) i;
    100 	dtable['='] = 0;
    101 
    102 	count = 0;
    103 	for (i = 0; i < len; i++) {
    104 		if (dtable[(unsigned char) src[i]] != 0x80)
    105 			count++;
    106 	}
    107 
    108 	if (count == 0)
    109 		return NULL;
    110 	extra_pad = (4 - count % 4) % 4;
    111 
    112 	olen = (count + extra_pad) / 4 * 3;
    113 	pos = out = os_malloc(olen);
    114 	if (out == NULL)
    115 		return NULL;
    116 
    117 	count = 0;
    118 	for (i = 0; i < len + extra_pad; i++) {
    119 		unsigned char val;
    120 
    121 		if (i >= len)
    122 			val = '=';
    123 		else
    124 			val = src[i];
    125 		tmp = dtable[val];
    126 		if (tmp == 0x80)
    127 			continue;
    128 
    129 		if (val == '=')
    130 			pad++;
    131 		block[count] = tmp;
    132 		count++;
    133 		if (count == 4) {
    134 			*pos++ = (block[0] << 2) | (block[1] >> 4);
    135 			*pos++ = (block[1] << 4) | (block[2] >> 2);
    136 			*pos++ = (block[2] << 6) | block[3];
    137 			count = 0;
    138 			if (pad) {
    139 				if (pad == 1)
    140 					pos--;
    141 				else if (pad == 2)
    142 					pos -= 2;
    143 				else {
    144 					/* Invalid padding */
    145 					os_free(out);
    146 					return NULL;
    147 				}
    148 				break;
    149 			}
    150 		}
    151 	}
    152 
    153 	*out_len = pos - out;
    154 	return out;
    155 }
    156 
    157 
    158 /**
    159  * base64_encode - Base64 encode
    160  * @src: Data to be encoded
    161  * @len: Length of the data to be encoded
    162  * @out_len: Pointer to output length variable, or %NULL if not used
    163  * Returns: Allocated buffer of out_len bytes of encoded data,
    164  * or %NULL on failure
    165  *
    166  * Caller is responsible for freeing the returned buffer. Returned buffer is
    167  * nul terminated to make it easier to use as a C string. The nul terminator is
    168  * not included in out_len.
    169  */
    170 char * base64_encode(const void *src, size_t len, size_t *out_len)
    171 {
    172 	return base64_gen_encode(src, len, out_len, base64_table,
    173 				 BASE64_PAD | BASE64_LF);
    174 }
    175 
    176 
    177 char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len)
    178 {
    179 	return base64_gen_encode(src, len, out_len, base64_table, BASE64_PAD);
    180 }
    181 
    182 
    183 char * base64_url_encode(const void *src, size_t len, size_t *out_len)
    184 {
    185 	return base64_gen_encode(src, len, out_len, base64_url_table, 0);
    186 }
    187 
    188 
    189 /**
    190  * base64_decode - Base64 decode
    191  * @src: Data to be decoded
    192  * @len: Length of the data to be decoded
    193  * @out_len: Pointer to output length variable
    194  * Returns: Allocated buffer of out_len bytes of decoded data,
    195  * or %NULL on failure
    196  *
    197  * Caller is responsible for freeing the returned buffer.
    198  */
    199 unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
    200 {
    201 	return base64_gen_decode(src, len, out_len, base64_table);
    202 }
    203 
    204 
    205 unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len)
    206 {
    207 	return base64_gen_decode(src, len, out_len, base64_url_table);
    208 }
    209