#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 */