* Download libtomcrypt, libtommath
* Unpack INSIDE the vpnc source tree
* Rename directories to be really named libtomcrypt and libtommath
* Inside vpnc source tree: patch -p1 < thispatchfile

Michael Weber <michaelw@foldr.org>

diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/Makefile vpnc-0.2-rm+zomb.1-tomcrypt/Makefile
--- vpnc-0.2-rm+zomb.1/Makefile	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/Makefile	2004-06-30 23:02:33.000000000 +0200
@@ -16,8 +16,8 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 CC=gcc
-CFLAGS=-W -Wall -O -g '-DVERSION="$(shell cat VERSION)"' $(shell libgcrypt-config --cflags)
-LDFLAGS=-g $(shell libgcrypt-config --libs)
+CFLAGS=-W -Wall -g -Ilibtommath -Ilibtomcrypt '-DVERSION="$(shell cat VERSION)"'
+LDFLAGS=-g -Llibtomcrypt -Llibtommath -ltomcrypt -ltommath
 
 ifeq ($(shell uname -s), Linux)
 SYSDEP=sysdep-linux.o
@@ -41,8 +41,17 @@
 endif
 
 vpnc : vpnc.o isakmp-pkt.o tunip.o $(SYSDEP) dh.o math_group.o
+	$(MAKE) -C libtommath
+	$(MAKE) -C libtomcrypt	
 	$(CC) -o $@ $^ $(LDFLAGS)
 
+install: vpnc
+	$(STRIP) vpnc
+	install -d $(DESTDIR)/usr/sbin
+	install --mode 0755 vpnc $(DESTDIR)/usr/sbin/vpnc
+	install --mode 0755 vpnc-connect    $(DESTDIR)/usr/sbin/vpnc-connect
+	install --mode 0755 vpnc-disconnect $(DESTDIR)/usr/sbin/vpnc-disconnect
+
 vpnc.o : isakmp.h isakmp-pkt.h dh.h sysdep.h math_group.h vpnc.h VERSION
 isakmp-pkt.o : isakmp.h isakmp-pkt.h vpnc.h
 tunip.o : sysdep.h vpnc.h
@@ -62,6 +71,8 @@
 release: VERSION vpnc-$(shell cat VERSION).tar.gz
 
 clean:
+	$(MAKE) -C libtommath clean
+	$(MAKE) -C libtomcrypt clean
 	-rm -f vpnc *.o
 
 .PHONY : clean
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/dh.c vpnc-0.2-rm+zomb.1-tomcrypt/dh.c
--- vpnc-0.2-rm+zomb.1/dh.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/dh.c	2004-06-13 14:02:34.000000000 +0200
@@ -42,7 +42,8 @@
 int
 dh_getlen (struct group *group)
 {
-  return group->getlen (group);
+  int len = group->getlen (group);
+  return len;
 }
 
 /*
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/isakmp-pkt.c vpnc-0.2-rm+zomb.1-tomcrypt/isakmp-pkt.c
--- vpnc-0.2-rm+zomb.1/isakmp-pkt.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/isakmp-pkt.c	2004-06-13 13:25:47.000000000 +0200
@@ -30,6 +30,7 @@
 xallocc (size_t x)
 {
   void *result;
+  if (x == 0) { ++x; }
   result = calloc (1, x);
   if (result == NULL)
     error (1, errno, "malloc of %lu bytes failed", (unsigned long) x);
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/math_group.c vpnc-0.2-rm+zomb.1-tomcrypt/math_group.c
--- vpnc-0.2-rm+zomb.1/math_group.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/math_group.c	2004-06-30 21:59:03.000000000 +0200
@@ -38,21 +38,23 @@
 #include <string.h>
 #include <netinet/in.h>
 
-#include <gcrypt.h>
+#include <mycrypt.h>
 
 #include "math_group.h"
 
+typedef mp_int mpint_t;
+
 /* We do not want to export these definitions.  */
 int modp_getlen (struct group *);
-void modp_getraw (struct group *, gcry_mpi_t, unsigned char *);
-int modp_setraw (struct group *, gcry_mpi_t, unsigned char *, int);
-int modp_setrandom (struct group *, gcry_mpi_t);
-int modp_operation (struct group *, gcry_mpi_t, gcry_mpi_t, gcry_mpi_t);
+void modp_getraw (struct group *, mpint_t *, unsigned char *);
+int modp_setraw (struct group *, mpint_t *, unsigned char *, int);
+int modp_setrandom (struct group *, mpint_t *);
+int modp_operation (struct group *, mpint_t *, mpint_t *, mpint_t *);
 
 struct modp_group {
-  gcry_mpi_t gen;			/* Generator */
-  gcry_mpi_t p;				/* Prime */
-  gcry_mpi_t a, b, c, d;
+  mpint_t gen;			/* Generator */
+  mpint_t p;				/* Prime */
+  mpint_t a, b, c, d;
 };
 
 /*
@@ -181,17 +183,18 @@
   memcpy (new, clone, sizeof (struct group));
 
   new->group = new_grp;
-  new_grp->p = gcry_mpi_copy (clone_grp->p);
-  new_grp->gen = gcry_mpi_copy (clone_grp->gen);
 
-  new_grp->a = gcry_mpi_new (clone->bits);
-  new_grp->b = gcry_mpi_new (clone->bits);
-  new_grp->c = gcry_mpi_new (clone->bits);
-
-  new->gen = new_grp->gen;
-  new->a = new_grp->a;
-  new->b = new_grp->b;
-  new->c = new_grp->c;
+  mp_init (&new_grp->p); mp_copy (&clone_grp->p, &new_grp->p);
+  mp_init (&new_grp->gen); mp_copy (&clone_grp->gen, &new_grp->gen);
+  
+  mp_init_size (&new_grp->a, (clone->bits + 7) / 8);
+  mp_init_size (&new_grp->b, (clone->bits + 7) / 8);
+  mp_init_size (&new_grp->c, (clone->bits + 7) / 8);
+
+  new->gen = &new_grp->gen;
+  new->a = &new_grp->a;
+  new->b = &new_grp->b;
+  new->c = &new_grp->c;
 
   return new;
 }
@@ -201,11 +204,11 @@
 {
   struct modp_group *grp = old->group;
 
-  gcry_mpi_release (grp->p);
-  gcry_mpi_release (grp->gen);
-  gcry_mpi_release (grp->a);
-  gcry_mpi_release (grp->b);
-  gcry_mpi_release (grp->c);
+  mp_clear (&grp->p);
+  mp_clear (&grp->gen);
+  mp_clear (&grp->a);
+  mp_clear (&grp->b);
+  mp_clear (&grp->c);
 
   free (grp);
 }
@@ -221,17 +224,17 @@
 
   group->bits = dscr->bits;
 
-  gcry_mpi_scan(&grp->p, GCRYMPI_FMT_HEX, dscr->prime, 0, NULL);
-  gcry_mpi_scan(&grp->gen, GCRYMPI_FMT_HEX, dscr->gen, 0, NULL);
-
-  grp->a = gcry_mpi_new (group->bits);
-  grp->b = gcry_mpi_new (group->bits);
-  grp->c = gcry_mpi_new (group->bits);
-
-  group->gen = grp->gen;
-  group->a = grp->a;
-  group->b = grp->b;
-  group->c = grp->c;
+  mp_init (&grp->p);   mp_read_radix (&grp->p, dscr->prime, 16);
+  mp_init (&grp->gen); mp_read_radix (&grp->gen, dscr->gen, 16);
+  
+  mp_init_size (&grp->a, (group->bits + 7) / 8);
+  mp_init_size (&grp->b, (group->bits + 7) / 8);
+  mp_init_size (&grp->c, (group->bits + 7) / 8);
+  
+  group->gen = &grp->gen;
+  group->a = &grp->a;
+  group->b = &grp->b;
+  group->c = &grp->c;
 
   group->group = grp;
 }
@@ -241,80 +244,63 @@
 {
   struct modp_group *grp = (struct modp_group *)group->group;
 
-  return (gcry_mpi_get_nbits (grp->p) + 7) / 8;
+  return mp_mag_size (&grp->p);
 }
 
 void
-modp_getraw (struct group *grp, gcry_mpi_t v, unsigned char *d)
+modp_getraw (struct group *grp, mpint_t *v, unsigned char *d)
 {
   size_t l, l2;
   unsigned char *tmp;
-  int ret;
+
+  l = grp->getlen(grp);
+  l2 = mp_mag_size (v);
+  assert (l2 >= l);
   
-  l = grp->getlen (grp);
-  ret = gcry_mpi_aprint(GCRYMPI_FMT_STD, &tmp, &l2, v);
+  tmp = malloc (l2);
+  assert (tmp != NULL);
+  
+  mp_tomag (v, tmp);
   memcpy(d, tmp + (l2-l), l);
-  gcry_free(tmp);
-#if 0
-  {
-	  char *p;
-	  gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, v);
-	  printf("export %d - %d(%d):\n%s\n", l, l2, ret, p);
-  	  gcry_free(p);
-  }
-#endif
+  free (tmp);
 }
 
 int
-modp_setraw (struct group *grp, gcry_mpi_t d, unsigned char *s, int l)
+modp_setraw (struct group *grp, mpint_t *d, unsigned char *s, int l)
 {
-  int i;
-  
   grp = 0; /* unused */
   
