b64.c (2100B)
1 #include "b64.h" 2 3 #include "dist.h" 4 5 static const char B64_ENC[] = 6 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 7 8 size_t dist_b64_encode(char* out, const uint8_t* in, size_t n) { 9 size_t i = 0, o = 0; 10 while (i + 3 <= n) { 11 uint32_t v = ((uint32_t)in[i] << 16) | ((uint32_t)in[i + 1] << 8) | 12 (uint32_t)in[i + 2]; 13 out[o++] = B64_ENC[(v >> 18) & 0x3f]; 14 out[o++] = B64_ENC[(v >> 12) & 0x3f]; 15 out[o++] = B64_ENC[(v >> 6) & 0x3f]; 16 out[o++] = B64_ENC[v & 0x3f]; 17 i += 3; 18 } 19 if (n - i == 1) { 20 uint32_t v = (uint32_t)in[i] << 16; 21 out[o++] = B64_ENC[(v >> 18) & 0x3f]; 22 out[o++] = B64_ENC[(v >> 12) & 0x3f]; 23 out[o++] = '='; 24 out[o++] = '='; 25 } else if (n - i == 2) { 26 uint32_t v = ((uint32_t)in[i] << 16) | ((uint32_t)in[i + 1] << 8); 27 out[o++] = B64_ENC[(v >> 18) & 0x3f]; 28 out[o++] = B64_ENC[(v >> 12) & 0x3f]; 29 out[o++] = B64_ENC[(v >> 6) & 0x3f]; 30 out[o++] = '='; 31 } 32 out[o] = '\0'; 33 return o; 34 } 35 36 /* Map a base64 character to its 6-bit value, or 64 for '=' / -1 on error. */ 37 static int b64_val(char c) { 38 if (c >= 'A' && c <= 'Z') return c - 'A'; 39 if (c >= 'a' && c <= 'z') return c - 'a' + 26; 40 if (c >= '0' && c <= '9') return c - '0' + 52; 41 if (c == '+') return 62; 42 if (c == '/') return 63; 43 if (c == '=') return 64; 44 return -1; 45 } 46 47 int dist_b64_decode(uint8_t* out, size_t* outlen, const char* in, 48 size_t inlen) { 49 size_t i = 0, o = 0; 50 if (inlen % 4u != 0u) return DIST_ERR; 51 while (i < inlen) { 52 int a = b64_val(in[i]); 53 int b = b64_val(in[i + 1]); 54 int c = b64_val(in[i + 2]); 55 int d = b64_val(in[i + 3]); 56 if (a < 0 || b < 0 || c < 0 || d < 0) return DIST_ERR; 57 if (a == 64 || b == 64) return DIST_ERR; /* pad only in last two slots */ 58 out[o++] = (uint8_t)((a << 2) | (b >> 4)); 59 if (c != 64) { 60 out[o++] = (uint8_t)((b << 4) | (c >> 2)); 61 if (d != 64) out[o++] = (uint8_t)((c << 6) | d); 62 } else if (d != 64) { 63 return DIST_ERR; /* '=' followed by non-'=' */ 64 } 65 i += 4; 66 } 67 *outlen = o; 68 return DIST_OK; 69 }