maint: update copyright
[gnulib.git] / lib / gc-libgcrypt.c
index 349d561..f6ecf0b 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-2014 Free Software Foundation, Inc.
  *
  * This file is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this file; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
+ * along with this file; if not, see <http://www.gnu.org/licenses/>.
  *
  */
 
 /* Note: This file is only built if GC uses Libgcrypt. */
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 /* Get prototype. */
 #include "gc.h"
 
+#include <stdlib.h>
+#include <string.h>
+
 /* Get libgcrypt API. */
 #include <gcrypt.h>
+#ifdef GNULIB_GC_MD2
+# include "md2.h"
+#endif
 
 #include <assert.h>
 
+#ifndef MIN_GCRYPT_VERSION
+# define MIN_GCRYPT_VERSION "1.4.4"
+#endif
+
 /* Initialization. */
 
 Gc_rc
@@ -42,12 +48,15 @@ gc_init (void)
   err = gcry_control (GCRYCTL_ANY_INITIALIZATION_P);
   if (err == GPG_ERR_NO_ERROR)
     {
-      if (gcry_check_version (GCRYPT_VERSION) == NULL)
-       return GC_INIT_ERROR;
+      if (gcry_control (GCRYCTL_DISABLE_SECMEM, NULL, 0))
+        return GC_INIT_ERROR;
+
+      if (gcry_check_version (MIN_GCRYPT_VERSION) == NULL)
+        return GC_INIT_ERROR;
 
       err = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0);
       if (err != GPG_ERR_NO_ERROR)
-       return GC_INIT_ERROR;
+        return GC_INIT_ERROR;
     }
 
   return GC_OK;
@@ -59,6 +68,8 @@ gc_done (void)
   return;
 }
 
+#ifdef GNULIB_GC_RANDOM
+
 /* Randomness. */
 
 Gc_rc
@@ -82,20 +93,381 @@ gc_random (char *data, size_t datalen)
   return GC_OK;
 }
 
+#endif
+
 /* Memory allocation. */
 
 void
 gc_set_allocators (gc_malloc_t func_malloc,
-                  gc_malloc_t secure_malloc,
-                  gc_secure_check_t secure_check,
-                  gc_realloc_t func_realloc, gc_free_t func_free)
+                   gc_malloc_t secure_malloc,
+                   gc_secure_check_t secure_check,
+                   gc_realloc_t func_realloc, gc_free_t func_free)
 {
   gcry_set_allocation_handler (func_malloc, secure_malloc, secure_check,
-                              func_realloc, func_free);
+                               func_realloc, func_free);
+}
+
+/* Ciphers. */
+
+Gc_rc
+gc_cipher_open (Gc_cipher alg, Gc_cipher_mode mode,
+                gc_cipher_handle * outhandle)
+{
+  int gcryalg, gcrymode;
+  gcry_error_t err;
+
+  switch (alg)
+    {
+    case GC_AES128:
+      gcryalg = GCRY_CIPHER_RIJNDAEL;
+      break;
+
+    case GC_AES192:
+      gcryalg = GCRY_CIPHER_RIJNDAEL;
+      break;
+
+    case GC_AES256:
+      gcryalg = GCRY_CIPHER_RIJNDAEL256;
+      break;
+
+    case GC_3DES:
+      gcryalg = GCRY_CIPHER_3DES;
+      break;
+
+    case GC_DES:
+      gcryalg = GCRY_CIPHER_DES;
+      break;
+
+    case GC_ARCFOUR128:
+    case GC_ARCFOUR40:
+      gcryalg = GCRY_CIPHER_ARCFOUR;
+      break;
+
+    case GC_ARCTWO40:
+      gcryalg = GCRY_CIPHER_RFC2268_40;
+      break;
+
+#ifdef HAVE_CAMELLIA
+    case GC_CAMELLIA128:
+      gcryalg = GCRY_CIPHER_CAMELLIA128;
+      break;
+
+    case GC_CAMELLIA256:
+      gcryalg = GCRY_CIPHER_CAMELLIA256;
+      break;
+#endif
+
+    default:
+      return GC_INVALID_CIPHER;
+    }
+
+  switch (mode)
+    {
+    case GC_ECB:
+      gcrymode = GCRY_CIPHER_MODE_ECB;
+      break;
+
+    case GC_CBC:
+      gcrymode = GCRY_CIPHER_MODE_CBC;
+      break;
+
+    case GC_STREAM:
+      gcrymode = GCRY_CIPHER_MODE_STREAM;
+      break;
+
+    default:
+      return GC_INVALID_CIPHER;
+    }
+
+  err = gcry_cipher_open ((gcry_cipher_hd_t *) outhandle,
+                          gcryalg, gcrymode, 0);
+  if (gcry_err_code (err))
+    return GC_INVALID_CIPHER;
+
+  return GC_OK;
+}
+
+Gc_rc
+gc_cipher_setkey (gc_cipher_handle handle, size_t keylen, const char *key)
+{
+  gcry_error_t err;
+
+  err = gcry_cipher_setkey ((gcry_cipher_hd_t) handle, key, keylen);
+  if (gcry_err_code (err))
+    return GC_INVALID_CIPHER;
+
+  return GC_OK;
+}
+
+Gc_rc
+gc_cipher_setiv (gc_cipher_handle handle, size_t ivlen, const char *iv)
+{
+  gcry_error_t err;
+
+  err = gcry_cipher_setiv ((gcry_cipher_hd_t) handle, iv, ivlen);
+  if (gcry_err_code (err))
+    return GC_INVALID_CIPHER;
+
+  return GC_OK;
+}
+
+Gc_rc
+gc_cipher_encrypt_inline (gc_cipher_handle handle, size_t len, char *data)
+{
+  if (gcry_cipher_encrypt ((gcry_cipher_hd_t) handle,
+                           data, len, NULL, len) != 0)
+    return GC_INVALID_CIPHER;
+
+  return GC_OK;
+}
+
+Gc_rc
+gc_cipher_decrypt_inline (gc_cipher_handle handle, size_t len, char *data)
+{
+  if (gcry_cipher_decrypt ((gcry_cipher_hd_t) handle,
+                           data, len, NULL, len) != 0)
+    return GC_INVALID_CIPHER;
+
+  return GC_OK;
+}
+
+Gc_rc
+gc_cipher_close (gc_cipher_handle handle)
+{
+  gcry_cipher_close (handle);
+
+  return GC_OK;
 }
 
 /* Hashes. */
 
