#ifndef EXCLUDE_COMMON #include "common/cs_base64.h" #include #include "common/cs_dbg.h" /* ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ */ #define NUM_UPPERCASES ('Z' - 'A' + 1) #define NUM_LETTERS (NUM_UPPERCASES * 2) #define NUM_DIGITS ('9' - '0' + 1) /* * Emit a base64 code char. * * Doesn't use memory, thus it's safe to use to safely dump memory in crashdumps */ static void cs_base64_emit_code(struct cs_base64_ctx *ctx, int v) { if (v < NUM_UPPERCASES) { ctx->b64_putc(v + 'A', ctx->user_data); } else if (v < (NUM_LETTERS)) { ctx->b64_putc(v - NUM_UPPERCASES + 'a', ctx->user_data); } else if (v < (NUM_LETTERS + NUM_DIGITS)) { ctx->b64_putc(v - NUM_LETTERS + '0', ctx->user_data); } else { ctx->b64_putc(v - NUM_LETTERS - NUM_DIGITS == 0 ? '+' : '/', ctx->user_data); } } static void cs_base64_emit_chunk(struct cs_base64_ctx *ctx) { int a, b, c; a = ctx->chunk[0]; b = ctx->chunk[1]; c = ctx->chunk[2]; cs_base64_emit_code(ctx, a >> 2); cs_base64_emit_code(ctx, ((a & 3) << 4) | (b >> 4)); if (ctx->chunk_size > 1) { cs_base64_emit_code(ctx, (b & 15) << 2 | (c >> 6)); } if (ctx->chunk_size > 2) { cs_base64_emit_code(ctx, c & 63); } } void cs_base64_init(struct cs_base64_ctx *ctx, cs_base64_putc_t b64_putc, void *user_data) { ctx->chunk_size = 0; ctx->b64_putc = b64_putc; ctx->user_data = user_data; } void cs_base64_update(struct cs_base64_ctx *ctx, const char *str, size_t len) { const unsigned char *src = (const unsigned char *) str; size_t i; for (i = 0; i < len; i++) { ctx->chunk[ctx->chunk_size++] = src[i]; if (ctx->chunk_size == 3) { cs_base64_emit_chunk(ctx); ctx->chunk_size = 0; } } } void cs_base64_finish(struct cs_base64_ctx *ctx) { if (ctx->chunk_size > 0) { int i; memset(&ctx->chunk[ctx->chunk_size], 0, 3 - ctx->chunk_size); cs_base64_emit_chunk(ctx); for (i = 0; i < (3 - ctx->chunk_size); i++) { ctx->b64_putc('=', ctx->user_data); } } } #define BASE64_ENCODE_BODY \ static const char *b64 = \ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; \ int i, j, a, b, c; \ \ for (i = j = 0; i < src_len; i += 3) { \ a = src[i]; \ b = i + 1 >= src_len ? 0 : src[i + 1]; \ c = i + 2 >= src_len ? 0 : src[i + 2]; \ \ BASE64_OUT(b64[a >> 2]); \ BASE64_OUT(b64[((a & 3) << 4) | (b >> 4)]); \ if (i + 1 < src_len) { \ BASE64_OUT(b64[(b & 15) << 2 | (c >> 6)]); \ } \ if (i + 2 < src_len) { \ BASE64_OUT(b64[c & 63]); \ } \ } \ \ while (j % 4 != 0) { \ BASE64_OUT('='); \ } \ #define BASE64_OUT(ch) \ do { \ dst[j++] = (ch); \ } while (0) void cs_base64_encode(const unsigned char *src, int src_len, char *dst, int *enc_len) { BASE64_ENCODE_BODY; if (enc_len != NULL) *enc_len = j; } #undef BASE64_OUT #if CS_ENABLE_STDIO #define BASE64_OUT(ch) \ do { \ fprintf(f, "%c", (ch)); \ j++; \ } while (0) void cs_fprint_base64(FILE *f, const unsigned char *src, int src_len) { BASE64_ENCODE_BODY; } #undef BASE64_OUT #endif /* CS_ENABLE_STDIO */ /* Convert one byte of encoded base64 input stream to 6-bit chunk */ static unsigned char from_b64(unsigned char ch) { /* Inverse lookup map */ static const unsigned char tab[128] = { 255, 255, 255, 255, 255, 255, 255, 255, /* 0 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 8 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 16 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 24 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 32 */ 255, 255, 255, 62, 255, 255, 255, 63, /* 40 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 48 */ 60, 61, 255, 255, 255, 200, 255, 255, /* 56 '=' is 200, on index 61 */ 255, 0, 1, 2, 3, 4, 5, 6, /* 64 */ 7, 8, 9, 10, 11, 12, 13, 14, /* 72 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 80 */ 23, 24, 25, 255, 255, 255, 255, 255, /* 88 */ 255, 26, 27, 28, 29, 30, 31, 32, /* 96 */ 33, 34, 35, 36, 37, 38, 39, 40, /* 104 */ 41, 42, 43, 44, 45, 46, 47, 48, /* 112 */ 49, 50, 51, 255, 255, 255, 255, 255, /* 120 */ }; return tab[ch & 127]; } int cs_base64_decode(const unsigned char *s, int len, char *dst, int *dec_len) { unsigned char a, b, c, d; int orig_len = len; char *orig_dst = dst; while (len >= 4 && (a = from_b64(s[0])) != 255 && (b = from_b64(s[1])) != 255 && (c = from_b64(s[2])) != 255 && (d = from_b64(s[3])) != 255) { s += 4; len -= 4; if (a == 200 || b == 200) break; /* '=' can't be there */ *dst++ = a << 2 | b >> 4; if (c == 200) break; *dst++ = b << 4 | c >> 2; if (d == 200) break; *dst++ = c << 6 | d; } if (dec_len != NULL) *dec_len = (dst - orig_dst); return orig_len - len; } #endif /* EXCLUDE_COMMON */