Don't include <config.h> twice; this doesn't work in some cases,
[gnulib.git] / lib / gc-libgcrypt.c
index 9272c19..a9e6279 100644 (file)
@@ -1,5 +1,5 @@
 /* gc-libgcrypt.c --- Crypto wrappers around Libgcrypt for GC.
- * Copyright (C) 2002, 2003, 2004, 2005  Simon Josefsson
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006  Simon Josefsson
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
 /* Get prototype. */
 #include "gc.h"
 
+#include <stdlib.h>
+#include <string.h>
+
 /* Get libgcrypt API. */
 #include <gcrypt.h>
+#ifdef GC_USE_MD2
+# include "md2.h"
+#endif
 
 #include <assert.h>
 
@@ -59,6 +65,8 @@ gc_done (void)
   return;
 }
 
+#ifdef GC_USE_RANDOM
+
 /* Randomness. */
 
 Gc_rc
@@ -82,6 +90,8 @@ gc_random (char *data, size_t datalen)
   return GC_OK;
 }
 
+#endif
+
 /* Memory allocation. */
 
 void
@@ -218,14 +228,37 @@ gc_cipher_close (gc_cipher_handle handle)
 
 /* Hashes. */
 
+typedef struct _gc_hash_ctx {
+  Gc_hash alg;
+  Gc_hash_mode mode;
+  gcry_md_hd_t gch;
+#ifdef GC_USE_MD2
+  char hash[GC_MD2_DIGEST_SIZE];
+  struct md2_ctx md2Context;
+#endif
+} _gc_hash_ctx;
+
 Gc_rc
 gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle)
 {
+  _gc_hash_ctx *ctx;
   int gcryalg, gcrymode;
   gcry_error_t err;
+  Gc_rc rc = GC_OK;
+
+  ctx = calloc (sizeof (*ctx), 1);
+  if (!ctx)
+    return GC_MALLOC_ERROR;
+
+  ctx->alg = hash;
+  ctx->mode = mode;
 
   switch (hash)
     {
+    case GC_MD2:
+      gcryalg = GCRY_MD_NONE;
+      break;
+
     case GC_MD4:
       gcryalg = GCRY_MD_MD4;
       break;
@@ -243,7 +276,7 @@ gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle)
       break;
 
     default:
-      return GC_INVALID_HASH;
+      rc = GC_INVALID_HASH;
     }
 
   switch (mode)
@@ -257,24 +290,43 @@ gc_hash_open (Gc_hash hash, Gc_hash_mode mode, gc_hash_handle * outhandle)
       break;
 
     default:
-      return GC_INVALID_HASH;
+      rc = GC_INVALID_HASH;
     }
 
-  err = gcry_md_open ((gcry_md_hd_t *) outhandle, gcryalg, gcrymode);
-  if (gcry_err_code (err))
-    return GC_INVALID_HASH;
+  if (rc == GC_OK && gcryalg != GCRY_MD_NONE)
+    {
+      err = gcry_md_open (&ctx->gch, gcryalg, gcrymode);
+      if (gcry_err_code (err))
+       rc = GC_INVALID_HASH;
+    }
 
-  return GC_OK;
+  if (rc == GC_OK)
+    *outhandle = ctx;
+  else
+    free (ctx);
+
+  return rc;
 }
 
 Gc_rc
 gc_hash_clone (gc_hash_handle handle, gc_hash_handle * outhandle)
 {
+  _gc_hash_ctx *in = handle;
+  _gc_hash_ctx *out;
   int err;
 
-  err = gcry_md_copy ((gcry_md_hd_t *) outhandle, (gcry_md_hd_t) handle);
+  *outhandle = out = calloc (sizeof (*out), 1);
+  if (!out)
+    return GC_MALLOC_ERROR;
+
+  memcpy (out, in, sizeof (*out));
+
+  err = gcry_md_copy (&out->gch, in->gch);
   if (err)
-    return GC_INVALID_HASH;
+    {
+      free (out);
+      return GC_INVALID_HASH;
+    }
 
   return GC_OK;
 }