+typedef struct _gc_hash_ctx {
+  Gc_hash alg;
+  Gc_hash_mode mode;
+  gcry_md_hd_t gch;
+#ifdef GNULIB_GC_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 = 0, gcrymode = 0;
+  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;
+
+    case GC_MD5:
+      gcryalg = GCRY_MD_MD5;
+      break;
+
+    case GC_SHA1:
+      gcryalg = GCRY_MD_SHA1;
+      break;
+
+    case GC_SHA256:
+      gcryalg = GCRY_MD_SHA256;
+      break;
+
+    case GC_SHA384:
+      gcryalg = GCRY_MD_SHA384;
+      break;
+
+    case GC_SHA512:
+      gcryalg = GCRY_MD_SHA512;
+      break;
+
+    case GC_SHA224:
+      gcryalg = GCRY_MD_SHA224;
+      break;
+
+    case GC_RMD160:
+      gcryalg = GCRY_MD_RMD160;
+      break;
+
+    default:
+      rc = GC_INVALID_HASH;
+    }
+
+  switch (mode)
+    {
+    case 0:
+      gcrymode = 0;
+      break;
+
+    case GC_HMAC:
+      gcrymode = GCRY_MD_FLAG_HMAC;
+      break;
+
+    default:
+      rc = 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;
+    }
+
+  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;
+
+  *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)
+    {
+      free (out);
+      return GC_INVALID_HASH;
+    }
+
+  return GC_OK;
+}
+
+size_t
+gc_hash_digest_length (Gc_hash hash)
+{
+  size_t len;
+
+  switch (hash)
+    {
+    case GC_MD2:
+      len = GC_MD2_DIGEST_SIZE;
+      break;
+
+    case GC_MD4:
+      len = GC_MD4_DIGEST_SIZE;
+      break;
+
+    case GC_MD5:
+      len = GC_MD5_DIGEST_SIZE;
+      break;
+
+    case GC_RMD160:
+      len = GC_RMD160_DIGEST_SIZE;
+      break;
+
+    case GC_SHA1:
+      len = GC_SHA1_DIGEST_SIZE;
+      break;
+
+    case GC_SHA256:
+      len = GC_SHA256_DIGEST_SIZE;
+      break;
+
+    case GC_SHA384:
+      len = GC_SHA384_DIGEST_SIZE;
+      break;
+
+    case GC_SHA512:
+      len = GC_SHA512_DIGEST_SIZE;
+      break;
+
+    case GC_SHA224:
+      len = GC_SHA224_DIGEST_SIZE;
+      break;
+
+    default:
+      return 0;
+    }
+
+  return len;
+}
+
+void
+gc_hash_hmac_setkey (gc_hash_handle handle, size_t len, const char *key)
+{
+  _gc_hash_ctx *ctx = handle;
+#ifdef GNULIB_GC_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)
+{
+  _gc_hash_ctx *ctx = handle;
+
+#ifdef GNULIB_GC_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;
+
+#ifdef GNULIB_GC_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;
+}
+
+void
+gc_hash_close (gc_hash_handle handle)
+{
+  _gc_hash_ctx *ctx = handle;
+
+#ifdef GNULIB_GC_MD2
+  if (ctx->alg != GC_MD2)
+#endif
+    gcry_md_close (ctx->gch);
+
+  free (ctx);
+}
+
 Gc_rc
 gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf)
 {
@@ -103,18 +475,61 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf)
 
   switch (hash)
     {
-#ifdef GC_USE_MD5
+#ifdef GNULIB_GC_MD2
+    case GC_MD2:
+      md2_buffer (in, inlen, resbuf);
+      return GC_OK;
+      break;
+#endif
+
+#ifdef GNULIB_GC_MD4
+    case GC_MD4:
+      gcryalg = GCRY_MD_MD4;
+      break;
+#endif
+
+#ifdef GNULIB_GC_MD5
     case GC_MD5:
       gcryalg = GCRY_MD_MD5;
       break;
 #endif
 
-#ifdef GC_USE_SHA1
+#ifdef GNULIB_GC_SHA1
     case GC_SHA1:
       gcryalg = GCRY_MD_SHA1;
       break;
 #endif
 
+#ifdef GNULIB_GC_SHA256
+    case GC_SHA256:
+      gcryalg = GCRY_MD_SHA256;
+      break;
+#endif
+
+#ifdef GNULIB_GC_SHA384
+    case GC_SHA384:
+      gcryalg = GCRY_MD_SHA384;
+      break;
+#endif
+
+#ifdef GNULIB_GC_SHA512
+    case GC_SHA512:
+      gcryalg = GCRY_MD_SHA512;
+      break;
+#endif
+
+#ifdef GNULIB_GC_SHA224
+    case GC_SHA224:
+      gcryalg = GCRY_MD_SHA224;
+      break;
+#endif
+
+#ifdef GNULIB_GC_RMD160
+    case GC_RMD160:
+      gcryalg = GCRY_MD_RMD160;
+      break;
+#endif
+
     default:
       return GC_INVALID_HASH;
     }
