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