diff --git a/base64.h b/base64.h index b45f9654d8024b91ca017933f833147a3e41154e..58e2879e05b5fa4acff34682af7b2f3bc4efae48 100644 --- a/base64.h +++ b/base64.h @@ -28,56 +28,96 @@ #include <inttypes.h> -/* Base64 encoding */ #define BASE64_BINARY_BLOCK_SIZE 3 #define BASE64_TEXT_BLOCK_SIZE 4 -/* Overlapping source and destination is allowed, as long as the start - * of the source area is not later than the start of the destination - * area. */ -unsigned /* Returns the length of encoded data */ -base64_encode(uint8_t *dst, - unsigned src_length, - const uint8_t *src); +/* Base64 encoding */ + +/* Maximum length of output for base64_encode_update. NOTE: Doesn't + * include any padding that base64_encode_final may add. */ +/* FIXME: Rewrite to only evaluate LENGTH once. */ +#define BASE64_ENCODE_LENGTH(length) ((length) + ((length) + 2)/3) -/* Precise length of encoded data (including padding) */ -#define BASE64_ENCODE_LENGTH(src_length) \ - ((BASE64_BINARY_BLOCK_SIZE - 1 + (src_length)) \ - / BASE64_BINARY_BLOCK_SIZE * BASE64_TEXT_BLOCK_SIZE) +/* Maximum lengbth of output generated by base64_encode_final. */ +#define BASE64_ENCODE_FINAL_LENGTH 3 + +/* Exact length of output generated by base64_encode_raw, including + * padding. */ +#define BASE64_ENCODE_RAW_LENGTH(length) ((((length) + 2)/3)*4) + +struct base64_encode_ctx +{ + unsigned word; /* Leftover bits */ + unsigned bits; /* Number of bits, always 0, 2, or 4. */ +}; + +void +base64_encode_init(struct base64_encode_ctx *ctx); + +/* Encodes a single byte. Returns amoutn of output (always 1 or 2). */ +unsigned +base64_encode_single(struct base64_encode_ctx *ctx, + uint8_t *dst, + uint8_t src); + +/* Returns the number of output characters. DST should point to an + * area of size at least BASE64_ENCODE_LENGTH(length). */ +unsigned +base64_encode_update(struct base64_encode_ctx *ctx, + uint8_t *dst, + unsigned length, + const uint8_t *src); + +/* DST should point to an area of size at least + * BASE64_ENCODE_FINAL_SIZE */ +unsigned +base64_encode_final(struct base64_encode_ctx *ctx, + uint8_t *dst); + +/* Lower level functions */ + +/* Encodes a string in one go, including any padding at the end. + * Generates exactly BASE64_ENCODE_RAW_LENGTH(length) bytes of output. + * Supports overlapped operation, if src <= dst. */ +void +base64_encode_raw(uint8_t *dst, unsigned length, const uint8_t *src); -/* Encode a single group */ void base64_encode_group(uint8_t *dst, uint32_t group); -/* FIXME: Perhaps rename to base64_decode_ctx? */ -struct base64_ctx /* Internal, do not modify */ + +/* Base64 decoding */ + +/* FIXME: Think more about this definition. */ +#define BASE64_DECODE_LENGTH(length) \ + ((length) * BASE64_BINARY_BLOCK_SIZE / BASE64_TEXT_BLOCK_SIZE) + +struct base64_decode_ctx { - uint16_t accum; /* Partial byte accumulated so far, filled msb first */ - int16_t shift; /* Bitshift for the next 6-bit segment added to buffer */ + enum + { + BASE64_DECODE_OK, + BASE64_DECODE_ERROR, + BASE64_DECODE_END + } status; + unsigned word; /* Leftover bits */ + unsigned bits; /* Number buffered bits */ }; void -base64_decode_init(struct base64_ctx *ctx); - -/* Overlapping source and destination is allowed, as long as the start - * of the source area is not before the start of the destination - * area. */ -unsigned /* Returns the length of decoded data */ -base64_decode_update(struct base64_ctx *ctx, - uint8_t *dst, - unsigned src_length, - const uint8_t *src); - -/* Maximum length of decoded data. - * - * NOTE: This size should work even for improper base 64 data. For - * example, consider an (encoded) input string of two bytes. When - * we'll generate one byte of output before noticing that the input is - * truncated. And BASE64_DECODE_LENGTH(2) == 2*3/4 == 1, so that is - * just fine. */ - -#define BASE64_DECODE_LENGTH(src_length) \ - ((src_length) * BASE64_BINARY_BLOCK_SIZE / BASE64_TEXT_BLOCK_SIZE) +base64_decode_init(struct base64_decode_ctx *ctx); + +/* Returns the number of output characters. DST should point to an + * area of size at least BASE64_DECODE_LENGTH(length). */ +unsigned +base64_decode_update(struct base64_decode_ctx *ctx, + uint8_t *dst, + unsigned length, + const uint8_t *src); + +/* Returns 1 on success. */ +int +base64_decode_status(struct base64_decode_ctx *ctx); #endif /* NETTLE_BASE64_H_INCLUDED */