base64.c revision 18298b00031545e253516c10b1af3b50fdfc36ac
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher/* Copyright (c) 2007 Dovecot authors, see the included COPYING file */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#include "lib.h"
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher#include "base64.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher#include "buffer.h"
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagherstatic const char b64enc[] =
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
f1fab7b8210af4ae94453265b607e2dab06789caStephen Gallagher
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagherstatic const unsigned char b64dec[256] = {
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0-7 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 8-15 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16-23 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24-31 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32-39 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40-47 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 48-55 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 56-63 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* 64-71 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* 72-79 */
897060147ddea72ecc1e86c6b7b915ff1d462f71Stephen Gallagher 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* 80-87 */
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* 88-95 */
84ae5edab16ad6be5e3be956cb6fa031c1428eb5Stephen Gallagher 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* 96-103 */
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* 104-111 */
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* 112-119 */
263e4574dacb4b7d2a18d5d42122bf3dce4c45b0Stephen Gallagher 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* 120-127 */
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128-255 */
263e4574dacb4b7d2a18d5d42122bf3dce4c45b0Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
263e4574dacb4b7d2a18d5d42122bf3dce4c45b0Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
e9ea1b4e59384cdfe3accdf31e5c579c3dad5591Stephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1df8e4158e752f1f010394d09e8a5e4f8201fd7eStephen Gallagher 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
void base64_encode(const void *src, size_t src_size, buffer_t *dest)
{
const unsigned char *src_c = src;
unsigned char tmp[4];
size_t src_pos;
for (src_pos = 0; src_pos < src_size; ) {
tmp[0] = b64enc[src_c[src_pos] >> 2];
switch (src_size - src_pos) {
case 1:
tmp[1] = b64enc[(src_c[src_pos] & 0x03) << 4];
tmp[2] = '=';
tmp[3] = '=';
src_pos++;
break;
case 2:
tmp[1] = b64enc[((src_c[src_pos] & 0x03) << 4) |
((src_c[src_pos+1] & 0xf0) >> 4)];
tmp[2] = b64enc[((src_c[src_pos+1] & 0x0f) << 2) |
((src_c[src_pos+2] & 0xc0) >> 6)];
tmp[3] = '=';
src_pos += 2;
break;
default:
tmp[1] = b64enc[((src_c[src_pos] & 0x03) << 4) |
((src_c[src_pos+1] & 0xf0) >> 4)];
tmp[2] = b64enc[((src_c[src_pos+1] & 0x0f) << 2) |
((src_c[src_pos+2] & 0xc0) >> 6)];
tmp[3] = b64enc[src_c[src_pos+2] & 0x3f];
src_pos += 3;
break;
}
buffer_append(dest, tmp, 4);
}
}
#define IS_EMPTY(c) \
((c) == '\n' || (c) == '\r' || (c) == ' ' || (c) == '\t')
int base64_decode(const void *src, size_t src_size,
size_t *src_pos_r, buffer_t *dest)
{
const unsigned char *src_c = src;
size_t src_pos;
unsigned char input[4], output[3];
int ret = 1;
for (src_pos = 0; src_pos+3 < src_size; ) {
input[0] = b64dec[src_c[src_pos]];
if (input[0] == 0xff) {
if (IS_EMPTY(src_c[src_pos++]))
continue;
return -1;
}
input[1] = b64dec[src_c[src_pos+1]];
if (input[1] == 0xff)
return -1;
output[0] = (input[0] << 2) | (input[1] >> 4);
input[2] = b64dec[src_c[src_pos+2]];
if (input[2] == 0xff) {
if (src_c[src_pos+2] != '=' || src_c[src_pos+3] != '=')
return -1;
buffer_append(dest, output, 1);
ret = 0;
src_pos += 4;
break;
}
output[1] = (input[1] << 4) | (input[2] >> 2);
input[3] = b64dec[src_c[src_pos+3]];
if (input[3] == 0xff) {
if (src_c[src_pos+3] != '=')
return -1;
buffer_append(dest, output, 2);
ret = 0;
src_pos += 4;
break;
}
output[2] = ((input[2] << 6) & 0xc0) | input[3];
buffer_append(dest, output, 3);
src_pos += 4;
}
for (; src_pos < src_size; src_pos++) {
if (!IS_EMPTY(src_c[src_pos]))
break;
}
if (src_pos_r != NULL)
*src_pos_r = src_pos;
return ret;
}
buffer_t *t_base64_decode_str(const char *str)
{
buffer_t *buf;
size_t len = strlen(str);
buf = buffer_create_dynamic(pool_datastack_create(),
MAX_BASE64_DECODED_SIZE(len));
(void)base64_decode(str, len, NULL, buf);
return buf;
}