diff options
-rw-r--r-- | cipher/ChangeLog | 9 | ||||
-rw-r--r-- | cipher/elgamal.c | 148 | ||||
-rw-r--r-- | cipher/pubkey.c | 43 | ||||
-rw-r--r-- | mpi/ChangeLog | 7 | ||||
-rw-r--r-- | mpi/mpi-pow.c | 3 | ||||
-rw-r--r-- | mpi/mpiutil.c | 11 | ||||
-rw-r--r-- | src/cipher.h | 5 | ||||
-rw-r--r-- | tests/ChangeLog | 15 | ||||
-rw-r--r-- | tests/Makefile.am | 10 | ||||
-rw-r--r-- | tests/ac-data.c | 7 | ||||
-rw-r--r-- | tests/pubkey.c | 76 | ||||
-rw-r--r-- | tests/random.c | 255 |
12 files changed, 539 insertions, 50 deletions
diff --git a/cipher/ChangeLog b/cipher/ChangeLog index b8ff7c5a..9c1e5128 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -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 diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 066ffb61..4a76e910 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -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) { diff --git a/cipher/pubkey.c b/cipher/pubkey.c index a833c3dd..0b14cb80 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -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); diff --git a/mpi/ChangeLog b/mpi/ChangeLog index 9a1e9dd6..dc6556d2 100644 --- a/mpi/ChangeLog +++ b/mpi/ChangeLog @@ -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*. diff --git a/mpi/mpi-pow.c b/mpi/mpi-pow.c index 61a115f4..4f3d73e4 100644 --- a/mpi/mpi-pow.c +++ b/mpi/mpi-pow.c @@ -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); diff --git a/mpi/mpiutil.c b/mpi/mpiutil.c index d74a1f89..20e1ff02 100644 --- a/mpi/mpiutil.c +++ b/mpi/mpiutil.c @@ -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; } diff --git a/src/cipher.h b/src/cipher.h index 7aeaef6a..17002ab3 100644 --- a/src/cipher.h +++ b/src/cipher.h @@ -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); diff --git a/tests/ChangeLog b/tests/ChangeLog index 07d5af04..f7811626 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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. diff --git a/tests/Makefile.am b/tests/Makefile.am index 6539d885..b13e16b1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,14 +19,18 @@ ## 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. diff --git a/tests/ac-data.c b/tests/ac-data.c index fc4be8a5..792c3dc5 100644 --- a/tests/ac-data.c +++ b/tests/ac-data.c @@ -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)); } diff --git a/tests/pubkey.c b/tests/pubkey.c index f71590d9..a2a1f32a 100644 --- a/tests/pubkey.c +++ b/tests/pubkey.c @@ -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 index 00000000..502a3758 --- /dev/null +++ b/tests/random.c @@ -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; +} |