/* * Base64 encode/decode functions used in sxmp * openssl stuff wasn't used to avoid additional memleaks and allocation, * deallocation of BIO and to avoid dependency, since not only openssl * might be in use * * (c) Alexander Vdolainen 2016 * * libsxmp is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libsxmp is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see ."; */ #include #include #include #include #include static const char b64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; static inline void encodeblock(unsigned char *in, unsigned char *out, int len) { out[0] = (unsigned char) b64[ (int)(in[0] >> 2) ]; out[1] = (unsigned char) b64[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ]; out[2] = (unsigned char) (len > 1 ? b64[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '='); out[3] = (unsigned char) (len > 2 ? b64[ (int)(in[2] & 0x3f) ] : '='); } static inline char __block(char b) { const char *j = strchr(b64, b); if(j) return j - b64; else return 0; } static inline void decodeblock(unsigned char *in, unsigned char *out) { char a = __block(in[0]); char b = __block(in[1]); char c = __block(in[2]); char d = __block(in[3]); out[0] = (unsigned char) (a << 2 | b >> 4); out[1] = (unsigned char) (b << 4 | c >> 2); out[2] = (unsigned char) (((c << 6) & 0xc0) | d); } size_t sxt_rawlen2b64len(size_t raw_length) { return (size_t)(((4 * raw_length / 3) + 3) & ~3); } size_t sxt_b64encode_in(const char *data, char *bdata, size_t data_len) { size_t bdata_len = 0, c = 0, n = 0; int len = 0, nil = 0, i; unsigned char ib[4]; if(!bdata) return -1; if(!data || !data_len) return -1; else bdata_len = sxt_rawlen2b64len(data_len); while(n != bdata_len) { if((c + 3) <= data_len) { len = 3; encodeblock((unsigned char *)data + c, (unsigned char *)bdata + n, len); n += 4; c += 3; } else { nil = (c + 3) - data_len; len = 0; for(i = 0; i < 3; i++) { if(i < nil + 1) { ib[i] = *((unsigned char *)data + (c + i)); len++; } else ib[i] = (unsigned char)0; } encodeblock(ib, (unsigned char *)bdata + n, len); break; } } return bdata_len; } char *sxt_b64encode(const char *data, size_t data_len) { char *bdata = NULL; size_t bdata_len = 0; if(!data || !data_len) return NULL; else bdata_len = sxt_rawlen2b64len(data_len); if(!(bdata = malloc(bdata_len))) return NULL; sxt_b64encode_in(data, bdata, data_len); return bdata; } size_t sxt_b64decode_in(const char *idata, size_t idata_len, char *data, size_t data_len) { size_t enc = 0, dec = 0; if(!idata || !idata_len) return -1; if(!data || !data_len) return -1; for(enc = 0; enc != idata_len; enc += 4) { if(dec >= data_len) return dec; decodeblock((unsigned char *)idata + enc, (unsigned char *)data + dec); dec += 3; } return dec; }