-  gcry_mpi_set_ui(d, 0);
-  for (i = 0; i < l; i++)
-    {
-      gcry_mpi_mul_2exp (d, d, 8);
-      gcry_mpi_add_ui (d, d, s[i]);
-    }
-#if 0
-  {
-	  char *p;
-	  gcry_mpi_aprint(GCRYMPI_FMT_HEX, (void **)&p, NULL, d);
-	  printf("import %d:\n%s\n", l, p);
-  	  gcry_free(p);
-  }
-#endif
+  mp_read_mag (d, s, l);
   return 0;
 }
 
 int
-modp_setrandom (struct group *grp, gcry_mpi_t d)
+modp_setrandom (struct group *grp, mpint_t *d)
 {
-  int i, l = grp->getlen (grp);
-  uint32_t tmp = 0;
-
-  gcry_mpi_set_ui (d, 0);
-
-  for (i = 0; i < l; i++)
-    {
-      if (i % 4)
-	gcry_randomize((unsigned char *)&tmp, sizeof(tmp), GCRY_WEAK_RANDOM);
-
-      gcry_mpi_mul_2exp (d, d, 8);
-      gcry_mpi_add_ui (d, d, tmp & 0xFF);
-      tmp >>= 8;
-    }
+  size_t l = grp->getlen (grp);
+  mp_rand (d, l * CHAR_BIT / DIGIT_BIT); /* XXX correct? */
   return 0;
 }
 
 int
-modp_operation (struct group *group, gcry_mpi_t d, gcry_mpi_t a, gcry_mpi_t e)
+modp_operation (struct group *group, mpint_t *d, mpint_t *a, mpint_t *e)
 {
   struct modp_group *grp = (struct modp_group *)group->group;
 
-  gcry_mpi_powm(d, a, e, grp->p);
+  mp_exptmod (a, e, &grp->p, d);
+#if 0  
+  {
+	  unsigned char buf[100000];
+	  mp_toradix (a, buf, 16);
+	  printf ("ta: %s\n", buf);
+	  mp_toradix (e, buf, 16);
+	  printf ("te: %s\n", buf);
+	  mp_toradix (&grp->p, buf, 16);
+	  printf ("tp: %s\n", buf);
+	  mp_toradix (d, buf, 16);
+	  printf ("td: %s\n", buf);
+  }
+#endif
+  
   return 0;
 }
-
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/sysdep-linux.c vpnc-0.2-rm+zomb.1-tomcrypt/sysdep-linux.c
--- vpnc-0.2-rm+zomb.1/sysdep-linux.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/sysdep-linux.c	2004-06-13 13:08:39.000000000 +0200
@@ -55,7 +55,7 @@
     if( *dev )
        strncpy(ifr.ifr_name, dev, IFNAMSIZ);
 
-    if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
+    if((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
        close(fd);
        return err;
     } 
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/tunip.c vpnc-0.2-rm+zomb.1-tomcrypt/tunip.c
--- vpnc-0.2-rm+zomb.1/tunip.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/tunip.c	2004-06-14 22:36:59.000000000 +0200
@@ -69,7 +69,7 @@
 #include <err.h>
 #endif
 
-#include <gcrypt.h>
+#include <mycrypt.h>
 #include "sysdep.h"
 #include "vpnc.h"
 
@@ -77,6 +77,11 @@
 
 #define UDP_PORT	2001
 
+extern const char *get_hash (int);
+extern const char *get_cipher (int);
+extern int get_cipher_block_length (int);
+extern int get_cipher_max_key_length (int);
+
 struct sa_desc {
     struct sa_desc *next;
 
@@ -94,7 +99,7 @@
     unsigned int enc_secret_size;
     unsigned int ivlen;
     /* Preprocessed encryption key */
-    gcry_cipher_hd_t cry_ctx;
+    symmetric_CBC cry_ctx;
     int cry_algo;
 
     /* Authentication secret */
@@ -419,20 +424,16 @@
 		 unsigned char *digest, unsigned char do_store,
 		 const unsigned char *secret, unsigned short secret_size)
 {
-    gcry_md_hd_t md_ctx;
     int ret;
-    unsigned char *hmac_digest;
-    unsigned int hmac_len;
-
-    /* See RFC 2104 */
-    gcry_md_open(&md_ctx, md_algo, GCRY_MD_FLAG_HMAC);
-    assert(md_ctx != 0);
-    ret = gcry_md_setkey(md_ctx, secret, secret_size);
-    assert(ret == 0);
-    gcry_md_write(md_ctx, data, data_size);
-    gcry_md_final(md_ctx);
-    hmac_digest = gcry_md_read(md_ctx, 0);
-    hmac_len = 12; /*gcry_md_get_algo_dlen(md_algo); see RFC .. only use 96 bit */
+    unsigned char hmac_digest[12];		/* 96 bit, see RFC2104*/
+    unsigned long hmac_len = sizeof hmac_digest;
+	int md;
+	
+	md = find_hash (get_hash (md_algo));
+	assert (md != -1);
+	hmac_memory (md, secret, secret_size,
+				 data, data_size,
+				 hmac_digest, &hmac_len);
 
     if (do_store) {
         memcpy(digest, hmac_digest, hmac_len);
@@ -440,7 +441,6 @@
     } else
         ret = memcmp(digest, hmac_digest, hmac_len);
     
-    gcry_md_close(md_ctx);
     return ret;
 }
 
@@ -459,6 +459,7 @@
     unsigned char *iv, *cleartext;
     int i, padding, pad_blksz;
     unsigned int cleartextlen;
+	int cipher;
 
     buf += MAX_HEADER;
 
@@ -475,7 +476,10 @@
      *	    obscure on that point.
      * seems fine
      */
-    gcry_cipher_algo_info(peer->remote_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &pad_blksz);
+
+	cipher = find_cipher (get_cipher (peer->remote_sa->cry_algo));
+	assert (cipher != -1);
+	pad_blksz = get_cipher_block_length (cipher);
     while (pad_blksz & 3) /* must be multiple of 4 */
 	    pad_blksz <<= 1;
     padding = pad_blksz - ((encap->buflen+2) % pad_blksz);
@@ -510,7 +514,8 @@
 
     /* Copy initialization vector in packet */
     iv = (unsigned char *)(eh + 1);
-    gcry_randomize(iv, peer->remote_sa->ivlen, GCRY_WEAK_RANDOM);
+
+	rng_get_bytes (iv, peer->remote_sa->ivlen, /* no callback */NULL);
 hex_dump("iv", iv, peer->remote_sa->ivlen);
 hex_dump("auth_secret", peer->remote_sa->auth_secret, peer->remote_sa->auth_secret_size);
 
@@ -538,8 +543,13 @@
 #endif
     
     {
-      gcry_cipher_setiv(peer->remote_sa->cry_ctx, iv, peer->remote_sa->ivlen);
-      gcry_cipher_encrypt(peer->remote_sa->cry_ctx, cleartext, cleartextlen, NULL, 0);
+		unsigned char *ptr;
+		DEBUG(2, printf ("YYY cleartextlen %d, ivlen %d\n", cleartextlen, peer->remote_sa->ivlen));
+		cbc_setiv (iv, peer->remote_sa->ivlen, &peer->remote_sa->cry_ctx); /* XXXX needed? */
+		for (ptr = cleartext; ptr < cleartext + cleartextlen; ptr += peer->remote_sa->ivlen) {
+			cbc_encrypt (ptr, /* ciphered */ptr,
+						 &peer->remote_sa->cry_ctx);
+		}
     }
 
 #if 1
@@ -584,6 +594,7 @@
     unsigned char *pad;
     unsigned char *iv;
     struct esp_encap_header *eh;
+	int cipher;
 
     eh = (struct esp_encap_header *)(encap->buf + encap->bufpayload);
     encap->var_header_size = peer->local_sa->ivlen;
@@ -613,12 +624,18 @@
 	}
     }
 
