1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
#include <string.h>
#include <stdlib.h>
#include "base64.h"
/*
* http://freecode-freecode.blogspot.com/2008/02/base64c.html
*/
/**
* characters used for Base64 encoding
*/
const char *BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
* encode three bytes using base64 (RFC 3548)
*
* @param triple three bytes that should be encoded
* @param result buffer of four characters where the result is stored
*/
void _base64_encode_triple(unsigned char triple[3], char result[4]) {
int tripleValue, i;
tripleValue = triple[0];
tripleValue *= 256;
tripleValue += triple[1];
tripleValue *= 256;
tripleValue += triple[2];
for (i=0; i<4; i++) {
result[3-i] = BASE64_CHARS[tripleValue%64];
tripleValue /= 64;
}
}
/**
* encode an array of bytes using Base64 (RFC 3548)
*
* @param source the source buffer
* @param sourcelen the length of the source buffer
* @param target the target buffer
* @param targetlen the length of the target buffer
* @return 1 on success, 0 otherwise
*/
int base64_encode(unsigned char *source, size_t sourcelen, char *target, size_t targetlen) {
/* check if the result will fit in the target buffer */
if ((sourcelen+2)/3*4 > targetlen-1)
return 0;
/* encode all full triples */
while (sourcelen >= 3) {
_base64_encode_triple(source, target);
sourcelen -= 3;
source += 3;
target += 4;
}
/* encode the last one or two characters */
if (sourcelen > 0) {
unsigned char temp[3];
memset(temp, 0, sizeof(temp));
memcpy(temp, source, sourcelen);
_base64_encode_triple(temp, target);
target[3] = '=';
if (sourcelen == 1)
target[2] = '=';
target += 4;
}
/* terminate the string */
target[0] = 0;
return 1;
}
/**
* determine the value of a base64 encoding character
*
* @param base64char the character of which the value is searched
* @return the value in case of success (0-63), -1 on failure
*/
int _base64_char_value(char base64char) {
if (base64char >= 'A' && base64char <= 'Z')
return base64char-'A';
if (base64char >= 'a' && base64char <= 'z')
return base64char-'a'+26;
if (base64char >= '0' && base64char <= '9')
return base64char-'0'+2*26;
if (base64char == '+')
return 2*26+10;
if (base64char == '/')
return 2*26+11;
return -1;
}
/**
* decode a 4 char base64 encoded byte triple
*
* @param quadruple the 4 characters that should be decoded
* @param result the decoded data
* @return lenth of the result (1, 2 or 3), 0 on failure
*/
int _base64_decode_triple(char quadruple[4], unsigned char *result) {
int i, triple_value, bytes_to_decode = 3, only_equals_yet = 1;
int char_value[4];
for (i=0; i<4; i++)
char_value[i] = _base64_char_value(quadruple[i]);
/* check if the characters are valid */
for (i=3; i>=0; i--) {
if (char_value[i]<0) {
if (only_equals_yet && quadruple[i]=='=') {
/* we will ignore this character anyway, make it something
* that does not break our calculations */
char_value[i]=0;
bytes_to_decode--;
continue;
}
return 0;
}
/* after we got a real character, no other '=' are allowed anymore */
only_equals_yet = 0;
}
/* if we got "====" as input, bytes_to_decode is -1 */
if (bytes_to_decode < 0)
bytes_to_decode = 0;
/* make one big value out of the partial values */
triple_value = char_value[0];
triple_value *= 64;
triple_value += char_value[1];
triple_value *= 64;
triple_value += char_value[2];
triple_value *= 64;
triple_value += char_value[3];
/* break the big value into bytes */
for (i=bytes_to_decode; i<3; i++)
triple_value /= 256;
for (i=bytes_to_decode-1; i>=0; i--) {
result[i] = triple_value%256;
triple_value /= 256;
}
return bytes_to_decode;
}
/**
* decode base64 encoded data
*
* @param source the encoded data (zero terminated)
* @param target pointer to the target buffer
* @param targetlen length of the target buffer
* @return length of converted data on success, -1 otherwise
*/
size_t base64_decode(char *source, unsigned char *target, size_t targetlen) {
char *src, *tmpptr;
char quadruple[4], tmpresult[3];
int i, tmplen = 3;
size_t converted = 0;
/* concatinate '===' to the source to handle unpadded base64 data */
src = (char *)malloc(strlen(source)+5);
if (src == NULL)
return -1;
strcpy(src, source);
strcat(src, "====");
tmpptr = src;
/* convert as long as we get a full result */
while (tmplen == 3) {
/* get 4 characters to convert */
for (i=0; i<4; i++) {
/* skip invalid characters - we won't reach the end */
while (*tmpptr != '=' && _base64_char_value(*tmpptr)<0)
tmpptr++;
quadruple[i] = *(tmpptr++);
}
/* convert the characters */
tmplen = _base64_decode_triple(quadruple, (unsigned char*)tmpresult);
/* check if the fit in the result buffer */
if ((int)targetlen < tmplen) {
free(src);
return -1;
}
/* put the partial result in the result buffer */
memcpy(target, tmpresult, tmplen);
target += tmplen;
targetlen -= tmplen;
converted += tmplen;
}
free(src);
return converted;
}
|