This is a first attempt at a "middle layer" crypto module. I have installed it in GNU SASL, which only need gc_md5, gc_hmac_md5 and gc_nonce. I have not tested this much. To see a more complete gc.h compare:
http://josefsson.org/cgi-bin/viewcvs.cgi/gsasl/lib/crypto/Attic/gc.h?rev=1.5&hideattic=0&view=auto http://cvs.gnupg.org/cgi-bin/viewcvs.cgi/gnutls/crypto/gc.h?rev=1.15&root=GNU+TLS+Library&view=auto http://cvs.gnupg.org/cgi-bin/viewcvs.cgi/gnutls/crypto/gc-nettle.c?rev=1.14&root=GNU+TLS+Library&view=auto Some notes: * Perhaps the /dev/*random reading should be separated into a separate module? It might be useful outside of the gc layer too. I'm also not sure about the names of those functions, they suggest a more higher-level API than what is really offered (i.e., the names "nonce" and "pseudo_random" and "random" imply certain cryptographic properties). Perhaps gc_dev_random and gc_dev_urandom? Or something. * The 'void*' vs 'char*' vs 'uint8_t*' vs 'unsigned char*' issue apply to this module as well. * The gc module doesn't depend directly on md5 nor hmac-md5. Instead, it include the same files in the Files: section, and the M4 function of those modules are called conditioned on whether libgcrypt is used or not. So if a file is added to the md5 module, the gc module would have to be updated too. I don't like this, but thought this was the simplest solution now. A better solution would involve making the md5/hmac-md5 m4 aware of gc, and that if gc is also used, and that if gc decide that libgcrypt should be used, the md5/hmac-md5 modules should not do anything. I'm sure there are plenty of other problems too, but this passes self tests in GNU SASL so it is fairly complete... Once this is installed, I can continue to add the modules that GnuTLS needs, which include encryption modules such as DES and AES. Thanks, Simon Index: modules/gc =================================================================== RCS file: modules/gc diff -N modules/gc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/gc 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,37 @@ +Description: +Core files for generic crypto package + +Files: +lib/gc.h +lib/gc-libgcrypt.c +lib/gc-gnulib.c +m4/gc.m4 +lib/md5.h +lib/md5.c +m4/md5.m4 +m4/uint32_t.m4 +lib/hmac.h +lib/hmac-md5.c +m4/hmac-md5.m4 +lib/memxor.h +lib/memxor.c +m4/memxor.m4 + +Depends-on: +havelib +restrict + +configure.ac: +gl_GC + +Makefile.am: +lib_LIBADD += $(LIBGCRYPT) + +Include: +"gc.h" + +License: +LGPL + +Maintainer: +Simon Josefsson Index: modules/gc-tests =================================================================== RCS file: modules/gc-tests diff -N modules/gc-tests --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/gc-tests 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,11 @@ +Files: +tests/test-gc.c + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-gc +noinst_PROGRAMS += test-gc +test_gc_SOURCES = test-gc.c Index: m4/gc.m4 =================================================================== RCS file: m4/gc.m4 diff -N m4/gc.m4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ m4/gc.m4 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,102 @@ +# gc.m4 serial 1 +dnl Copyright (C) 2005 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_GC], +[ + AC_LIBSOURCES([gc.h, gc-gnulib.c, gc-libgcrypt.c]) + AC_ARG_WITH(libgcrypt, + AS_HELP_STRING([--with-libgcrypt], [use libgcrypt for low-level crypto]), + libgcrypt=$withval, libgcrypt=no) + if test "$libgcrypt" != no; then + AC_LIB_HAVE_LINKFLAGS([gcrypt]) + fi + if test "$ac_cv_libgcrypt" = yes; then + AC_CHECK_HEADER(gcrypt.h) + AC_LIBOBJ([gc-libgcrypt]) + else + AC_LIBOBJ([gc-gnulib]) + gl_MD5 + gl_MEMXOR + gl_HMAC_MD5 + + # Devices with randomness. + # FIXME: Are these the best defaults? + + case "${target}" in + *-openbsd*) + NAME_OF_RANDOM_DEVICE="/dev/srandom" + NAME_OF_PSEUDO_RANDOM_DEVICE="/dev/prandom" + NAME_OF_NONCE_DEVICE="/dev/urandom" + ;; + + *-netbsd*) + NAME_OF_RANDOM_DEVICE="/dev/srandom" + NAME_OF_PSEUDO_RANDOM_DEVICE="/dev/urandom" + NAME_OF_NONCE_DEVICE="/dev/urandom" + ;; + + *-solaris* | *-irix* | *-dec-osf* ) + NAME_OF_RANDOM_DEVICE="/dev/random" + NAME_OF_PSEUDO_RANDOM_DEVICE="/dev/random" + NAME_OF_NONCE_DEVICE="/dev/random" + ;; + + *) + NAME_OF_RANDOM_DEVICE="/dev/random" + NAME_OF_PSEUDO_RANDOM_DEVICE="/dev/urandom" + NAME_OF_NONCE_DEVICE="/dev/urandom" + ;; + esac + + AC_MSG_CHECKING([device with (strong) random data...]) + AC_ARG_ENABLE(random-device, + AC_HELP_STRING([--enable-random-device], + [device with (strong) randomness (for Nettle)]), + NAME_OF_RANDOM_DEVICE=$enableval) + AC_MSG_RESULT($NAME_OF_RANDOM_DEVICE) + + AC_MSG_CHECKING([device with pseudo random data...]) + AC_ARG_ENABLE(pseudo-random-device, + AC_HELP_STRING([--enable-pseudo-random-device], + [device with pseudo randomness (for Nettle)]), + NAME_OF_PSEUDO_RANDOM_DEVICE=$enableval) + AC_MSG_RESULT($NAME_OF_PSEUDO_RANDOM_DEVICE) + + AC_MSG_CHECKING([device with unpredictable data for nonces...]) + AC_ARG_ENABLE(nonce-device, + AC_HELP_STRING([--enable-nonce-device], + [device with unpredictable nonces (for Nettle)]), + NAME_OF_NONCE_DEVICE=$enableval) + AC_MSG_RESULT($NAME_OF_NONCE_DEVICE) + + if test "$cross_compiling" != yes; then + AC_CHECK_FILE($NAME_OF_RANDOM_DEVICE,, AC_MSG_ERROR([[ + *** Device for (strong) random data $NAME_OF_RANDOM_DEVICE does not exist + ]])) + AC_CHECK_FILE($NAME_OF_PSEUDO_RANDOM_DEVICE,, AC_MSG_ERROR([[ + *** Device for pseudo-random data $NAME_OF_PSEUDO_RANDOM_DEVICE does not exist + ]])) + AC_CHECK_FILE($NAME_OF_NONCE_DEVICE,, AC_MSG_ERROR([[ + *** Device for unpredictable nonces $NAME_OF_NONCE_DEVICE does not exist + ]])) + else + AC_MSG_NOTICE([[Cross compiling, assuming random devices exists...]]) + fi + + # FIXME: Open+read 42 bytes+close twice and compare data. Should differ. + + AC_DEFINE_UNQUOTED(NAME_OF_RANDOM_DEVICE, "$NAME_OF_RANDOM_DEVICE", + [defined to the name of the (strong) random device]) + AC_DEFINE_UNQUOTED(NAME_OF_PSEUDO_RANDOM_DEVICE, + "$NAME_OF_PSEUDO_RANDOM_DEVICE", + [defined to the name of the pseudo random device]) + AC_DEFINE_UNQUOTED(NAME_OF_NONCE_DEVICE, "$NAME_OF_NONCE_DEVICE", + [defined to the name of the unpredictable nonce device]) + fi +]) + +# Prerequisites of lib/gc.h +AC_DEFUN([gl_PREREQ_GC], [:]) Index: lib/gc.h =================================================================== RCS file: lib/gc.h diff -N lib/gc.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/gc.h 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,63 @@ +/* gc.h --- Header file for implementation agnostic crypto wrapper API. + * Copyright (C) 2002, 2003, 2004, 2005 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 + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * This file 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 + * 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. + * + */ + +#ifndef GC_H +# define GC_H + +/* Get size_t. */ +# include <stddef.h> + +#define GC_MD5_DIGEST_SIZE 16 + +enum Gc_rc + { + GC_OK = 0, + GC_MALLOC_ERROR, + GC_INIT_ERROR, + GC_RANDOM_ERROR, + GC_INVALID_CIPHER, + GC_INVALID_HASH, + GC_PKCS5_INVALID_ITERATION_COUNT, + GC_PKCS5_INVALID_DERIVED_KEY_LENGTH, + GC_PKCS5_DERIVED_KEY_TOO_LONG + }; +typedef enum Gc_rc Gc_rc; + +extern int gc_init (void); +extern void gc_done (void); + +/* Memory allocation (avoid). */ +typedef void *(*gc_malloc_t) (size_t n); +typedef int (*gc_secure_check_t) (const void *); +typedef void *(*gc_realloc_t) (void *p, size_t n); +typedef void (*gc_free_t) (void *); +extern 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); + +/* One-call interface. */ +extern int gc_md5 (const void *in, size_t inlen, void *resbuf); +extern int gc_hmac_md5 (const void *key, size_t keylen, + const void *in, size_t inlen, + char *resbuf); + +#endif /* GC_H */ Index: lib/gc-gnulib.c =================================================================== RCS file: lib/gc-gnulib.c diff -N lib/gc-gnulib.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/gc-gnulib.c 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,149 @@ +/* gc-gl-common.c --- Common gnulib internal crypto interface functions + * Copyright (C) 2002, 2003, 2004, 2005 Simon Josefsson + * + * This file is part of GC. + * + * GC 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. + * + * GC 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 License along with GC; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + */ + +/* Note: This file is only built if GC uses internal functions. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> + +/* Get prototype. */ +#include <gc.h> + +/* For randomize. */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <string.h> + +int +gc_init (void) +{ + return 0; +} + +void +gc_done (void) +{ + return; +} + +/* Randomness. */ + +static int +randomize (int level, char *data, size_t datalen) +{ + int fd; + const char *device; + size_t len = 0; + int rc; + + switch (level) + { + case 0: + device = NAME_OF_NONCE_DEVICE; + break; + + case 1: + device = NAME_OF_PSEUDO_RANDOM_DEVICE; + break; + + default: + device = NAME_OF_RANDOM_DEVICE; + break; + } + + fd = open (device, O_RDONLY); + if (fd < 0) + return GC_RANDOM_ERROR; + + do + { + ssize_t tmp; + + tmp = read (fd, data, datalen); + + if (tmp < 0) + return GC_RANDOM_ERROR; + + len += tmp; + } + while (len < datalen); + + rc = close (fd); + if (rc < 0) + return GC_RANDOM_ERROR; + + return GC_OK; +} + +int +gc_nonce (char *data, size_t datalen) +{ + return randomize (0, data, datalen); +} + +int +gc_pseudo_random (char *data, size_t datalen) +{ + return randomize (1, data, datalen); +} + +int +gc_random (char *data, size_t datalen) +{ + return randomize (2, data, datalen); +} + +/* 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) +{ + return; +} + +#include "md5.h" + +int +gc_md5 (const void *in, size_t inlen, void *resbuf) +{ + md5_buffer (in, inlen, resbuf); + return 0; +} + +#include "hmac.h" + +int +gc_hmac_md5 (const void *key, size_t keylen, + const void *in, size_t inlen, char *resbuf) +{ + hmac_md5 (key, keylen, in, inlen, resbuf); + return 0; +} Index: lib/gc-libgcrypt.c =================================================================== RCS file: lib/gc-libgcrypt.c diff -N lib/gc-libgcrypt.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lib/gc-libgcrypt.c 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,156 @@ +/* gc-libgcrypt.c --- Crypto wrappers around Libgcrypt for GC. + * Copyright (C) 2002, 2003, 2004, 2005 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 + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * This file 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 + * 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. + * + */ + +/* Note: This file is only built if GC uses Libgcrypt. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +/* Get prototype. */ +#include "gc.h" + +/* Get libgcrypt API. */ +#include <gcrypt.h> + +#include <assert.h> + +/* Initialization. */ + +int +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; + + err = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL, 0); + if (err != GPG_ERR_NO_ERROR) + return GC_INIT_ERROR; + } + + return GC_OK; +} + +void +gc_done (void) +{ + return; +} + +/* Randomness. */ + +int +gc_nonce (char *data, size_t datalen) +{ + gcry_create_nonce ((unsigned char *) data, datalen); + return GC_OK; +} + +int +gc_pseudo_random (char *data, size_t datalen) +{ + gcry_randomize ((unsigned char *) data, datalen, GCRY_STRONG_RANDOM); + return GC_OK; +} + +int +gc_random (char *data, size_t datalen) +{ + gcry_randomize ((unsigned char *) data, datalen, GCRY_VERY_STRONG_RANDOM); + return GC_OK; +} + +/* 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) +{ + gcry_set_allocation_handler (func_malloc, secure_malloc, secure_check, + func_realloc, func_free); +} + +/* One-call interface. */ + +int +gc_md5 (const void *in, size_t inlen, void *resbuf) +{ + size_t outlen = gcry_md_get_algo_dlen (GCRY_MD_MD5); + gcry_md_hd_t hd; + gpg_error_t err; + unsigned char *p; + + assert (outlen == 16); + + err = gcry_md_open (&hd, GCRY_MD_MD5, 0); + if (err != GPG_ERR_NO_ERROR) + return GC_INVALID_HASH; + + gcry_md_write (hd, in, inlen); + + p = gcry_md_read (hd, GCRY_MD_MD5); + if (p == NULL) + return GC_INVALID_HASH; + + memcpy (resbuf, p, outlen); + + gcry_md_close (hd); + + return GC_OK; +} + +int +gc_hmac_md5 (const void *key, size_t keylen, + 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); + + err = gcry_md_open (&mdh, GCRY_MD_MD5, 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) + return GC_INVALID_HASH; + + gcry_md_write (mdh, in, inlen); + + hash = gcry_md_read (mdh, GCRY_MD_MD5); + if (hash == NULL) + return GC_INVALID_HASH; + + memcpy (resbuf, hash, hlen); + + gcry_md_close (mdh); + + return GC_OK; +} Index: tests/test-gc.c =================================================================== RCS file: tests/test-gc.c diff -N tests/test-gc.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/test-gc.c 5 Oct 2005 15:46:17 -0000 @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005 Free Software Foundation + * Written by Simon Josefsson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include "gc.h" + +int +main (int argc, char *argv[]) +{ + + /* Test vectors from RFC 1321. */ + + { + char *in = "abcdefghijklmnopqrstuvwxyz"; + size_t inlen = strlen (in); + char *expect = + "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"; + char out[16]; + + /* MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b */ + + if (gc_md5 (in, inlen, out) != 0) + { + printf ("gc_md5 call failed\n"); + return 1; + } + + if (memcmp (out, expect, 16) != 0) + { + size_t i; + printf ("md5 1 missmatch. expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", expect[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", out[i] & 0xFF); + printf ("\n"); + return 1; + } + } + + /* Test vectors from RFC 2104. */ + + { + char *key = + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; + size_t key_len = 16; + char *data = "Hi There"; + size_t data_len = 8; + char *digest = + "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d"; + char out[16]; + + /* + key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b + key_len = 16 bytes + data = "Hi There" + data_len = 8 bytes + digest = 0x9294727a3638bb1c13f48ef8158bfc9d + */ + + if (gc_hmac_md5 (key, key_len, data, data_len, out) != 0) + { + printf ("call failure\n"); + return 1; + } + + if (memcmp (digest, out, 16) != 0) + { + size_t i; + printf ("hash 1 missmatch. expected:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", digest[i] & 0xFF); + printf ("\ncomputed:\n"); + for (i = 0; i < 16; i++) + printf ("%02x ", out[i] & 0xFF); + printf ("\n"); + return 1; + } + } + + return 0; +} _______________________________________________ bug-gnulib mailing list bug-gnulib@gnu.org http://lists.gnu.org/mailman/listinfo/bug-gnulib