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