Add generic crypto module.
authorSimon Josefsson <simon@josefsson.org>
Sat, 8 Oct 2005 08:33:07 +0000 (08:33 +0000)
committerSimon Josefsson <simon@josefsson.org>
Sat, 8 Oct 2005 08:33:07 +0000 (08:33 +0000)
lib/gc-gnulib.c [new file with mode: 0644]
lib/gc-libgcrypt.c [new file with mode: 0644]
lib/gc.h [new file with mode: 0644]
m4/gc.m4 [new file with mode: 0644]
modules/gc [new file with mode: 0644]
modules/gc-tests [new file with mode: 0644]
tests/test-gc.c [new file with mode: 0644]

diff --git a/lib/gc-gnulib.c b/lib/gc-gnulib.c
new file mode 100644 (file)
index 0000000..99d6dc2
--- /dev/null
@@ -0,0 +1,153 @@
+/* gc-gl-common.c --- Common gnulib internal crypto interface functions
+ * 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 internal functions. */
+
+#ifdef 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 <errno.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)
+       {
+         int save_errno = errno;
+         close (fd);
+         errno = save_errno;
+         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;
+}
diff --git a/lib/gc-libgcrypt.c b/lib/gc-libgcrypt.c
new file mode 100644 (file)
index 0000000..f4a93d3
--- /dev/null
@@ -0,0 +1,165 @@
+/* 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. */
+
+#ifdef 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)
+    {
+      gcry_md_close (mdh);
+      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)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  gcry_md_write (mdh, in, inlen);
+
+  hash = gcry_md_read (mdh, GCRY_MD_MD5);
+  if (hash == NULL)
+    {
+      gcry_md_close (mdh);
+      return GC_INVALID_HASH;
+    }
+
+  memcpy (resbuf, hash, hlen);
+
+  gcry_md_close (mdh);
+
+  return GC_OK;
+}
diff --git a/lib/gc.h b/lib/gc.h
new file mode 100644 (file)
index 0000000..e40a681
--- /dev/null
+++ b/lib/gc.h
@@ -0,0 +1,203 @@
+/* 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);
+
+/*
+  TODO:
+
+  From: Simon Josefsson <jas@extundo.com>
+  Subject: Re: generic crypto
+  Newsgroups: gmane.comp.lib.gnulib.bugs
+  Cc: bug-gnulib@gnu.org
+  Date: Fri, 07 Oct 2005 12:50:57 +0200
+  Mail-Copies-To: nobody
+
+  Paul Eggert <eggert@CS.UCLA.EDU> writes:
+
+  > Simon Josefsson <jas@extundo.com> writes:
+  >
+  >> * Perhaps the /dev/*random reading should be separated into a separate
+  >>   module?  It might be useful outside of the gc layer too.
+  >
+  > Absolutely.  I've been meaning to do that for months (for a "shuffle"
+  > program I want to add to coreutils), but hadn't gotten around to it.
+  > It would have to be generalized a bit.  I'd like to have the file
+  > descriptor cached, for example.
+
+  I'll write a separate module for that part.
+
+  I think we should even add a good PRNG that is re-seeded from
+  /dev/*random frequently.  GnuTLS can need a lot of random data on a
+  big server, more than /dev/random can supply.  And /dev/urandom might
+  not be strong enough.  Further, the security of /dev/*random can also
+  be questionable.
+
+  >>   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).
+  >
+  > Could you expand a bit more on that?  What is the relationship between
+  > nonce/pseudorandom/random and the /dev/ values you are using?
+
+  There is none, that is the problem.
+
+  Applications generally need different kind of "random" numbers.
+  Sometimes they just need some random data and doesn't care whether it
+  is possible for an attacker to compute the string (aka a "nonce").
+  Sometimes they need data that is very difficult to compute (i.e.,
+  computing it require inverting SHA1 or similar).  Sometimes they need
+  data that is not possible to compute, i.e., it wants real entropy
+  collected over time on the system.  Collecting the last kind of random
+  data is very expensive, so it must not be used too often.  The second
+  kind of random data ("pseudo random") is typically generated by
+  seeding a good PRNG with a couple of hundred bytes of real entropy
+  from the "real random" data pool.  The "nonce" is usually computed
+  using the PRNG as well, because PRNGs are usually fast.
+
+  Pseudo-random data is typically used for session keys.  Strong random
+  data is often used to generate long-term keys (e.g., private RSA
+  keys).
+
+  Of course, there are many subtleties.  There are several different
+  kind of nonce:s.  Sometimes a nonce is just an ever-increasing
+  integer, starting from 0.  Sometimes it is assumed to be unlikely to
+  be the same as previous nonces, but without a requirement that the
+  nonce is possible to guess.  MD5(system clock) would thus suffice, if
+  it isn't called too often.  You can guess what the next value will be,
+  but it will always be different.
+
+  The problem is that /dev/*random doesn't offer any kind of semantic
+  guarantees.  But applications need an API that make that promise.
+
+  I think we should do this in several steps:
+
+  1) Write a module that can read from /dev/*random.
+
+  2) Add a module for a known-good PRNG suitable for random number
+  generation, that can be continuously re-seeded.
+
+  3) Add a high-level module that provide various different randomness
+  functions.  One for nonces, perhaps even different kind of nonces,
+  one for pseudo random data, and one for strong random data.  It is
+  not clear whether we can hope to achieve the last one in a portable
+  way.
+
+  Further, it would be useful to allow users to provide their own
+  entropy source as a file, used to seed the PRNG or initialize the
+  strong randomness pool.  This is used on embedded platforms that
+  doesn't have enough interrupts to hope to generate good random data.
+
+  > For example, why not use OpenBSD's /dev/arandom?
+
+  I don't trust ARC4.  For example, recent cryptographic efforts
+  indicate that you must throw away the first 512 bytes generated from
+  the PRNG for it to be secure.  I don't know whether OpenBSD do this.
+  Further, I recall some eprint paper on RC4 security that didn't
+  inspire confidence.
+
+  While I trust the random devices in OpenBSD more than
+  Solaris/AIX/HPUX/etc, I think that since we need something better on
+  Solaris/AIX/HPUX we'd might as well use it on OpenBSD or even Linux
+  too.
+
+  > Here is one thought.  The user could specify a desired quality level
+  > range, and the implementation then would supply random data that is at
+  > least as good as the lower bound of the range.  I.e., ihe
+  > implementation refuses to produce any random data if it can't generate
+  > data that is at least as good as the lower end of the range.  The
+  > upper bound of the range is advice from the user not to be any more
+  > expensive than that, but the implementation can ignore the advice if
+  > it doesn't have anything cheaper.
+
+  I'm not sure this is a good idea.  Users can't really be expected to
+  understand this.  Further, applications need many different kind of
+  random data.  Selecting the randomness level for each by the user will
+  be too complicated.
+
+  I think it is better if the application decide, from its cryptographic
+  requirement, what entropy quality it require, and call the proper API.
+  Meeting the implied semantic properties should be the job for gnulib.
+
+  >> Perhaps gc_dev_random and gc_dev_urandom?
+  >
+  > To some extent.  I'd rather insulate the user from the details of
+  > where the random numbers come from.  On the other hand we need to
+  > provide a way for applications to specify a file that contains
+  > random bits, so that people can override the defaults.
+
+  Agreed.
+
+  This may require some thinking before it is finalized.  Is it ok to
+  install the GC module as-is meanwhile?  Then I can continue to add the
+  stuff that GnuTLS need, and then come back to re-working the
+  randomness module.  That way, we have two different projects that use
+  the code.  GnuTLS includes the same randomness code that was in GNU
+  SASL and that is in the current gc module.  I feel much more
+  comfortable working in small steps at a time, rather then working on
+  this for a long time in gnulib and only later integrate the stuff in
+  GnuTLS.
+
+  Thanks,
+  Simon
+ */
+
+#endif /* GC_H */
diff --git a/m4/gc.m4 b/m4/gc.m4
new file mode 100644 (file)
index 0000000..a36c2a9
--- /dev/null
+++ b/m4/gc.m4
@@ -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], [:])
diff --git a/modules/gc b/modules/gc
new file mode 100644 (file)
index 0000000..129cf6d
--- /dev/null
@@ -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
diff --git a/modules/gc-tests b/modules/gc-tests
new file mode 100644 (file)
index 0000000..2c10e42
--- /dev/null
@@ -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
diff --git a/tests/test-gc.c b/tests/test-gc.c
new file mode 100644 (file)
index 0000000..fd153c3
--- /dev/null
@@ -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.  */
+
+#ifdef 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;
+}