1  /*
2   * Base64 encoding/decoding (RFC1341)
3   * Copyright (c) 2005-2019, Jouni Malinen <j@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  
base64_gen_encode(const unsigned char * src,size_t len,size_t * out_len,const char * table,int add_pad)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  
base64_gen_decode(const char * src,size_t len,size_t * out_len,const char * table)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   */
base64_encode(const void * src,size_t len,size_t * out_len)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  
base64_encode_no_lf(const void * src,size_t len,size_t * out_len)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  
base64_url_encode(const void * src,size_t len,size_t * out_len)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   */
base64_decode(const char * src,size_t len,size_t * out_len)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  
base64_url_decode(const char * src,size_t len,size_t * out_len)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