@@ -282,52 +334,78 @@ gc_hash_clone (gc_hash_handle handle, gc_hash_handle * outhandle)
 size_t
 gc_hash_digest_length (Gc_hash hash)
 {
-  int gcryalg;
+  size_t len;
 
   switch (hash)
     {
+    case GC_MD2:
+      len = GC_MD2_DIGEST_SIZE;
+      break;
+
     case GC_MD4:
-      gcryalg = GCRY_MD_MD4;
+      len = GC_MD4_DIGEST_SIZE;
       break;
 
     case GC_MD5:
-      gcryalg = GCRY_MD_MD5;
+      len = GC_MD5_DIGEST_SIZE;
       break;
 
-    case GC_SHA1:
-      gcryalg = GCRY_MD_SHA1;
+    case GC_RMD160:
+      len = GC_RMD160_DIGEST_SIZE;
       break;
 
-    case GC_RMD160:
-      gcryalg = GCRY_MD_RMD160;
+    case GC_SHA1:
+      len = GC_SHA1_DIGEST_SIZE;
       break;
 
     default:
       return 0;
     }
 
-  return gcry_md_get_algo_dlen (gcryalg);
+  return len;
 }
 
 void
 gc_hash_hmac_setkey (gc_hash_handle handle, size_t len, const char *key)
 {
-  gcry_md_setkey ((gcry_md_hd_t) handle, key, len);
+  _gc_hash_ctx *ctx = handle;
+#ifdef GC_USE_MD2
+  if (ctx->alg != GC_MD2)
+#endif
+    gcry_md_setkey (ctx->gch, key, len);
 }
 
 void
 gc_hash_write (gc_hash_handle handle, size_t len, const char *data)
 {
-  gcry_md_write ((gcry_md_hd_t) handle, data, len);
+  _gc_hash_ctx *ctx = handle;
+
+#ifdef GC_USE_MD2
+  if (ctx->alg == GC_MD2)
+    md2_process_bytes (data, len, &ctx->md2Context);
+  else
+#endif
+    gcry_md_write (ctx->gch, data, len);
 }
 
 const char *
 gc_hash_read (gc_hash_handle handle)
 {
+  _gc_hash_ctx *ctx = handle;
   const char *digest;
 
-  gcry_md_final ((gcry_md_hd_t) handle);
-  digest = gcry_md_read ((gcry_md_hd_t) handle, 0);
+#ifdef GC_USE_MD2
+  if (ctx->alg == GC_MD2)
+    {
+      md2_finish_ctx (&ctx->md2Context, ctx->hash);
+      digest = ctx->hash;
+    }
+  else
+#endif
+    {
+      gcry_md_final (ctx->gch);
+      digest = gcry_md_read (ctx->gch, 0);
+    }
 
   return digest;
 }
@@ -335,7 +413,14 @@ gc_hash_read (gc_hash_handle handle)
 void
 gc_hash_close (gc_hash_handle handle)
 {
-  gcry_md_close ((gcry_md_hd_t) handle);
+  _gc_hash_ctx *ctx = handle;
+
+#ifdef GC_USE_MD2
+  if (ctx->alg != GC_MD2)
+#endif
+    gcry_md_close (ctx->gch);
+
+  free (ctx);
 }
 
 Gc_rc
@@ -345,6 +430,13 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf)
 
   switch (hash)
     {
+#ifdef GC_USE_MD2
+    case GC_MD2:
+      md2_buffer (in, inlen, resbuf);
+      return GC_OK;
+      break;
+#endif
+
 #ifdef GC_USE_MD4
     case GC_MD4:
       gcryalg = GCRY_MD_MD4;
@@ -380,6 +472,15 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf)
 
 /* One-call interface. */
 
+#ifdef GC_USE_MD2
+Gc_rc
+gc_md2 (const void *in, size_t inlen, void *resbuf)
+{
+  md2_buffer (in, inlen, resbuf);
+  return GC_OK;
+}
+#endif
+
 #ifdef GC_USE_MD4
 Gc_rc
 gc_md4 (const void *in, size_t inlen, void *resbuf)