Ported last changes from 1.2.
authorWerner Koch <wk@gnupg.org>
Fri, 23 Feb 2007 17:47:56 +0000 (17:47 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 23 Feb 2007 17:47:56 +0000 (17:47 +0000)
Updated some tests.
Support for passphrase generated Elgamal keys.

12 files changed:
cipher/ChangeLog
cipher/elgamal.c
cipher/pubkey.c
mpi/ChangeLog
mpi/mpi-pow.c
mpi/mpiutil.c
src/cipher.h
tests/ChangeLog
tests/Makefile.am
tests/ac-data.c
tests/pubkey.c
tests/random.c [new file with mode: 0644]

index b8ff7c5..9c1e512 100644 (file)
@@ -1,3 +1,12 @@
+2007-02-23  Werner Koch  <wk@g10code.com>
+
+       * elgamal.c (generate): Removed unused variable TEMP.
+       (test_keys): New arg NODIE.
+       (generate_using_x, _gcry_elg_generate_using_x): New.
+       * pubkey.c (pubkey_generate): New arg XVALUE and direct call to
+       the new elgamal generate fucntion.
+       (gcry_pk_genkey): Parse the new "xvalue" tag.
+
 2007-02-22  Werner Koch  <wk@g10code.com>
 
        * pubkey.c (sexp_data_to_mpi): Handle dynamically allocated
index 066ffb6..4a76e91 100644 (file)
@@ -1,4 +1,4 @@
-/* Elgamal.c  -  ElGamal Public Key encryption
+/* Elgamal.c  -  Elgamal Public Key encryption
  * Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
@@ -47,7 +47,7 @@ typedef struct
 } ELG_secret_key;
 
 
-static void test_keys (ELG_secret_key *sk, unsigned nbits);
+static int test_keys (ELG_secret_key *sk, unsigned int nbits, int nodie);
 static gcry_mpi_t gen_k (gcry_mpi_t p, int small_k);
 static void generate (ELG_secret_key *sk, unsigned nbits, gcry_mpi_t **factors);
 static int  check_secret_key (ELG_secret_key *sk);
@@ -123,34 +123,46 @@ wiener_map( unsigned int n )
   return  n / 8 + 200;
 }
 
-static void
-test_keys( ELG_secret_key *sk, unsigned nbits )
+static int
+test_keys ( ELG_secret_key *sk, unsigned int nbits, int nodie )
 {
   ELG_public_key pk;
   gcry_mpi_t test = gcry_mpi_new ( 0 );
   gcry_mpi_t out1_a = gcry_mpi_new ( nbits );
   gcry_mpi_t out1_b = gcry_mpi_new ( nbits );
   gcry_mpi_t out2 = gcry_mpi_new ( nbits );
+  int failed = 0;
 
   pk.p = sk->p;
   pk.g = sk->g;
   pk.y = sk->y;
 
-  gcry_mpi_randomize( test, nbits, GCRY_WEAK_RANDOM );
+  gcry_mpi_randomize ( test, nbits, GCRY_WEAK_RANDOM );
 
-  do_encrypt( out1_a, out1_b, test, &pk );
-  decrypt( out2, out1_a, out1_b, sk );
-  if( mpi_cmp( test, out2 ) )
-    log_fatal("ElGamal operation: encrypt, decrypt failed\n");
+  do_encrypt ( out1_a, out1_b, test, &pk );
+  decrypt ( out2, out1_a, out1_b, sk );
+  if ( mpi_cmp( test, out2 ) )
+    failed |= 1;
 
-  sign( out1_a, out1_b, test, sk );
-  if( !verify( out1_a, out1_b, test, &pk ) )
-    log_fatal("ElGamal operation: sign, verify failed\n");
+  sign ( out1_a, out1_b, test, sk );
+  if ( !verify( out1_a, out1_b, test, &pk ) )
+    failed |= 2;
 
   gcry_mpi_release ( test );
   gcry_mpi_release ( out1_a );
   gcry_mpi_release ( out1_b );
   gcry_mpi_release ( out2 );
+
+  if (failed && !nodie)
+    log_fatal ("Elgamal test key for %s %s failed\n",
+               (failed & 1)? "encrypt+decrypt":"",
+               (failed & 2)? "sign+verify":"");
+  if (failed && DBG_CIPHER) 
+    log_debug ("Elgamal test key for %s %s failed\n",
+               (failed & 1)? "encrypt+decrypt":"",
+               (failed & 2)? "sign+verify":"");
+
+  return failed;
 }
 
 
@@ -239,7 +251,7 @@ gen_k( gcry_mpi_t p, int small_k )
 
 /****************
  * Generate a key pair with a key of size NBITS
- * Returns: 2 structures filles with all needed values
+ * Returns: 2 structures filled with all needed values
  *         and an array with n-1 factors of (p-1)
  */
 static void
@@ -250,13 +262,11 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors )
   gcry_mpi_t g;
   gcry_mpi_t x;    /* the secret exponent */
   gcry_mpi_t y;
