--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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 */
--- /dev/null
+# 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], [:])
--- /dev/null
+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
--- /dev/null
+Files:
+tests/test-gc.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-gc
+noinst_PROGRAMS += test-gc
+test_gc_SOURCES = test-gc.c
--- /dev/null
+/*
+ * 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;
+}