#include "precomp.h" #include #include #include #include "base64.h" using namespace std; /* * The Base 64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y */ const char BASE64::alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const char BASE64::values[] = { /* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */ -1,-1,-1,62,-1,-1,-1,63, /* ()*+'-./ - 40 -> 47 */ 52,53,54,55,56,57,58,59,60,61, /* 0123456789 - 48 -> 57 */ -1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */ 3, 4, 5, 6, 7, 8, 9,10,11,12, /* DEFGHIJKLM - 68 -> 77 */ 13,14,15,16,17,18,19,20,21,22, /* NOPQRSTUVW - 78 -> 87 */ 23,24,25,-1,-1,-1,-1,-1,-1,26, /* XYZ[\]^_`a - 88 -> 97 */ 27,28,29,30,31,32,33,34,35,36, /* bcdefghijk - 98 -> 107 */ 37,38,39,40,41,42,43,44,45,46, /* lmnopqrstu - 108 -> 117 */ 47,48,49,50,51, /* vwxyz - 118 -> 122 */ -1,-1,-1,-1,-1,-1,-1,-1, /* - 123 -> 130 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */ -1,-1,-1,-1,-1, /* - 251 -> 255 */ }; BASE64::BASE64() { } BASE64::~BASE64() { } string BASE64::encode(unsigned char * buf, int len, bool padding) { int pad; int enclen = encode_pad_length(len, &pad); string encbuf; if (!padding) pad = 0; encbuf.resize(enclen + pad); /* Allow for trailing NUL */ encode_exactly(buf, len, encbuf.data(), enclen); if (pad) memset(encbuf.data() + enclen, '=', pad); return encbuf; } /** * encode_exactly * * Encode `len' bytes from `buf' unsignedo `enclen' bytes starting from `encbuf'. * Caller must have ensured that there was EXACTLY the needed room in encbuf. */ void BASE64::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen) { int i = 0; /* Input accumulator, 0 for trailing pad */ unsigned char const *ip = buf + len; /* Input pounsigneder, one byte off end */ char *op = encbuf + enclen; /* Output pounsigneder, one byte off end */ assert(buf); assert(encbuf); assert(len > 0); assert(enclen >= len * 4 / 3); /* * In the following picture, we represent how the 3 bytes of input * are split unsignedo groups of 6 bits, each group being encoded as a * single base64 digit. * * input byte 0 1 2 * +--------+--------+--------+ * |01234501|23450123|45012345| * +--------+--------+--------+ * <----><-----><-----><----> * output digit 0 1 2 3 * * * Because of possible padding, which must be done as if the input * was 0, and because the fractional part is at the end, we'll * start encoding from the end. The encoding loop is unrolled for * greater performance (using the infamous Duff's device to directly * switch at the proper stage within the do {} while loop). */ switch (len % 3) { case 0: do { assert(op - encbuf >= 4); i = (unsigned char) *--ip; /* Input #2 */ *--op = alphabet[i & 0x3f]; /* Ouput #3 */ i >>= 6; /* upper <45>, input #2 */ /* FALLTHROUGH */ case 2: i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */ *--op = alphabet[i & 0x3f]; /* Output #2 */ i >>= 6; /* upper <2345>, input #1 */ /* FALLTHROUGH */ case 1: i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */ *--op = alphabet[i & 0x3f]; /* Output #1 */ i >>= 6; /* upper <012345>, input #0 */ *--op = alphabet[i & 0x3f]; /* Output #0 */ i >>= 6; /* Holds nothing, MBZ */ assert(i == 0); assert(op >= encbuf); } while (op > encbuf); } } /** * encode_pad_length * * Compute the number of base64 digits and amount of padding necessary * to encode `len' bytes. * * Returns the number of base64 digits necessary. * Furthermore, if `pad' is a non-NULL pounsigneder, it is filled with the amount * of padding chars that would be necessary. */ int BASE64::encode_pad_length(int len, int *pad) { int ndigits; /* Base64 digits necessary */ int npad = 0; /* Final padding chars necessary */ int tcount; /* Amount of full triplets */ int remainder; /* Amount of input bytes in final triplet */ assert(len > 0); tcount = len / 3; remainder = len - (tcount * 3); assert((unsigned) remainder >= 0); switch (remainder) { case 0: npad = 0; break; case 1: npad = 2; break; case 2: npad = 1; break; default: assert(0); /* Not possible */ } ndigits = tcount * 4; /* Each full triplet encoded on 4 bytes */ if (npad != 0) ndigits += (4 - npad); if (pad) *pad = npad; return ndigits; } /** * base64_decode * * Decode `len' bytes starting at `buf' unsignedo new allocated buffer. * * Returns the new decoded buffer, or NULL if the input was not valid base64 * encoding. The caller knows the length of the returned buffer: it's the * size of the input divided by 4 and multiplied by 3. If `outlen' is non-NULL, * it is filled with the amount of bytes decoded unsignedo the buffer (without * trailing padding). */ vector BASE64::decode(const char * buf, int len, int * outlen) { int declen; vector decbuf; int decoded; if (len == -1) len = strlen(buf); // if (len == 0 || (len & 0x3)) /* Empty, or padding bytes missing */ // return NULL; declen = (len >> 2) * 3; decbuf.resize(declen * sizeof(unsigned char)); decoded = decode_into(buf, len, decbuf.data(), declen); if (decoded == 0) decbuf.clear(); if (outlen) *outlen = decoded; return decbuf; } /** * decode_into * * Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf', * faking the necessary amount of padding if necessary. * Caller must have ensured that there was sufficient room in decbuf. * * Returns the amount of bytes decoded (without trailing padding) if successful, * 0 if the input was not valid base32. */ int BASE64::decode_into(const char *buf, int len, unsigned char *decbuf, int declen) { int padding = 0; if (len & 0x3) padding = 4 - (len & 0x3); return decode_alphabet(values, buf, len + padding, decbuf, declen, padding); } /* * decode_alphabet * * Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf'. * Caller must have ensured that there was sufficient room in decbuf. * Uses the specified decoding alphabet. * * `padding', when non-zero, is the amount of padding that is missing from * the input buffer and which we must assume. * * Return decoded bytes if successful, 0 if the input was not valid base32. */ int BASE64::decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding) { int i = 0; /* Input accumulator, 0 for trailing pad */ char const *ip = buf + len; /* Input pounsigneder, one byte off end */ int dlen = (len >> 2) * 3; /* Exact decoded length */ unsigned char *op; /* Output pounsigneder, one byte off end */ int bytes; /* Bytes decoded without padding */ char v; assert(buf); assert(decbuf); assert(len > 0); assert((len & 0x3) == 0); /* `len' is a multiple of 4 bytes */ //assert(declen >= dlen); /* * If the last byte of input is '=', there is padding and we need to * zero the tail of the decoding buffer. * * Likewise, when `padding' is non-zero, act as if the '=' were there. */ if (buf[len-1] == '=' || padding > 0) { int pad = 0; int n = 0; /* Amount of bytes to zero */ int s = 0; /* Amount of bytes to zero */ /* * Remove and count trailing input padding bytes. */ if (padding == 0) { while (*--ip == '=') pad++; ip++; /* Pounsigneds one byte after real non-padding input */ } else { pad = padding; ip -= padding; } switch (pad) { case 1: n = 1; s = 0; break; case 2: n = 2; s = 1; break; default: return 0; /* Cannot be valid base64 */ } memset(decbuf + (dlen - n), 0, n); op = decbuf + (dlen - s); bytes = dlen - n; } else { op = decbuf + dlen; bytes = dlen; } /* * In the following picture, we represent how the 4 bytes of input, * each consisting of only 6 bits of information forming a base64 digit, * are concatenated back unsignedo 3 bytes of binary information. * * input digit 0 1 2 3 * <----><-----><-----><----> * +--------+--------+--------+ * |01234501|23450123|45012345| * +--------+--------+--------+ * output byte 0 1 2 * * Because of possible padding, which must be done as if the input * was 0, and because the fractional part is at the end, we'll * start decoding from the end. The decoding loop is unrolled for * greater performance (using the infamous Duff's device to directly * switch at the proper stage within the do {} while loop). */ switch ((ip - buf) % 4) { case 0: do { v = valmap[(unsigned char) *--ip]; /* Input #3 */ if (v < 0) return 0; i = v; /* FALLTHROUGH */ case 3: v = valmap[(unsigned char) *--ip]; /* Input #2 */ if (v < 0) return 0; i |= v << 6; /* had 6 bits */ *--op = i & 0xff; /* Output #2 */ i >>= 8; /* lower <0123> of output #1 */ /* FALLTHROUGH */ case 2: v = valmap[(unsigned char) *--ip]; /* Input #1 */ if (v < 0) return 0; i |= v << 4; /* had 4 bits */ *--op = i & 0xff; /* Output #1 */ i >>= 8; /* lower <01> of output #0 */ /* FALLTHROUGH */ case 1: v = valmap[(unsigned char) *--ip]; /* Input #0 */ if (v < 0) return 0; i |= v << 2; /* had 2 bits */ *--op = i & 0xff; /* Output #0 */ i >>= 8; /* Holds nothing, MBZ */ assert(i == 0); assert(op >= decbuf); } while (op > decbuf); } return bytes; }