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 out = os_malloc(olen); 47 if (out == NULL) 48 return NULL; 49 50 end = src + len; 51 in = src; 52 pos = out; 53 line_len = 0; 54 while (end - in >= 3) { 55 *pos++ = base64_table[in[0] >> 2]; 56 *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 57 *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; 58 *pos++ = base64_table[in[2] & 0x3f]; 59 in += 3; 60 line_len += 4; 61 if (line_len >= 72) { 62 *pos++ = '\n'; 63 line_len = 0; 64 } 65 } 66 67 if (end - in) { 68 *pos++ = base64_table[in[0] >> 2]; 69 if (end - in == 1) { 70 *pos++ = base64_table[(in[0] & 0x03) << 4]; 71 *pos++ = '='; 72 } else { 73 *pos++ = base64_table[((in[0] & 0x03) << 4) | 74 (in[1] >> 4)]; 75 *pos++ = base64_table[(in[1] & 0x0f) << 2]; 76 } 77 *pos++ = '='; 78 line_len += 4; 79 } 80 81 if (line_len) 82 *pos++ = '\n'; 83 84 *pos = '\0'; 85 if (out_len) 86 *out_len = pos - out; 87 return out; 88 } 89 90 91 /** 92 * base64_decode - Base64 decode 93 * @src: Data to be decoded 94 * @len: Length of the data to be decoded 95 * @out_len: Pointer to output length variable 96 * Returns: Allocated buffer of out_len bytes of decoded data, 97 * or %NULL on failure 98 * 99 * Caller is responsible for freeing the returned buffer. 100 */ 101 unsigned char * base64_decode(const unsigned char *src, size_t len, 102 size_t *out_len) 103 { 104 unsigned char dtable[256], *out, *pos, in[4], block[4], tmp; 105 size_t i, count, olen; 106 107 os_memset(dtable, 0x80, 256); 108 for (i = 0; i < sizeof(base64_table) - 1; i++) 109 dtable[base64_table[i]] = (unsigned char) i; 110 dtable['='] = 0; 111 112 count = 0; 113 for (i = 0; i < len; i++) { 114 if (dtable[src[i]] != 0x80) 115 count++; 116 } 117 118 if (count == 0 || count % 4) 119 return NULL; 120 121 olen = count / 4 * 3; 122 pos = out = os_malloc(olen); 123 if (out == NULL) 124 return NULL; 125 126 count = 0; 127 for (i = 0; i < len; i++) { 128 tmp = dtable[src[i]]; 129 if (tmp == 0x80) 130 continue; 131 132 in[count] = src[i]; 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 } 141 } 142 143 if (pos > out) { 144 if (in[2] == '=') 145 pos -= 2; 146 else if (in[3] == '=') 147 pos--; 148 } 149 150 *out_len = pos - out; 151 return out; 152 } 153 154 155 #ifdef TEST_MAIN 156 #include <stdio.h> 157 158 int main(int argc, char *argv[]) 159 { 160 FILE *f; 161 size_t len, elen; 162 unsigned char *buf, *e; 163 164 if (argc != 4) { 165 printf("Usage: base64 <encode|decode> <in file> <out file>\n"); 166 return -1; 167 } 168 169 buf = os_readfile(argv[2], &len); 170 if (buf == NULL) 171 return -1; 172 173 if (strcmp(argv[1], "encode") == 0) 174 e = base64_encode(buf, len, &elen); 175 else 176 e = base64_decode(buf, len, &elen); 177 if (e == NULL) 178 return -2; 179 f = fopen(argv[3], "w"); 180 if (f == NULL) 181 return -3; 182 fwrite(e, 1, elen, f); 183 fclose(f); 184 free(e); 185 186 return 0; 187 } 188 #endif /* TEST_MAIN */ 189