1 /* 2 * Base64 encoding/decoding (RFC1341) 3 * Copyright (c) 2005-2011, 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 11 #include "os.h" 12 #include "base64.h" 13 14 static const unsigned char base64_table[65] = 15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 16 17 /** 18 * base64_encode - Base64 encode 19 * @src: Data to be encoded 20 * @len: Length of the data to be encoded 21 * @out_len: Pointer to output length variable, or %NULL if not used 22 * Returns: Allocated buffer of out_len bytes of encoded data, 23 * or %NULL on failure 24 * 25 * Caller is responsible for freeing the returned buffer. Returned buffer is 26 * nul terminated to make it easier to use as a C string. The nul terminator is 27 * not included in out_len. 28 */ 29 unsigned char * base64_encode(const unsigned char *src, size_t len, 30 size_t *out_len) 31 { 32 unsigned char *out, *pos; 33 const unsigned char *end, *in; 34 size_t olen; 35 int line_len; 36 37 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ 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++ = base64_table[(in[0] >> 2) & 0x3f]; 52 *pos++ = base64_table[(((in[0] & 0x03) << 4) | 53 (in[1] >> 4)) & 0x3f]; 54 *pos++ = base64_table[(((in[1] & 0x0f) << 2) | 55 (in[2] >> 6)) & 0x3f]; 56 *pos++ = base64_table[in[2] & 0x3f]; 57 in += 3; 58 line_len += 4; 59 if (line_len >= 72) { 60 *pos++ = '\n'; 61 line_len = 0; 62 } 63 } 64 65 if (end - in) { 66 *pos++ = base64_table[(in[0] >> 2) & 0x3f]; 67 if (end - in == 1) { 68 *pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f]; 69 *pos++ = '='; 70 } else { 71 *pos++ = base64_table[(((in[0] & 0x03) << 4) | 72 (in[1] >> 4)) & 0x3f]; 73 *pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f]; 74 } 75 *pos++ = '='; 76 line_len += 4; 77 } 78 79 if (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 /** 90 * base64_decode - Base64 decode 91 * @src: Data to be decoded 92 * @len: Length of the data to be decoded 93 * @out_len: Pointer to output length variable 94 * Returns: Allocated buffer of out_len bytes of decoded data, 95 * or %NULL on failure 96 * 97 * Caller is responsible for freeing the returned buffer. 98 */ 99 unsigned char * base64_decode(const unsigned char *src, size_t len, 100 size_t *out_len) 101 { 102 unsigned char dtable[256], *out, *pos, block[4], tmp; 103 size_t i, count, olen; 104 int pad = 0; 105 106 os_memset(dtable, 0x80, 256); 107 for (i = 0; i < sizeof(base64_table) - 1; i++) 108 dtable[base64_table[i]] = (unsigned char) i; 109 dtable['='] = 0; 110 111 count = 0; 112 for (i = 0; i < len; i++) { 113 if (dtable[src[i]] != 0x80) 114 count++; 115 } 116 117 if (count == 0 || count % 4) 118 return NULL; 119 120 olen = count / 4 * 3; 121 pos = out = os_malloc(olen); 122 if (out == NULL) 123 return NULL; 124 125 count = 0; 126 for (i = 0; i < len; i++) { 127 tmp = dtable[src[i]]; 128 if (tmp == 0x80) 129 continue; 130 131 if (src[i] == '=') 132 pad++; 133 block[count] = tmp; 134 count++; 135 if (count == 4) { 136 *pos++ = (block[0] << 2) | (block[1] >> 4); 137 *pos++ = (block[1] << 4) | (block[2] >> 2); 138 *pos++ = (block[2] << 6) | block[3]; 139 count = 0; 140 if (pad) { 141 if (pad == 1) 142 pos--; 143 else if (pad == 2) 144 pos -= 2; 145 else { 146 /* Invalid padding */ 147 os_free(out); 148 return NULL; 149 } 150 break; 151 } 152 } 153 } 154 155 *out_len = pos - out; 156 return out; 157 } 158