2007-07-27 05:35:13 -04:00
|
|
|
/** Base64 encode/decode implementation.
|
|
|
|
* @file */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "util/base64.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
|
|
|
|
static unsigned char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
char *
|
2021-12-03 06:34:00 -05:00
|
|
|
base64_encode(char *in)
|
2006-06-14 08:41:59 -04:00
|
|
|
{
|
|
|
|
assert(in && *in);
|
|
|
|
if_assert_failed return NULL;
|
2006-06-14 08:46:30 -04:00
|
|
|
|
2006-06-14 08:41:59 -04:00
|
|
|
return base64_encode_bin(in, strlen(in), NULL);
|
|
|
|
}
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
char *
|
2021-12-03 06:34:00 -05:00
|
|
|
base64_encode_bin(char *in, int inlen, int *outlen)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char *out;
|
|
|
|
char *outstr;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
assert(in && *in);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
2022-01-16 13:09:27 -05:00
|
|
|
out = outstr = (char *)mem_alloc((inlen / 3) * 4 + 4 + 1);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!out) return NULL;
|
|
|
|
|
|
|
|
while (inlen >= 3) {
|
|
|
|
*out++ = base64_chars[ *in >> 2 ];
|
|
|
|
*out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
|
|
|
|
*out++ = base64_chars[ (*(in + 1) << 2 | *(in + 2) >> 6) & 63 ];
|
|
|
|
*out++ = base64_chars[ *(in + 2) & 63 ];
|
|
|
|
inlen -= 3; in += 3;
|
|
|
|
}
|
|
|
|
if (inlen == 1) {
|
|
|
|
*out++ = base64_chars[ *in >> 2 ];
|
|
|
|
*out++ = base64_chars[ *in << 4 & 63 ];
|
|
|
|
*out++ = '=';
|
|
|
|
*out++ = '=';
|
|
|
|
}
|
|
|
|
if (inlen == 2) {
|
|
|
|
*out++ = base64_chars[ *in >> 2 ];
|
|
|
|
*out++ = base64_chars[ (*in << 4 | *(in + 1) >> 4) & 63 ];
|
|
|
|
*out++ = base64_chars[ (*(in + 1) << 2) & 63 ];
|
|
|
|
*out++ = '=';
|
|
|
|
}
|
|
|
|
*out = 0;
|
|
|
|
|
2006-06-14 08:41:59 -04:00
|
|
|
if (outlen)
|
|
|
|
*outlen = out-outstr;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
return outstr;
|
|
|
|
}
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
char *
|
2022-01-30 08:48:43 -05:00
|
|
|
base64_decode(const char *in)
|
2006-06-14 08:41:59 -04:00
|
|
|
{
|
|
|
|
assert(in && *in);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
|
|
|
return base64_decode_bin(in, strlen(in), NULL);
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2007-07-27 05:35:13 -04:00
|
|
|
/** Decode a Base64 string.
|
|
|
|
* @param in Input Base64 string
|
|
|
|
* @param inlen Length of @a in, in bytes
|
|
|
|
* @param[out] outlen Length of decoded string
|
|
|
|
*
|
|
|
|
* @returns the string decoded (must be freed by the caller)
|
|
|
|
* or NULL if an error occurred (syntax error or out of memory) */
|
2021-01-02 10:20:27 -05:00
|
|
|
char *
|
2022-01-30 08:48:43 -05:00
|
|
|
base64_decode_bin(const char *in, int inlen, int *outlen)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
static unsigned char is_base64_char[256]; /* static to force initialization at zero */
|
|
|
|
static unsigned char decode[256];
|
2021-01-02 10:20:27 -05:00
|
|
|
char *out;
|
|
|
|
char *outstr;
|
2005-09-15 09:58:31 -04:00
|
|
|
int count = 0;
|
|
|
|
unsigned int bits = 0;
|
|
|
|
static int once = 0;
|
|
|
|
|
|
|
|
assert(in && *in);
|
|
|
|
if_assert_failed return NULL;
|
|
|
|
|
2022-01-16 13:09:27 -05:00
|
|
|
outstr = out = (char *)mem_alloc(inlen / 4 * 3 + 1);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (!outstr) return NULL;
|
|
|
|
|
|
|
|
if (!once) {
|
|
|
|
int i = sizeof(base64_chars) - 1;
|
|
|
|
|
|
|
|
while (i >= 0) {
|
|
|
|
is_base64_char[base64_chars[i]] = 1;
|
|
|
|
decode[base64_chars[i]] = i;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
once = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*in) {
|
|
|
|
if (*in == '=') break;
|
2021-01-02 10:20:27 -05:00
|
|
|
if (!is_base64_char[(unsigned char)*in])
|
2005-09-15 09:58:31 -04:00
|
|
|
goto decode_error;
|
|
|
|
|
2021-01-02 10:20:27 -05:00
|
|
|
bits += decode[(unsigned char)*in];
|
2005-09-15 09:58:31 -04:00
|
|
|
count++;
|
|
|
|
if (count == 4) {
|
|
|
|
*out++ = bits >> 16;
|
|
|
|
*out++ = (bits >> 8) & 0xff;
|
|
|
|
*out++ = bits & 0xff;
|
|
|
|
bits = 0;
|
|
|
|
count = 0;
|
|
|
|
} else {
|
|
|
|
bits <<= 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
++in;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*in) {
|
|
|
|
if (count) goto decode_error;
|
|
|
|
} else { /* '=' */
|
|
|
|
switch (count) {
|
|
|
|
case 1:
|
|
|
|
goto decode_error;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
*out++ = bits >> 10;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
*out++ = bits >> 16;
|
|
|
|
*out++ = (bits >> 8) & 0xff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*out = 0;
|
2006-06-14 08:41:59 -04:00
|
|
|
|
|
|
|
if (outlen)
|
|
|
|
*outlen = out-outstr;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
return outstr;
|
|
|
|
|
|
|
|
decode_error:
|
|
|
|
mem_free(outstr);
|
|
|
|
return NULL;
|
|
|
|
}
|