/* gc-libgcrypt.c --- Crypto wrappers around Libgcrypt for GC.
- * Copyright (C) 2002, 2003, 2004, 2005 Simon Josefsson
+ * Copyright (C) 2002-2013 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. */
-int
+Gc_rc
gc_init (void)
{
gcry_error_t err;
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;
return;
}
+#ifdef GNULIB_GC_RANDOM
+
/* Randomness. */
-int
+Gc_rc
gc_nonce (char *data, size_t datalen)
{
gcry_create_nonce ((unsigned char *) data, datalen);
return GC_OK;
}
-int
+Gc_rc
gc_pseudo_random (char *data, size_t datalen)
{
gcry_randomize ((unsigned char *) data, datalen, GCRY_STRONG_RANDOM);
return GC_OK;
}
-int
+Gc_rc
gc_random (char *data, size_t datalen)
{
gcry_randomize ((unsigned char *) data, datalen, GCRY_VERY_STRONG_RANDOM);
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. */
-int
-gc_hash_buffer (int hash, const void *in, size_t inlen, char *resbuf)
+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)
{
int gcryalg;
switch (hash)
{
+#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 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;
/* One-call interface. */
-int
+#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)
{
size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_MD5);
gpg_error_t err;
unsigned char *p;
- assert (outlen == 16);
+ assert (outlen == GC_MD5_DIGEST_SIZE);
err = gcry_md_open (&hd, GCRY_MD_MD5, 0);
if (err != GPG_ERR_NO_ERROR)
p = gcry_md_read (hd, GCRY_MD_MD5);
if (p == NULL)
{
- gcry_md_close (mdh);
+ gcry_md_close (hd);
+ return GC_INVALID_HASH;
+ }
+
+ memcpy (resbuf, p, outlen);
+
+ gcry_md_close (hd);
+
+ return GC_OK;
+}
+#endif
+
+#ifdef GNULIB_GC_SHA1
+Gc_rc
+gc_sha1 (const void *in, size_t inlen, void *resbuf)
+{
+ size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
+ gcry_md_hd_t hd;
+ gpg_error_t err;
+ unsigned char *p;
+
+ assert (outlen == GC_SHA1_DIGEST_SIZE);
+
+ err = gcry_md_open (&hd, GCRY_MD_SHA1, 0);
+ if (err != GPG_ERR_NO_ERROR)
+ return GC_INVALID_HASH;
+
+ gcry_md_write (hd, in, inlen);
+
+ p = gcry_md_read (hd, GCRY_MD_SHA1);
+ if (p == NULL)
+ {
+ gcry_md_close (hd);
return GC_INVALID_HASH;
}
return GC_OK;
}
+#endif
-int
+#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)
return GC_OK;
}
+#endif
+
+#ifdef GNULIB_GC_HMAC_SHA1
+Gc_rc
+gc_hmac_sha1 (const void *key, size_t keylen,
+ 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 == GC_SHA1_DIGEST_SIZE);
+
+ err = gcry_md_open (&mdh, GCRY_MD_SHA1, 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_SHA1);
+ 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_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