base64.c (6565B)
1 /* Licensed under BSD-MIT - see LICENSE file for details */ 2 #include "base64.h" 3 4 #include <errno.h> 5 #include <string.h> 6 #include <assert.h> 7 #include <stdint.h> 8 9 /** 10 * sixbit_to_b64 - maps a 6-bit value to the base64 alphabet 11 * @param map A base 64 map (see base64_init_map) 12 * @param sixbit Six-bit value to map 13 * @return a base 64 character 14 */ 15 static char sixbit_to_b64(const base64_maps_t *maps, const uint8_t sixbit) 16 { 17 assert(sixbit <= 63); 18 19 return maps->encode_map[(unsigned char)sixbit]; 20 } 21 22 /** 23 * sixbit_from_b64 - maps a base64-alphabet character to its 6-bit value 24 * @param maps A base 64 maps structure (see base64_init_maps) 25 * @param sixbit Six-bit value to map 26 * @return a six-bit value 27 */ 28 static int8_t sixbit_from_b64(const base64_maps_t *maps, 29 const unsigned char b64letter) 30 { 31 int8_t ret; 32 33 ret = maps->decode_map[(unsigned char)b64letter]; 34 if (ret == (char)0xff) { 35 errno = EDOM; 36 return -1; 37 } 38 39 return ret; 40 } 41 42 bool base64_char_in_alphabet(const base64_maps_t *maps, const char b64char) 43 { 44 return (maps->decode_map[(const unsigned char)b64char] != (char)0xff); 45 } 46 47 void base64_init_maps(base64_maps_t *dest, const char src[64]) 48 { 49 unsigned char i; 50 51 memcpy(dest->encode_map,src,64); 52 memset(dest->decode_map,0xff,256); 53 for (i=0; i<64; i++) { 54 dest->decode_map[(unsigned char)src[i]] = i; 55 } 56 } 57 58 size_t base64_encoded_length(size_t srclen) 59 { 60 return ((srclen + 2) / 3) * 4; 61 } 62 63 void base64_encode_triplet_using_maps(const base64_maps_t *maps, 64 char dest[4], const char src[3]) 65 { 66 char a = src[0]; 67 char b = src[1]; 68 char c = src[2]; 69 70 dest[0] = sixbit_to_b64(maps, (a & 0xfc) >> 2); 71 dest[1] = sixbit_to_b64(maps, ((a & 0x3) << 4) | ((b & 0xf0) >> 4)); 72 dest[2] = sixbit_to_b64(maps, ((c & 0xc0) >> 6) | ((b & 0xf) << 2)); 73 dest[3] = sixbit_to_b64(maps, c & 0x3f); 74 } 75 76 void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4], 77 const char *src, const size_t srclen) 78 { 79 char longsrc[3] = { 0 }; 80 81 assert(srclen <= 3); 82 83 memcpy(longsrc, src, srclen); 84 base64_encode_triplet_using_maps(maps, dest, longsrc); 85 memset(dest+1+srclen, '=', 3-srclen); 86 } 87 88 ssize_t base64_encode_using_maps(const base64_maps_t *maps, 89 char *dest, const size_t destlen, 90 const char *src, const size_t srclen) 91 { 92 size_t src_offset = 0; 93 size_t dest_offset = 0; 94 95 if (destlen < base64_encoded_length(srclen)) { 96 errno = EOVERFLOW; 97 return -1; 98 } 99 100 while (srclen - src_offset >= 3) { 101 base64_encode_triplet_using_maps(maps, &dest[dest_offset], &src[src_offset]); 102 src_offset += 3; 103 dest_offset += 4; 104 } 105 106 if (src_offset < srclen) { 107 base64_encode_tail_using_maps(maps, &dest[dest_offset], &src[src_offset], srclen-src_offset); 108 dest_offset += 4; 109 } 110 111 memset(&dest[dest_offset], '\0', destlen-dest_offset); 112 113 return dest_offset; 114 } 115 116 size_t base64_decoded_length(size_t srclen) 117 { 118 return ((srclen+3)/4*3); 119 } 120 121 ssize_t base64_decode_quartet_using_maps(const base64_maps_t *maps, char dest[3], 122 const char src[4]) 123 { 124 signed char a; 125 signed char b; 126 signed char c; 127 signed char d; 128 129 a = sixbit_from_b64(maps, src[0]); 130 b = sixbit_from_b64(maps, src[1]); 131 c = sixbit_from_b64(maps, src[2]); 132 d = sixbit_from_b64(maps, src[3]); 133 134 if ((a == -1) || (b == -1) || (c == -1) || (d == -1)) { 135 return -1; 136 } 137 138 dest[0] = (a << 2) | (b >> 4); 139 dest[1] = ((b & 0xf) << 4) | (c >> 2); 140 dest[2] = ((c & 0x3) << 6) | d; 141 142 return 0; 143 } 144 145 146 ssize_t base64_decode_tail_using_maps(const base64_maps_t *maps, char *dest, 147 const char * src, const size_t srclen) 148 { 149 char longsrc[4]; 150 int quartet_result; 151 size_t insize = srclen; 152 153 while (insize != 0 && 154 src[insize-1] == '=') { /* throw away padding symbols */ 155 insize--; 156 } 157 if (insize == 0) { 158 return 0; 159 } 160 if (insize == 1) { 161 /* the input is malformed.... */ 162 errno = EINVAL; 163 return -1; 164 } 165 memcpy(longsrc, src, insize); 166 memset(longsrc+insize, 'A', 4-insize); 167 quartet_result = base64_decode_quartet_using_maps(maps, dest, longsrc); 168 if (quartet_result == -1) { 169 return -1; 170 } 171 172 return insize - 1; 173 } 174 175 ssize_t base64_decode_using_maps(const base64_maps_t *maps, 176 char *dest, const size_t destlen, 177 const char *src, const size_t srclen) 178 { 179 ssize_t dest_offset = 0; 180 ssize_t i; 181 ssize_t more; 182 183 if (destlen < base64_decoded_length(srclen)) { 184 errno = EOVERFLOW; 185 return -1; 186 } 187 188 for(i=0; srclen - i > 4; i+=4) { 189 if (base64_decode_quartet_using_maps(maps, &dest[dest_offset], &src[i]) == -1) { 190 return -1; 191 } 192 dest_offset += 3; 193 } 194 195 more = base64_decode_tail_using_maps(maps, &dest[dest_offset], &src[i], srclen - i); 196 if (more == -1) { 197 return -1; 198 } 199 dest_offset += more; 200 201 memset(&dest[dest_offset], '\0', destlen-dest_offset); 202 203 return dest_offset; 204 } 205 206 207 208 209 /** 210 * base64_maps_rfc4648 - pregenerated maps struct for rfc4648 211 */ 212 const base64_maps_t base64_maps_rfc4648 = { 213 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 214 215 "\xff\xff\xff\xff\xff" /* 0 */ \ 216 "\xff\xff\xff\xff\xff" /* 5 */ \ 217 "\xff\xff\xff\xff\xff" /* 10 */ \ 218 "\xff\xff\xff\xff\xff" /* 15 */ \ 219 "\xff\xff\xff\xff\xff" /* 20 */ \ 220 "\xff\xff\xff\xff\xff" /* 25 */ \ 221 "\xff\xff\xff\xff\xff" /* 30 */ \ 222 "\xff\xff\xff\xff\xff" /* 35 */ \ 223 "\xff\xff\xff\x3e\xff" /* 40 */ \ 224 "\xff\xff\x3f\x34\x35" /* 45 */ \ 225 "\x36\x37\x38\x39\x3a" /* 50 */ \ 226 "\x3b\x3c\x3d\xff\xff" /* 55 */ \ 227 "\xff\xff\xff\xff\xff" /* 60 */ \ 228 "\x00\x01\x02\x03\x04" /* 65 A */ \ 229 "\x05\x06\x07\x08\x09" /* 70 */ \ 230 "\x0a\x0b\x0c\x0d\x0e" /* 75 */ \ 231 "\x0f\x10\x11\x12\x13" /* 80 */ \ 232 "\x14\x15\x16\x17\x18" /* 85 */ \ 233 "\x19\xff\xff\xff\xff" /* 90 */ \ 234 "\xff\xff\x1a\x1b\x1c" /* 95 */ \ 235 "\x1d\x1e\x1f\x20\x21" /* 100 */ \ 236 "\x22\x23\x24\x25\x26" /* 105 */ \ 237 "\x27\x28\x29\x2a\x2b" /* 110 */ \ 238 "\x2c\x2d\x2e\x2f\x30" /* 115 */ \ 239 "\x31\x32\x33\xff\xff" /* 120 */ \ 240 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */ \ 241 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 242 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 243 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */ \ 244 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 245 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 246 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */ \ 247 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 248 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 249 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */ \ 250 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 251 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \ 252 "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */ 253 }; 254