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]; 52 *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 53 *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; 54 *pos++ = base64_table[in[2] & 0x3f]; 55 in += 3; 56 line_len += 4; 57 if (line_len >= 72) { 58 *pos++ = '\n'; 59 line_len = 0; 60 } 61 } 62 63 if (end - in) { 64 *pos++ = base64_table[in[0] >> 2]; 65 if (end - in == 1) { 66 *pos++ = base64_table[(in[0] & 0x03) << 4]; 67 *pos++ = '='; 68 } else { 69 *pos++ = base64_table[((in[0] & 0x03) << 4) | 70 (in[1] >> 4)]; 71 *pos++ = base64_table[(in[1] & 0x0f) << 2]; 72 } 73 *pos++ = '='; 74 line_len += 4; 75 } 76 77 if (line_len) 78 *pos++ = '\n'; 79 80 *pos = '\0'; 81 if (out_len) 82 *out_len = pos - out; 83 return out; 84 } 85 86 87 /** 88 * base64_decode - Base64 decode 89 * @src: Data to be decoded 90 * @len: Length of the data to be decoded 91 * @out_len: Pointer to output length variable 92 * Returns: Allocated buffer of out_len bytes of decoded data, 93 * or %NULL on failure 94 * 95 * Caller is responsible for freeing the returned buffer. 96 */ 97 unsigned char * base64_decode(const unsigned char *src, size_t len, 98 size_t *out_len) 99 { 100 unsigned char dtable[256], *out, *pos, block[4], tmp; 101 size_t i, count, olen; 102 int pad = 0; 103 104 os_memset(dtable, 0x80, 256); 105 for (i = 0; i < sizeof(base64_table) - 1; i++) 106 dtable[base64_table[i]] = (unsigned char) i; 107 dtable['='] = 0; 108 109 count = 0; 110 for (i = 0; i < len; i++) { 111 if (dtable[src[i]] != 0x80) 112 count++; 113 } 114 115 if (count == 0 || count % 4) 116 return NULL; 117 118 olen = count / 4 * 3; 119 pos = out = os_malloc(olen); 120 if (out == NULL) 121 return NULL; 122 123 count = 0; 124 for (i = 0; i < len; i++) { 125 tmp = dtable[src[i]]; 126 if (tmp == 0x80) 127 continue; 128 129 if (src[i] == '=') 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