base64.c (4143B)
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 "base64.h" 10 #include <stdlib.h> 11 #include <string.h> 12 #include <assert.h> 13 14 static const unsigned char base64_table[65] = 15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 16 17 static const unsigned char base62_table[] = 18 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 19 20 /** 21 * base64_encode - Base64 encode 22 * @src: Data to be encoded 23 * @len: Length of the data to be encoded 24 * @out_len: Pointer to output length variable, or %NULL if not used 25 * Returns: Allocated buffer of out_len bytes of encoded data, 26 * or %NULL on failure 27 * 28 * Caller is responsible for freeing the returned buffer. Returned buffer is 29 * nul terminated to make it easier to use as a C string. The nul terminator is 30 * not included in out_len. 31 */ 32 33 unsigned char * base_encode(const unsigned char *src, size_t len, 34 unsigned char *out, size_t out_capacity, 35 size_t *out_len, const unsigned char *base_table) 36 { 37 unsigned char *pos; 38 const unsigned char *end, *in; 39 size_t olen; 40 41 olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ 42 olen++; /* nul termination */ 43 if (olen < len) 44 return NULL; /* integer overflow */ 45 if (olen > out_capacity) 46 return NULL; /* buffer overflow */ 47 if (out == NULL) 48 return NULL; 49 50 end = src + len; 51 in = src; 52 pos = out; 53 while (end - in >= 3) { 54 *pos++ = base_table[in[0] >> 2]; 55 *pos++ = base_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 56 *pos++ = base_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; 57 *pos++ = base_table[in[2] & 0x3f]; 58 in += 3; 59 } 60 61 if (end - in) { 62 *pos++ = base_table[in[0] >> 2]; 63 if (end - in == 1) { 64 *pos++ = base_table[(in[0] & 0x03) << 4]; 65 *pos++ = '='; 66 } else { 67 *pos++ = base_table[((in[0] & 0x03) << 4) | 68 (in[1] >> 4)]; 69 *pos++ = base_table[(in[1] & 0x0f) << 2]; 70 } 71 *pos++ = '='; 72 } 73 74 *pos = '\0'; 75 if (out_len) 76 *out_len = pos - out; 77 return out; 78 } 79 80 unsigned char * 81 base64_encode(const unsigned char *src, size_t len, unsigned char *out, 82 size_t out_capacity, size_t *out_len) { 83 return base_encode(src, len, out, out_capacity, out_len, base64_table); 84 } 85 86 unsigned char * 87 base62_encode(const unsigned char *src, size_t len, unsigned char *out, 88 size_t out_capacity, size_t *out_len) { 89 return base_encode(src, len, out, out_capacity, out_len, base62_table); 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: Pointer to output buffer 98 * @out_len: Pointer to output length variable 99 * Returns: Allocated buffer of out_len bytes of decoded data, 100 * or %NULL on failure 101 * 102 * Caller is responsible for freeing the returned buffer. 103 */ 104 unsigned char * base64_decode(const unsigned char *src, size_t len, 105 unsigned char *out, size_t out_capacity, 106 size_t *out_size) 107 { 108 unsigned char dtable[256], *pos, block[4], tmp; 109 size_t i, count, olen; 110 int pad = 0; 111 112 memset(dtable, 0x80, 256); 113 for (i = 0; i < sizeof(base64_table) - 1; i++) 114 dtable[base64_table[i]] = (unsigned char) i; 115 dtable['='] = 0; 116 117 count = 0; 118 for (i = 0; i < len; i++) { 119 if (dtable[src[i]] != 0x80) 120 count++; 121 } 122 123 if (count == 0 || count % 4) 124 return NULL; 125 126 olen = count / 4 * 3; 127 128 if (out_capacity < olen) 129 return NULL; 130 131 pos = out; 132 if (out == NULL) 133 return NULL; 134 135 count = 0; 136 for (i = 0; i < len; i++) { 137 tmp = dtable[src[i]]; 138 if (tmp == 0x80) 139 continue; 140 141 if (src[i] == '=') 142 pad++; 143 block[count] = tmp; 144 count++; 145 if (count == 4) { 146 *pos++ = (block[0] << 2) | (block[1] >> 4); 147 assert((size_t)(pos - out) < out_capacity); 148 *pos++ = (block[1] << 4) | (block[2] >> 2); 149 assert((size_t)(pos - out) < out_capacity); 150 *pos++ = (block[2] << 6) | block[3]; 151 assert((size_t)(pos - out) < out_capacity); 152 count = 0; 153 if (pad) { 154 if (pad == 1) 155 pos--; 156 else if (pad == 2) 157 pos -= 2; 158 else { 159 /* Invalid padding */ 160 return NULL; 161 } 162 break; 163 } 164 } 165 } 166 167 *out_size = pos - out; 168 return out; 169 }