@@ -126,7 +541,48 @@ gc_hash_buffer (Gc_hash hash, const void *in, size_t inlen, char *resbuf)
 
 /* One-call interface. */
 
-#ifdef GC_USE_MD5
+#ifdef GNULIB_GC_MD2
+Gc_rc
+gc_md2 (const void *in, size_t inlen, void *resbuf)
+{
+  md2_buffer (in, inlen, resbuf);
+  return GC_OK;
+}
+#endif
+
+#ifdef GNULIB_GC_MD4
+Gc_rc
+gc_md4 (const void *in, size_t inlen, void *resbuf)
+{
+  size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_MD4);
+  gcry_md_hd_t hd;
+  gpg_error_t err;
+  unsigned char *p;
+
+  assert (outlen == GC_MD4_DIGEST_SIZE);
+
+  err = gcry_md_open (&hd, GCRY_MD_MD4, 0);
+  if (err != GPG_ERR_NO_ERROR)
+    return GC_INVALID_HASH;
+
+  gcry_md_write (hd, in, inlen);
+
+  p = gcry_md_read (hd, GCRY_MD_MD4);
+  if (p == NULL)
+    {
+      gcry_md_close (hd);
+      return GC_INVALID_HASH;
+    }
+
+  memcpy (resbuf, p, outlen);
+
+  gcry_md_close (hd);
+
+  return GC_OK;
+}
+#endif
+
+#ifdef GNULIB_GC_MD5
 Gc_rc
 gc_md5 (const void *in, size_t inlen, void *resbuf)
 {
@@ -158,7 +614,7 @@ gc_md5 (const void *in, size_t inlen, void *resbuf)
 }
 #endif
 