-    gcry_cipher_algo_info(peer->local_sa->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &blksz);
-    if ((len % blksz) != 0) {
-        syslog(LOG_ALERT,
-	       "payload len %d not a multiple of algorithm block size %d",
-	       len, blksz);
-	return -1;
+    {
+		cipher = find_cipher (get_cipher (peer->local_sa->cry_algo));
+		assert (cipher != -1);
+		blksz = get_cipher_block_length (cipher);
+			
+		if ((len % blksz) != 0) {
+			syslog(LOG_ALERT,
+				   "payload len %d not a multiple of algorithm block size %d",
+				   len, blksz);
+			return -1;
+		}
+	
     }
 
 #if 0
@@ -632,12 +649,18 @@
     
     {
       unsigned char *data;
+	  unsigned char *ptr;
+	  
       
       data = (encap->buf+encap->bufpayload
 	      +encap->fixed_header_size
 	      +encap->var_header_size);
-      gcry_cipher_setiv(peer->local_sa->cry_ctx, iv, peer->local_sa->ivlen);
-      gcry_cipher_decrypt(peer->local_sa->cry_ctx, data, len, NULL, 0);
+	  cbc_setiv (iv, peer->local_sa->ivlen, &peer->local_sa->cry_ctx); /* XXXX needed? */
+	  assert (peer->local_sa->ivlen == get_cipher_block_length (cipher));
+	  for (ptr = data; ptr < data + len; ptr += peer->local_sa->ivlen) {
+		  cbc_decrypt (/* cipher */ptr, ptr, &peer->local_sa->cry_ctx);
+	  }
+	  
     }
 
 #if 0
@@ -657,7 +680,7 @@
 			    +encap->var_header_size+len-1];
 
     if (padlen+2 > len) {
-        syslog(LOG_ALERT, "Inconsistent padlen");
+        syslog(LOG_ALERT, "Inconsistent padlen %d", padlen);
 	return -1;
     }
     if (next_header != IPPROTO_IPIP) {
@@ -847,6 +870,8 @@
 
   static struct sa_desc tous_sa, tothem_sa;
   time_t t = time(NULL);
+  int cipher = find_cipher (get_cipher (cry_algo));
+  assert (cipher != -1);
 
   if (encap_esp_new(&meth, IPPROTO_ESP) == -1)
     exit(1);
@@ -860,10 +885,16 @@
   tous_sa.md_algo = md_algo;
   tous_sa.spi = htonl (tous_spi);
   tous_sa.enc_secret = tous_key;
-  gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tous_sa.enc_secret_size));
+  tous_sa.enc_secret_size = get_cipher_max_key_length (cipher);
+  
 hex_dump("tous.enc_secret", tous_sa.enc_secret, tous_sa.enc_secret_size);
   tous_sa.auth_secret = tous_key + tous_sa.enc_secret_size;
-  tous_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
+  {
+	  int md = find_hash (get_hash (md_algo));
+	  assert (md != -1);
+	  
+	  tous_sa.auth_secret_size = hash_descriptor[md].hashsize;
+  }
 hex_dump("tous.auth_secret", tous_sa.auth_secret, tous_sa.auth_secret_size);
   memcpy (&tous_sa.init, tous_dest, sizeof (struct sockaddr_in));
   memcpy (&tous_sa.dest, tous_dest, sizeof (struct sockaddr_in));
@@ -873,10 +904,14 @@
       tous_sa.use_dest = 1;
     }
   tous_sa.cry_algo = cry_algo;
-  gcry_cipher_open(&tous_sa.cry_ctx, tous_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
-  gcry_cipher_setkey(tous_sa.cry_ctx, tous_sa.enc_secret, tous_sa.enc_secret_size);
-  gcry_cipher_algo_info(tous_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tous_sa.ivlen));
-  
+  {
+	  unsigned char iv[MAXBLOCKSIZE];	/* unused IV, gets corrected later */
+	  cbc_start (cipher, iv, 
+				 tous_sa.enc_secret, tous_sa.enc_secret_size,
+				 /* default rounds */0, &tous_sa.cry_ctx);
+  }
+  tous_sa.ivlen = get_cipher_block_length (cipher);
+		  
   tothem_sa.next = local_sa_list;
   local_sa_list = &tothem_sa;
   tothem_sa.em = &meth;
@@ -886,10 +921,15 @@
   tothem_sa.md_algo = md_algo;
   tothem_sa.spi = htonl (tothem_spi);
   tothem_sa.enc_secret = tothem_key;
-  gcry_cipher_algo_info(cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(tothem_sa.enc_secret_size));
+  tothem_sa.enc_secret_size = get_cipher_max_key_length (cipher);
 hex_dump("tothem.enc_secret", tothem_sa.enc_secret, tothem_sa.enc_secret_size);
   tothem_sa.auth_secret = tothem_key + tothem_sa.enc_secret_size;
-  tothem_sa.auth_secret_size = gcry_md_get_algo_dlen(md_algo);
+  {
+	  int md = find_hash (get_hash (md_algo));
+	  assert (md != -1);
+	  
+	  tothem_sa.auth_secret_size = hash_descriptor[md].hashsize;
+  }
 hex_dump("tothem.auth_secret", tothem_sa.auth_secret, tothem_sa.auth_secret_size);
   memcpy (&tothem_sa.init, tothem_dest, sizeof (struct sockaddr_in));
   memcpy (&tothem_sa.dest, tothem_dest, sizeof (struct sockaddr_in));
@@ -899,9 +939,14 @@
       tothem_sa.use_dest = 1;
     }
   tothem_sa.cry_algo = cry_algo;
-  gcry_cipher_open(&tothem_sa.cry_ctx, tothem_sa.cry_algo, GCRY_CIPHER_MODE_CBC, 0);
-  gcry_cipher_setkey(tothem_sa.cry_ctx, tothem_sa.enc_secret, tothem_sa.enc_secret_size);
-  gcry_cipher_algo_info(tothem_sa.cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(tothem_sa.ivlen));
+  {
+	  unsigned char iv[MAXBLOCKSIZE]; 	/* unused IV, corrected later */
+	  cbc_start (cipher,
+				 iv,
+				 tothem_sa.enc_secret, tothem_sa.enc_secret_size,
+				 /* default rounds */0, &tothem_sa.cry_ctx);
+  }
+  tothem_sa.ivlen = get_cipher_block_length (cipher);
   
   vpnpeer.tun_fd = tun_fd;
   vpnpeer.local_sa = &tous_sa;
