diff --git a/ChangeLog b/ChangeLog
index 86699f654c27d8072ed38217d389f800106450c0..1346675b50ad2e34b5df97ddc400732b1dbec3a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-03-25  Niels M�ller  <nisse@lysator.liu.se>
+
+	* Makefile.in (nettle_SOURCES): Added sha384-meta.c.
+
+	* sha384-meta.c: New file.
+
+	* sha.h: Added declarations for sha384. Some are aliases for the
+	corresponding sha512 definition.
+
+	* sha512.c (sha512_write_digest): New function.
+	(sha512_digest): Use it.
+	(sha384_init): New function.
+	(sha384_digest): New function.
+
 2010-03-24  Niels M�ller  <nisse@lysator.liu.se>
 
 	* sha512.c: (sha512_digest): Simplified handling of any final
diff --git a/Makefile.in b/Makefile.in
index be5416ebc111ec987781fae3234af61bc519af08..d636865c5d099f6125a12beb892d3ed363b62eba 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -65,7 +65,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
 		 md2.c md2-meta.c md4.c md4-meta.c \
 		 md5.c md5-compress.c md5-compat.c md5-meta.c \
 		 sha1.c sha1-compress.c sha1-meta.c sha256.c sha256-compress.c sha256-meta.c \
-		 sha512.c sha512-compress.c sha512-meta.c \
+		 sha512.c sha512-compress.c sha384-meta.c sha512-meta.c \
 		 serpent.c serpent-meta.c \
 		 twofish.c twofish-meta.c \
 		 yarrow256.c yarrow_key_event.c \
diff --git a/nettle-meta.h b/nettle-meta.h
index c5d664eb931f37223f90680843c4da852ae28193..068456cf95b8ffb303e017400801446db1d60fce 100644
--- a/nettle-meta.h
+++ b/nettle-meta.h
@@ -138,6 +138,7 @@ extern const struct nettle_hash nettle_md4;
 extern const struct nettle_hash nettle_md5;
 extern const struct nettle_hash nettle_sha1;
 extern const struct nettle_hash nettle_sha256;
+extern const struct nettle_hash nettle_sha384;
 extern const struct nettle_hash nettle_sha512;
 
 struct nettle_armor
diff --git a/sha.h b/sha.h
index cf4743e6fd7f5a892a9731792c88b3b53d14a956..5dbffd7ef9a761c4736f8493af4ec892128177b9 100644
--- a/sha.h
+++ b/sha.h
@@ -39,6 +39,8 @@ extern "C" {
 #define sha256_init nettle_sha256_init
 #define sha256_update nettle_sha256_update
 #define sha256_digest nettle_sha256_digest
+#define sha384_init nettle_sha384_init
+#define sha384_digest nettle_sha384_digest
 #define sha512_init nettle_sha512_init
 #define sha512_update nettle_sha512_update
 #define sha512_digest nettle_sha512_digest
@@ -147,6 +149,24 @@ 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. */
+
+#define SHA384_DIGEST_SIZE 48
+#define SHA384_DATA_SIZE SHA512_DATA_SIZE
+#define sha384_ctx sha512_ctx
+
+void
+sha384_init(struct sha512_ctx *ctx);
+
+#define sha384_update nettle_sha512_update
+
+void
+sha384_digest(struct sha512_ctx *ctx,
+	      unsigned length,
+	      uint8_t *digest);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/sha384-meta.c b/sha384-meta.c
new file mode 100644
index 0000000000000000000000000000000000000000..0c022391ba1da36992614832986b0139079ecc15
--- /dev/null
+++ b/sha384-meta.c
@@ -0,0 +1,32 @@
+/* sha384-meta.c */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2002, 2010 Niels M�ller
+ *  
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ * 
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "nettle-meta.h"
+
+#include "sha.h"
+
+const struct nettle_hash nettle_sha384
+= _NETTLE_HASH(sha384, SHA384);
diff --git a/sha512.c b/sha512.c
index ec3c12fdc98ada5c929b5d3cd59a08011f37aa07..244ac805a14e8e997f504af7117ae7138827fff8 100644
--- a/sha512.c
+++ b/sha512.c
@@ -216,17 +216,15 @@ sha512_final(struct sha512_ctx *ctx)
   _nettle_sha512_compress(ctx->state, ctx->block, K);
 }
 
-void
-sha512_digest(struct sha512_ctx *ctx,
-	      unsigned length,
-	      uint8_t *digest)
+static void
+sha512_write_digest(struct sha512_ctx *ctx,
+		    unsigned length,
+		    uint8_t *digest)
 {
   unsigned i;
   unsigned words;
   unsigned leftover;
   
-  assert(length <= SHA512_DIGEST_SIZE);
-
   sha512_final(ctx);
   
   words = length / 8;
@@ -245,6 +243,56 @@ sha512_digest(struct sha512_ctx *ctx,
 	word >>= 8;
       } while (leftover);
     }
+}
 
+void
+sha512_digest(struct sha512_ctx *ctx,
+	      unsigned length,
+	      uint8_t *digest)
+{
+  assert(length <= SHA512_DIGEST_SIZE);
+
+  sha512_write_digest(ctx, length, digest);
   sha512_init(ctx);
 }
+
+/* sha384 variant. FIXME: Move to separate file? */
+void
+sha384_init(struct sha512_ctx *ctx)
+{
+  /* Initial values, generated by the gp script
+       {
+         for (i = 9,16,
+	   root = prime(i)^(1/2);
+	   fraction = root - floor(root);
+	   print(floor(2^64 * fraction));
+	 );
+       }
+. */
+  static const uint64_t H0[_SHA512_DIGEST_LENGTH] =
+  {
+    0xCBBB9D5DC1059ED8ULL, 0x629A292A367CD507ULL,
+    0x9159015A3070DD17ULL, 0x152FECD8F70E5939ULL,
+    0x67332667FFC00B31ULL, 0x8EB44A8768581511ULL,
+    0xDB0C2E0D64F98FA7ULL, 0x47B5481DBEFA4FA4ULL,
+  };
+
+  memcpy(ctx->state, H0, sizeof(H0));
+
+  /* Initialize bit count */
+  ctx->count_low = ctx->count_high = 0;
+  
+  /* Initialize buffer */
+  ctx->index = 0;
+}
+
+void
+sha384_digest(struct sha512_ctx *ctx,
+	      unsigned length,
+	      uint8_t *digest)
+{
+  assert(length <= SHA384_DIGEST_SIZE);
+
+  sha512_write_digest(ctx, length, digest);
+  sha384_init(ctx);
+}