base64.c revision 1f69aa52ea2e0a73ac502565df8c666ee49cab6a
1/* 2 * Base64 encoding/decoding (RFC1341) 3 * Copyright (c) 2005-2011, Jouni Malinen <j@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 20static 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 */ 35unsigned 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 */ 103unsigned char * base64_decode(const unsigned char *src, size_t len, 104 size_t *out_len) 105{ 106 unsigned char dtable[256], *out, *pos, block[4], tmp; 107 size_t i, count, olen; 108 int pad = 0; 109 110 os_memset(dtable, 0x80, 256); 111 for (i = 0; i < sizeof(base64_table) - 1; i++) 112 dtable[base64_table[i]] = (unsigned char) i; 113 dtable['='] = 0; 114 115 count = 0; 116 for (i = 0; i < len; i++) { 117 if (dtable[src[i]] != 0x80) 118 count++; 119 } 120 121 if (count == 0 || count % 4) 122 return NULL; 123 124 olen = count / 4 * 3; 125 pos = out = os_malloc(olen); 126 if (out == NULL) 127 return NULL; 128 129 count = 0; 130 for (i = 0; i < len; i++) { 131 tmp = dtable[src[i]]; 132 if (tmp == 0x80) 133 continue; 134 135 if (src[i] == '=') 136 pad++; 137 block[count] = tmp; 138 count++; 139 if (count == 4) { 140 *pos++ = (block[0] << 2) | (block[1] >> 4); 141 *pos++ = (block[1] << 4) | (block[2] >> 2); 142 *pos++ = (block[2] << 6) | block[3]; 143 count = 0; 144 if (pad) { 145 if (pad == 1) 146 pos--; 147 else if (pad == 2) 148 pos -= 2; 149 else { 150 /* Invalid padding */ 151 os_free(out); 152 return NULL; 153 } 154 break; 155 } 156 } 157 } 158 159 *out_len = pos - out; 160 return out; 161} 162