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