-#ifdef GC_USE_SHA1
+#ifdef GNULIB_GC_SHA1
 Gc_rc
 gc_sha1 (const void *in, size_t inlen, void *resbuf)
 {
@@ -190,17 +646,17 @@ gc_sha1 (const void *in, size_t inlen, void *resbuf)
 }
 #endif
 
-#ifdef GC_USE_HMAC_MD5
+#ifdef GNULIB_GC_HMAC_MD5
 Gc_rc
 gc_hmac_md5 (const void *key, size_t keylen,
-            const void *in, size_t inlen, char *resbuf)
+             const void *in, size_t inlen, char *resbuf)
 {
   size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_MD5);
   gcry_md_hd_t mdh;
   unsigned char *hash;
   gpg_error_t err;
 
-  assert (hlen == 16);
+  assert (hlen == GC_MD5_DIGEST_SIZE);
 
   err = gcry_md_open (&mdh, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
   if (err != GPG_ERR_NO_ERROR)
@@ -230,17 +686,17 @@ gc_hmac_md5 (const void *key, size_t keylen,
 }
 #endif
 
-#ifdef GC_USE_HMAC_SHA1
+#ifdef GNULIB_GC_HMAC_SHA1
 Gc_rc
 gc_hmac_sha1 (const void *key, size_t keylen,
-             const void *in, size_t inlen, char *resbuf)
+              const void *in, size_t inlen, char *resbuf)
 {
   size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
   gcry_md_hd_t mdh;
   unsigned char *hash;
   gpg_error_t err;
 
-  assert (hlen == 16);
+  assert (hlen == GC_SHA1_DIGEST_SIZE);
 
   err = gcry_md_open (&mdh, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC);
   if (err != GPG_ERR_NO_ERROR)
@@ -269,3 +725,83 @@ gc_hmac_sha1 (const void *key, size_t keylen,
   return GC_OK;
 }
 #endif
+
+#ifdef GNULIB_GC_HMAC_SHA256
+Gc_rc
+gc_hmac_sha256 (const void *key, size_t keylen,
+             const void *in, size_t inlen, char *resbuf)
+{
+  size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_SHA256);
+  gcry_md_hd_t mdh;
+  unsigned char *hash;
+  gpg_error_t err;
+
+  assert (hlen == GC_SHA256_DIGEST_SIZE);
+
+  err = gcry_md_open (&mdh, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+  if (err != GPG_ERR_NO_ERROR)
+    return GC_INVALID_HASH;
+
+  err = gcry_md_setkey (mdh, key, keylen);
+  if (err != GPG_ERR_NO_ERROR)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  gcry_md_write (mdh, in, inlen);
+
+  hash = gcry_md_read (mdh, GCRY_MD_SHA256);
+  if (hash == NULL)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  memcpy (resbuf, hash, hlen);
+
+  gcry_md_close (mdh);
+
+  return GC_OK;
+}
+#endif
+
+#ifdef GNULIB_GC_HMAC_SHA512
+Gc_rc
+gc_hmac_sha512 (const void *key, size_t keylen,
+              const void *in, size_t inlen, char *resbuf)
+{
+  size_t hlen = gcry_md_get_algo_dlen (GCRY_MD_SHA512);
+  gcry_md_hd_t mdh;
+  unsigned char *hash;
+  gpg_error_t err;
+
+  assert (hlen == GC_SHA512_DIGEST_SIZE);
+
+  err = gcry_md_open (&mdh, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC);
+  if (err != GPG_ERR_NO_ERROR)
+    return GC_INVALID_HASH;
+
+  err = gcry_md_setkey (mdh, key, keylen);
+  if (err != GPG_ERR_NO_ERROR)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  gcry_md_write (mdh, in, inlen);
+
+  hash = gcry_md_read (mdh, GCRY_MD_SHA512);
+  if (hash == NULL)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  memcpy (resbuf, hash, hlen);
+
+  gcry_md_close (mdh);
+
+  return GC_OK;
+}
+#endif