diff -Nur --exclude=TAGS --exclude=debian --exclude=vpnc.8 --exclude=vpnc.conf --exclude=vpnc-connect --exclude=vpnc-disconnect vpnc-0.2-rm+zomb.1/vpnc.c vpnc-0.2-rm+zomb.1-tomcrypt/vpnc.c
--- vpnc-0.2-rm+zomb.1/vpnc.c	2004-08-06 00:19:26.000000000 +0200
+++ vpnc-0.2-rm+zomb.1-tomcrypt/vpnc.c	2004-08-06 00:17:23.000000000 +0200
@@ -1,5 +1,6 @@
 /* IPSec VPN client compatible with Cisco equipment.
    Copyright (C) 2002, 2003  Geoffrey Keating and Maurice Massar
+   libtomcrypt interfacing: Michael Weber <michaelw@foldr.org>
 
    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
@@ -34,7 +35,7 @@
 #include <sys/ioctl.h>
 #include <sys/utsname.h>
 
-#include <gcrypt.h>
+#include <mycrypt.h>
 
 #include "isakmp-pkt.h"
 #include "sysdep.h"
@@ -94,6 +95,19 @@
 	SUPP_ALGO_CRYPT
 };
 
+enum supp_md {
+	MD_MD5 = 1,
+	MD_SHA1,
+};
+
+enum supp_cipher {
+	CIPHER_DES = 1,
+	CIPHER_3DES,
+	CIPHER_AES128,
+	CIPHER_AES192,
+	CIPHER_AES256,
+};
+
 typedef struct {
 	const char *name;
 	int my_id, ike_sa_id, ipsec_sa_id;
@@ -109,16 +123,16 @@
 };
 
 supported_algo_t supp_hash[] = {
-	{ "md5", GCRY_MD_MD5, IKE_HASH_MD5, IPSEC_AUTH_HMAC_MD5, 0 },
-	{ "sha1", GCRY_MD_SHA1, IKE_HASH_SHA, IPSEC_AUTH_HMAC_SHA, 0 }
+	{ "md5", MD_MD5, IKE_HASH_MD5, IPSEC_AUTH_HMAC_MD5, 0 },
+	{ "sha1", MD_SHA1, IKE_HASH_SHA, IPSEC_AUTH_HMAC_SHA, 0 }
 };
 
 supported_algo_t supp_crypt[] = {
-	{ "des", GCRY_CIPHER_DES, IKE_ENC_DES_CBC, ISAKMP_IPSEC_ESP_DES, 0 }, /*note: working, but not recommended */
-	{ "3des", GCRY_CIPHER_3DES, IKE_ENC_3DES_CBC, ISAKMP_IPSEC_ESP_3DES, 0 },
-	{ "aes128", GCRY_CIPHER_AES128, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 128 },
-	{ "aes192", GCRY_CIPHER_AES192, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 192 },
-	{ "aes256", GCRY_CIPHER_AES256, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 256 },
+	{ "des", CIPHER_DES, IKE_ENC_DES_CBC, ISAKMP_IPSEC_ESP_DES, 0 }, /*note: working, but not recommended */
+	{ "3des", CIPHER_3DES, IKE_ENC_3DES_CBC, ISAKMP_IPSEC_ESP_3DES, 0 },
+	{ "aes128", CIPHER_AES128, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 128 },
+	{ "aes192", CIPHER_AES192, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 192 },
+	{ "aes256", CIPHER_AES256, IKE_ENC_AES_CBC, ISAKMP_IPSEC_ESP_AES, 256 },
 };
 
 const supported_algo_t *
@@ -277,6 +291,17 @@
 static int timeout = 5000;  /* 5 seconds */
 static uint8_t *resend_hash = NULL;
 
+static void
+sha1_memory (void *buf, size_t bufsz, void *hash)
+{
+	hash_state sha1;
+	
+	sha1_init (&sha1);
+	sha1_process (&sha1, buf, bufsz);
+	sha1_done (&sha1, hash);
+}
+
+
 static int
 recv_ignore_dup (void *recvbuf, size_t recvbufsize, uint8_t reply_extype)
 {
@@ -312,9 +337,11 @@
 	return -1;
       }
 
-      hash_len = gcry_md_get_algo_dlen(GCRY_MD_SHA1);
+	  
+      hash_len = sha1_desc.hashsize;
       resend_check_hash = malloc(hash_len);
-      gcry_md_hash_buffer(GCRY_MD_SHA1, resend_check_hash, recvbuf, recvsize);
+
+      sha1_memory (recvbuf, recvsize, resend_check_hash);
       if (resend_hash && memcmp(resend_hash, resend_check_hash, hash_len) == 0) {
 	free(resend_check_hash);
 	return -1;
@@ -420,7 +447,7 @@
   r->u.sa.proposals = new_isakmp_payload (ISAKMP_PAYLOAD_P);
   r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_ISAKMP;
   for (crypt = 0; crypt < sizeof(supp_crypt) / sizeof(supp_crypt[0]); crypt++) {
-    if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES)&&(opt_1des == 0))
+    if ((supp_crypt[crypt].my_id == CIPHER_DES)&&(opt_1des == 0))
       continue;
     keylen = supp_crypt[crypt].keylen;
     for (hash = 0; hash < sizeof(supp_hash) / sizeof(supp_hash[0]); hash++) {
@@ -459,46 +486,111 @@
   int do_pfs;
 };
 
+const char *
+get_hash (enum supp_md md)
+{
+	switch (md) {
+	case MD_MD5: return md5_desc.name;
+	case MD_SHA1: return sha1_desc.name;
+	default: return NULL;
+	}
+}
+
+const char *
+get_cipher (enum supp_cipher cipher)
+{
+	switch (cipher) {
+	case CIPHER_DES: return des_desc.name;
+	case CIPHER_3DES: return des3_desc.name;
+	case CIPHER_AES128:
+	case CIPHER_AES192:
+	case CIPHER_AES256: return aes_desc.name;
+	default: return NULL;
+	}
+}
+
+int
+get_cipher_block_length (int cipher)
+/* correct block length of libtomcrypt */
+{
+	int len = cipher_descriptor[cipher].block_length;
+/* 	if (cipher == find_cipher (des_desc.name)) { */
+/* 		len = 8; */
+/* 	} else if (cipher == find_cipher (des3_desc.name)) { */
+/* 		len = 8; */
+/* 	} */
+	return len;
+}
+
+int get_cipher_max_key_length (int cipher)
+/* correct key length of libtomcrypt */
+{
+	int len = cipher_descriptor[cipher].max_key_length;
+/* 	if (cipher == find_cipher (des_desc.name)) { */
+/* 		len = 21; */
+/* 	} else if (&cipher_descriptor[cipher] == &des3_desc) { */
+/* 		len = 21; */
+/* 	} */
+	return len;
+}
+
+
 void
 isakmp_crypt (struct sa_block *s, uint8_t *block, size_t blocklen, int enc)
 {
   unsigned char *new_iv;
-  gcry_cipher_hd_t cry_ctx;
   
-  if (blocklen < ISAKMP_PAYLOAD_O 
+  if (blocklen < ISAKMP_PAYLOAD_O
       || ((blocklen - ISAKMP_PAYLOAD_O) % s->ivlen != 0))
     abort ();
-
   if ((memcmp (block + ISAKMP_MESSAGE_ID_O, s->current_iv_msgid, 4) != 0)&&(enc >= 0))
     {
-      unsigned char *iv;
-      gcry_md_hd_t md_ctx;
-      
-       gcry_md_open(&md_ctx, s->md_algo, 0);
-      gcry_md_write(md_ctx, s->initial_iv, s->ivlen);
-      gcry_md_write(md_ctx, block + ISAKMP_MESSAGE_ID_O, 4);
-      gcry_md_final(md_ctx);
-      iv = gcry_md_read(md_ctx, 0);
-      memcpy (s->current_iv, iv, s->ivlen);
+      hash_state md_ctx;
+	  int md = find_hash (get_hash (s->md_algo));
+	  assert (md != -1);
+	  
+	  hash_descriptor[md].init (&md_ctx);
+	  hash_descriptor[md].process (&md_ctx, s->initial_iv, s->ivlen);
+	  hash_descriptor[md].process (&md_ctx, block + ISAKMP_MESSAGE_ID_O, 4);
+	  hash_descriptor[md].done (&md_ctx, s->current_iv);
       memcpy (s->current_iv_msgid, block + ISAKMP_MESSAGE_ID_O, 4);
-      gcry_md_close(md_ctx);
     }
-
-  new_iv = xallocc (s->ivlen);
-  gcry_cipher_open(&cry_ctx, s->cry_algo, GCRY_CIPHER_MODE_CBC, 0);
-  gcry_cipher_setkey(cry_ctx, s->key, s->keylen);
-  gcry_cipher_setiv(cry_ctx, s->current_iv, s->ivlen);
-  if (!enc) {
-    memcpy (new_iv, block + blocklen - s->ivlen, s->ivlen);
-    gcry_cipher_decrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O, NULL, 0);
-    memcpy (s->current_iv, new_iv, s->ivlen);
-  } else { /* enc == -1 (no longer used) || enc == 1 */
-    gcry_cipher_encrypt(cry_ctx, block + ISAKMP_PAYLOAD_O, blocklen - ISAKMP_PAYLOAD_O, NULL, 0);
-    if (enc > 0)
-      memcpy (s->current_iv, block + blocklen - s->ivlen, s->ivlen);
-  }
-  gcry_cipher_close(cry_ctx);
   
+  {
+	  symmetric_CBC skey;
+	  int res;
+	  int cipher = find_cipher (get_cipher (s->cry_algo));
+	  assert (cipher != -1);
+	  assert (s->ivlen == get_cipher_block_length (cipher));
+	  
+	  new_iv = xallocc (s->ivlen);
+	  
+	  if ((res = cbc_start (cipher, s->current_iv, s->key, s->keylen,
+							/* default rounds */0, &skey)) != CRYPT_OK) {
+		  error (1, 0, "unsupported key length %d for cipher %s",
+				 s->keylen * 8, cipher_descriptor[cipher].name);
+	  }
+	  
+	  if (!enc) {
+		  uint8_t *ptr;
+		  memcpy (new_iv, block + blocklen - s->ivlen, s->ivlen);
+		  for (ptr = block + ISAKMP_PAYLOAD_O; ptr < block + blocklen;
+			   ptr += s->ivlen) {
+			  cbc_decrypt (ptr, ptr, &skey);
+		  }
+		  memcpy (s->current_iv, new_iv, s->ivlen);
+	  } else {
+		  uint8_t *ptr;
+		  for (ptr = block + ISAKMP_PAYLOAD_O; ptr < block + blocklen;
+			   ptr += s->ivlen) {
+			  cbc_encrypt (ptr, ptr, &skey);
+		  }
+		  
+		  if (enc > 0) {
+			  memcpy (s->current_iv, block + blocklen - s->ivlen, s->ivlen);
+		  }
+	  }
+  }
 }
 
 static uint8_t r_packet[2048];
