diff --git a/include/common/base64.h b/include/common/base64.h index bd77c687a2..e668001f40 100644 --- a/include/common/base64.h +++ b/include/common/base64.h @@ -17,6 +17,8 @@ #include int a2base64(char *in, int ilen, char *out, int olen); +int base64dec(const char *in, size_t ilen, char *out, size_t olen); + extern const char base64tab[]; #endif /* _COMMON_BASE64_H */ diff --git a/src/base64.c b/src/base64.c index e0126225e7..ea244a25f7 100644 --- a/src/base64.c +++ b/src/base64.c @@ -1,7 +1,8 @@ /* - * Ascii to Base64 conversion as described in RFC1421. + * ASCII <-> Base64 conversion as described in RFC1421. * * Copyright 2006-2008 Willy Tarreau + * Copyright 2009-2010 Krzysztof Piotr Oledzki * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -10,10 +11,19 @@ * */ +#include +#include + #include #include +#define B64BASE '#' /* arbitrary chosen base value */ +#define B64CMIN '+' +#define B64CMAX 'z' +#define B64PADV 64 /* Base64 chosen special pad value */ + const char base64tab[65]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const char base64rev[]="b###cXYZ[\\]^_`a###d###$%&'()*+,-./0123456789:;<=######>?@ABCDEFGHIJKLMNOPQRSTUVW"; /* Encodes bytes from to for at most chars (including * the trailing zero). Returns the number of bytes written. No check is made @@ -57,3 +67,71 @@ int a2base64(char *in, int ilen, char *out, int olen) return convlen; } + +/* Decodes bytes from to for at most chars. + * Returns the number of bytes converted. No check is made for + * or to be NULL. Returns -1 if is invalid or ilen + * has wrong size, -2 if is too short. + * 1 to 3 output bytes are produced for 4 input bytes. + */ +int base64dec(const char *in, size_t ilen, char *out, size_t olen) { + + unsigned char t[4]; + signed char b; + int convlen = 0, i = 0, pad = 0; + + if (ilen % 4) + return -1; + + if (olen < ilen / 4 * 3) + return -2; + + while (ilen) { + + /* if (*p < B64CMIN || *p > B64CMAX) */ + b = (signed char)*in - B64CMIN; + if ((unsigned char)b > (B64CMAX-B64CMIN)) + return -1; + + b = base64rev[b] - B64BASE - 1; + + /* b == -1: invalid character */ + if (b < 0) + return -1; + + /* padding has to be continous */ + if (pad && b != B64PADV) + return -1; + + /* valid padding: "XX==" or "XXX=", but never "X===" or "====" */ + if (pad && i < 2) + return -1; + + if (b == B64PADV) + pad++; + + t[i++] = b; + + if (i == 4) { + /* + * WARNING: we allow to write little more data than we + * should, but the checks from the beginning of the + * functions guarantee that we can safely do that. + */ + + /* xx000000 xx001111 xx111122 xx222222 */ + out[convlen] = ((t[0] << 2) + (t[1] >> 4)); + out[convlen+1] = ((t[1] << 4) + (t[2] >> 2)); + out[convlen+2] = ((t[2] << 6) + (t[3] >> 0)); + + convlen += 3-pad; + + pad = i = 0; + } + + in++; + ilen--; + } + + return convlen; +}