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 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