[7ed3199] | 1 | /***************************************************************************\ |
---|
| 2 | * * |
---|
| 3 | * BitlBee - An IRC to IM gateway * |
---|
| 4 | * Base64 handling functions. encode_real() is mostly based on the y64 en- * |
---|
| 5 | * coder from libyahoo2. Moving it to a new file because it's getting big. * |
---|
| 6 | * * |
---|
| 7 | * Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> * |
---|
| 8 | * * |
---|
| 9 | * This program is free software; you can redistribute it and/or modify * |
---|
| 10 | * it under the terms of the GNU General Public License as published by * |
---|
| 11 | * the Free Software Foundation; either version 2 of the License, or * |
---|
| 12 | * (at your option) any later version. * |
---|
| 13 | * * |
---|
| 14 | * This program is distributed in the hope that it will be useful, * |
---|
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
---|
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
---|
| 17 | * GNU General Public License for more details. * |
---|
| 18 | * * |
---|
| 19 | * You should have received a copy of the GNU General Public License along * |
---|
| 20 | * with this program; if not, write to the Free Software Foundation, Inc., * |
---|
| 21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * |
---|
| 22 | * * |
---|
| 23 | \***************************************************************************/ |
---|
| 24 | |
---|
| 25 | #include <glib.h> |
---|
| 26 | #include <string.h> |
---|
| 27 | #include "base64.h" |
---|
| 28 | |
---|
| 29 | static const char real_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
---|
| 30 | |
---|
| 31 | char *tobase64(const char *text) |
---|
| 32 | { |
---|
[3b6eadc] | 33 | return base64_encode((const unsigned char *)text, strlen(text)); |
---|
[7ed3199] | 34 | } |
---|
| 35 | |
---|
[3b6eadc] | 36 | char *base64_encode(const unsigned char *in, int len) |
---|
[7ed3199] | 37 | { |
---|
| 38 | char *out; |
---|
| 39 | |
---|
| 40 | out = g_malloc((len + 2) /* the == padding */ |
---|
| 41 | / 3 /* every 3-byte block */ |
---|
| 42 | * 4 /* becomes a 4-byte one */ |
---|
| 43 | + 1); /* and of course, ASCIIZ! */ |
---|
| 44 | |
---|
| 45 | base64_encode_real((unsigned char*) in, len, (unsigned char*) out, real_b64); |
---|
| 46 | |
---|
| 47 | return out; |
---|
| 48 | } |
---|
| 49 | |
---|
| 50 | int base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, const char *b64digits) |
---|
| 51 | { |
---|
| 52 | int outlen = 0; |
---|
| 53 | |
---|
| 54 | for (; inlen >= 3; inlen -= 3) |
---|
| 55 | { |
---|
| 56 | out[outlen++] = b64digits[in[0] >> 2]; |
---|
| 57 | out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; |
---|
| 58 | out[outlen++] = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; |
---|
| 59 | out[outlen++] = b64digits[in[2] & 0x3f]; |
---|
| 60 | in += 3; |
---|
| 61 | } |
---|
| 62 | if (inlen > 0) |
---|
| 63 | { |
---|
| 64 | out[outlen++] = b64digits[in[0] >> 2]; |
---|
| 65 | if (inlen > 1) |
---|
| 66 | { |
---|
| 67 | out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; |
---|
| 68 | out[outlen++] = b64digits[((in[1]<<2) & 0x3c)]; |
---|
| 69 | } |
---|
| 70 | else |
---|
| 71 | { |
---|
| 72 | out[outlen++] = b64digits[((in[0]<<4) & 0x30)]; |
---|
| 73 | out[outlen++] = b64digits[64]; |
---|
| 74 | } |
---|
| 75 | out[outlen++] = b64digits[64]; |
---|
| 76 | } |
---|
| 77 | out[outlen] = 0; |
---|
| 78 | |
---|
| 79 | return outlen; |
---|
| 80 | } |
---|
| 81 | |
---|
| 82 | /* Just a simple wrapper, but usually not very convenient because of zero |
---|
| 83 | termination. */ |
---|
| 84 | char *frombase64(const char *in) |
---|
| 85 | { |
---|
| 86 | unsigned char *out; |
---|
| 87 | |
---|
| 88 | base64_decode(in, &out); |
---|
| 89 | |
---|
| 90 | return (char*) out; |
---|
| 91 | } |
---|
| 92 | |
---|
| 93 | /* FIXME: Lookup table stuff is not threadsafe! (But for now BitlBee is not threaded.) */ |
---|
| 94 | int base64_decode(const char *in, unsigned char **out) |
---|
| 95 | { |
---|
| 96 | static char b64rev[256] = { 0 }; |
---|
| 97 | int len, i; |
---|
| 98 | |
---|
| 99 | /* Create a reverse-lookup for the Base64 sequence. */ |
---|
| 100 | if( b64rev[0] == 0 ) |
---|
| 101 | { |
---|
| 102 | memset( b64rev, 0xff, 256 ); |
---|
| 103 | for( i = 0; i <= 64; i ++ ) |
---|
| 104 | b64rev[(int)real_b64[i]] = i; |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | len = strlen( in ); |
---|
| 108 | *out = g_malloc( ( len + 6 ) / 4 * 3 ); |
---|
| 109 | len = base64_decode_real( (unsigned char*) in, *out, b64rev ); |
---|
| 110 | *out = g_realloc( *out, len + 1 ); |
---|
| 111 | out[0][len] = 0; /* Zero termination can't hurt. */ |
---|
| 112 | |
---|
| 113 | return len; |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | int base64_decode_real(const unsigned char *in, unsigned char *out, char *b64rev) |
---|
| 117 | { |
---|
| 118 | int i, outlen = 0; |
---|
| 119 | |
---|
[50d26f3] | 120 | for( i = 0; in[i] && in[i+1] && in[i+2] && in[i+3]; i += 4 ) |
---|
[7ed3199] | 121 | { |
---|
| 122 | int sx; |
---|
| 123 | |
---|
| 124 | sx = b64rev[(int)in[i+0]]; |
---|
| 125 | if( sx >= 64 ) |
---|
| 126 | break; |
---|
| 127 | out[outlen] = ( sx << 2 ) & 0xfc; |
---|
| 128 | |
---|
| 129 | sx = b64rev[(int)in[i+1]]; |
---|
| 130 | if( sx >= 64 ) |
---|
| 131 | break; |
---|
| 132 | out[outlen] |= ( sx >> 4 ) & 0x03; |
---|
| 133 | outlen ++; |
---|
| 134 | out[outlen] = ( sx << 4 ) & 0xf0; |
---|
| 135 | |
---|
| 136 | sx = b64rev[(int)in[i+2]]; |
---|
| 137 | if( sx >= 64 ) |
---|
| 138 | break; |
---|
| 139 | out[outlen] |= ( sx >> 2 ) & 0x0f; |
---|
| 140 | outlen ++; |
---|
| 141 | out[outlen] = ( sx << 6 ) & 0xc0; |
---|
| 142 | |
---|
| 143 | sx = b64rev[(int)in[i+3]]; |
---|
| 144 | if( sx >= 64 ) |
---|
| 145 | break; |
---|
| 146 | out[outlen] |= sx; |
---|
| 147 | outlen ++; |
---|
| 148 | } |
---|
| 149 | |
---|
| 150 | /* If sx > 64 the base64 string was damaged. Should we ignore this? */ |
---|
| 151 | |
---|
| 152 | return outlen; |
---|
| 153 | } |
---|