@@ -511,7 +603,8 @@
   unsigned char i_nonce[20];
   struct group *dh_grp;
   unsigned char *dh_public;
-  unsigned char *returned_hash;
+  unsigned char returned_hash[MAXBLOCKSIZE];
+  unsigned long returned_hash_len = sizeof returned_hash;
   static const uint8_t xauth_vid[] = XAUTH_VENDOR_ID;
   static const uint8_t unity_vid[] = UNITY_VENDOR_ID;
   static const uint8_t unknown_vid[] = UNKNOWN_VENDOR_ID;
@@ -525,12 +618,12 @@
   struct isakmp_packet *p1;
   
 DEBUG(2, printf("S4.1\n"));
-  gcry_randomize(d->i_cookie, ISAKMP_COOKIE_LENGTH, GCRY_STRONG_RANDOM);
+ rng_get_bytes (d->i_cookie, ISAKMP_COOKIE_LENGTH, /* no callback */NULL); 
   d->do_pfs = -1;
   if (d->i_cookie[0] == 0)
     d->i_cookie[0] = 1;
 hex_dump("i_cookie", d->i_cookie, ISAKMP_COOKIE_LENGTH);
-  gcry_randomize(i_nonce, sizeof (i_nonce), GCRY_STRONG_RANDOM);
+ rng_get_bytes (i_nonce, sizeof i_nonce, /* no callback */NULL); 
 hex_dump("i_nonce", i_nonce, sizeof (i_nonce));
 DEBUG(2, printf("S4.2\n"));
   /* Set up the Diffie-Hellman stuff.  */
@@ -579,6 +672,7 @@
     /* Now, send that packet and receive a new one.  */
     r_length = sendrecv (r_packet, sizeof (r_packet), 
 			 pkt, pkt_len, 0);
+	DEBUG(3, printf ("S4.3 r_length: %d\n", r_length));
     free (pkt);
   }
 DEBUG(2, printf("S4.4\n"));
@@ -592,8 +686,7 @@
      struct isakmp_payload *hash = NULL;
      struct isakmp_payload *idp = NULL;
      int seen_xauth_vid = 0;
-     unsigned char *skeyid;
-     gcry_md_hd_t skeyid_ctx;
+     unsigned char skeyid[MAXBLOCKSIZE];
      
      reject = 0;
      r = parse_isakmp_packet (r_packet, r_length, &reject);
@@ -725,11 +818,18 @@
 	 }
 
      if (reject == 0) {
-        d->md_len = gcry_md_get_algo_dlen(d->md_algo);
-        gcry_cipher_algo_info(d->cry_algo, GCRYCTL_GET_BLKLEN, NULL, &(d->ivlen));
-        gcry_cipher_algo_info(d->cry_algo, GCRYCTL_GET_KEYLEN, NULL, &(d->keylen));
+		 int md = find_hash (get_hash (d->md_algo));
+		 int cipher = find_cipher (get_cipher (d->cry_algo));
+		 assert (md != -1);
+		 assert (cipher != -1);
+
+		 d->md_len = hash_descriptor[md].hashsize;
+		 d->ivlen  = get_cipher_block_length (cipher);
+		 d->keylen = get_cipher_max_key_length (cipher);
      }
-
+     DEBUG(2, printf("md_len %d, cipher block len %d, key len %d\n",
+                     d->md_len, d->ivlen, d->keylen));
+	 DEBUG(2, printf ("key length: %d, %d\n", ke->u.ke.length, dh_getlen (dh_grp)));
      if (reject == 0
 	 && (ke == NULL || ke->u.ke.length != dh_getlen (dh_grp)))
        reject = ISAKMP_N_INVALID_KEY_INFORMATION;
@@ -749,23 +849,30 @@
 
      /* Generate SKEYID.  */
      {
-       gcry_md_open(&skeyid_ctx, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(skeyid_ctx, shared_key, strlen (shared_key));
-       gcry_md_write(skeyid_ctx, i_nonce, sizeof (i_nonce));
-       gcry_md_write(skeyid_ctx, nonce->u.nonce.data, nonce->u.nonce.length);
-       gcry_md_final(skeyid_ctx);
-       skeyid = gcry_md_read(skeyid_ctx, 0);
+		 hmac_state hmac;
+		 unsigned long skeyid_len = sizeof skeyid;
+		 int md = find_hash (get_hash (d->md_algo));
+		 assert (md != -1);
+		 
+		 hmac_init (&hmac, md, shared_key, strlen (shared_key));
+		 hmac_process (&hmac, i_nonce, sizeof i_nonce);
+		 hmac_process (&hmac, nonce->u.nonce.data, nonce->u.nonce.length);
+		 hmac_done (&hmac, skeyid, &skeyid_len);
 hex_dump("skeyid", skeyid, d->md_len);
      }
 
      /* Verify the hash.  */
      {
-       gcry_md_hd_t hm;
-       unsigned char *expected_hash;
+       unsigned char expected_hash[MAXBLOCKSIZE];
        uint8_t *sa_f, *idi_f, *idp_f;
        size_t sa_size, idi_size, idp_size;
        struct isakmp_payload *sa, *idi;
 
+	   hmac_state hmac;
+	   unsigned long expected_hash_len = sizeof expected_hash;
+	   int md = find_hash (get_hash (d->md_algo));
+	   assert (md != -1);
+	   
        sa = p1->payload;
        for (idi = sa; idi->type != ISAKMP_PAYLOAD_ID; idi = idi->next)
 	 ;
@@ -776,36 +883,33 @@
        flatten_isakmp_payload (idi, &idi_f, &idi_size);
        flatten_isakmp_payload (idp, &idp_f, &idp_size);
 
-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(hm, skeyid, d->md_len);
-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, sa_f + 4, sa_size - 4);
-       gcry_md_write(hm, idp_f + 4, idp_size - 4);
-       gcry_md_final(hm);
-       expected_hash = gcry_md_read(hm, 0);
-       
+	   hmac_init (&hmac, md, skeyid, d->md_len);
+	   hmac_process (&hmac, ke->u.ke.data, ke->u.ke.length);
+	   hmac_process (&hmac, dh_public, dh_getlen (dh_grp));
+	   hmac_process (&hmac, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, sa_f + 4, sa_size - 4);
+	   hmac_process (&hmac, idp_f + 4, idp_size - 4);
+	   hmac_done (&hmac, expected_hash, &expected_hash_len);
+	   
        if (memcmp (expected_hash, hash->u.hash.data, d->md_len) != 0)
 	 {
 	   error (1, 0, "hash comparison failed: %s\ncheck group password!", 
 		  isakmp_notify_to_error (ISAKMP_N_AUTHENTICATION_FAILED));
 	 }
-       gcry_md_close(hm);
 
-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(hm, skeyid, d->md_len);
-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, sa_f + 4, sa_size - 4);
-       gcry_md_write(hm, idi_f + 4, idi_size - 4);
-       gcry_md_final(hm);
-       returned_hash = xallocc(d->md_len);
-       memcpy(returned_hash, gcry_md_read(hm, 0), d->md_len);
-       gcry_md_close(hm);
+	   md = find_hash (get_hash (d->md_algo));
+	   assert (md != -1);
+	   
+	   hmac_init (&hmac, md, skeyid, d->md_len);
+	   hmac_process (&hmac, dh_public, dh_getlen (dh_grp));
+	   hmac_process (&hmac, ke->u.ke.data, ke->u.ke.length);
+	   hmac_process (&hmac, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, sa_f + 4, sa_size - 4);
+	   hmac_process (&hmac, idi_f + 4, idi_size - 4);
+	   hmac_done (&hmac, returned_hash, &returned_hash_len);
+
 hex_dump("returned_hash", returned_hash, d->md_len);
        
        free (sa_f);