-  gcry_mpi_t temp;
   unsigned int qbits;
   unsigned int xbits;
   byte *rndbuf;
 
   p_min1 = gcry_mpi_new ( nbits );
-  temp   = gcry_mpi_new( nbits );
   qbits = wiener_map( nbits );
   if( qbits & 1 ) /* better have a even one */
     qbits++;
@@ -332,11 +342,90 @@ generate ( ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t **ret_factors )
   sk->y = y;
   sk->x = x;
 
+  gcry_mpi_release ( p_min1 );
+
   /* Now we can test our keys (this should never fail!) */
-  test_keys( sk, nbits - 64 );
+  test_keys ( sk, nbits - 64, 0 );
+}
+
+
+/* Generate a key pair with a key of size NBITS not using a random
+   value for the secret key but the one given as X.  This is useful to
+   implement a passphrase based decryption for a public key based
+   encryption.  It has appliactions in backup systems.
+   Returns: A structure filled with all needed values and an array
+           with n-1 factors of (p-1).  */
+static gcry_err_code_t
+generate_using_x (ELG_secret_key *sk, unsigned int nbits, gcry_mpi_t x,
+                  gcry_mpi_t **ret_factors )
+{
+  gcry_mpi_t p;      /* The prime.  */
+  gcry_mpi_t p_min1; /* The prime minus 1.  */
+  gcry_mpi_t g;      /* The generator.  */
+  gcry_mpi_t y;      /* g^x mod p.  */
+  unsigned int qbits;
+  unsigned int xbits;
+
+  sk->p = NULL;
+  sk->g = NULL;
+  sk->y = NULL;
+  sk->x = NULL;
+
+  /* Do a quick check to see whether X is suitable.  */
+  xbits = mpi_get_nbits (x);
+  if ( xbits < 64 || xbits >= nbits )
+    return GPG_ERR_INV_VALUE;
+
+  p_min1 = gcry_mpi_new ( nbits );
+  qbits  = wiener_map ( nbits );
+  if ( (qbits & 1) ) /* Better have an even one.  */
+    qbits++;
+  g = mpi_alloc (1);
+  p = _gcry_generate_elg_prime ( 0, nbits, qbits, g, ret_factors );
+  mpi_sub_ui (p_min1, p, 1);
+
+  if (DBG_CIPHER)
+    log_debug ("using a supplied x of size %u", xbits );
+  if ( !(mpi_cmp_ui ( x, 0 ) > 0 && mpi_cmp ( x, p_min1 ) <0 ) )
+    {
+      gcry_mpi_release ( p_min1 );
+      gcry_mpi_release ( p );
+      gcry_mpi_release ( g );
+      return GPG_ERR_INV_VALUE;
+    }
+
+  y = gcry_mpi_new (nbits);
+  gcry_mpi_powm ( y, g, x, p );
+
+  if ( DBG_CIPHER ) 
+    {
+      progress ('\n');
+      log_mpidump ("elg  p= ", p );
+      log_mpidump ("elg  g= ", g );
+      log_mpidump ("elg  y= ", y );
+      log_mpidump ("elg  x= ", x );
+    }
+
+  /* Copy the stuff to the key structures */
+  sk->p = p;
+  sk->g = g;
+  sk->y = y;
+  sk->x = gcry_mpi_copy (x);
 
   gcry_mpi_release ( p_min1 );
-  gcry_mpi_release ( temp   );
+
+  /* Now we can test our keys. */
+  if ( test_keys ( sk, nbits - 64, 1 ) )
+    {
+      gcry_mpi_release ( sk->p ); sk->p = NULL;
+      gcry_mpi_release ( sk->g ); sk->g = NULL;
+      gcry_mpi_release ( sk->y ); sk->y = NULL;
+      gcry_mpi_release ( sk->x ); sk->x = NULL;
+      return GPG_ERR_BAD_SECKEY;
+    }
+
+  return 0;
 }
 
 
