diff --git a/sha.h b/sha.h
index 5dbffd7ef9a761c4736f8493af4ec892128177b9..41afde4b6ac78b76efcba0e0bd1edd8b6d8487db 100644
--- a/sha.h
+++ b/sha.h
@@ -36,6 +36,8 @@ extern "C" {
 #define sha1_init nettle_sha1_init
 #define sha1_update nettle_sha1_update
 #define sha1_digest nettle_sha1_digest
+#define sha224_init nettle_sha224_init
+#define sha224_digest nettle_sha224_digest
 #define sha256_init nettle_sha256_init
 #define sha256_update nettle_sha256_update
 #define sha256_digest nettle_sha256_digest
@@ -114,6 +116,24 @@ sha256_digest(struct sha256_ctx *ctx,
 void
 _nettle_sha256_compress(uint32_t *state, const uint8_t *data, const uint32_t *k);
 
+
+/* SHA224, a truncated SHA256 with different initial state. */
+
+#define SHA224_DIGEST_SIZE 28
+#define SHA224_DATA_SIZE SHA256_DATA_SIZE
+#define sha224_ctx sha256_ctx
+
+void
+sha224_init(struct sha256_ctx *ctx);
+
+#define sha224_update nettle_sha256_update
+
+void
+sha224_digest(struct sha256_ctx *ctx,
+	      unsigned length,
+	      uint8_t *digest);
+
+
 /* SHA512 */
 
 #define SHA512_DIGEST_SIZE 64
@@ -149,9 +169,8 @@ sha512_digest(struct sha512_ctx *ctx,
 void
 _nettle_sha512_compress(uint64_t *state, const uint8_t *data, const uint64_t *k);
 
-/* SHA384. */
-/* This is the same algorithm as SHA512, but with different initial
-   state and truncated output. */
+
+/* SHA384, a truncated SHA512 with different initial state. */
 
 #define SHA384_DIGEST_SIZE 48
 #define SHA384_DATA_SIZE SHA512_DATA_SIZE
diff --git a/sha256.c b/sha256.c
index 9a3f1bb2cba48feefbb5dce09ad7013c3564a9eb..fa4f735b5979cde6a0a3e89733e893bb433a9c32 100644
--- a/sha256.c
+++ b/sha256.c
@@ -38,6 +38,7 @@
 #include "sha.h"
 
 #include "macros.h"
+#include "nettle-write.h"
 
 /* Generated by the shadata program. */
 static const uint32_t
@@ -172,42 +173,42 @@ sha256_digest(struct sha256_ctx *ctx,
 	      unsigned length,
 	      uint8_t *digest)
 {
-  unsigned i;
-  unsigned words;
-  unsigned leftover;
-  
   assert(length <= SHA256_DIGEST_SIZE);
 
   sha256_final(ctx);
+  _nettle_write_be32(length, digest, ctx->state);
+  sha256_init(ctx);
+}
+
+/* sha224 variant. FIXME: Move to seperate file? */
+
+void
+sha224_init(struct sha256_ctx *ctx)
+{
+  /* Initial values. I's unclear how they are chosen. */
+  static const uint32_t H0[_SHA256_DIGEST_LENGTH] =
+  {
+    0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+    0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+  };
+
+  memcpy(ctx->state, H0, sizeof(H0));
+
+  /* Initialize bit count */
+  ctx->count_low = ctx->count_high = 0;
   
-  words = length / 4;
-  leftover = length % 4;
+  /* Initialize buffer */
+  ctx->index = 0;
+}
 
-  for (i = 0; i < words; i++, digest += 4)
-    WRITE_UINT32(digest, ctx->state[i]);
+void
+sha224_digest(struct sha256_ctx *ctx,
+	      unsigned length,
+	      uint8_t *digest)
+{
+  assert(length <= SHA224_DIGEST_SIZE);
 
-  if (leftover)
-    {
-      uint32_t word;
-      unsigned j = leftover;
-      
-      assert(i < _SHA256_DIGEST_LENGTH);
-      
-      word = ctx->state[i];
-      
-      switch (leftover)
-	{
-	default:
-	  abort();
-	case 3:
-	  digest[--j] = (word >> 8) & 0xff;
-	  /* Fall through */
-	case 2:
-	  digest[--j] = (word >> 16) & 0xff;
-	  /* Fall through */
-	case 1:
-	  digest[--j] = (word >> 24) & 0xff;
-	}
-    }
-  sha256_init(ctx);
+  sha256_final(ctx);
+  _nettle_write_be32(length, digest, ctx->state);
+  sha224_init(ctx);
 }