@@ -815,53 +919,54 @@
 
      /* Determine all the SKEYID_x keys.  */
      {
-       gcry_md_hd_t hm;
        int i;
        static const unsigned char c012[3] = { 0, 1, 2 };
        unsigned char *skeyid_e;
        unsigned char *dh_shared_secret;
+	   hmac_state hmac;
+       int md = find_hash (get_hash (d->md_algo));
+	   unsigned long hash_len;
+	   assert (md != -1);
 
        /* Determine the shared secret.  */
        dh_shared_secret = xallocc(dh_getlen (dh_grp));
        dh_create_shared (dh_grp, dh_shared_secret, ke->u.ke.data);
 hex_dump("dh_shared_secret", dh_shared_secret, dh_getlen (dh_grp));
 
-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(hm, skeyid, d->md_len);
-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, c012+0, 1);
-       gcry_md_final(hm);
+	   
        d->skeyid_d = xallocc(d->md_len);
-       memcpy(d->skeyid_d, gcry_md_read(hm, 0), d->md_len);
-       gcry_md_close(hm);
+	   hash_len = d->md_len;
+	   
+	   hmac_init (&hmac, md, skeyid, d->md_len);
+	   hmac_process (&hmac, dh_shared_secret, dh_getlen (dh_grp));
+	   hmac_process (&hmac, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, c012+0, 1);
+	   hmac_done (&hmac, d->skeyid_d, &hash_len);
 hex_dump("skeyid_d", d->skeyid_d, d->md_len);
        
-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(hm, skeyid, d->md_len);
-       gcry_md_write(hm, d->skeyid_d, d->md_len);
-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, c012+1, 1);
-       gcry_md_final(hm);
        d->skeyid_a = xallocc(d->md_len);
-       memcpy(d->skeyid_a, gcry_md_read(hm, 0), d->md_len);
-       gcry_md_close(hm);
+	   hash_len = d->md_len;
+	   
+	   hmac_init (&hmac, md, skeyid, d->md_len);
+	   hmac_process (&hmac, d->skeyid_d, d->md_len);
+	   hmac_process (&hmac, dh_shared_secret, dh_getlen (dh_grp));
+	   hmac_process (&hmac, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, c012+1, 1);
+	   hmac_done (&hmac, d->skeyid_a, &hash_len);
 hex_dump("skeyid_a", d->skeyid_a, d->md_len);
        
-       gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-       gcry_md_setkey(hm, skeyid, d->md_len);
-       gcry_md_write(hm, d->skeyid_a, d->md_len);
-       gcry_md_write(hm, dh_shared_secret, dh_getlen (dh_grp));
-       gcry_md_write(hm, d->i_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, d->r_cookie, ISAKMP_COOKIE_LENGTH);
-       gcry_md_write(hm, c012+2, 1);
-       gcry_md_final(hm);
        skeyid_e = xallocc(d->md_len);
-       memcpy(skeyid_e, gcry_md_read(hm, 0), d->md_len);
-       gcry_md_close(hm);
+	   hash_len = d->md_len;
+	   
+	   hmac_init (&hmac, md, skeyid, d->md_len);
+	   hmac_process (&hmac, d->skeyid_a, d->md_len);
+	   hmac_process (&hmac, dh_shared_secret, dh_getlen (dh_grp));
+	   hmac_process (&hmac, d->i_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, d->r_cookie, ISAKMP_COOKIE_LENGTH);
+	   hmac_process (&hmac, c012+2, 1);
+	   hmac_done (&hmac, skeyid_e, &hash_len);
 hex_dump("skeyid_e", skeyid_e, d->md_len);
 
        memset (dh_shared_secret, 0, sizeof (dh_shared_secret));
@@ -871,16 +976,14 @@
        
        if (d->keylen > d->md_len) {
          for (i = 0; i * d->md_len < d->keylen; i++) {
-           gcry_md_open(&hm, d->md_algo, GCRY_MD_FLAG_HMAC);
-           gcry_md_setkey(hm, skeyid_e, d->md_len);
-	   if (i == 0)
-             gcry_md_write(hm, "" /* &'\0' */, 1);
-	   else
-             gcry_md_write(hm, d->key + (i-1) * d->md_len, d->md_len);
-           gcry_md_final(hm);
-           memcpy(d->key + i * d->md_len, gcry_md_read(hm, 0),
-		  min(d->md_len, d->keylen - i*d->md_len));
-           gcry_md_close(hm);
+			 hmac_init (&hmac, md, skeyid_e, d->md_len);
+			 if (i == 0) {
+				 hmac_process (&hmac, "" /* &'\0' */, 1); 
+			 } else {
+				 hmac_process (&hmac, d->key + (i-1) * d->md_len, d->md_len);
+			 }
+			 hash_len = min(d->md_len, d->keylen - i*d->md_len);
+			 hmac_done (&hmac, d->key + i * d->md_len, &hash_len);
          }
        } else { /* keylen <= md_len*/
            memcpy(d->key, skeyid_e, d->keylen);
@@ -892,21 +995,19 @@
 
      /* Determine the initial 3DES IV.  */
      {
-       gcry_md_hd_t hm;
-       
-       assert(d->ivlen < d->md_len);
-       gcry_md_open(&hm, d->md_algo, 0);
-       gcry_md_write(hm, dh_public, dh_getlen (dh_grp));
-       gcry_md_write(hm, ke->u.ke.data, ke->u.ke.length);
-       gcry_md_final(hm);
-       d->current_iv = xallocc(d->ivlen);
-       memcpy(d->current_iv, gcry_md_read(hm, 0), d->ivlen);
-       gcry_md_close(hm);
+		 hash_state md_ctx;
+		 int md = find_hash (get_hash (d->md_algo));
+		 assert (md != -1);
+		 
+		 assert(d->ivlen < d->md_len);
+		 d->current_iv = xallocc(d->md_len);
+		 hash_descriptor[md].init (&md_ctx);
+		 hash_descriptor[md].process (&md_ctx, dh_public, dh_getlen (dh_grp));
+		 hash_descriptor[md].process (&md_ctx, ke->u.ke.data, ke->u.ke.length);
+		 hash_descriptor[md].done (&md_ctx, d->current_iv);
 hex_dump("current_iv", d->current_iv, d->ivlen);
        memset (d->current_iv_msgid, 0, 4);
      }
-     
-     gcry_md_close(skeyid_ctx);
   }
 
 DEBUG(2, printf("S4.5\n"));
