supercop

Basic CLI for supercop
git clone git://git.finwo.net/app/supercop
Log | Files | Refs | README | LICENSE

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