|
Packit |
8480eb |
#include <base64.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* characters used for Base64 encoding
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static const char *BASE64_CHARS =
|
|
Packit |
8480eb |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* encode three bytes using base64 (RFC 3548)
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* @param triple three bytes that should be encoded
|
|
Packit |
8480eb |
* @param result buffer of four characters where the result is stored
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static void _base64_encode_triple(unsigned char triple[3], char result[4])
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int tripleValue, i;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
tripleValue = triple[0];
|
|
Packit |
8480eb |
tripleValue *= 256;
|
|
Packit |
8480eb |
tripleValue += triple[1];
|
|
Packit |
8480eb |
tripleValue *= 256;
|
|
Packit |
8480eb |
tripleValue += triple[2];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
for (i=0; i<4; i++) {
|
|
Packit |
8480eb |
result[3 - i] = BASE64_CHARS[tripleValue % 64];
|
|
Packit |
8480eb |
tripleValue /= 64;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* encode an array of bytes using Base64 (RFC 3548)
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* @param source the source buffer
|
|
Packit |
8480eb |
* @param sourcelen the length of the source buffer
|
|
Packit |
8480eb |
* @param target the target buffer
|
|
Packit |
8480eb |
* @param targetlen the length of the target buffer
|
|
Packit |
8480eb |
* @return 1 on success, 0 otherwise
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
int base64_encode(char *source, size_t sourcelen, char *target, size_t targetlen)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
/* check if the result will fit in the target buffer */
|
|
Packit |
8480eb |
if ((sourcelen + 2)/ 3*4 > targetlen - 1)
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* encode all full triples */
|
|
Packit |
8480eb |
while (sourcelen >= 3) {
|
|
Packit |
8480eb |
_base64_encode_triple(source, target);
|
|
Packit |
8480eb |
sourcelen -= 3;
|
|
Packit |
8480eb |
source += 3;
|
|
Packit |
8480eb |
target += 4;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* encode the last one or two characters */
|
|
Packit |
8480eb |
if (sourcelen > 0) {
|
|
Packit |
8480eb |
unsigned char temp[3];
|
|
Packit |
8480eb |
memset(temp, 0, sizeof(temp));
|
|
Packit |
8480eb |
memcpy(temp, source, sourcelen);
|
|
Packit |
8480eb |
_base64_encode_triple(temp, target);
|
|
Packit |
8480eb |
target[3] = '=';
|
|
Packit |
8480eb |
if (sourcelen == 1)
|
|
Packit |
8480eb |
target[2] = '=';
|
|
Packit |
8480eb |
target += 4;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* terminate the string */
|
|
Packit |
8480eb |
target[0] = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return 1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* determine the value of a base64 encoding character
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* @param base64char the character of which the value is searched
|
|
Packit |
8480eb |
* @return the value in case of success (0-63), -1 on failure
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static int _base64_char_value(char base64char)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
if (base64char >= 'A' && base64char <= 'Z')
|
|
Packit |
8480eb |
return base64char-'A';
|
|
Packit |
8480eb |
if (base64char >= 'a' && base64char <= 'z')
|
|
Packit |
8480eb |
return base64char-'a'+26;
|
|
Packit |
8480eb |
if (base64char >= '0' && base64char <= '9')
|
|
Packit |
8480eb |
return base64char-'0'+2*26;
|
|
Packit |
8480eb |
if (base64char == '+')
|
|
Packit |
8480eb |
return 2*26+10;
|
|
Packit |
8480eb |
if (base64char == '/')
|
|
Packit |
8480eb |
return 2*26+11;
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* decode a 4 char base64 encoded byte triple
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* @param quadruple the 4 characters that should be decoded
|
|
Packit |
8480eb |
* @param result the decoded data
|
|
Packit |
8480eb |
* @return lenth of the result (1, 2 or 3), 0 on failure
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
static int _base64_decode_triple(char quadruple[4], char *result)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1;
|
|
Packit |
8480eb |
int char_value[4];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
for (i=0; i<4; i++)
|
|
Packit |
8480eb |
char_value[i] = _base64_char_value(quadruple[i]);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* check if the characters are valid */
|
|
Packit |
8480eb |
for (i=3; i>=0; i--) {
|
|
Packit |
8480eb |
if (char_value[i]<0) {
|
|
Packit |
8480eb |
if (only_equals_yet && quadruple[i]=='=') {
|
|
Packit |
8480eb |
/* we will ignore this character anyway, make it
|
|
Packit |
8480eb |
* something that does not break our calculations */
|
|
Packit |
8480eb |
char_value[i]=0;
|
|
Packit |
8480eb |
bytes_to_decode--;
|
|
Packit |
8480eb |
continue;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
return 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
/* after we got a real character, no other '=' are allowed anymore */
|
|
Packit |
8480eb |
only_equals_yet = 0;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* if we got "====" as input, bytes_to_decode is -1 */
|
|
Packit |
8480eb |
if (bytes_to_decode < 0)
|
|
Packit |
8480eb |
bytes_to_decode = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* make one big value out of the partial values */
|
|
Packit |
8480eb |
triple_value = char_value[0];
|
|
Packit |
8480eb |
triple_value *= 64;
|
|
Packit |
8480eb |
triple_value += char_value[1];
|
|
Packit |
8480eb |
triple_value *= 64;
|
|
Packit |
8480eb |
triple_value += char_value[2];
|
|
Packit |
8480eb |
triple_value *= 64;
|
|
Packit |
8480eb |
triple_value += char_value[3];
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* break the big value into bytes */
|
|
Packit |
8480eb |
for (i=bytes_to_decode; i<3; i++)
|
|
Packit |
8480eb |
triple_value /= 256;
|
|
Packit |
8480eb |
for (i=bytes_to_decode-1; i>=0; i--) {
|
|
Packit |
8480eb |
result[i] = triple_value%256;
|
|
Packit |
8480eb |
triple_value /= 256;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
return bytes_to_decode;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/*
|
|
Packit |
8480eb |
* decode base64 encoded data
|
|
Packit |
8480eb |
*
|
|
Packit |
8480eb |
* @param source the encoded data (zero terminated)
|
|
Packit |
8480eb |
* @param target pointer to the target buffer
|
|
Packit |
8480eb |
* @param targetlen length of the target buffer
|
|
Packit |
8480eb |
* @return length of converted data on success, -1 otherwise
|
|
Packit |
8480eb |
*/
|
|
Packit |
8480eb |
size_t base64_decode(char *source, char *target, size_t targetlen)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *src, *tmpptr;
|
|
Packit |
8480eb |
char quadruple[4], tmpresult[3];
|
|
Packit |
8480eb |
int i, tmplen = 3;
|
|
Packit |
8480eb |
size_t converted = 0;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* concatinate '===' to the source to handle unpadded base64 data */
|
|
Packit |
8480eb |
src = malloc(strlen(source)+5);
|
|
Packit |
8480eb |
if (src == NULL)
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
strcpy(src, source);
|
|
Packit |
8480eb |
strcat(src, "====");
|
|
Packit |
8480eb |
tmpptr = src;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
memset(target, 0, targetlen);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* convert as long as we get a full result */
|
|
Packit |
8480eb |
while (tmplen == 3) {
|
|
Packit |
8480eb |
/* get 4 characters to convert */
|
|
Packit |
8480eb |
for (i = 0; i < 4; i++) {
|
|
Packit |
8480eb |
/* skip invalid characters - we won't reach the end */
|
|
Packit |
8480eb |
while (*tmpptr != '=' && _base64_char_value(*tmpptr) < 0)
|
|
Packit |
8480eb |
tmpptr++;
|
|
Packit |
8480eb |
quadruple[i] = *(tmpptr++);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* convert the characters */
|
|
Packit |
8480eb |
tmplen = _base64_decode_triple(quadruple, tmpresult);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* check if the fit in the result buffer */
|
|
Packit |
8480eb |
if (targetlen < tmplen) {
|
|
Packit |
8480eb |
free(src);
|
|
Packit |
8480eb |
return -1;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
/* put the partial result in the result buffer */
|
|
Packit |
8480eb |
memcpy(target, tmpresult, tmplen);
|
|
Packit |
8480eb |
target += tmplen;
|
|
Packit |
8480eb |
targetlen -= tmplen;
|
|
Packit |
8480eb |
converted += tmplen;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
free(src);
|
|
Packit |
8480eb |
return converted;
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
#if 0
|
|
Packit |
8480eb |
#include <stdio.h>
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
int main(int argc, char **argv)
|
|
Packit |
8480eb |
{
|
|
Packit |
8480eb |
char *source = "testt(estt#wot%est'ing";
|
|
Packit |
8480eb |
int source_len = strlen(source);
|
|
Packit |
8480eb |
char dest[80];
|
|
Packit |
8480eb |
int dest_len = 79;
|
|
Packit |
8480eb |
char decoded[80];
|
|
Packit |
8480eb |
int decode_len = 79;
|
|
Packit |
8480eb |
int len;
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
printf("string %s\n", source);
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
if (base64_encode(source, source_len, dest, dest_len))
|
|
Packit |
8480eb |
printf("encoded %s len %d\n", dest, strlen(dest));
|
|
Packit |
8480eb |
|
|
Packit |
8480eb |
len = base64_decode(dest, decoded, decode_len);
|
|
Packit |
8480eb |
if (len != -1)
|
|
Packit |
8480eb |
printf("decoded %s len %d\n", decoded, len);
|
|
Packit |
8480eb |
}
|
|
Packit |
8480eb |
#endif
|