@@ -926,6 +1027,7 @@
     p2->payload = new_isakmp_data_payload (ISAKMP_PAYLOAD_HASH,
 					   returned_hash, 
 					   d->md_len);
+	DEBUG(2, printf ("S4.5 md_len %d\n", d->md_len));
     p2->payload->next = pl = new_isakmp_payload (ISAKMP_PAYLOAD_N);
     pl->u.n.doi = ISAKMP_DOI_IPSEC;
     pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
@@ -939,21 +1041,26 @@
     pl->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_VID,
 					     unity_vid, sizeof (unity_vid));
     flatten_isakmp_packet (p2, &p2kt, &p2kt_len, d->ivlen);
+	DEBUG(3, printf ("DEBUG packet\n"));
+	uint16_t reject = 0;
+	struct isakmp_packet *dbg_p = parse_isakmp_packet (p2kt, p2kt_len, &reject);
+	DEBUG(3, printf ("reject %d, p2kt_len %d, d->ivlen %d\n", reject, p2kt_len, d->ivlen));
     free_isakmp_packet (p2);
     isakmp_crypt (d, p2kt, p2kt_len, 1);
 
     d->initial_iv = xallocc(d->ivlen);
     memcpy (d->initial_iv, d->current_iv, d->ivlen);
+	DEBUG(3, printf ("XXX2 ivlen %d\n", d->ivlen));
 hex_dump("initial_iv", d->initial_iv, d->ivlen);
     
     /* Now, send that packet and receive a new one.  */
     r_length = sendrecv (r_packet, sizeof (r_packet), 
 			 p2kt, p2kt_len, 0);
+	DEBUG(3, printf ("S4.5 r_length %d, %d\n", r_length, p2kt_len));
     free (p2kt);
   }
 DEBUG(2, printf("S4.6\n"));
   
-  free(returned_hash);
 }
 
 static uint16_t
@@ -967,8 +1074,9 @@
   uint16_t reject = 0;
   
   *r_p = NULL;
