b64.c (3179B)
1 #include <stdlib.h> 2 3 #include "b64.h" 4 5 #ifdef __cplusplus 6 extern "C" { 7 #endif 8 9 static const char asc_b64_alphabet[] = 10 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 11 12 char *asc_b64_encode(const unsigned char *in, size_t len, size_t *outlen) { 13 size_t rawlen, full_lines, i, o, raw; 14 char *out; 15 unsigned int n; 16 17 if (!in || !outlen || len == 0) return NULL; 18 // 4 chars per 3 bytes, plus '\n' per 64-char line, plus trailing '\n' 19 rawlen = ((len + 2) / 3) * 4; 20 full_lines = (rawlen + 63) / 64; 21 out = malloc(rawlen + full_lines + 1); 22 if (!out) return NULL; 23 24 o = 0; 25 raw = 0; 26 for (i = 0; i < len; i += 3) { 27 size_t rem = len - i; 28 n = (unsigned int)in[i] << 16; 29 if (rem > 1) n |= (unsigned int)in[i + 1] << 8; 30 if (rem > 2) n |= in[i + 2]; 31 out[o++] = asc_b64_alphabet[(n >> 18) & 0x3F]; 32 out[o++] = asc_b64_alphabet[(n >> 12) & 0x3F]; 33 out[o++] = (rem > 1) ? asc_b64_alphabet[(n >> 6) & 0x3F] : '='; 34 out[o++] = (rem > 2) ? asc_b64_alphabet[n & 0x3F] : '='; 35 raw += 4; 36 if (raw % 64 == 0) out[o++] = '\n'; 37 } 38 if (out[o - 1] != '\n') out[o++] = '\n'; 39 out[o] = '\0'; 40 *outlen = o; 41 return out; 42 } 43 44 static int asc_b64_value(unsigned char c) { 45 if (c >= 'A' && c <= 'Z') return c - 'A'; 46 if (c >= 'a' && c <= 'z') return c - 'a' + 26; 47 if (c >= '0' && c <= '9') return c - '0' + 52; 48 if (c == '+') return 62; 49 if (c == '/') return 63; 50 return -1; 51 } 52 53 static int asc_b64_is_ws(unsigned char c) { 54 return c == ' ' || c == '\t' || c == '\r' || c == '\n'; 55 } 56 57 unsigned char *asc_b64_decode(const unsigned char *in, size_t len, size_t *outlen) { 58 size_t cleanlen = 0, i, o; 59 unsigned char *clean, *out; 60 unsigned int n; 61 int a, b, c, d; 62 63 if (!in || !outlen || len == 0) return NULL; 64 clean = malloc(len); 65 if (!clean) return NULL; 66 for (i = 0; i < len; i++) { 67 if (asc_b64_is_ws(in[i])) continue; 68 if (in[i] == '=' || asc_b64_value(in[i]) >= 0) { 69 clean[cleanlen++] = in[i]; 70 } else { 71 free(clean); 72 return NULL; 73 } 74 } 75 // Input must arrive in complete 4-char quanta 76 if (cleanlen == 0 || cleanlen % 4 != 0) { 77 free(clean); 78 return NULL; 79 } 80 out = malloc((cleanlen / 4) * 3); 81 if (!out) { 82 free(clean); 83 return NULL; 84 } 85 o = 0; 86 for (i = 0; i < cleanlen; i += 4) { 87 a = asc_b64_value(clean[i]); 88 b = asc_b64_value(clean[i + 1]); 89 c = (clean[i + 2] == '=') ? 0 : asc_b64_value(clean[i + 2]); 90 d = (clean[i + 3] == '=') ? 0 : asc_b64_value(clean[i + 3]); 91 // Padding only valid as the last quantum's tail 92 if (a < 0 || b < 0 || c < 0 || d < 0 || 93 clean[i] == '=' || clean[i + 1] == '=' || 94 (clean[i + 2] == '=' && clean[i + 3] != '=') || 95 ((clean[i + 2] == '=' || clean[i + 3] == '=') && i + 4 != cleanlen)) { 96 free(clean); 97 free(out); 98 return NULL; 99 } 100 n = ((unsigned int)a << 18) | ((unsigned int)b << 12) | 101 ((unsigned int)c << 6) | (unsigned int)d; 102 out[o++] = (n >> 16) & 0xFF; 103 if (clean[i + 2] != '=') out[o++] = (n >> 8) & 0xFF; 104 if (clean[i + 3] != '=') out[o++] = n & 0xFF; 105 } 106 free(clean); 107 *outlen = o; 108 return out; 109 } 110 111 #ifdef __cplusplus 112 } // extern "C" 113 #endif