diff --git a/base64-decode.c b/base64-decode.c index f622baa..fbaf54f 100644 --- a/base64-decode.c +++ b/base64-decode.c @@ -43,7 +43,7 @@ #define TABLE_END -3 static const signed char -decode_table[0x100] = +default_decode_table[0x100] = { /* White space is HT, VT, FF, CR, LF and SPC */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, @@ -64,10 +64,40 @@ decode_table[0x100] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; +static const signed char +urlextended_decode_table[0x100] = +{ + /* White space is HT, VT, FF, CR, LF and SPC */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + void base64_decode_init(struct base64_decode_ctx *ctx) { ctx->word = ctx->bits = ctx->padding = 0; + ctx->alphabet = BASE64_ALPHABET; +} + +void +base64url_decode_init(struct base64_decode_ctx *ctx) +{ + ctx->word = ctx->bits = ctx->padding = 0; + ctx->alphabet = BASE64URL_ALPHABET; } int @@ -76,8 +106,11 @@ base64_decode_single(struct base64_decode_ctx *ctx, uint8_t src) { int data; - - data = decode_table[src]; + + if (ctx->alphabet == BASE64URL_ALPHABET) + data = urlextended_decode_table[src]; + else + data = default_decode_table[src]; switch(data) { diff --git a/base64-encode.c b/base64-encode.c index 313c512..fcf8546 100644 --- a/base64-encode.c +++ b/base64-encode.c @@ -38,11 +38,16 @@ #include "base64.h" -static const uint8_t encode_table[64] = +static const uint8_t default_encode_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/"; +static const uint8_t urlextended_encode_table[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_"; + #define ENCODE(x) (encode_table[0x3F & (x)]) void @@ -52,6 +57,7 @@ base64_encode_raw(uint8_t *dst, size_t length, const uint8_t *src) uint8_t *out = dst + BASE64_ENCODE_RAW_LENGTH(length); unsigned left_over = length % 3; + const uint8_t *encode_table = default_encode_table; if (left_over) { @@ -97,6 +103,7 @@ base64_encode(uint8_t *dst, unsigned n = src_length / 3; unsigned left_over = src_length % 3; unsigned done = 0; + const uint8_t *encode_table = default_encode_table; if (left_over) { @@ -134,6 +141,7 @@ base64_encode(uint8_t *dst, void base64_encode_group(uint8_t *dst, uint32_t group) { + const uint8_t *encode_table = default_encode_table; *dst++ = ENCODE(group >> 18); *dst++ = ENCODE(group >> 12); *dst++ = ENCODE(group >> 6); @@ -144,6 +152,14 @@ void base64_encode_init(struct base64_encode_ctx *ctx) { ctx->word = ctx->bits = 0; + ctx->alphabet = BASE64_ALPHABET; +} + +void +base64url_encode_init(struct base64_encode_ctx *ctx) +{ + ctx->word = ctx->bits = 0; + ctx->alphabet = BASE64URL_ALPHABET; } /* Encodes a single byte. */ @@ -155,6 +171,7 @@ base64_encode_single(struct base64_encode_ctx *ctx, unsigned done = 0; unsigned word = ctx->word << 8 | src; unsigned bits = ctx->bits + 8; + const uint8_t *encode_table = (ctx->alphabet == BASE64URL_ALPHABET ? urlextended_encode_table : default_encode_table); while (bits >= 6) { @@ -182,6 +199,7 @@ base64_encode_update(struct base64_encode_ctx *ctx, size_t left = length; unsigned left_over; size_t bulk; + const uint8_t *encode_table = (ctx->alphabet == BASE64URL_ALPHABET ? urlextended_encode_table : default_encode_table); while (ctx->bits && left) { @@ -221,6 +239,7 @@ base64_encode_final(struct base64_encode_ctx *ctx, { unsigned done = 0; unsigned bits = ctx->bits; + const uint8_t *encode_table = (ctx->alphabet == BASE64URL_ALPHABET ? urlextended_encode_table : default_encode_table); if (bits) { diff --git a/base64.h b/base64.h index a6fb823..4f6d5e3 100644 --- a/base64.h +++ b/base64.h @@ -42,12 +42,14 @@ extern "C" { /* Name mangling */ #define base64_encode_init nettle_base64_encode_init +#define base64url_encode_init nettle_base64url_encode_init #define base64_encode_single nettle_base64_encode_single #define base64_encode_update nettle_base64_encode_update #define base64_encode_final nettle_base64_encode_final #define base64_encode_raw nettle_base64_encode_raw #define base64_encode_group nettle_base64_encode_group #define base64_decode_init nettle_base64_decode_init +#define base64url_decode_init nettle_base64url_decode_init #define base64_decode_single nettle_base64_decode_single #define base64_decode_update nettle_base64_decode_update #define base64_decode_final nettle_base64_decode_final @@ -55,6 +57,10 @@ extern "C" { #define BASE64_BINARY_BLOCK_SIZE 3 #define BASE64_TEXT_BLOCK_SIZE 4 +/* which alphabet to use */ +#define BASE64_ALPHABET 0 +#define BASE64URL_ALPHABET 1 + /* Base64 encoding */ /* Maximum length of output for base64_encode_update. NOTE: Doesn't @@ -73,11 +79,17 @@ struct base64_encode_ctx { unsigned word; /* Leftover bits */ unsigned bits; /* Number of bits, always 0, 2, or 4. */ + unsigned alphabet; /* which alphabet to use for encoding */ }; +/* initialize encoding context for base-64 */ void base64_encode_init(struct base64_encode_ctx *ctx); +/* initialize encoding context for base-64 with URL safe extended alphabet */ +void +base64url_encode_init(struct base64_encode_ctx *ctx); + /* Encodes a single byte. Returns amount of output (always 1 or 2). */ size_t base64_encode_single(struct base64_encode_ctx *ctx, @@ -123,11 +135,17 @@ struct base64_decode_ctx /* Number of padding characters encountered */ unsigned padding; + unsigned alphabet; /* which alphabet to use for encoding */ }; +/* initialize encoding context for base-64 */ void base64_decode_init(struct base64_decode_ctx *ctx); +/* initialize encoding context for base-64 with URL safe extended alphabet */ +void +base64url_decode_init(struct base64_decode_ctx *ctx); + /* Decodes a single byte. Returns amount of output (0 or 1), or -1 on * errors. */ int