-  
-  if (r_length < ISAKMP_PAYLOAD_O 
+
+  DEBUG(2, printf ("packet length: %d\n", r_length));
+  if (r_length < ISAKMP_PAYLOAD_O
       || ((r_length - ISAKMP_PAYLOAD_O) % s->ivlen
 	  != 0))
     return ISAKMP_N_UNEQUAL_PAYLOAD_LENGTHS;
@@ -990,9 +1098,11 @@
   
   {
     size_t sz, spos;
-    gcry_md_hd_t hm;
-    unsigned char *expected_hash;
+    hmac_state hmac;
+    unsigned char expected_hash[MAXBLOCKSIZE];
+    unsigned long expected_hash_len = sizeof expected_hash;
     struct isakmp_payload *h = r->payload;
+	int md;
     
     if (h == NULL
 	|| h->type != ISAKMP_PAYLOAD_HASH
@@ -1009,15 +1119,16 @@
 	 sz += r_packet [sz+2] << 8 | r_packet[sz+3])
       ;
     sz += r_packet [sz+2] << 8 | r_packet[sz+3];
-    
-    gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
-    gcry_md_setkey(hm, s->skeyid_a, s->md_len);
-    gcry_md_write(hm, r_packet + ISAKMP_MESSAGE_ID_O, 4);
-    if (nonce)
-      gcry_md_write(hm, nonce, nonce_size);
-    gcry_md_write(hm, r_packet + spos, sz - spos);
-    gcry_md_final(hm);
-    expected_hash = gcry_md_read(hm, 0);
+
+	md = find_hash (get_hash (s->md_algo));
+	assert (md != -1);
+	hmac_init (&hmac, md, s->skeyid_a, s->md_len);
+	hmac_process (&hmac, r_packet + ISAKMP_MESSAGE_ID_O, 4);
+    if (nonce) {
+		hmac_process (&hmac, nonce, nonce_size);
+	}
+	hmac_process (&hmac, r_packet + spos, sz - spos);
+	hmac_done (&hmac, expected_hash, &expected_hash_len);
     
     if(opt_debug >= 3) {
 	    printf("hashlen: %d\n", s->md_len);
@@ -1029,7 +1140,6 @@
     reject = 0;
     if (memcmp (h->u.hash.data, expected_hash, s->md_len) != 0)
       reject = ISAKMP_N_AUTHENTICATION_FAILED;
-    gcry_md_close(hm);
 #if 0
     if (reject != 0)
       return reject;
@@ -1048,7 +1158,9 @@
   struct isakmp_packet *p;
   uint8_t *pl_flat;
   size_t pl_size;
-  gcry_md_hd_t hm;
+  hmac_state hmac;
+  int md;
+  unsigned long hash_len;
   uint8_t msgid_sent[4];
 
   /* Build up the packet.  */
@@ -1065,36 +1177,37 @@
   p->payload->u.hash.data = xallocc (s->md_len);
   
   /* Set the MAC.  */
-  gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
-  gcry_md_setkey(hm, s->skeyid_a, s->md_len);
+  md = find_hash (get_hash (s->md_algo));
+  hmac_init (&hmac, md, s->skeyid_a, s->md_len);
   
   if (pl == NULL) {
     DEBUG(3, printf("authing NULL package!\n"));
-    gcry_md_write(hm, "" /* \0 */, 1);
+	hmac_process (&hmac, "" /* \0 */, 1);
   }
   
   msgid_sent[0] = msgid >> 24;
   msgid_sent[1] = msgid >> 16;
   msgid_sent[2] = msgid >> 8;
   msgid_sent[3] = msgid;
-  gcry_md_write(hm, msgid_sent, sizeof (msgid_sent));
+  hmac_process (&hmac, msgid_sent, sizeof msgid_sent);
 
-  if (nonce_i != NULL)
-    gcry_md_write(hm, nonce_i, ni_len);
+  if (nonce_i != NULL) {
+	  hmac_process (&hmac, nonce_i, ni_len);
+  }
   
-  if (nonce_r != NULL)
-    gcry_md_write(hm, nonce_r, nr_len);
+  if (nonce_r != NULL) {
+	  hmac_process (&hmac, nonce_r, nr_len);
+  }
   
   if (pl != NULL) {
     flatten_isakmp_payload (pl, &pl_flat, &pl_size);
-    gcry_md_write(hm, pl_flat, pl_size);
+	hmac_process (&hmac, pl_flat, pl_size);
     memset (pl_flat, 0, pl_size);
     free (pl_flat);
   }
-
-  gcry_md_final(hm);
-  memcpy(p->payload->u.hash.data, gcry_md_read(hm, 0), s->md_len);
-  gcry_md_close(hm);
+  
+  hash_len = s->md_len;
+  hmac_done (&hmac, p->payload->u.hash.data, &hash_len);
 
   flatten_isakmp_packet (p, p_flat, p_size, s->ivlen);
   free_isakmp_packet (p);
@@ -1143,14 +1256,15 @@
   uint32_t msgid;
 
 DEBUG(1, printf("\n\n---!!!!!!!!! entering phase2_fatal !!!!!!!!!---\n\n\n"));
-  gcry_randomize((uint8_t *) &msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+  rng_get_bytes ((uint8_t *) &msgid, sizeof msgid, /* no callback */NULL);
+  
   pl = new_isakmp_payload (ISAKMP_PAYLOAD_N);
   pl->u.n.doi = ISAKMP_DOI_IPSEC;
   pl->u.n.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
   pl->u.n.type = id;
   sendrecv_phase2 (s, pl, ISAKMP_EXCHANGE_INFORMATIONAL, msgid, 2, 0,0,0,0,0,0,0);
   
-  gcry_randomize((uint8_t *) &msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+  rng_get_bytes ((uint8_t *) &msgid, sizeof msgid, /* no callback */NULL);
   pl = new_isakmp_payload (ISAKMP_PAYLOAD_D);
   pl->u.d.doi = ISAKMP_DOI_IPSEC;
   pl->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
@@ -1183,13 +1297,14 @@
       
 DEBUG(2, printf("S5.2\n"));
       reject = unpack_verify_phase2 (s, r_packet, r_length, &r, NULL, 0);
+      DEBUG(2, printf ("S5.2.1 r_length: %d\n", r_length));
       if (reject == ISAKMP_N_PAYLOAD_MALFORMED)
 	{
 	  r_length = sendrecv (r_packet, sizeof (r_packet), NULL, 0, 0);
 	  continue;
 	}
-      
-  
+      DEBUG(2, printf ("S5.2.2 r_length: %d\n", r_length));
+	  
       /* check for notices */
       if (reject == 0 && 
 	  r->exchange_type == ISAKMP_EXCHANGE_INFORMATIONAL &&
@@ -1421,7 +1536,7 @@
   
   uname(&uts);
   
-  gcry_randomize((uint8_t *)&msgid, sizeof (msgid), GCRY_WEAK_RANDOM);
+  rng_get_bytes ((uint8_t *) &msgid, sizeof msgid, /* no callback */NULL);
   if (msgid == 0)
     msgid = 1;
   
@@ -1587,16 +1702,24 @@
 	    const uint8_t *ni_data, size_t ni_size,
 	    const uint8_t *nr_data, size_t nr_size)
 {
-  gcry_md_hd_t hm;
+  hmac_state hmac;
   uint8_t *block;
   int i;
   int blksz;
   int cnt;
-  
-  int md_len = gcry_md_get_algo_dlen(md_algo);
+  int md;
+  int md_len;
   int cry_len;
+  int cipher;
+  
+  md = find_hash (get_hash (md_algo));
+  assert (md != -1);
+  md_len = hash_descriptor[md].hashsize;
+
+  cipher = find_cipher (get_cipher (crypt_algo));
+  assert (cipher != -1);
+  cry_len = get_cipher_max_key_length (cipher);
   
-  gcry_cipher_algo_info(crypt_algo, GCRYCTL_GET_KEYLEN, NULL, &cry_len);
   blksz = md_len + cry_len;
   cnt = (blksz + s->md_len - 1) / s->md_len;
   block = xallocc (cnt * s->md_len);
@@ -1606,19 +1729,24 @@
 
   for (i = 0; i < cnt; i++)
     {
-      gcry_md_open(&hm, s->md_algo, GCRY_MD_FLAG_HMAC);
-      gcry_md_setkey(hm, s->skeyid_d, s->md_len);
-      if (i != 0)
-	gcry_md_write(hm, block + (i-1) * s->md_len, s->md_len);
-      if (dh_shared != NULL)
-	gcry_md_write(hm, dh_shared, dh_size);
-      gcry_md_write(hm, &protocol, 1);
-      gcry_md_write(hm, (uint8_t *)&spi, sizeof (spi));
-      gcry_md_write(hm, ni_data, ni_size);
-      gcry_md_write(hm, nr_data, nr_size);
-      gcry_md_final(hm);
-      memcpy(block + i * s->md_len, gcry_md_read(hm, 0), s->md_len);
-      gcry_md_close(hm);
+		unsigned long hash_len;
+		int smd = find_hash (get_hash (s->md_algo));
+		assert (smd != -1);
+		
+		hmac_init (&hmac, smd, s->skeyid_d, s->md_len);
+		if (i != 0) {
+			hmac_process (&hmac, block + (i-1) * s->md_len, s->md_len);
+		}
+		
+		if (dh_shared != NULL) {
+			hmac_process (&hmac, dh_shared, dh_size);
+		}
+		hmac_process (&hmac, &protocol, 1);
+		hmac_process (&hmac, (uint8_t *)&spi, sizeof spi);
+		hmac_process (&hmac, ni_data, ni_size);
+		hmac_process (&hmac, nr_data, nr_size);
+		hash_len = s->md_len;
+		hmac_done (&hmac, block + i * s->md_len, &hash_len);
     }
   return block;
 }
@@ -1669,7 +1797,7 @@
   memcpy (r->u.sa.proposals->u.p.spi, &s->tous_esp_spi, 4);
   r->u.sa.proposals->u.p.prot_id = ISAKMP_IPSEC_PROTO_IPSEC_ESP;
   for (crypt = 0; crypt < sizeof(supp_crypt) / sizeof(supp_crypt[0]); crypt++) {
-    if ((supp_crypt[crypt].my_id == GCRY_CIPHER_DES)&&(opt_1des == 0))
+    if ((supp_crypt[crypt].my_id == CIPHER_DES)&&(opt_1des == 0))
       continue;
     keylen = supp_crypt[crypt].keylen;
     for (hash = 0; hash < sizeof(supp_hash) / sizeof(supp_hash[0]); hash++) {
@@ -1709,10 +1837,11 @@
     dh_create_exchange(dh_grp, dh_public);
 hex_dump("dh_public", dh_public, dh_getlen (dh_grp));
   }
+
+  rng_get_bytes ((uint8_t *)&s->tous_esp_spi, sizeof s->tous_esp_spi, /* no callback */NULL);
   
-  gcry_randomize((uint8_t *)&s->tous_esp_spi, sizeof (s->tous_esp_spi), GCRY_WEAK_RANDOM);
   rp = make_our_sa_ipsec(s);
-  gcry_randomize((uint8_t *)nonce, sizeof (nonce), GCRY_WEAK_RANDOM);
+  rng_get_bytes ((uint8_t *)nonce, sizeof nonce, /* no callback */NULL);
   rp->next = new_isakmp_data_payload (ISAKMP_PAYLOAD_NONCE,
 				      nonce, sizeof (nonce));
   
@@ -1736,7 +1865,8 @@
     rp->next->next->next = us;
   }
 
-  gcry_randomize((uint8_t *)&msgid, sizeof (&msgid), GCRY_WEAK_RANDOM);
+  rng_get_bytes ((uint8_t *) &msgid, sizeof msgid, /* no callback */NULL);
+  /* XXXX gcry_randomize((uint8_t *)&msgid, sizeof (&msgid), GCRY_WEAK_RANDOM);*/
   if (msgid == 0)
     msgid = 1;
   
@@ -1920,7 +2050,7 @@
     struct isakmp_payload *d_isakmp, *d_ipsec;
     uint32_t del_msgid;
 
-    gcry_randomize((uint8_t *)&del_msgid, sizeof (del_msgid), GCRY_WEAK_RANDOM);
+	rng_get_bytes ((uint8_t *) &del_msgid, sizeof del_msgid, /* no callback */NULL);
     d_isakmp = new_isakmp_payload (ISAKMP_PAYLOAD_D);
     d_isakmp->u.d.doi = ISAKMP_DOI_IPSEC;
     d_isakmp->u.d.protocol = ISAKMP_IPSEC_PROTO_ISAKMP;
@@ -2179,7 +2309,7 @@
 	    break;
 	  }
       }
-      if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0)
+      if (config_names[i].name == NULL && line[0] != '#' && line[0] != 0 && opt_debug >= 3)
 	error(0, 0, "warning: unknown configuration directive in %s at line %d",
 	       name, linenum);
     }
@@ -2218,8 +2348,19 @@
   const uint8_t hex_test[] = { 0, 1, 2, 3};
   
   test_pack_unpack();
-  gcry_check_version("1.1.12");
-  gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 );
+
+  /* init libtomcrypt */
+  srand (time(NULL)); 						/* XXXXXX use real PRNG (seed) */
+  register_hash (&sha1_desc);
+  register_hash (&md5_desc);
+
+  register_cipher (&des_desc);
+  register_cipher (&des3_desc);
+  register_cipher (&aes_desc);
+
+  register_prng (&yarrow_desc);
+  
+  /* init other stuff */
   group_init();
   hex_dump("hex_test", hex_test, sizeof(hex_test));
 
@@ -2258,7 +2399,7 @@
 	    unsigned int i;
 	    
 	    printf ("vpnc version " VERSION "\n");
-	    printf ("Copyright (C) 2002, 2003 Geoffrey Keating, Maurice Massar\n");
+	    printf ("Copyright (C) 2002, 2003 Geoffrey Keating, Maurice Massar, Michael Weber\n");
 	    printf ("%s",
 "vpnc comes with NO WARRANTY, to the extent permitted by law.\n"
 "You may redistribute copies of vpnc under the terms of the GNU General\n"