@@ -523,7 +612,7 @@ verify(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_public_key *pkey )
  *********************************************/
 
 gcry_err_code_t
-_gcry_elg_generate (int algo, unsigned nbits, unsigned long dummy,
+_gcry_elg_generate (int algo, unsigned int nbits, unsigned long dummy,
                     gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   ELG_secret_key sk;
@@ -541,6 +630,29 @@ _gcry_elg_generate (int algo, unsigned nbits, unsigned long dummy,
 }
 
 
+/* This is a specila generate function which is not called via the
+   module interface.  */
+gcry_err_code_t
+_gcry_elg_generate_using_x (int algo, unsigned int nbits, gcry_mpi_t x,
+                            gcry_mpi_t *skey, gcry_mpi_t **retfactors)
+{
+  gcry_err_code_t ec;
+  ELG_secret_key sk;
+
+  (void)algo;
+
+  ec = generate_using_x (&sk, nbits, x, retfactors);
+  if (!ec)
+    {
+      skey[0] = sk.p;
+      skey[1] = sk.g;
+      skey[2] = sk.y;
+      skey[3] = sk.x;
+    }
+  return ec;
+}
+
+
 gcry_err_code_t
 _gcry_elg_check_secret_key (int algo, gcry_mpi_t *skey)
 {
index a833c3d..0b14cb8 100644 (file)
@@ -497,7 +497,7 @@ pubkey_get_nenc (int algorithm)
 
 static gcry_err_code_t
 pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
-                 unsigned long use_e,
+                 unsigned long use_e, gcry_mpi_t xvalue,
                  gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO;
@@ -511,11 +511,22 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
     {
       /* Hack to pass QBITS to the DSA generation.  */
       if (qbits && pubkey->spec == &_gcry_pubkey_spec_dsa)
-        err = _gcry_dsa_generate2
-          (algorithm, nbits, qbits, 0, skey, retfactors);
+        {
+          err = _gcry_dsa_generate2
+            (algorithm, nbits, qbits, 0, skey, retfactors);
+        }
+#ifdef USE_ELGAMAL
+      else if (xvalue && pubkey->spec == &_gcry_pubkey_spec_elg)
+        {
+          err = _gcry_elg_generate_using_x
+            (algorithm, nbits, xvalue, skey, retfactors);
+        }
+#endif /*USE_ELGAMAL*/
       else
-        err = ((gcry_pk_spec_t *) pubkey->spec)->generate 
-          (algorithm, nbits, use_e, skey, retfactors);
+        {
+          err = ((gcry_pk_spec_t *) pubkey->spec)->generate 
+            (algorithm, nbits, use_e, skey, retfactors);
+        }
       _gcry_module_release (pubkey);
     }
   ath_mutex_unlock (&pubkeys_registered_lock);
@@ -1918,6 +1929,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   unsigned int nbits = 0;
   unsigned long use_e = 0;
   unsigned int qbits;
+  gcry_mpi_t xvalue = NULL;
   char *name_terminated;
 
   REGISTER_DEFAULT_PUBKEYS;
@@ -2018,6 +2030,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   else
     qbits = 0;
 
+  /* Parse the optional xvalue element. */
+  l2 = gcry_sexp_find_token (list, "xvalue", 0);
+  if (l2)
+    {
+      xvalue = gcry_sexp_nth_mpi (l2, 1, 0);
+      if (!xvalue)
+        {
+          rc = GPG_ERR_BAD_MPI;
+          goto leave;
+        }
+    }
+
   /* Now parse the required nbits element. */
   l2 = gcry_sexp_find_token (list, "nbits", 0);
   gcry_sexp_release (list);
@@ -2048,7 +2072,8 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   nbits = (unsigned int) strtoul (name_terminated, NULL, 0);
   gcry_free (name_terminated);
 
-  rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, skey, &factors);
+  rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, xvalue,
+                        skey, &factors);
   if (rc)
     goto leave;
 
@@ -2140,7 +2165,9 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
  leave:
   release_mpi_array (skey);
   /* Don't free SKEY itself, it is a static array. */
-    
+
+  gcry_mpi_release (xvalue);
+  
   if (factors)
     {
       release_mpi_array ( factors );
@@ -2151,7 +2178,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
     gcry_sexp_release (l2);
   if (list)
     gcry_sexp_release (list);
-  
+
   if (module)
     {
       ath_mutex_lock (&pubkeys_registered_lock);
index 9a1e9dd..dc6556d 100644 (file)
@@ -1,3 +1,10 @@
+2007-02-23  Werner Koch  <wk@g10code.com>
+
+       * mpi-pow.c (gcry_mpi_powm): Remove unused var ESIGN.
+
+       * mpiutil.c (gcry_mpi_get_flag): Let it return a value to silent
+       MIPSpro cc warning.
+
 2007-02-21  Werner Koch  <wk@g10code.com>
 
        * mpicoder.c (_gcry_mpi_set_buffer): Made BUFFER a void*.
index 61a115f..4f3d73e 100644 (file)
@@ -41,7 +41,7 @@ gcry_mpi_powm( gcry_mpi_t res, gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod)
 {
     mpi_ptr_t  rp, ep, mp, bp;
     mpi_size_t esize, msize, bsize, rsize;
-    int        esign, msign, bsign, rsign;
+    int               msign, bsign, rsign;
     int        esec,  msec,  bsec,  rsec;
     mpi_size_t size;
     int mod_shift_cnt;
@@ -58,7 +58,6 @@ gcry_mpi_powm( gcry_mpi_t res, gcry_mpi_t base, gcry_mpi_t expo, gcry_mpi_t mod)
     esize = expo->nlimbs;
     msize = mod->nlimbs;
     size = 2 * msize;
-    esign = expo->sign;
     msign = mod->sign;
 
     esec = mpi_is_secure(expo);
index d74a1f8..20e1ff0 100644 (file)
@@ -463,10 +463,13 @@ gcry_mpi_clear_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 int
 gcry_mpi_get_flag( gcry_mpi_t a, enum gcry_mpi_flag flag )
 {
-    switch( flag ) {
-      case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
-      case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
-      default: log_bug("invalid flag value\n");
+  switch (flag)
+    {
+    case GCRYMPI_FLAG_SECURE: return (a->flags & 1);
+    case GCRYMPI_FLAG_OPAQUE: return (a->flags & 4);
+    default: log_bug("invalid flag value\n");
     }
+  /*NOTREACHED*/
+  return 0;
 }
 
index 7aeaef6..17002ab 100644 (file)
@@ -45,6 +45,11 @@ gcry_err_code_t _gcry_dsa_generate2 (int algo, unsigned int nbits,
 
 /*-- elgamal.c --*/
 void _gcry_register_pk_elg_progress (gcry_handler_progress_t cb, void *cb_data);
+gcry_err_code_t _gcry_elg_generate_using_x (int algo, unsigned int nbits,
+                                            gcry_mpi_t x, 
+                                            gcry_mpi_t *skey,
+                                            gcry_mpi_t **retfactors);
+
 /*-- primegen.c --*/
 void _gcry_register_primegen_progress (gcry_handler_progress_t cb, void *cb_data);
 
index 07d5af0..f781162 100644 (file)
@@ -1,3 +1,18 @@
+2007-02-23  Werner Koch  <wk@g10code.com>
+
+       * Makefile.am (TEST): Run benchmark as last. 
+
+       * ac-data.c (check_sexp_conversion): Print label only in verbose
+       mode.
+
+       * pubkey.c (main): Run test just 2 times instead of 10.
+       (get_elg_key_new): New.
+       (check_run): Also run tests with Elgamal keys.
+       (check_keys): New arg NBITS_DATA.
+       (get_elg_key_new): Use only 400 for the 512 bit Elgamal test.
+
+       * random.c: New.
+
 2007-02-22  Werner Koch  <wk@g10code.com>
 
        * basic.c (check_pubkey_sign): Also try signing using an OID.
index 6539d88..b13e16b 100644 (file)
 ## Process this file with automake to produce Makefile.in
 
 TESTS = t-mpi-bit prime register ac ac-schemes ac-data basic \
-        tsexp keygen pubkey benchmark hmac keygrip
+        tsexp keygen pubkey hmac keygrip
 
 # pkbench uses mmap for no good reason.  Needs to be fixed.  Code for
-# this can be found in libksba/tests.
+# this can be found in libksba/tests. 
+# random tests forking thus no a test for W32 does not make any sense.
 if !HAVE_W32_SYSTEM
-TESTS += pkbench 
+TESTS += pkbench random
 endif
 
+# The last test to run.
+TESTS += benchmark
+
 
 # Need to include ../src in addition to top_srcdir because gcrypt.h is
 # a built header.
index fc4be8a..792c3dc 100644 (file)
@@ -78,8 +78,11 @@ check_sexp_conversion (gcry_ac_data_t data, const char **identifiers)
       assert_err (err);
       err = gcry_ac_data_get_index (data2, 0, i, &label2, &mpi2);
       assert_err (err);
-      fprintf (stderr, "Label1=`%s'\n", label1);
-      fprintf (stderr, "Label1=`%s'\n", label2);
+      if (verbose)
+        {
+          fprintf (stderr, "Label1=`%s'\n", label1);
+          fprintf (stderr, "Label2=`%s'\n", label2);
+        }
       assert (! strcmp (label1, label2));
       assert (! gcry_mpi_cmp (mpi1, mpi2));
     }
index f71590d..a2a1f32 100644 (file)
@@ -63,7 +63,6 @@ static const char sample_public_key_1[] =
 " )\n"
 ")\n";
 
-#define RANDOM_DATA_NBITS 800
 
 static int verbose;
 
@@ -134,15 +133,15 @@ check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
 }
 
 static void
-check_keys (gcry_sexp_t pkey, gcry_sexp_t skey)
+check_keys (gcry_sexp_t pkey, gcry_sexp_t skey, unsigned int nbits_data)
 {
   gcry_sexp_t plain;
   gcry_mpi_t x;
   int rc;
   
   /* Create plain text.  */
-  x = gcry_mpi_new (RANDOM_DATA_NBITS);
-  gcry_mpi_randomize (x, RANDOM_DATA_NBITS, GCRY_WEAK_RANDOM);
+  x = gcry_mpi_new (nbits_data);
+  gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM);
   
   rc = gcry_sexp_build (&plain, NULL, "(data (flags raw) (value %m))", x);
   if (rc)
@@ -154,10 +153,11 @@ check_keys (gcry_sexp_t pkey, gcry_sexp_t skey)
   gcry_mpi_release (x);
 
   /* Create plain text.  */
-  x = gcry_mpi_new (RANDOM_DATA_NBITS);
-  gcry_mpi_randomize (x, RANDOM_DATA_NBITS, GCRY_WEAK_RANDOM);
+  x = gcry_mpi_new (nbits_data);
+  gcry_mpi_randomize (x, nbits_data, GCRY_WEAK_RANDOM);
   
-  rc = gcry_sexp_build (&plain, NULL, "(data (flags raw no-blinding) (value %m))", x);
+  rc = gcry_sexp_build (&plain, NULL, 
+                        "(data (flags raw no-blinding) (value %m))", x);
   if (rc)
     die ("converting data for encryption failed: %s\n",
         gcry_strerror (rc));
@@ -212,20 +212,70 @@ get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   *skey = sec_key;
 }
 
+
+static void
+get_elg_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int fixed_x)
+{
+  gcry_sexp_t key_spec, key, pub_key, sec_key;
+  int rc;
+
+  rc = gcry_sexp_new 
+    (&key_spec, 
+     (fixed_x
+      ? "(genkey (elg (nbits 4:1024)(xvalue my.not-so-secret.key)))"
+      : "(genkey (elg (nbits 3:512)))"),
+     0, 1);
+
+  if (rc)
+    die ("error creating S-expression: %s\n", gcry_strerror (rc));
+  rc = gcry_pk_genkey (&key, key_spec);
+  gcry_sexp_release (key_spec);
+  if (rc)
+    die ("error generating Elgamal key: %s\n", gcry_strerror (rc));
+    
+  pub_key = gcry_sexp_find_token (key, "public-key", 0);
+  if (!pub_key)
+    die ("public part missing in key\n");
+
+  sec_key = gcry_sexp_find_token (key, "private-key", 0);
+  if (!sec_key)
+    die ("private part missing in key\n");
+
+  gcry_sexp_release (key);
+  *pkey = pub_key;
+  *skey = sec_key;
+}
+
 static void
 check_run (void)
 {
   gcry_sexp_t pkey, skey;
 
-  /* Check sample keys.  */
+  if (verbose)
+    fprintf (stderr, "Checking sample key.\n");
   get_keys_sample (&pkey, &skey);
-  check_keys (pkey, skey);
+  check_keys (pkey, skey, 800);
   gcry_sexp_release (pkey);
   gcry_sexp_release (skey);
   
-  /* Check newly generated keys.  */
+  if (verbose)
+    fprintf (stderr, "Checking generated RSA key.\n");
   get_keys_new (&pkey, &skey);
-  check_keys (pkey, skey);
+  check_keys (pkey, skey, 800);
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
+
+  if (verbose)
+    fprintf (stderr, "Checking generated Elgamal key.\n");
+  get_elg_key_new (&pkey, &skey, 0);
+  check_keys (pkey, skey, 400 );
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
+
+  if (verbose)
+    fprintf (stderr, "Checking passphrase generated Elgamal key.\n");
+  get_elg_key_new (&pkey, &skey, 1);
+  check_keys (pkey, skey, 800);
   gcry_sexp_release (pkey);
   gcry_sexp_release (skey);
 }
@@ -234,7 +284,7 @@ int
 main (int argc, char **argv)
 {
   int debug = 0;
-  int i = 10;
+  int i;
 
   if (argc > 1 && !strcmp (argv[1], "--verbose"))
     verbose = 1;
@@ -250,7 +300,7 @@ main (int argc, char **argv)
   /* No valuable keys are create, so we can speed up our RNG. */
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
-  for (; i > 0; i--)
+  for (i=0; i < 2; i++)
     check_run ();
   
   return 0;
diff --git a/tests/random.c b/tests/random.c
new file mode 100644 (file)
index 0000000..502a375
--- /dev/null
@@ -0,0 +1,255 @@
+/* random.c - part of the Libgcrypt test suite.
+   Copyright (C) 2005 Free Software Foundation, Inc.
+
+   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 of the
+   License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+   USA.  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "../src/gcrypt.h"
+
+static int verbose;
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  exit (1);
+}
+
+
+static void
+print_hex (const char *text, const void *buf, size_t n)
+{
+  const unsigned char *p = buf;
+
+  fputs (text, stdout);
+  for (; n; n--, p++)
+    printf ("%02X", *p);
+  putchar ('\n');
+}
+
+
+static int
+writen (int fd, const void *buf, size_t nbytes)
+{
+  size_t nleft = nbytes;
+  int nwritten;
+  
+  while (nleft > 0)
+    {
+      nwritten = write (fd, buf, nleft);
+      if (nwritten < 0)
+        {
+          if (errno == EINTR)
+            nwritten = 0;
+          else 
+            return -1;
+        }
+      nleft -= nwritten;
+      buf = (const char*)buf + nwritten;
+    }
+    
+  return 0;
+}
+
+static int
+readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
+{
+  size_t nleft = buflen;
+  int nread;
+  char *p;
+  
+  p = buf;
+  while ( nleft > 0 )
+    {
+      nread = read ( fd, buf, nleft );
+      if (nread < 0)
+        {
+          if (nread == EINTR)
+            nread = 0;
+          else 
+            return -1;
+        }
+      else if (!nread)
+        break; /* EOF */
+      nleft -= nread;
+      buf = (char*)buf + nread;
+    }
+  if (ret_nread)
+    *ret_nread = buflen - nleft;
+  return 0;
+}
+
+
+
+/* Check that forking won't return the same random. */
+static void
+check_forking (void)
+{
+  pid_t pid;
+  int rp[2];
+  int i, status;
+  size_t nread;
+  char tmp1[16], tmp1c[16], tmp1p[16];
+  
+  /* We better make sure that the RNG has been initialzied. */
+  gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+  if (verbose)
+    print_hex ("initial random: ", tmp1, sizeof tmp1);
+
+  if (pipe (rp) == -1)
+    die ("pipe failed: %s\n", strerror (errno));
+
+  pid = fork ();
+  if (pid == (pid_t)(-1))
+    die ("fork failed: %s\n", strerror (errno));
+  if (!pid)
+    {
+      gcry_randomize (tmp1c, sizeof tmp1c, GCRY_STRONG_RANDOM);
+      if (writen (rp[1], tmp1c, sizeof tmp1c))
+        die ("write failed: %s\n", strerror (errno));
+      if (verbose)
+        {
+          print_hex ("  child random: ", tmp1c, sizeof tmp1c);
+          fflush (stdout);
+        }
+      _exit (0);
+    }
+  gcry_randomize (tmp1p, sizeof tmp1p, GCRY_STRONG_RANDOM);
+  if (verbose)
+    print_hex (" parent random: ", tmp1p, sizeof tmp1p);
+
+  close (rp[1]);
+  if (readn (rp[0], tmp1c, sizeof tmp1c, &nread))
+    die ("read failed: %s\n", strerror (errno)); 
+  if (nread != sizeof tmp1c)
+    die ("read too short\n");
+
+  while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+    ;
+  if (i != (pid_t)(-1)
+      && WIFEXITED (status) && !WEXITSTATUS (status))
+    ;
+  else
+    die ("child failed\n");
+
+  if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
+    die ("parent and child got the same random number\n");
+}
+
+
+
+/* Check that forking won't return the same nonce. */
+static void
+check_nonce_forking (void)
+{
+  pid_t pid;
+  int rp[2];
+  int i, status;
+  size_t nread;
+  char nonce1[10], nonce1c[10], nonce1p[10];
+  
+  /* We won't get the same nonce back if we never initialized the
+     nonce subsystem, thus we get one nonce here and forget about
+     it. */
+  gcry_create_nonce (nonce1, sizeof nonce1);
+  if (verbose)
+    print_hex ("initial nonce: ", nonce1, sizeof nonce1);
+
+  if (pipe (rp) == -1)
+    die ("pipe failed: %s\n", strerror (errno));
+
+  pid = fork ();
+  if (pid == (pid_t)(-1))
+    die ("fork failed: %s\n", strerror (errno));
+  if (!pid)
+    {
+      gcry_create_nonce (nonce1c, sizeof nonce1c);
+      if (writen (rp[1], nonce1c, sizeof nonce1c))
+        die ("write failed: %s\n", strerror (errno));
+      if (verbose)
+        {
+          print_hex ("  child nonce: ", nonce1c, sizeof nonce1c);
+          fflush (stdout);
+        }
+      _exit (0);
+    }
+  gcry_create_nonce (nonce1p, sizeof nonce1p);
+  if (verbose)
+    print_hex (" parent nonce: ", nonce1p, sizeof nonce1p);
+
+  close (rp[1]);
+  if (readn (rp[0], nonce1c, sizeof nonce1c, &nread))
+    die ("read failed: %s\n", strerror (errno)); 
+  if (nread != sizeof nonce1c)
+    die ("read too short\n");
+
+  while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+    ;
+  if (i != (pid_t)(-1)
+      && WIFEXITED (status) && !WEXITSTATUS (status))
+    ;
+  else
+    die ("child failed\n");
+
+  if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
+    die ("parent and child got the same nonce\n");
+}
+
+
+
+
+
+
+int
+main (int argc, char **argv)
+{
+  int debug = 0;
+
+  if ((argc > 1) && (! strcmp (argv[1], "--verbose")))
+    verbose = 1;
+  else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
+    verbose = debug = 1;
+
+  signal (SIGPIPE, SIG_IGN);
+
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+
+  check_forking ();
+  check_nonce_forking ();
+
+  return 0;
+}