See ChangeLog: Fri Jul 14 19:38:23 CEST 2000 Werner Koch
authorWerner Koch <wk@gnupg.org>
Fri, 14 Jul 2000 17:34:52 +0000 (17:34 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 14 Jul 2000 17:34:52 +0000 (17:34 +0000)
35 files changed:
ChangeLog
acconfig.h
acinclude.m4
cipher/ChangeLog
cipher/Makefile.am
cipher/blowfish.c
cipher/cast5.c
cipher/des.c
cipher/dsa.c
cipher/elgamal.c
cipher/md.c
cipher/md5.c
cipher/primegen.c
cipher/pubkey.c
cipher/random.c
cipher/rmd160.c
cipher/rndegd.c
cipher/rndunix.c
cipher/rndw32.c
cipher/rsa.c [new file with mode: 0644]
cipher/rsa.h [new file with mode: 0644]
cipher/sha1.c
cipher/tiger.c
cipher/twofish.c
configure.in
jnlib/ChangeLog
jnlib/argparse.c
jnlib/dotlock.c
jnlib/dotlock.h
src/ChangeLog
src/Makefile.am
src/gcrypt-config.in
src/gcrypt.h
src/secmem.c
src/sexp.c

index e0091e2..d33da81 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,69 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  The big merge between this one and the stable branch 1.0.  Still need
+  to merge TNANKS, AUTHORS and such.  It probaly does not compile yet.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Fixed syntax error in C code.
+
+  * configure.in: Add check for termio.h, wait unctiosn and sigaction.
+
+  * acinclude.m4, configure.in (GNUPG_CHECK_GNUMAKE): New.
+
+  * acinclude.m4 (MKDIR_TAKES_ONE_ARG): Check some headers. By Gaël Quéri.
+
+  * configure.in (AM_INIT_AUTOMAKE): Use this now. By Gaël.
+
+  * acinclude.m4 (GNUPG_CHECK_EXPORTDYNAMIC): Replacement for
+  GNUPG_CHECK_RDYNAMIC which should handle gcc with non GNU ld nicer.
+  Contributed by Dave Dykstra.
+  * configure.in (GNYPG_CHECK_RDYNAMIC): Replaced by the new check.
+
+  * configure.in: Add a test for unisgned long long.
+
+  * configure.in (DYNLINK_MOD_CFLAGS): Set different for NetBSD.
+
+  * configure.in: Add check for clock_gettime
+
+  * configure.in (ALL_LINGUAS): Add nl.
+  * configure.in (ALL_LINGUAS): Add Esperanto.
+  * configure.in (ALL_LINGUAS): Add sv and ja.
+
+  * configure.in: Use /usr/local for CFLAGS and LDFLAGS when
+  target is freebsd.  By Rémi.
+
+  * configure.in: Do not set development version when the version has
+  a dash in it.  Suggested by Dave Dykstra.
+
+  * configure.in: Removed substitution for doc/gph/Makefile.
+  Do all the gcc warning only in maintainer mode.
+
+  * configure.in (dlopen): Use CHECK_FUNC for a test of dlopen in libc.
+  Suggested by Alexandre Oliva.
+  (-Wall): Moved the settting of gcc warning options near to the end
+  so that tests don't get confused.  Suggested by Paul D. Smith.
+
+  * acinclude.m4 (GNUPG_SYS_NM_PARSE): Added BSDI support.
+  (GNUPG_CHECK_RDYNAMIC): Ditto.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Changed the way to test for
+  librt.  Test suggested by Jeff Long.
+
+  * acinclude.m4 (GNUPG_CHECK_MLOCK): Do librt check only when
+  we can't link a test program.  This way GNU systems don't need
+  to link against linrt.
+  (GNUPG_CHECK_IPC): Fixed use of TRY_COMPILE macro.  From Tim Mooney.
+
+  * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add support for
+  DJGPP.
+  (GNUPG_CHECK_MLOCK): Check whether mlock sits in librt.
+
+  * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Add NetBSD. By Thomas Klausner.
+
+  * acconfig.h (HAVE_MLOCK): Added
+
 Mon Mar 13 19:22:46 CET 2000  Werner Koch  <wk@openit.de>
 
-       * configure.in: Now uses the Docbook M$s from GPH.
+       * configure.in: Now uses the Docbook M4s from GPH.
 
 Mon Jan 31 17:46:35 CET 2000  Werner Koch  <wk@>
 
index d364c7b..a2c9128 100644 (file)
@@ -53,6 +53,8 @@
 
 #undef HAVE_STPCPY
 
+#undef HAVE_MLOCK
+
 
 #undef BIG_ENDIAN_HOST
 #undef LITTLE_ENDIAN_HOST
index 20c92be..9f8bfd0 100644 (file)
@@ -50,6 +50,25 @@ AC_DEFUN(GNUPG_FIX_HDR_VERSION,
   ])
 
 
+dnl GNUPG_CHECK_GNUMAKE
+dnl
+AC_DEFUN(GNUPG_CHECK_GNUMAKE,
+  [
+    if ${MAKE-make} --version 2>/dev/null | grep '^GNU ' >/dev/null 2>&1; then
+        :
+    else
+        AC_MSG_WARN([[
+***
+*** It seems that you are not using GNU make.  Some make tools have serious
+*** flaws and you may not be able to build this software at all. Before you
+*** complain, please try GNU make:  GNU make is easy to build and available
+*** at all GNU archives.  It is always available from ftp.gnu.org:/gnu/make.
+***]])
+    fi
+  ])
+
+
+
 dnl GNUPG_LINK_FILES( SRC, DEST )
 dnl same as AC_LINK_FILES, but collect the files to link in
 dnl some special variables and do the link
@@ -212,39 +231,38 @@ define(GNUPG_CHECK_PIC,
 
 
 ######################################################################
-# Check for rdynamic flag
-# This sets CFLAGS_RDYNAMIC to the required flags
+# Check for export-dynamic flag
+# This sets CFLAGS_EXPORTDYNAMIC to the required flags
 ######################################################################
-dnl GNUPG_CHECK_RDYNAMIC
+dnl GNUPG_CHECK_EXPORTDYNAMIC
 dnl
-define(GNUPG_CHECK_RDYNAMIC,
-  [ AC_MSG_CHECKING(how to specify -rdynamic)
-    CFLAGS_RDYNAMIC=
+define(GNUPG_CHECK_EXPORTDYNAMIC,
+  [ AC_MSG_CHECKING(how to specify -export-dynamic)
     if test "$cross_compiling" = yes; then
-        AC_MSG_RESULT(assume none)
+      AC_MSG_RESULT(assume none)
+      CFLAGS_EXPORTDYNAMIC=""
     else
-        case "$host_os" in
-          solaris* )
-            CFLAGS_RDYNAMIC="-Wl,-dy"
-            ;;
-
-          hpux* )
-            CFLAGS_RDYNAMIC="-Wl,-E"
-            ;;
-
-          openbsd* | freebsd2* | osf4* | irix* )
-            CFLAGS_RDYNAMIC=""
-            ;;
-
-          * )
-            CFLAGS_RDYNAMIC="-Wl,-export-dynamic"
-            ;;
-        esac
-        AC_MSG_RESULT($CFLAGS_RDYNAMIC)
+      AC_CACHE_VAL(gnupg_cv_export_dynamic,[
+      if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 |
+                                          grep "GNU ld" >/dev/null]); then
+          # using gnu's linker
+          gnupg_cv_export_dynamic="-Wl,-export-dynamic"
+      else
+          case "$host_os" in
+            hpux* )
+              gnupg_cv_export_dynamic="-Wl,-E"
+              ;;
+            * )
+              gnupg_cv_export_dynamic=""
+              ;;
+          esac
+      fi
+      ])
+      AC_MSG_RESULT($gnupg_cv_export_dynamic)
+      CFLAGS_EXPORTDYNAMIC="$gnupg_cv_export_dynamic"
     fi
   ])
 
-
 #####################################################################
 # Check for SysV IPC  (from GIMP)
 #   And see whether we have a SHM_LOCK (FreeBSD does not have it).
@@ -299,7 +317,8 @@ define(GNUPG_CHECK_IPC,
           AC_TRY_COMPILE([#include <sys/types.h>
              #include <sys/ipc.h>
              #include <sys/shm.h>],[
-             int foo( int shm_id ) {  shmctl(shm_id, SHM_LOCK, 0); }
+             int shm_id;
+             shmctl(shm_id, SHM_LOCK, 0);
              ],
              gnupg_cv_ipc_have_shm_lock="yes",
              gnupg_cv_ipc_have_shm_lock="no"
@@ -318,11 +337,46 @@ define(GNUPG_CHECK_IPC,
 ######################################################################
 # Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock
 # is not called from uid 0 (not tested whether uid 0 works)
+# For DECs Tru64 we have also to check whether mlock is in librt
+# mlock is there a macro using memlk()
 ######################################################################
 dnl GNUPG_CHECK_MLOCK
 dnl
 define(GNUPG_CHECK_MLOCK,
   [ AC_CHECK_FUNCS(mlock)
+    if test "$ac_cv_func_mlock" = "no"; then
+        AC_CHECK_HEADERS(sys/mman.h)
+        if test "$ac_cv_header_sys_mman_h" = "yes"; then
+            # Add librt to LIBS:
+            AC_CHECK_LIB(rt, memlk)
+            AC_CACHE_CHECK([whether mlock is in sys/mman.h],
+                            gnupg_cv_mlock_is_in_sys_mman,
+                [AC_TRY_LINK([
+                    #include <assert.h>
+                    #ifdef HAVE_SYS_MMAN_H
+                    #include <sys/mman.h>
+                    #endif
+                ], [
+                    int i;
+                    mkdir ("foo", 0);
+                    /* glibc defines this for functions which it implements
+                     * to always fail with ENOSYS.  Some functions are actually
+                     * named something starting with __ and the normal name
+                     * is an alias.  */
+                    #if defined (__stub_mlock) || defined (__stub___mlock)
+                    choke me
+                    #else
+                    mlock(&i, 4);
+                    #endif
+                    ; return 0;
+                ],
+                gnupg_cv_mlock_is_in_sys_mman=yes,
+                gnupg_cv_mlock_is_in_sys_mman=no)])
+            if test "$gnupg_cv_mlock_is_in_sys_mman" = "yes"; then
+                AC_DEFINE(HAVE_MLOCK)
+            fi
+        fi
+    fi
     if test "$ac_cv_func_mlock" = "yes"; then
         AC_MSG_CHECKING(whether mlock is broken)
           AC_CACHE_VAL(gnupg_cv_have_broken_mlock,
@@ -372,9 +426,10 @@ define(GNUPG_CHECK_MLOCK,
   ])
 
 
-################################################################
 
+################################################################
 # GNUPG_PROG_NM - find the path to a BSD-compatible name lister
+################################################################
 AC_DEFUN(GNUPG_PROG_NM,
 [AC_MSG_CHECKING([for BSD-compatible nm])
 AC_CACHE_VAL(ac_cv_path_NM,
@@ -433,7 +488,7 @@ case "$host_os" in
 aix*)
   ac_symcode='[BCDTU]'
   ;;
-freebsd* | netbsd* | openbsd* | sunos* | cygwin32* | mingw32*)
+freebsd* | netbsd* | openbsd* | bsdi* | sunos* | cygwin32* | mingw32*)
   ac_sympat='_\([_A-Za-z][_A-Za-z0-9]*\)'
   ac_symxfrm='_\1 \1'
   ;;
@@ -586,7 +641,7 @@ AC_CHECK_TOOL(AS, as, false)
 AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE,
 [tmp_do_check="no"
 case "${target}" in
-    i386-emx-os2 | i[3456]86-pc-os2*emx )
+    i386-emx-os2 | i[3456]86-pc-os2*emx | i386-pc-msdosdjgpp)
         ac_cv_sys_symbol_underscore=yes
         ;;
     *)
@@ -645,7 +700,8 @@ dnl Stolen from gcc
 dnl Define MKDIR_TAKES_ONE_ARG if mkdir accepts only one argument instead
 dnl of the usual 2.
 AC_DEFUN(GNUPG_FUNC_MKDIR_TAKES_ONE_ARG,
-[AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
+[AC_CHECK_HEADERS(sys/stat.h unistd.h direct.h)
+AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
 [AC_TRY_COMPILE([
 #include <sys/types.h>
 #ifdef HAVE_SYS_STAT_H
@@ -663,7 +719,6 @@ if test $gnupg_cv_mkdir_takes_one_arg = yes ; then
 fi
 ])
 
-
 dnl GPH_PROG_DOCBOOK()
 dnl Check whether we have the needed Docbook environment
 dnl and issue a warning if this is not the case.
index 49595a9..877a2ad 100644 (file)
@@ -1,3 +1,85 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  * md.c (gcry_md_ctl): Support GCRYCTL_{START,STOP}_DUMP.
+
+  * Makefile.am: Never compile mingw32 as module.
+
+  * Makefile.am: Tweaked module build and removed libtool
+
+  * Makefile.am:  Replaced -O1 by -O. Suggested by Alec Habig.
+
+  * elgamal.c (sign): Removed inactive code.
+
+  * rsa.c, rsa.h: New based on the old module version (only in CVS for now).
+  * pubkey.c (setup_pubkey_table): Added commented support for RSA.
+
+  * rndunix.c (waitpid): New. For UTS 2.1.  All by Dave Dykstra.
+  (my_popen): Do the FD_CLOEXEC only if it is available
+  (start_gatherer): Cope with missing _SC_OPEN_MAX
+
+  * rndunix.c: Add some more headers for QNX. By Sam Roberts.
+
+  * rndegd.c (gather_random): Shortcut level 0.
+  * rndunix.c (gather_random): Ditto.
+  * rndw32.c (gather_random): Ditto.
+
+  * rndw32.c: Replaced with code from Cryptlib and commented the old stuff.
+  * rndw32.c: Add some debuging code enabled by an environment variable.
+
+  * random.c (read_seed_file): Binary open for DOSish system
+  (update_random_seed_file): Ditto.
+  * random.c [MINGW32]: Include process.h for getpid.
+  * random.c (fast_random_poll): Add clock_gettime() as fallback for
+  system which support this POSIX.4 fucntion. By Sam Roberts.
+
+  * random.c (read_seed_file): Removed the S_ISLNK test becuase it
+  is already covered by !S_ISREG and is not defined in Unixware.
+  Reported by Dave Dykstra.
+  (update_random_seed_file): Silently ignore update request when pool
+  is not filled.
+
+  * random.c (read_seed_file): New.
+  (set_random_seed_file): New.
+  (read_pool): Try to read the seeding file.
+  (update_random_seed_file): New.
+
+  (read_pool): Do an initial extra seeding when level 2 quality random
+  is requested the first time. This requestes at least POOLSIZE/2 bytes
+  of entropy.  Compined with the seeding file this should make normal
+  random bytes cheaper and increase the quality of the random bytes
+  used for key generation.
+
+  * random.c (read_pool): Print a more friendly error message in
+  cases when too much random is requested in one call.
+
+  * random.c (fast_random_poll): Check whether RUSAGE_SELF is defined;
+  this is not the case for some ESIX and Unixware, although they have
+  getrusage().
+
+  * primegen.c (generate_elg_prime): All primes are now generated with
+  the lowest random quality level.  Because they are public anyway we
+  don't need stronger random and by this we do not drain the systems
+  entropy so much.
+
+  * primegen.c (register_primegen_progress): New.
+  * dsa.c (register_pk_dsa_progress): New.
+  * elgamal.c (register_pk_elg_progress): New.
+
+  * elgamal.c (wiener_map): New.
+  (gen_k): Use a much smaller k.
+  (generate): Calculate the qbits using the wiener map and
+  choose an x at a size comparable to the one choosen in gen_k
+
+  * rmd160.c (rmd160_get_info): Moved casting to the left side due to a
+  problem with UTS4.3. Suggested by Dave Dykstra.
+  * sha1.c (sha1_get_info): Ditto.
+  * tiger.c (tiger_get_info): Ditto.
+  * md5.c (md5_get_info): Ditto
+  * des.c (des_get_info): Ditto.
+  * blowfish.c (blowfish_get_info): Ditto.
+  * cast5.c (cast5_get_info): Ditto.
+  * twofish.c (twofish_get_info): Ditto.
+
 Fri Mar 24 11:25:45 CET 2000  Werner Koch  <wk@openit.de>
 
        * md.c (md_open): Add hmac arg and allocate space for the pads.
index aa766bb..9792419 100644 (file)
@@ -5,15 +5,8 @@ INCLUDES = -I$(top_srcdir)/gcrypt
 
 noinst_LTLIBRARIES = libcipher.la
 
-# The configure script greps the module names from the following lines.
-# You must also add all these names to EXTRA_PROGRAMS some lines below
-# and EXTRA_foo_SOURCES entries.
-# Hmmm is there a more easy way to do this?  (EXTRA_PROGRAMS
-# might also list programs which are not modules)
-# MODULES: rndunix rndlinux rndegd rndw32
-# MODULES: sha1 rmd160 md5 tiger
-EXTRA_PROGRAMS = rndunix rndlinux rndegd rndw32 \
-                sha1 rmd160 md5 tiger
+# The configure script greps the module names from the EXTRA_PROGRAMS line
+EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 rmd160 md5 tiger
 
 EXTRA_rndlinux_SOURCES = rndlinux.c
 EXTRA_rndunix_SOURCES = rndunix.c
@@ -73,7 +66,7 @@ libcipher_la_LIBADD =     @STATIC_CIPHER_OBJS@
 
 tiger: $(srcdir)/tiger.c
        `echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o tiger $(srcdir)/tiger.c | \
-           sed -e 's/-O[2-9s]*/-O1/g' `
+           sed -e 's/-O[2-9s]*/-O/g' `
 
 tiger.o: $(srcdir)/tiger.c
        `echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `
@@ -98,9 +91,3 @@ rndlinux: $(srcdir)/rndlinux.c
 rndegd: $(srcdir)/rndegd.c
        $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c
 
-# We need to have a better system for selection which modules
-# to compile.  For now this works.
-rndw32: $(srcdir)/rndw32.c
-       echo "#!/bin/sh" >rndw32
-       echo "Not usable as a module" >>rndw32
-
index e7f047f..2bdb3b5 100644 (file)
@@ -584,9 +584,12 @@ blowfish_get_info( int algo, size_t *keylen,
     *keylen = 128;
     *blocksize = BLOWFISH_BLOCKSIZE;
     *contextsize = sizeof(BLOWFISH_context);
-    *r_setkey = FNCCAST_SETKEY(bf_setkey);
-    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
-    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+    *(int  (**)(BLOWFISH_context*, byte*, unsigned))r_setkey
+                                                       = bf_setkey;
+    *(void (**)(BLOWFISH_context*, byte*, byte*))r_encrypt
+                                                       = encrypt_block;
+    *(void (**)(BLOWFISH_context*, byte*, byte*))r_decrypt
+                                                       = decrypt_block;
 
     if( algo == CIPHER_ALGO_BLOWFISH )
        return "BLOWFISH";
index aaa0a42..64f6bb0 100644 (file)
@@ -610,9 +610,13 @@ cast5_get_info( int algo, size_t *keylen,
     *keylen = 128;
     *blocksize = CAST5_BLOCKSIZE;
     *contextsize = sizeof(CAST5_context);
-    *r_setkey = FNCCAST_SETKEY(cast_setkey);
-    *r_encrypt= FNCCAST_CRYPT(encrypt_block);
-    *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+    *(int  (**)(CAST5_context*, byte*, unsigned))r_setkey
+                                                       = cast_setkey;
+    *(void (**)(CAST5_context*, byte*, byte*))r_encrypt
+                                                       = encrypt_block;
+    *(void (**)(CAST5_context*, byte*, byte*))r_decrypt
+                                                       = decrypt_block;
+
 
     if( algo == CIPHER_ALGO_CAST5 )
        return "CAST5";
index af5b584..9c3c541 100644 (file)
@@ -1001,9 +1001,12 @@ des_get_info( int algo, size_t *keylen,
        *keylen = 192;
        *blocksize = 8;
        *contextsize = sizeof(struct _tripledes_ctx);
-       *r_setkey = FNCCAST_SETKEY(do_tripledes_setkey);
-       *r_encrypt= FNCCAST_CRYPT(do_tripledes_encrypt);
-       *r_decrypt= FNCCAST_CRYPT(do_tripledes_decrypt);
+       *(int  (**)(struct _tripledes_ctx*, byte*, unsigned))r_setkey
+                                                       = do_tripledes_setkey;
+       *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_encrypt
+                                                       = do_tripledes_encrypt;
+       *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_decrypt
+                                                       = do_tripledes_decrypt;
        return "3DES";
     }
     return NULL;
index 1f132ae..255fa37 100644 (file)
@@ -1,5 +1,5 @@
 /* dsa.c  -  DSA signature scheme
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -52,13 +52,28 @@ static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
 static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
 static int  verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
+
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
+
 /****************
  * Generate a random secret exponent k less than q
  */
index 02995e0..f2c029b 100644 (file)
@@ -1,5 +1,5 @@
 /* elgamal.c  -  ElGamal Public Key encryption
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * For a description of the algorithm, see:
  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
@@ -56,13 +56,67 @@ static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
 static int  verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
 
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
+
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
+/****************
+ * Michael Wiener's table on subgroup sizes to match field sizes
+ * (floating around somewhere - Fixme: need a reference)
+ */
+static unsigned int
+wiener_map( unsigned int n )
+{
+    static struct { unsigned int p_n, q_n; } t[] =
+    {  /*   p    q      attack cost */
+       {  512, 119 },  /* 9 x 10^17 */
+       {  768, 145 },  /* 6 x 10^21 */
+       { 1024, 165 },  /* 7 x 10^24 */
+       { 1280, 183 },  /* 3 x 10^27 */
+       { 1536, 198 },  /* 7 x 10^29 */
+       { 1792, 212 },  /* 9 x 10^31 */
+       { 2048, 225 },  /* 8 x 10^33 */
+       { 2304, 237 },  /* 5 x 10^35 */
+       { 2560, 249 },  /* 3 x 10^37 */
+       { 2816, 259 },  /* 1 x 10^39 */
+       { 3072, 269 },  /* 3 x 10^40 */
+       { 3328, 279 },  /* 8 x 10^41 */
+       { 3584, 288 },  /* 2 x 10^43 */
+       { 3840, 296 },  /* 4 x 10^44 */
+       { 4096, 305 },  /* 7 x 10^45 */
+       { 4352, 313 },  /* 1 x 10^47 */
+       { 4608, 320 },  /* 2 x 10^48 */
+       { 4864, 328 },  /* 2 x 10^49 */
+       { 5120, 335 },  /* 3 x 10^50 */
+       { 0, 0 }
+    };
+    int i;
+
+    for(i=0; t[i].p_n; i++ )  {
+       if( n <= t[i].p_n )
+           return t[i].q_n;
+    }
+    /* not in table - use some arbitrary high number ;-) */
+    return  n / 8 + 200;
+}
+
 static void
 test_keys( ELG_secret_key *sk, unsigned nbits )
 {
@@ -104,38 +158,44 @@ gen_k( MPI p )
     MPI k = mpi_alloc_secure( 0 );
     MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
     MPI p_1 = mpi_copy(p);
-    unsigned int nbits = mpi_get_nbits(p);
-    unsigned int nbytes = (nbits+7)/8;
+    unsigned int orig_nbits = mpi_get_nbits(p);
+    unsigned int nbits, nbytes;
     char *rndbuf = NULL;
 
+    /* IMO using a k much lesser than p is sufficient and it greatly
+     * improves the encryption performance.  We use Wiener's table
+     * and add a large safety margin.
+     */
+    nbits = wiener_map( orig_nbits ) * 3 / 2;
+    if( nbits >= orig_nbits )
+       BUG();
+
+    nbytes = (nbits+7)/8;
     if( DBG_CIPHER )
        log_debug("choosing a random k ");
     mpi_sub_ui( p_1, p, 1);
     for(;;) {
-       if( DBG_CIPHER )
-           progress('.');
        if( !rndbuf || nbits < 32 ) {
            g10_free(rndbuf);
            rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
        }
        else { /* change only some of the higher bits */
-           /* we could imporove this by directly requesting more memory
+           /* we could improve this by directly requesting more memory
             * at the first call to get_random_bytes() and use this the here
-            * maybe it is easier to do this directly in random.c */
+            * maybe it is easier to do this directly in random.c
+            * Anyway, it is highly inlikely that we will ever reach this code
+            */
            char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
            memcpy( rndbuf, pp, 4 );
            g10_free(pp);
+           log_debug("gen_k: tsss, never expected to reach this\n");
        }
        mpi_set_buffer( k, rndbuf, nbytes, 0 );
 
        for(;;) {
-           /* make sure that the number is of the exact lenght */
-           if( mpi_test_bit( k, nbits-1 ) )
-               mpi_set_highbit( k, nbits-1 );
-           else {
-               mpi_set_highbit( k, nbits-1 );
-               mpi_clear_bit( k, nbits-1 );
-           }
+           /* Hmm, actually we don't need this step here
+            * because we use k much smaller than p - we do it anyway
+            * just in case the keep on adding a one to k ;) */
            if( !(mpi_cmp( k, p_1 ) < 0) ) {  /* check: k < (p-1) */
                if( DBG_CIPHER )
                    progress('+');
@@ -149,6 +209,8 @@ gen_k( MPI p )
            if( mpi_gcd( temp, k, p_1 ) )
                goto found;  /* okay, k is relatively prime to (p-1) */
            mpi_add_ui( k, k, 1 );
+           if( DBG_CIPHER )
+               progress('.');
        }
     }
   found:
@@ -167,7 +229,7 @@ gen_k( MPI p )
  *         and an array with n-1 factors of (p-1)
  */
 static void
-generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+generate(  ELG_secret_key *sk, unsigned int nbits, MPI **ret_factors )
 {
     MPI p;    /* the prime */
     MPI p_min1;
@@ -175,19 +237,15 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
     MPI x;    /* the secret exponent */
     MPI y;
     MPI temp;
-    unsigned qbits;
+    unsigned int qbits;
+    unsigned int xbits;
     byte *rndbuf;
 
     p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
     temp   = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
-    if( nbits < 512 )
-       qbits = 120;
-    else if( nbits <= 1024 )
-       qbits = 160;
-    else if( nbits <= 2048 )
-       qbits = 200;
-    else
-       qbits = 240;
+    qbits = wiener_map( nbits );
+    if( qbits & 1 ) /* better have a even one */
+       qbits++;
     g = mpi_alloc(1);
     p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
     mpi_sub_ui(p_min1, p, 1);
@@ -198,18 +256,26 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
      * This must be a very good random number because this is the
      * secret part.  The prime is public and may be shared anyway,
      * so a random generator level of 1 is used for the prime.
+     *
+     * I don't see a reason to have a x of about the same size
+     * as the p.  It should be sufficient to have one about the size
+     * of q or the later used k plus a large safety margin. Decryption
+     * will be much faster with such an x.
      */
-    x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+    xbits = qbits * 3 / 2;
+    if( xbits >= nbits )
+       BUG();
+    x = mpi_alloc_secure( xbits/BITS_PER_MPI_LIMB );
     if( DBG_CIPHER )
-       log_debug("choosing a random x ");
+       log_debug("choosing a random x of size %u", xbits );
     rndbuf = NULL;
     do {
        if( DBG_CIPHER )
            progress('.');
        if( rndbuf ) { /* change only some of the higher bits */
-           if( nbits < 16 ) {/* should never happen ... */
+           if( xbits < 16 ) {/* should never happen ... */
                g10_free(rndbuf);
-               rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+               rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
                                                   GCRY_VERY_STRONG_RANDOM );
            }
            else {
@@ -220,11 +286,11 @@ generate(  ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
            }
        }
        else {
-           rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+           rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
                                               GCRY_VERY_STRONG_RANDOM );
        }
-       mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
-       mpi_clear_highbit( x, nbits+1 );
+       mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
+       mpi_clear_highbit( x, xbits+1 );
     } while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
     g10_free(rndbuf);
 
@@ -311,7 +377,6 @@ decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
     MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
 
     /* output = b/(a^x) mod p */
-
     gcry_mpi_powm( t1, a, skey->x, skey->p );
     mpi_invm( t1, t1, skey->p );
     mpi_mulm( output, b, t1, skey->p );
@@ -351,10 +416,6 @@ sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
     gcry_mpi_powm( a, skey->g, k, skey->p );
     mpi_mul(t, skey->x, a );
     mpi_subm(t, input, t, p_1 );
-    while( mpi_is_neg(t) ) {
-       BUG();  /* That is nonsense code - left over from a very early test?*/
-       mpi_add(t, t, p_1);
-    }
     mpi_invm(inv, k, p_1 );
     mpi_mulm(b, t, inv, p_1 );
 
@@ -557,7 +618,7 @@ elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
 
 
 
-unsigned
+unsigned int
 elg_get_nbits( int algo, MPI *pkey )
 {
     if( !is_ELGAMAL(algo) )
@@ -587,10 +648,10 @@ elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
     *nsig = 2;
 
     switch( algo ) {
-      case PUBKEY_ALGO_ELGAMAL:
+      case GCRY_PK_ELG:
        *use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
        return "ELG";
-      case PUBKEY_ALGO_ELGAMAL_E:
+      case GCRY_PK_ELG_E:
        *use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
        return "ELG-E";
       default: *use = 0; return NULL;
index 9879520..e8ac8ac 100644 (file)
@@ -562,6 +562,12 @@ gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
        else if ( !(rc = prepare_macpads( hd, buffer, buflen )) )
            gcry_md_reset( hd );
     }
+    else if( cmd == GCRYCTL_START_DUMP ) {
+       md_start_debug( hd, buffer );
+    }
+    else if( cmd == GCRYCTL_STOP_DUMP ) {
+       md_stop_debug( hd );
+    }
     else
        rc = GCRYERR_INV_OP;
     return set_lasterr( rc );
@@ -834,7 +840,7 @@ gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes)
 
 
 
-void
+static void
 md_start_debug( GCRY_MD_HD md, const char *suffix )
 {
     static int idx=0;
@@ -851,7 +857,7 @@ md_start_debug( GCRY_MD_HD md, const char *suffix )
        log_debug("md debug: can't open %s\n", buf );
 }
 
-void
+static void
 md_stop_debug( GCRY_MD_HD md )
 {
     if( md->ctx->debug ) {
index 161d443..c4351f1 100644 (file)
@@ -344,10 +344,10 @@ md5_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 16;
-    *r_init  = (void (*)(void *))md5_init;
-    *r_write = (void (*)(void *, byte*, size_t))md5_write;
-    *r_final = (void (*)(void *))md5_final;
-    *r_read  = (byte *(*)(void *))md5_read;
+    *(void  (**)(MD5_CONTEXT *))r_init                = md5_init;
+    *(void  (**)(MD5_CONTEXT *, byte*, size_t))r_write = md5_write;
+    *(void  (**)(MD5_CONTEXT *))r_final               = md5_final;
+    *(byte *(**)(MD5_CONTEXT *))r_read                = md5_read;
 
     return "MD5";
 }
index 2f16b08..f5dca85 100644 (file)
@@ -1,5 +1,5 @@
 /* primegen.c - prime number generator
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -38,11 +38,24 @@ static int check_prime( MPI prime, MPI val_2 );
 static int is_prime( MPI n, int steps, int *count );
 static void m_out_of_n( char *array, int m, int n );
 
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_primegen_progress ( void (*cb)( void *, int), void *cb_data )
+{
+    progress_cb = cb;
+    progress_cb_data = cb_data;
+}
+
 
 static void
 progress( int c )
 {
-    fputc( c, stderr );
+    if ( progress_cb )
+       progress_cb ( progress_cb_data, c );
+    else
+       fputc( c, stderr );
 }
 
 
@@ -117,8 +130,8 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
        log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
                    pbits, req_qbits, qbits, fbits, n  );
     prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) /  BITS_PER_MPI_LIMB );
-    q = gen_prime( qbits, 0, 1 );
-    q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+    q = gen_prime( qbits, 0, 0 );
+    q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL;
 
     /* allocate an array to hold the factors + 2 for later usage */
     factors = g10_xcalloc( n+2, sizeof *factors );
@@ -177,7 +190,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
                count1 = 0;
                qbits++;
                progress('>');
-               q = gen_prime( qbits, 0, 1 );
+               q = gen_prime( qbits, 0, 0 );
                goto next_try;
            }
        }
@@ -188,7 +201,7 @@ generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
                count2 = 0;
                qbits--;
                progress('<');
-               q = gen_prime( qbits, 0, 1 );
+               q = gen_prime( qbits, 0, 0 );
                goto next_try;
            }
        }
index 3ace1d8..b139720 100644 (file)
@@ -1,5 +1,5 @@
 /* pubkey.c  - pubkey dispatcher
- *     Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -30,6 +30,9 @@
 #include "cipher.h"
 #include "elgamal.h"
 #include "dsa.h"
+#if 0
+#include "rsa.h"
+#endif
 #include "dynload.h"
 
 /* FIXME: use set_lasterr() */
@@ -193,6 +196,60 @@ setup_pubkey_table(void)
        BUG();
     i++;
 
+  #if 0
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = rsa_encrypt;
+    pubkey_table[i].decrypt         = rsa_decrypt;
+    pubkey_table[i].sign            = rsa_sign;
+    pubkey_table[i].verify          = rsa_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = rsa_encrypt;
+    pubkey_table[i].decrypt         = rsa_decrypt;
+    pubkey_table[i].sign            = dummy_sign;
+    pubkey_table[i].verify          = dummy_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+    pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
+    pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+                                        &pubkey_table[i].npkey,
+                                        &pubkey_table[i].nskey,
+                                        &pubkey_table[i].nenc,
+                                        &pubkey_table[i].nsig,
+                                        &pubkey_table[i].use );
+    pubkey_table[i].generate        = rsa_generate;
+    pubkey_table[i].check_secret_key = rsa_check_secret_key;
+    pubkey_table[i].encrypt         = dummy_encrypt;
+    pubkey_table[i].decrypt         = dummy_decrypt;
+    pubkey_table[i].sign            = rsa_sign;
+    pubkey_table[i].verify          = rsa_verify;
+    pubkey_table[i].get_nbits       = rsa_get_nbits;
+    if( !pubkey_table[i].name )
+       BUG();
+    i++;
+  #endif
+
     for( ; i < TABLE_SIZE; i++ )
        pubkey_table[i].name = NULL;
 }
index 38991a1..f8faeeb 100644 (file)
@@ -1,5 +1,5 @@
 /* random.c  - random number generator
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <fcntl.h>
 #ifdef HAVE_GETHRTIME
   #include <sys/times.h>
 #endif
 #ifdef HAVE_GETTIMEOFDAY
   #include <sys/times.h>
 #endif
+#ifdef HAVE_CLOCK_GETTIME
+  #include <time.h>
+#endif
 #ifdef HAVE_GETRUSAGE
   #include <sys/resource.h>
 #endif
+#ifdef __MINGW32__
+  #include <process.h>
+#endif
 #include "g10lib.h"
 #include "rmd.h"
 #include "random.h"
@@ -89,6 +96,9 @@ static size_t pool_writepos;
 static int pool_filled;
 static int pool_balance;
 static int just_mixed;
+static int did_initial_extra_seeding;
+static char *seed_file_name;
+static int allow_seed_file_update;
 
 static int secure_alloc;
 static int quick_test;
@@ -274,6 +284,139 @@ mix_pool(byte *pool)
     }
 }
 
+void
+set_random_seed_file( const char *name )
+{
+    if( seed_file_name )
+       BUG();
+    seed_file_name = g10_xstrdup( name );
+}
+
+/****************
+ * Read in a seed form the random_seed file
+ * and return true if this was successful
+ */
+static int
+read_seed_file()
+{
+    int fd;
+    struct stat sb;
+    unsigned char buffer[POOLSIZE];
+    int n;
+
+    if( !seed_file_name )
+       return 0;
+
+  #ifdef HAVE_DOSISH_SYSTEM
+    fd = open( seed_file_name, O_RDONLY | O_BINARY );
+  #else
+    fd = open( seed_file_name, O_RDONLY );
+  #endif
+    if( fd == -1 && errno == ENOENT) {
+       allow_seed_file_update = 1;
+       return 0;
+    }
+
+    if( fd == -1 ) {
+       log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+       return 0;
+    }
+    if( fstat( fd, &sb ) ) {
+       log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+       close(fd);
+       return 0;
+    }
+    if( !S_ISREG(sb.st_mode) ) {
+       log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+       close(fd);
+       return 0;
+    }
+    if( !sb.st_size ) {
+       log_info(_("note: random_seed file is empty\n") );
+       close(fd);
+       allow_seed_file_update = 1;
+       return 0;
+    }
+    if( sb.st_size != POOLSIZE ) {
+       log_info(_("warning: invalid size of random_seed file - not used\n") );
+       close(fd);
+       return 0;
+    }
+    do {
+       n = read( fd, buffer, POOLSIZE );
+    } while( n == -1 && errno == EINTR );
+    if( n != POOLSIZE ) {
+       log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+       close(fd);
+       return 0;
+    }
+
+    close(fd);
+
+    add_randomness( buffer, POOLSIZE, 0 );
+    /* add some minor entropy to the pool now (this will also force a mixing) */
+    {  pid_t x = getpid();
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    {  time_t x = time(NULL);
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    {  clock_t x = clock();
+       add_randomness( &x, sizeof(x), 0 );
+    }
+    /* And read a few bytes from our entropy source.  By using
+     * a level of 0 this will not block and might not return anything
+     * with some entropy drivers, however the rndlinux driver will use
+     * /dev/urandom and return some stuff - Do not read to much as we
+     * want to be friendly to the scare system entropy resource. */
+    read_random_source( 0, 16, 0 );
+
+    allow_seed_file_update = 1;
+    return 1;
+}
+
+void
+update_random_seed_file()
+{
+    ulong *sp, *dp;
+    int fd, i;
+
+    if( !seed_file_name || !is_initialized || !pool_filled )
+       return;
+    if( !allow_seed_file_update ) {
+       log_info(_("note: random_seed file not updated\n"));
+       return;
+    }
+
+
+    /* copy the entropy pool to a scratch pool and mix both of them */
+    for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+                                   i < POOLWORDS; i++, dp++, sp++ ) {
+       *dp = *sp + ADD_VALUE;
+    }
+    mix_pool(rndpool); rndstats.mixrnd++;
+    mix_pool(keypool); rndstats.mixkey++;
+
+  #ifdef HAVE_DOSISH_SYSTEM
+    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+                                                       S_IRUSR|S_IWUSR );
+  #else
+    fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+  #endif
+    if( fd == -1 ) {
+       log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+       return;
+    }
+    do {
+       i = write( fd, keypool, POOLSIZE );
+    } while( i == -1 && errno == EINTR );
+    if( i != POOLSIZE ) {
+       log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+    }
+    if( close(fd) )
+       log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+}
+
 
 static void
 read_pool( byte *buffer, size_t length, int level )
@@ -281,8 +424,31 @@ read_pool( byte *buffer, size_t length, int level )
     int i;
     ulong *sp, *dp;
 
-    if( length >= POOLSIZE )
-       BUG(); /* not allowed */
+    if( length >= POOLSIZE ) {
+       log_fatal(_("too many random bits requested; the limit is %d\n"),
+                 POOLSIZE*8-1 );
+    }
+
+    if( !pool_filled ) {
+       if( read_seed_file() )
+           pool_filled = 1;
+    }
+
+    /* For level 2 quality (key generation) we alwas make
+     * sure that the pool has been seeded enough initially */
+    if( level == 2 && !did_initial_extra_seeding ) {
+       size_t needed;
+
+       pool_balance = 0;
+       needed = length - pool_balance;
+       if( needed < POOLSIZE/2 )
+           needed = POOLSIZE/2;
+       else if( needed > POOLSIZE )
+           BUG();
+       read_random_source( 3, needed, 2 );
+       pool_balance += needed;
+       did_initial_extra_seeding=1;
+    }
 
     /* for level 2 make sure that there is enough random in the pool */
     if( level == 2 && pool_balance < length ) {
@@ -347,6 +513,12 @@ read_pool( byte *buffer, size_t length, int level )
 /****************
  * Add LENGTH bytes of randomness from buffer to the pool.
  * source may be used to specify the randomness source.
+ * Source is:
+ *     0 - used ony for initialization
+ *     1 - fast random poll function
+ *     2 - normal poll function
+ *     3 - used when level 2 random quality has been requested
+ *         to do an extra pool seed.
  */
 static void
 add_randomness( const void *buffer, size_t length, int source )
@@ -410,6 +582,13 @@ fast_random_poll()
        add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
        add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
     }
+  #elif HAVE_CLOCK_GETTIME
+    {  struct timespec tv;
+       if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+           BUG();
+       add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+       add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+    }
   #else /* use times */
     #ifndef HAVE_DOSISH_SYSTEM
     {  struct tms buf;
@@ -419,13 +598,28 @@ fast_random_poll()
     #endif
   #endif
   #ifdef HAVE_GETRUSAGE
+    #ifndef RUSAGE_SELF
+      #ifdef __GCC__
+       #warning There is no RUSAGE_SELF on this system
+      #endif
+    #else
     {  struct rusage buf;
        if( getrusage( RUSAGE_SELF, &buf ) )
            BUG();
        add_randomness( &buf, sizeof buf, 1 );
        memset( &buf, 0, sizeof buf );
     }
+    #endif
   #endif
+    /* time and clock are availabe on all systems - so
+     * we better do it just in case one of the above functions
+     * didn't work */
+    {  time_t x = time(NULL);
+       add_randomness( &x, sizeof(x), 1 );
+    }
+    {  clock_t x = clock();
+       add_randomness( &x, sizeof(x), 1 );
+    }
 }
 
 
@@ -472,9 +666,9 @@ gather_faked( void (*add)(const void*, size_t, int), int requester,
       #endif
        initialized=1;
       #ifdef HAVE_RAND
-       srand( time(NULL) * getpid());
+       srand(make_timestamp()*getpid());
       #else
-       srandom( time(NULL) * getpid());
+       srandom(make_timestamp()*getpid());
       #endif
     }
 
index 7b23008..fb9d6fa 100644 (file)
@@ -562,10 +562,10 @@ rmd160_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 20;
-    *r_init  = (void (*)(void *))rmd160_init;
-    *r_write = (void (*)(void *, byte*, size_t))rmd160_write;
-    *r_final = (void (*)(void *))rmd160_final;
-    *r_read  = (byte *(*)(void *))rmd160_read;
+    *(void  (**)(RMD160_CONTEXT *))r_init                = rmd160_init;
+    *(void  (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+    *(void  (**)(RMD160_CONTEXT *))r_final               = rmd160_final;
+    *(byte *(**)(RMD160_CONTEXT *))r_read                = rmd160_read;
 
     return "RIPEMD160";
 }
index 4d5f0ef..f6870cd 100644 (file)
@@ -1,5 +1,5 @@
 /* rndegd.c  - interface to the EGD
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -117,9 +117,13 @@ do_read( int fd, void *buf, size_t nbytes )
 
 
 
-/* Note: we always use the highest level.
+/****************
+ * Note: we always use the highest level.
  * TO boost the performance we may want to add some
  * additional code for level 1
+ *
+ * Using a level of 0 should never block and better add nothing
+ * to the pool.  So this is just a dummy for EGD.
  */
 static int
 gather_random( void (*add)(const void*, size_t, int), int requester,
@@ -133,7 +137,8 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
 
     if( !length )
        return 0;
-
+    if( !level )
+       return 0;
 
   restart:
     if( do_restart ) {
index 4ab9f65..99a416e 100644 (file)
@@ -77,7 +77,7 @@
 #ifndef __QNX__
 #include <sys/resource.h>
 #endif                         /* __QNX__ */
-#ifdef _AIX
+#if defined( _AIX ) || defined( __QNX__ )
 #include <sys/select.h>
 #endif                         /* _AIX */
 #ifndef __QNX__
 #endif                         /* __hpux 9.x, after that it's in unistd.h */
 #include <sys/wait.h>
 /* #include <kitchensink.h> */
+#ifdef __QNX__
+#include <signal.h>
+#include <process.h>
+#endif               /* __QNX__ */
 #include <errno.h>
 
 #include "types.h"  /* for byte and u32 typedefs */
 #include "g10lib.h"
 
 #ifndef EAGAIN
-  #define EAGAIN  EWOULDBLOCK
+#define EAGAIN EWOULDBLOCK
+#endif
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
 #endif
 
 #define GATHER_BUFSIZE         49152   /* Usually about 25K are filled */
@@ -306,6 +316,32 @@ typedef struct {
     char data[500];    /* gathered data */
 } GATHER_MSG;
 
+#ifndef HAVE_WAITPID
+pid_t
+waitpid(pid_t pid, int *statptr, int options)
+{
+     #ifdef HAVE_WAIT4
+       return wait4(pid, statptr, options, NULL);
+     #else
+       /* If wait4 is also not available, try wait3 for SVR3 variants */
+       /* Less ideal because can't actually request a specific pid */
+       /* For that reason, first check to see if pid is for an */
+       /*   existing process. */
+       int tmp_pid, dummystat;;
+       if (kill(pid, 0) == -1) {
+               errno = ECHILD;
+               return -1;
+       }
+       if (statptr == NULL)
+               statptr = &dummystat;
+       while (((tmp_pid = wait3(statptr, options, 0)) != pid) &&
+                   (tmp_pid != -1) && (tmp_pid != 0) && (pid != -1))
+           ;
+       return tmp_pid;
+     #endif
+}
+#endif
+
 /* Under SunOS popen() doesn't record the pid of the child process.  When
  * pclose() is called, instead of calling waitpid() for the correct child, it
  * calls wait() repeatedly until the right child is reaped.  The problem is
@@ -376,7 +412,9 @@ my_popen(struct RI *entry)
      * close on exec, so new children won't see it */
     close(pipedes[STDOUT_FILENO]);
 
+#ifdef FD_CLOEXEC
     fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
+#endif
 
     stream = fdopen(pipedes[STDIN_FILENO], "r");
 
@@ -616,6 +654,7 @@ start_gatherer( int pipefd )
     }
     /* close all files but the ones we need */
     {  int nmax, n1, n2, i;
+      #ifdef _SC_OPEN_MAX
        if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) {
          #ifdef _POSIX_OPEN_MAX
            nmax = _POSIX_OPEN_MAX;
@@ -623,6 +662,9 @@ start_gatherer( int pipefd )
            nmax = 20; /* assume a reasonable value */
          #endif
        }
+      #else
+       nmax = 20; /* assume a reasonable value */
+      #endif
        n1 = fileno( stderr );
        n2 = dbgfp? fileno( dbgfp ) : -1;
        for(i=0; i < nmax; i++ ) {
@@ -718,6 +760,10 @@ read_a_msg( int fd, GATHER_MSG *msg )
 }
 
 
+/****************
+ * Using a level of 0 should never block and better add nothing
+ * to the pool.  So this is just a dummy for this gatherer.
+ */
 static int
 gather_random( void (*add)(const void*, size_t, int), int requester,
               size_t length, int level )
@@ -727,6 +773,9 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     GATHER_MSG msg;
     size_t n;
 
+    if( !level )
+       return 0;
+
     if( !gatherer_pid ) {
        /* make sure we are not setuid */
        if( getuid() != geteuid() )
index c104585..2583069 100644 (file)
@@ -1,5 +1,6 @@
-/* rndw32.c  - interface to the Winseed DLL
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+/* rndw32.c  - W32 entropy gatherer
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ *     Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
  *
  * This file is part of GnuPG.
  *
  * 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
+ *
+ *************************************************************************
+ * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
+ * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
+ * copyright notice:
+ *
+ * This module is part of the cryptlib continuously seeded pseudorandom
+ * number generator.  For usage conditions, see lib_rand.c
+ *
+ * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
+ *
+ * This module and the misc/rnd*.c modules represent the cryptlib
+ * continuously seeded pseudorandom number generator (CSPRNG) as described in
+ * my 1998 Usenix Security Symposium paper "The generation of random numbers
+ * for cryptographic purposes".
+ *
+ * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+ * 1997, 1998, 1999, all rights reserved.  Redistribution of the CSPRNG
+ * modules and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice
+ *    and this permission notice in its entirety.
+ *
+ * 2. Redistributions in binary form must reproduce the copyright notice in
+ *    the documentation and/or other materials provided with the distribution.
+ *
+ * 3. A copy of any bugfixes or enhancements made must be provided to the
+ *    author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+ *    baseline version of the code.
+ *
+ * ALTERNATIVELY, the code may be distributed under the terms of the GNU
+ * General Public License, version 2 or any later version published by the
+ * Free Software Foundation, in which case the provisions of the GNU GPL are
+ * required INSTEAD OF the above restrictions.
+ *
+ * Although not required under the terms of the GPL, it would still be nice if
+ * you could make any changes available to the author to allow a consistent
+ * code base to be maintained
+ *************************************************************************
  */
 
 #include <config.h>
 
 #include <windows.h>
 
+
 #include "types.h"
 #include "g10lib.h"
 #include "dynload.h"
 
+/* We do not use the netropy DLL anymore because a standalone program is
+ * easier to maintain and */
+/*#define USE_ENTROPY_DLL*/
+
+
 
 #ifdef IS_MODULE
   #define _(a) (a)
 #endif
 
 
+static int debug_me;
+
+#ifdef USE_ENTROPY_DLL
+
 #define WIN32_SLOW_SEEDER      0
 #define WIN32_FAST_SEEDER      1
 
 #define PCP_DLL_FUNC           8
 #define PCP_UNKNOWN_SEEDER_TYPE 9
 
+
+/****************
+ * We sometimes get a SEEDER_TOO_SMALL error, in which case we increment
+ * the internal buffer by SEEDER_INC_CHUNK until we reach MAX_SEEDER_SIZE
+ * MAX_SEEDER_SIZE is used as an arbitrary limit to protect against
+ * bugs in Winseed.
+ */
+#define MAX_SEEDER_SIZE  500000
+#define SEEDER_INC_CHUNK  50000
+
+
 typedef void *WIN32_SEEDER;
 
 static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
@@ -68,8 +130,6 @@ static WIN32_SEEDER slow_seeder, fast_seeder;
 static byte *entropy_buffer;
 static size_t entropy_buffer_size;
 
-static char *entropy_dll;
-
 /****************
  * Load and initialize the winseed DLL
  * NOTE: winseed is not part of the GnuPG distribution.  It should be available
@@ -80,11 +140,17 @@ static char *entropy_dll;
 static void
 load_and_init_winseed( void )
 {
-    int hInstance;
+    HANDLE hInstance;
     void *addr;
     unsigned int reason = 0;
     unsigned int n1, n2;
-    const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
+    const char *dllname;
+
+    dllname = read_w32_registry_string( "HKEY_LOCAL_MACHINE",
+                                       "Software\\GNU\\GnuPG",
+                                       "EntropyDLL" );
+    if( !dllname )
+       dllname = "c:/gnupg/entropy.dll";
 
     hInstance = LoadLibrary( dllname );
     if( !hInstance )
@@ -119,15 +185,14 @@ load_and_init_winseed( void )
        g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
        goto failure;
     }
-    g10_log_info("slow and fast seeders created.\n");
     n1 = get_internal_seed_size( slow_seeder );
-    g10_log_info("slow buffer size=%u\n", n1);
+    /*g10_log_info("slow buffer size=%u\n", n1);*/
     n2 = get_internal_seed_size( fast_seeder );
-    g10_log_info("fast buffer size=%u\n", n2);
+    /*g10_log_info("fast buffer size=%u\n", n2);*/
 
     entropy_buffer_size =  n1 > n2? n1: n2;
-    entropy_buffer = g10_xmalloc( entropy_buffer_size );
-    g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
+    entropy_buffer = m_alloc( entropy_buffer_size );
+    /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/
 
     return;
 
@@ -150,13 +215,16 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     unsigned int result;
     unsigned int nbytes;
 
+    if( !level )
+       return 0;
+
     if( !slow_seeder )
        load_and_init_winseed();
 
     /* Our estimation on how much entropy we should use is very vague.
      * Winseed delivers some amount of entropy on each slow poll and
      * we add it to our random pool.  Depending on the required quality
-     * level we adjust the requested length so that for higer quality
+     * level we adjust the requested length so that for higher quality
      * we make sure to add more entropy to our pool.  However, as we don't
      * like to waste any entropy collected by winseed, we always add
      * at least everything we got from winseed.
@@ -169,17 +237,35 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
     for(;;) {
        nbytes = entropy_buffer_size;
        result = get_seed( slow_seeder, entropy_buffer, &nbytes);
+       if( result == PCP_SEEDER_TOO_SMALL ) {
+           unsigned int n1 = get_internal_seed_size( slow_seeder );
+
+           if( n1 > MAX_SEEDER_SIZE ) {
+               g10_log_fatal("rndw32: internal seeder problem (size=%u)\n",
+                                                                         n1);
+               return -1; /* actually never reached */
+           }
+           n1 += SEEDER_INC_CHUNK;
+           set_internal_seed_size( slow_seeder, n1 );
+           if( n1 > entropy_buffer_size ) {
+               entropy_buffer_size =  n1;
+               entropy_buffer = m_realloc( entropy_buffer,
+                                           entropy_buffer_size );
+           }
+           continue;
+       }
+
+
        if( result ) {
            g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
            return -1; /* actually never reached */
        }
-       g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
-                     level, (unsigned int)length, (unsigned int)nbytes );
+       /*g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
+                     level, (unsigned int)length, (unsigned int)nbytes );*/
        (*add)( entropy_buffer, nbytes, requester );
        if( length <= nbytes )
            return 0; /* okay */
        length -= nbytes;
-       g10_log_info("rndw32: need more\n");
     }
 }
 
@@ -206,6 +292,619 @@ gather_random_fast( void (*add)(const void*, size_t, int), int requester )
     return 0;
 }
 
+#else /* !USE_ENTROPY_DLL */
+/* This is the new code which does not require the entropy.dll */
+
+/*
+ * Definitions which are missing from the current GNU Windows32Api
+ */
+
+#define TH32CS_SNAPHEAPLIST 1
+#define TH32CS_SNAPPROCESS  2
+#define TH32CS_SNAPTHREAD   4
+#define TH32CS_SNAPMODULE   8
+#define TH32CS_SNAPALL     (1|2|4|8)
+#define TH32CS_INHERIT     0x80000000
+
+#define IOCTL_DISK_PERFORMANCE 0x00070020
+#define VER_PLATFORM_WIN32_WINDOWS 1
+
+
+typedef struct {
+    DWORD dwSize;
+    DWORD th32ProcessID;
+    DWORD th32HeapID;
+    DWORD dwFlags;
+} HEAPLIST32;
+
+typedef struct {
+    DWORD dwSize;
+    HANDLE hHandle;
+    DWORD dwAddress;
+    DWORD dwBlockSize;
+    DWORD dwFlags;
+    DWORD dwLockCount;
+    DWORD dwResvd;
+    DWORD th32ProcessID;
+    DWORD th32HeapID;
+} HEAPENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD cntUsage;
+    DWORD th32ProcessID;
+    DWORD th32DefaultHeapID;
+    DWORD th32ModuleID;
+    DWORD cntThreads;
+    DWORD th32ParentProcessID;
+    LONG  pcPriClassBase;
+    DWORD dwFlags;
+    char  szExeFile[260];
+} PROCESSENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD cntUsage;
+    DWORD th32ThreadID;
+    DWORD th32OwnerProcessID;
+    LONG  tpBasePri;
+    LONG  tpDeltaPri;
+    DWORD dwFlags;
+} THREADENTRY32;
+
+typedef struct {
+    DWORD dwSize;
+    DWORD th32ModuleID;
+    DWORD th32ProcessID;
+    DWORD GlblcntUsage;
+    DWORD ProccntUsage;
+    BYTE  *modBaseAddr;
+    DWORD modBaseSize;
+    HMODULE hModule;
+    char  szModule[256];
+    char  szExePath[260];
+} MODULEENTRY32;
+
+
+
+/* Type definitions for function pointers to call Toolhelp32 functions
+ * used with the windows95 gatherer */
+typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
+typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
+typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
+typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
+typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
+                                  DWORD th32HeapID);
+typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
+typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
+
+/* Type definitions for function pointers to call NetAPI32 functions */
+typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
+                                          DWORD dwLevel, DWORD dwOptions,
+                                          LPBYTE * lpBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
+
+
+/* When we query the performance counters, we allocate an initial buffer and
+ * then reallocate it as required until RegQueryValueEx() stops returning
+ * ERROR_MORE_DATA.  The following values define the initial buffer size and
+ * step size by which the buffer is increased
+ */
+#define PERFORMANCE_BUFFER_SIZE        65536   /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP        16384   /* Step by 16K */
+
+
+static void
+slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
+{
+    static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
+    static MODULEWALK pModule32First = NULL;
+    static MODULEWALK pModule32Next = NULL;
+    static PROCESSWALK pProcess32First = NULL;
+    static PROCESSWALK pProcess32Next = NULL;
+    static THREADWALK pThread32First = NULL;
+    static THREADWALK pThread32Next = NULL;
+    static HEAPLISTWALK pHeap32ListFirst = NULL;
+    static HEAPLISTWALK pHeap32ListNext = NULL;
+    static HEAPFIRST pHeap32First = NULL;
+    static HEAPNEXT pHeap32Next = NULL;
+    HANDLE hSnapshot;
+
+
+    /* initialize the Toolhelp32 function pointers */
+    if ( !pCreateToolhelp32Snapshot ) {
+       HANDLE hKernel;
+
+       if ( debug_me )
+           log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
+
+       /* Obtain the module handle of the kernel to retrieve the addresses
+        * of the Toolhelp32 functions */
+       if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
+           g10_log_fatal ( "rndw32: can't get module handle\n" );
+       }
+
+       /* Now get pointers to the functions */
+       pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
+                                                 "CreateToolhelp32Snapshot");
+       pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
+       pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
+       pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
+                                                       "Process32First");
+       pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
+                                                      "Process32Next");
+       pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
+       pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
+       pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
+                                                         "Heap32ListFirst");
+       pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
+                                                        "Heap32ListNext");
+       pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
+       pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
+
+       if (    !pCreateToolhelp32Snapshot
+            || !pModule32First || !pModule32Next
+            || !pProcess32First || !pProcess32Next
+            || !pThread32First  || !pThread32Next
+            || !pHeap32ListFirst || !pHeap32ListNext
+            || !pHeap32First     || !pHeap32Next  ) {
+           g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
+       }
+    }
+
+    /* Take a snapshot of everything we can get to which is currently
+     * in the system */
+    if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
+       g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
+    }
+
+    /* Walk through the local heap */
+    {  HEAPLIST32 hl32;
+       hl32.dwSize = sizeof (HEAPLIST32);
+       if (pHeap32ListFirst (hSnapshot, &hl32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
+           do {
+               HEAPENTRY32 he32;
+
+               /* First add the information from the basic Heaplist32 struct */
+               (*add) ( &hl32, sizeof (hl32), requester );
+
+               /* Now walk through the heap blocks getting information
+                * on each of them */
+               he32.dwSize = sizeof (HEAPENTRY32);
+               if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
+                   do {
+                       (*add) ( &he32, sizeof (he32), requester );
+                   } while (pHeap32Next (&he32));
+               }
+           } while (pHeap32ListNext (hSnapshot, &hl32));
+       }
+    }
+
+
+    /* Walk through all processes */
+    {  PROCESSENTRY32 pe32;
+       pe32.dwSize = sizeof (PROCESSENTRY32);
+       if (pProcess32First (hSnapshot, &pe32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
+           do {
+               (*add) ( &pe32, sizeof (pe32), requester );
+           } while (pProcess32Next (hSnapshot, &pe32));
+       }
+    }
+
+    /* Walk through all threads */
+    {  THREADENTRY32 te32;
+       te32.dwSize = sizeof (THREADENTRY32);
+       if (pThread32First (hSnapshot, &te32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
+           do {
+               (*add) ( &te32, sizeof (te32), requester );
+           } while (pThread32Next (hSnapshot, &te32));
+       }
+    }
+
+    /* Walk through all modules associated with the process */
+    {  MODULEENTRY32 me32;
+       me32.dwSize = sizeof (MODULEENTRY32);
+       if (pModule32First (hSnapshot, &me32)) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
+           do {
+               (*add) ( &me32, sizeof (me32), requester );
+           } while (pModule32Next (hSnapshot, &me32));
+       }
+    }
+
+    CloseHandle (hSnapshot);
+}
+
+
+
+static void
+slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
+{
+    static int is_initialized = 0;
+    static NETSTATISTICSGET pNetStatisticsGet = NULL;
+    static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+    static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
+    static int is_workstation = 1;
+
+    static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
+    PERF_DATA_BLOCK *pPerfData;
+    HANDLE hDevice, hNetAPI32 = NULL;
+    DWORD dwSize, status;
+    int nDrive;
+
+    if ( !is_initialized ) {
+       HKEY hKey;
+
+       if ( debug_me )
+           log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
+       /* Find out whether this is an NT server or workstation if necessary */
+       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+                         "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+                         0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+           BYTE szValue[32];
+           dwSize = sizeof (szValue);
+
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
+           status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
+                                     szValue, &dwSize);
+           if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
+               /* Note: There are (at least) three cases for ProductType:
+                * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
+                * NT Server acting as a Domain Controller */
+               is_workstation = 0;
+               if ( debug_me )
+                   log_debug ("rndw32: this is a NT server\n");
+           }
+           RegCloseKey (hKey);
+       }
+
+       /* Initialize the NetAPI32 function pointers if necessary */
+       if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
+           pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
+                                                      "NetStatisticsGet");
+           pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
+                                                      "NetApiBufferSize");
+           pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
+                                                      "NetApiBufferFree");
+
+           if ( !pNetStatisticsGet
+                || !pNetApiBufferSize || !pNetApiBufferFree ) {
+               FreeLibrary (hNetAPI32);
+               hNetAPI32 = NULL;
+               g10_log_debug ("rndw32: No NETAPI found\n" );
+           }
+       }
+
+       is_initialized = 1;
+    }
+
+    /* Get network statistics. Note: Both NT Workstation and NT Server by
+     * default will be running both the workstation and server services.  The
+     * heuristic below is probably useful though on the assumption that the
+     * majority of the network traffic will be via the appropriate service.
+     * In any case the network statistics return almost no randomness */
+    {  LPBYTE lpBuffer;
+       if (hNetAPI32 && !pNetStatisticsGet (NULL,
+                          is_workstation ? L"LanmanWorkstation" :
+                          L"LanmanServer", 0, 0, &lpBuffer) ) {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
+           pNetApiBufferSize (lpBuffer, &dwSize);
+           (*add) ( lpBuffer, dwSize,requester );
+           pNetApiBufferFree (lpBuffer);
+       }
+    }
+
+    /* Get disk I/O statistics for all the hard drives */
+    for (nDrive = 0;; nDrive++) {
+       DISK_PERFORMANCE diskPerformance;
+       char szDevice[50];
+
+       /* Check whether we can access this device */
+       sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
+       hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                             NULL, OPEN_EXISTING, 0, NULL);
+       if (hDevice == INVALID_HANDLE_VALUE)
+           break;
+
+       /* Note: This only works if you have turned on the disk performance
+        * counters with 'diskperf -y'.  These counters are off by default */
+       if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+                            &diskPerformance, sizeof (DISK_PERFORMANCE),
+                            &dwSize, NULL))
+       {
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
+                                                                 nDrive );
+           (*add) ( &diskPerformance, dwSize, requester );
+       }
+       else {
+           log_info ("NOTE: you should run 'diskperf -y' "
+                     "to enable the disk statistics\n");
+       }
+       CloseHandle (hDevice);
+    }
+
+  #if 0 /* we don't need this in GnuPG  */
+    /* Wait for any async keyset driver binding to complete.  You may be
+     * wondering what this call is doing here... the reason it's necessary is
+     * because RegQueryValueEx() will hang indefinitely if the async driver
+     * bind is in progress.  The problem occurs in the dynamic loading and
+     * linking of driver DLL's, which work as follows:
+     *
+     * hDriver = LoadLibrary( DRIVERNAME );
+     * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
+     * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
+     *
+     * If RegQueryValueEx() is called while the GetProcAddress()'s are in
+     * progress, it will hang indefinitely.  This is probably due to some
+     * synchronisation problem in the NT kernel where the GetProcAddress()
+     * calls affect something like a module reference count or function
+     * reference count while RegQueryValueEx() is trying to take a snapshot
+     * of the statistics, which include the reference counts.  Because of
+     * this, we have to wait until any async driver bind has completed
+     * before we can call RegQueryValueEx() */
+    waitSemaphore (SEMAPHORE_DRIVERBIND);
+  #endif
+
+    /* Get information from the system performance counters.  This can take
+     * a few seconds to do.  In some environments the call to
+     * RegQueryValueEx() can produce an access violation at some random time
+     * in the future, adding a short delay after the following code block
+     * makes the problem go away.  This problem is extremely difficult to
+     * reproduce, I haven't been able to get it to occur despite running it
+     * on a number of machines.  The best explanation for the problem is that
+     * on the machine where it did occur, it was caused by an external driver
+     * or other program which adds its own values under the
+     * HKEY_PERFORMANCE_DATA key.  The NT kernel calls the required external
+     * modules to map in the data, if there's a synchronisation problem the
+     * external module would write its data at an inappropriate moment,
+     * causing the access violation.  A low-level memory checker indicated
+     * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
+     * interminable number of calls down inside RegQueryValueEx(), was
+     * overwriting memory (it wrote twice the allocated size of a buffer to a
+     * buffer allocated by the NT kernel).  This may be what's causing the
+     * problem, but since it's in the kernel there isn't much which can be
+     * done.
+     *
+     * In addition to these problems the code in RegQueryValueEx() which
+     * estimates the amount of memory required to return the performance
+     * counter information isn't very accurate, since it always returns a
+     * worst-case estimate which is usually nowhere near the actual amount
+     * required.  For example it may report that 128K of memory is required,
+     * but only return 64K of data */
+    {  pPerfData =  m_alloc (cbPerfData);
+       for (;;) {
+           dwSize = cbPerfData;
+           if ( debug_me )
+               log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
+           status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
+                                     NULL, (LPBYTE) pPerfData, &dwSize);
+           if (status == ERROR_SUCCESS) {
+               if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
+                   (*add) ( pPerfData, dwSize, requester );
+               }
+               else
+                   g10_log_debug ( "rndw32: no PERF signature\n");
+               break;
+           }
+           else if (status == ERROR_MORE_DATA) {
+               cbPerfData += PERFORMANCE_BUFFER_STEP;
+               pPerfData = m_realloc (pPerfData, cbPerfData);
+           }
+           else {
+               g10_log_debug ( "rndw32: get performance data problem\n");
+               break;
+           }
+       }
+       m_free (pPerfData);
+    }
+    /* Although this isn't documented in the Win32 API docs, it's necessary
+       to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
+       implicitly opened on the first call to RegQueryValueEx()).  If this
+       isn't done then any system components which provide performance data
+       can't be removed or changed while the handle remains active */
+    RegCloseKey (HKEY_PERFORMANCE_DATA);
+}
+
+
+static int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+                                         size_t length, int level )
+{
+    static int is_initialized;
+    static int is_windows95;
+
+
+    if( !level )
+       return 0;
+    /* We don't differentiate between level 1 and 2 here because
+     * there is no nternal entropy pool as a scary resource.  It may
+     * all work slower, but because our entropy source will never
+     * block but deliver some not easy to measure entropy, we assume level 2
+     */
+
+
+    if ( !is_initialized ) {
+       OSVERSIONINFO osvi = { sizeof( osvi ) };
+       DWORD platform;
+
+       GetVersionEx( &osvi );
+       platform = osvi.dwPlatformId;
+       is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;
+
+       if ( platform == VER_PLATFORM_WIN32s ) {
+           g10_log_fatal("can't run on a W32s platform\n" );
+       }
+       is_initialized = 1;
+       if ( debug_me )
+           log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
+    }
+
+
+    if ( debug_me )
+       log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
+                          requester, (unsigned int)length, level );
+
+    if (is_windows95 ) {
+       slow_gatherer_windows95( add, requester );
+    }
+    else {
+       slow_gatherer_windowsNT( add, requester );
+    }
+
+    return 0;
+}
+
+
+
+static int
+gather_random_fast( void (*add)(const void*, size_t, int), int requester )
+{
+    static int addedFixedItems = 0;
+
+    if ( debug_me )
+       log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
+
+    /* Get various basic pieces of system information: Handle of active
+     * window, handle of window with mouse capture, handle of clipboard owner
+     * handle of start of clpboard viewer list, pseudohandle of current
+     * process, current process ID, pseudohandle of current thread, current
+     * thread ID, handle of desktop window, handle  of window with keyboard
+     * focus, whether system queue has any events, cursor position for last
+     * message, 1 ms time for last message, handle of window with clipboard
+     * open, handle of process heap, handle of procs window station, types of
+     * events in input queue, and milliseconds since Windows was started */
+    {  byte buffer[20*sizeof(ulong)], *bufptr;
+       bufptr = buffer;
+      #define ADD(f)  do { ulong along = (ulong)(f);                 \
+                          memcpy (bufptr, &along, sizeof (along) );  \
+                          bufptr += sizeof (along); } while (0)
+       ADD ( GetActiveWindow ());
+       ADD ( GetCapture ());
+       ADD ( GetClipboardOwner ());
+       ADD ( GetClipboardViewer ());
+       ADD ( GetCurrentProcess ());
+       ADD ( GetCurrentProcessId ());
+       ADD ( GetCurrentThread ());
+       ADD ( GetCurrentThreadId ());
+       ADD ( GetDesktopWindow ());
+       ADD ( GetFocus ());
+       ADD ( GetInputState ());
+       ADD ( GetMessagePos ());
+       ADD ( GetMessageTime ());
+       ADD ( GetOpenClipboardWindow ());
+       ADD ( GetProcessHeap ());
+       ADD ( GetProcessWindowStation ());
+       ADD ( GetQueueStatus (QS_ALLEVENTS));
+       ADD ( GetTickCount ());
+
+       assert ( bufptr-buffer < sizeof (buffer) );
+       (*add) ( buffer, bufptr-buffer, requester );
+      #undef ADD
+    }
+
+    /* Get multiword system information: Current caret position, current
+     * mouse cursor position */
+    {  POINT point;
+       GetCaretPos (&point);
+       (*add) ( &point, sizeof (point), requester );
+       GetCursorPos (&point);
+       (*add) ( &point, sizeof (point), requester );
+    }
+
+    /* Get percent of memory in use, bytes of physical memory, bytes of free
+     * physical memory, bytes in paging file, free bytes in paging file, user
+     * bytes of address space, and free user bytes */
+    {  MEMORYSTATUS memoryStatus;
+       memoryStatus.dwLength = sizeof (MEMORYSTATUS);
+       GlobalMemoryStatus (&memoryStatus);
+       (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
+    }
+
+    /* Get thread and process creation time, exit time, time in kernel mode,
+       and time in user mode in 100ns intervals */
+    {  HANDLE handle;
+       FILETIME creationTime, exitTime, kernelTime, userTime;
+       DWORD minimumWorkingSetSize, maximumWorkingSetSize;
+
+       handle = GetCurrentThread ();
+       GetThreadTimes (handle, &creationTime, &exitTime,
+                                              &kernelTime, &userTime);
+       (*add) ( &creationTime, sizeof (creationTime), requester );
+       (*add) ( &exitTime, sizeof (exitTime), requester );
+       (*add) ( &kernelTime, sizeof (kernelTime), requester );
+       (*add) ( &userTime, sizeof (userTime), requester );
+
+       handle = GetCurrentProcess ();
+       GetProcessTimes (handle, &creationTime, &exitTime,
+                                               &kernelTime, &userTime);
+       (*add) ( &creationTime, sizeof (creationTime), requester );
+       (*add) ( &exitTime, sizeof (exitTime), requester );
+       (*add) ( &kernelTime, sizeof (kernelTime), requester );
+       (*add) ( &userTime, sizeof (userTime), requester );
+
+       /* Get the minimum and maximum working set size for the current process */
+       GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
+                                         &maximumWorkingSetSize);
+       (*add) ( &minimumWorkingSetSize,
+                                  sizeof (&minimumWorkingSetSize), requester );
+       (*add) ( &maximumWorkingSetSize,
+                                  sizeof (&maximumWorkingSetSize), requester );
+    }
+
+
+    /* The following are fixed for the lifetime of the process so we only
+     * add them once */
+    if (!addedFixedItems) {
+       STARTUPINFO startupInfo;
+
+       /* Get name of desktop, console window title, new window position and
+        * size, window flags, and handles for stdin, stdout, and stderr */
+       startupInfo.cb = sizeof (STARTUPINFO);
+       GetStartupInfo (&startupInfo);
+       (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
+       addedFixedItems = 1;
+    }
+
+    /* The performance of QPC varies depending on the architecture it's
+     * running on and on the OS.  Under NT it reads the CPU's 64-bit timestamp
+     * counter (at least on a Pentium and newer '486's, it hasn't been tested
+     * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
+     * timer.  There are vague mumblings in the docs that it may fail if the
+     * appropriate hardware isn't available (possibly '386's or MIPS machines
+     * running NT), but who's going to run NT on a '386? */
+    {  LARGE_INTEGER performanceCount;
+       if (QueryPerformanceCounter (&performanceCount)) {
+           if ( debug_me )
+               log_debug ("rndw32#gather_random_fast: perf data\n");
+           (*add) (&performanceCount, sizeof (&performanceCount), requester);
+       }
+       else { /* Millisecond accuracy at best... */
+           DWORD aword = GetTickCount ();
+           (*add) (&aword, sizeof (aword), requester );
+       }
+    }
+
+    return 0;
+}
+
+
+
+
+
+#endif /* !USE_ENTROPY_DLL */
 
 
 #ifndef IS_MODULE
@@ -232,6 +931,8 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
     void *ret;
     int i = *sequence;
 
+    debug_me = !!getenv("DEBUG_RNDW32");
+
     do {
        if ( i >= DIM(func_table) || i < 0 ) {
            return NULL;
@@ -246,14 +947,6 @@ gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
     return ret;
 }
 
-#ifdef USE_STATIC_RNDW32
-void
-rndw32_set_dll_name( const char *name )
-{
-    entropy_dll = m_strdup( name );
-}
-#endif
-
 #ifndef IS_MODULE
 void
 rndw32_constructor(void)
diff --git a/cipher/rsa.c b/cipher/rsa.c
new file mode 100644 (file)
index 0000000..5d852cd
--- /dev/null
@@ -0,0 +1,375 @@
+/* rsa.c  -  RSA function
+ *     Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ ***********************************************************************
+ * ATTENTION: This code should not be used in the United States
+ * before the U.S. Patent #4,405,829 expires on September 20, 2000!
+ ***********************************************************************
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "rsa.h"
+
+
+typedef struct {
+    MPI n;         /* modulus */
+    MPI e;         /* exponent */
+} RSA_public_key;
+
+
+typedef struct {
+    MPI n;         /* public modulus */
+    MPI e;         /* public exponent */
+    MPI d;         /* exponent */
+    MPI p;         /* prime  p. */
+    MPI q;         /* prime  q. */
+    MPI u;         /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+static void test_keys( RSA_secret_key *sk, unsigned nbits );
+static void generate( RSA_secret_key *sk, unsigned nbits );
+static int  check_secret_key( RSA_secret_key *sk );
+static void public(MPI output, MPI input, RSA_public_key *skey );
+static void secret(MPI output, MPI input, RSA_secret_key *skey );
+
+
+static void
+test_keys( RSA_secret_key *sk, unsigned nbits )
+{
+    RSA_public_key pk;
+    MPI test = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    MPI out1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    MPI out2 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+
+    pk.n = sk->n;
+    pk.e = sk->e;
+    {  char *p = get_random_bits( nbits, 0, 0 );
+       mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+       m_free(p);
+    }
+
+    public( out1, test, &pk );
+    secret( out2, out1, sk );
+    if( mpi_cmp( test, out2 ) )
+       log_fatal("RSA operation: public, secret failed\n");
+    secret( out1, test, sk );
+    public( out2, out1, &pk );
+    if( mpi_cmp( test, out2 ) )
+       log_fatal("RSA operation: secret, public failed\n");
+    mpi_free( test );
+    mpi_free( out1 );
+    mpi_free( out2 );
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ */
+static void
+generate( RSA_secret_key *sk, unsigned nbits )
+{
+    MPI p, q; /* the two primes */
+    MPI d;    /* the private key */
+    MPI u;
+    MPI t1, t2;
+    MPI n;    /* the public key */
+    MPI e;    /* the exponent */
+    MPI phi;  /* helper: (p-a)(q-1) */
+    MPI g;
+    MPI f;
+
+    /* select two (very secret) primes */
+    p = generate_secret_prime( nbits / 2 );
+    q = generate_secret_prime( nbits / 2 );
+    if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q (for calc of u)*/
+       mpi_swap(p,q);
+    /* calculate Euler totient: phi = (p-1)(q-1) */
+    t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+    t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+    phi = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    g  = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB  );
+    f  = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB  );
+    mpi_sub_ui( t1, p, 1 );
+    mpi_sub_ui( t2, q, 1 );
+    mpi_mul( phi, t1, t2 );
+    mpi_gcd(g, t1, t2);
+    mpi_fdiv_q(f, phi, g);
+    /* multiply them to make the private key */
+    n = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_mul( n, p, q );
+    /* find a public exponent  */
+    e = mpi_alloc( (6+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_set_ui( e, 17); /* start with 17 */
+    while( !mpi_gcd(t1, e, phi) ) /* (while gcd is not 1) */
+       mpi_add_ui( e, e, 2);
+    /* calculate the secret key d = e^1 mod phi */
+    d = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_invm(d, e, f );
+    /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+    u = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+    mpi_invm(u, p, q );
+
+    if( DBG_CIPHER ) {
+       log_mpidump("  p= ", p );
+       log_mpidump("  q= ", q );
+       log_mpidump("phi= ", phi );
+       log_mpidump("  g= ", g );
+       log_mpidump("  f= ", f );
+       log_mpidump("  n= ", n );
+       log_mpidump("  e= ", e );
+       log_mpidump("  d= ", d );
+       log_mpidump("  u= ", u );
+    }
+
+    mpi_free(t1);
+    mpi_free(t2);
+    mpi_free(phi);
+    mpi_free(f);
+    mpi_free(g);
+
+    sk->n = n;
+    sk->e = e;
+    sk->p = p;
+    sk->q = q;
+    sk->d = d;
+    sk->u = u;
+
+    /* now we can test our keys (this should never fail!) */
+    test_keys( sk, nbits - 64 );
+}
+
+
+/****************
+ * Test wether the secret key is valid.
+ * Returns: true if this is a valid key.
+ */
+static int
+check_secret_key( RSA_secret_key *sk )
+{
+    int rc;
+    MPI temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
+
+    mpi_mul(temp, sk->p, sk->q );
+    rc = mpi_cmp( temp, sk->n );
+    mpi_free(temp);
+    return !rc;
+}
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ *     c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+static void
+public(MPI output, MPI input, RSA_public_key *pkey )
+{
+    if( output == input ) { /* powm doesn't like output and input the same */
+       MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+       mpi_powm( x, input, pkey->e, pkey->n );
+       mpi_set(output, x);
+       mpi_free(x);
+    }
+    else
+       mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ *     m = c^d mod n
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ *
+ * FIXME: We should better use the Chinese Remainder Theorem
+ */
+static void
+secret(MPI output, MPI input, RSA_secret_key *skey )
+{
+    mpi_powm( output, input, skey->d, skey->n );
+}
+
+
+/*********************************************
+ **************  interface  ******************
+ *********************************************/
+
+int
+rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+    RSA_secret_key sk;
+
+    if( !is_RSA(algo) )
+       return G10ERR_PUBKEY_ALGO;
+
+    generate( &sk, nbits );
+    skey[0] = sk.n;
+    skey[1] = sk.e;
+    skey[2] = sk.d;
+    skey[3] = sk.p;
+    skey[4] = sk.q;
+    skey[5] = sk.u;
+    /* make an empty list of factors */
+    *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+    return 0;
+}
+
+
+int
+rsa_check_secret_key( int algo, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( !is_RSA(algo) )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    if( !check_secret_key( &sk ) )
+       return G10ERR_BAD_SECKEY;
+
+    return 0;
+}
+
+
+
+int
+rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+    RSA_public_key pk;
+
+    if( algo != 1 && algo != 2 )
+       return G10ERR_PUBKEY_ALGO;
+
+    pk.n = pkey[0];
+    pk.e = pkey[1];
+    resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.n ) );
+    public( resarr[0], data, &pk );
+    return 0;
+}
+
+int
+rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( algo != 1 && algo != 2 )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    *result = mpi_alloc_secure( mpi_get_nlimbs( sk.n ) );
+    secret( *result, data[0], &sk );
+    return 0;
+}
+
+int
+rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+    RSA_secret_key sk;
+
+    if( algo != 1 && algo != 3 )
+       return G10ERR_PUBKEY_ALGO;
+
+    sk.n = skey[0];
+    sk.e = skey[1];
+    sk.d = skey[2];
+    sk.p = skey[3];
+    sk.q = skey[4];
+    sk.u = skey[5];
+    resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.n ) );
+    secret( resarr[0], data, &sk );
+
+    return 0;
+}
+
+int
+rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+          int (*cmp)(void *opaque, MPI tmp), void *opaquev )
+{
+    RSA_public_key pk;
+    MPI result;
+    int rc;
+
+    if( algo != 1 && algo != 3 )
+       return G10ERR_PUBKEY_ALGO;
+    pk.n = pkey[0];
+    pk.e = pkey[1];
+    result = mpi_alloc( (160+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
+    public( result, data[0], &pk );
+    /*rc = (*cmp)( opaquev, result );*/
+    rc = mpi_cmp( result, hash )? G10ERR_BAD_SIGN:0;
+    mpi_free(result);
+
+    return rc;
+}
+
+
+unsigned int
+rsa_get_nbits( int algo, MPI *pkey )
+{
+    if( !is_RSA(algo) )
+       return 0;
+    return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm.  We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ *         the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ *           1 set : allows encryption
+ */
+const char *
+rsa_get_info( int algo,
+             int *npkey, int *nskey, int *nenc, int *nsig, int *usage )
+{
+    *npkey = 2;
+    *nskey = 6;
+    *nenc = 1;
+    *nsig = 1;
+
+    switch( algo ) {
+      case 1: *usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA";
+      case 2: *usage = PUBKEY_USAGE_ENC; return "RSA-E";
+      case 3: *usage = PUBKEY_USAGE_SIG; return "RSA-S";
+      default:*usage = 0; return NULL;
+    }
+}
+
diff --git a/cipher/rsa.h b/cipher/rsa.h
new file mode 100644 (file)
index 0000000..8b60ecb
--- /dev/null
@@ -0,0 +1,36 @@
+/* rsa.h
+ *     Copyright (C) 1997,1998 by Werner Koch (dd9jn)
+ *     Copyright (C) 2000 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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
+ */
+#ifndef G10_RSA_H
+#define G10_RSA_H
+
+int rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int rsa_check_secret_key( int algo, MPI *skey );
+int rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+                   int (*cmp)(void *, MPI), void *opaquev );
+unsigned rsa_get_nbits( int algo, MPI *pkey );
+const char *rsa_get_info( int algo, int *npkey, int *nskey,
+                                   int *nenc, int *nsig, int *use );
+
+
+#endif /*G10_RSA_H*/
index f231e37..aa3ac09 100644 (file)
@@ -337,10 +337,10 @@ sha1_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 20;
-    *r_init  = (void (*)(void *))sha1_init;
-    *r_write = (void (*)(void *, byte*, size_t))sha1_write;
-    *r_final = (void (*)(void *))sha1_final;
-    *r_read  = (byte *(*)(void *))sha1_read;
+    *(void  (**)(SHA1_CONTEXT *))r_init                = sha1_init;
+    *(void  (**)(SHA1_CONTEXT *, byte*, size_t))r_write = sha1_write;
+    *(void  (**)(SHA1_CONTEXT *))r_final               = sha1_final;
+    *(byte *(**)(SHA1_CONTEXT *))r_read                = sha1_read;
 
     return "SHA1";
 }
index 0e42160..abe449a 100644 (file)
@@ -899,10 +899,10 @@ tiger_get_info( int algo, size_t *contextsize,
     *r_asnoid = asn;
     *r_asnlen = DIM(asn);
     *r_mdlen = 24;
-    *r_init  = (void (*)(void *))tiger_init;
-    *r_write = (void (*)(void *, byte*, size_t))tiger_write;
-    *r_final = (void (*)(void *))tiger_final;
-    *r_read  = (byte *(*)(void *))tiger_read;
+    *(void  (**)(TIGER_CONTEXT *))r_init                = tiger_init;
+    *(void  (**)(TIGER_CONTEXT *, byte*, size_t))r_write = tiger_write;
+    *(void  (**)(TIGER_CONTEXT *))r_final               = tiger_final;
+    *(byte *(**)(TIGER_CONTEXT *))r_read                = tiger_read;
 
     return "TIGER";
 }
index 1eea4b8..5766021 100644 (file)
 /* Prototype for the self-test function. */
 static const char *selftest(void);
 
-/* Macros used by the info function. */
-#define FNCCAST_SETKEY(f)  ((int(*)(void*, byte*, unsigned))(f))
-#define FNCCAST_CRYPT(f)   ((void(*)(void*, byte*, byte*))(f))
-
 /* Structure for an expanded Twofish key.  s contains the key-dependent
  * S-boxes composed with the MDS matrix; w contains the eight "whitening"
  * subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys.  Note
@@ -990,16 +986,20 @@ twofish_get_info (int algo, size_t *keylen,
     *keylen = algo==10? 256 : 128;
     *blocksize = 16;
     *contextsize = sizeof (TWOFISH_context);
-    *r_setkey = FNCCAST_SETKEY (twofish_setkey);
-    *r_encrypt= FNCCAST_CRYPT (twofish_encrypt);
-    *r_decrypt= FNCCAST_CRYPT (twofish_decrypt);
-
-   if( algo == 10 )
-     return "TWOFISH";
-   if (algo == 102) /* This algorithm number is assigned for
-                    * experiments, so we can use it */
-     return "TWOFISH128";
-   return NULL;
+
+    *(int  (**)(TWOFISH_context*, const byte*, const unsigned))r_setkey
+                                                       = twofish_setkey;
+    *(void (**)(const TWOFISH_context*, byte*, const byte*))r_encrypt
+                                                       = twofish_encrypt;
+    *(void (**)(const TWOFISH_context*, byte*, const byte*))r_decrypt
+                                                       = twofish_decrypt;
+
+    if( algo == 10 )
+       return "TWOFISH";
+    if (algo == 102) /* This algorithm number is assigned for
+                     * experiments, so we can use it */
+       return "TWOFISH128";
+    return NULL;
 }
 
 
index fddb93d..b3e44ec 100644 (file)
@@ -11,19 +11,17 @@ AC_PREREQ(2.13)
 AC_INIT(g10/gpg.c)
 AC_CONFIG_AUX_DIR(scripts)
 AM_CONFIG_HEADER(config.h)
+AC_CANONICAL_SYSTEM
+AM_INIT_AUTOMAKE(gnupg,`cat $srcdir/VERSION`)
 
-
-VERSION=`cat $srcdir/VERSION`
-PACKAGE=gnupg
-ALL_LINGUAS="de es_ES fr it pl pt_BR pt_PT ru"
+ALL_LINGUAS="da de eo es_ES fr id it ja nl pl pt_BR pt_PT ru sv"
 static_modules="sha1 md5 rmd160"
-AC_SUBST(VERSION)
-AC_SUBST(PACKAGE)
-AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+static_random_module=""
+
+AC_PROG_AWK
 
-MODULES_IN_CIPHER=`awk '/# MODULES: / { for(i=3;i<=NF;i++) print $i}' \
-                                                $srcdir/cipher/Makefile.am`
+MODULES_IN_CIPHER=`$AWK '/^EXTRA_PROGRAMS/ { for(i=3;i<=NF;i++) print $i}' \
+                                              $srcdir/cipher/Makefile.am`
 
 dnl
 dnl  Check for random module options
@@ -132,7 +130,6 @@ AM_MAINTAINER_MODE
 
 dnl Checks for programs.
 
-AC_CANONICAL_SYSTEM
 dnl
 dnl Setup some stuff depending on host/target.
 dnl
@@ -145,8 +142,10 @@ case "${target}" in
         CC="${target}-gcc"
         CPP="${target}-gcc -E"
         RANLIB="${target}-ranlib"
+        disallowed_modules="rndunix rndlinux rndegd"
         ;;
     *)
+        disallowed_modules="rndw32"
        ;;
 esac
 
@@ -177,9 +176,6 @@ AM_PROG_LIBTOOL
 
 
 MPI_OPT_FLAGS=""
-if test "$GCC" = yes; then
-    CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
-fi
 
 
 try_gettext=yes
@@ -213,6 +209,12 @@ case "${target}" in
         try_gdbm="no"
         ;;
 
+    *-*-freebsd*)
+       # FreeBSD
+       CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+       LDFLAGS="$LDFLAGS -L/usr/local/lib"
+       ;;
+
     *-*-hpux*)
         if test -z "$GCC" ; then
             CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE"
@@ -234,7 +236,7 @@ esac
 AC_SUBST(MPI_OPT_FLAGS)
 GNUPG_SYS_SYMBOL_UNDERSCORE
 GNUPG_CHECK_PIC
-GNUPG_CHECK_RDYNAMIC
+GNUPG_CHECK_EXPORTDYNAMIC
 if test "$NO_PIC" = yes; then
     try_dynload=no
 fi
@@ -272,6 +274,13 @@ case "${target}" in
         NAME_OF_DEV_URANDOM="/dev/urandom"
         DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
         ;;
+
+    *-netbsd*)
+        NAME_OF_DEV_RANDOM="/dev/random"
+        NAME_OF_DEV_URANDOM="/dev/urandom"
+        DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+        ;;
+
     *)
         NAME_OF_DEV_RANDOM="/dev/random"
         NAME_OF_DEV_URANDOM="/dev/urandom"
@@ -327,21 +336,21 @@ if test "$try_dynload" = yes ; then
   if test "$ac_cv_lib_dl_dlopen" = "yes"; then
     AC_DEFINE(USE_DYNAMIC_LINKING)
     AC_DEFINE(HAVE_DL_DLOPEN)
-    DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+    DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
     use_gnupg_extensions=yes
   else
-    AC_CHECK_LIB(c,dlopen)
-    if test "$ac_cv_lib_c_dlopen" = "yes"; then
+    AC_CHECK_FUNCS(dlopen)
+    if test "$ac_cv_func_dlopen" = "yes"; then
       AC_DEFINE(USE_DYNAMIC_LINKING)
       AC_DEFINE(HAVE_DL_DLOPEN)
-      DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+      DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
       use_gnupg_extensions=yes
     else
       AC_CHECK_LIB(dld,shl_load)
       if test "$ac_cv_lib_dld_shl_load" = "yes"; then
         AC_DEFINE(USE_DYNAMIC_LINKING)
         AC_DEFINE(HAVE_DL_SHL_LOAD)
-        DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+        DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
         use_gnupg_extensions=yes
 dnl -----------------
 dnl  DLD is not ready for use. So I better disable this test
@@ -350,7 +359,7 @@ dnl    AC_CHECK_LIB(dld,dld_link)
 dnl    if test "$ac_cv_lib_dld_dld_link" = "yes"; then
 dnl      AC_DEFINE(USE_DYNAMIC_LINKING)
 dnl      AC_DEFINE(HAVE_DLD_DLD_LINK)
-dnl      DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+dnl      DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
 dnl      use_gnupg_extensions=yes
 dnl ---------------
       fi
@@ -371,7 +380,7 @@ AC_SUBST(DYNLINK_MOD_CFLAGS)
 
 dnl Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h langinfo.h)
+AC_CHECK_HEADERS(unistd.h langinfo.h termio.h)
 
 
 dnl Checks for typedefs, structures, and compiler characteristics.
@@ -393,6 +402,7 @@ GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
 AC_CHECK_SIZEOF(unsigned short, 2)
 AC_CHECK_SIZEOF(unsigned int, 4)
 AC_CHECK_SIZEOF(unsigned long, 4)
+AC_CHECK_SIZEOF(unsigned long long, 0)
 
 if test "$ac_cv_sizeof_unsigned_short" = "0" \
    || test "$ac_cv_sizeof_unsigned_int" = "0" \
@@ -405,8 +415,9 @@ fi
 dnl Checks for library functions.
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap)
-AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit)
+AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit clock_gettime)
 AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo)
+AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask)
 
 GNUPG_CHECK_MLOCK
 GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
@@ -483,29 +494,27 @@ fi
 dnl
 dnl Figure out the default linkage mode for cipher modules
 dnl
-dnl (We always need a static rmd160)
 print_egd_notice=no
-static_modules="$static_modules rmd160"
 if test "$use_static_rnd" = default; then
   if test "$ac_cv_have_dev_random" = yes; then
-      static_modules="$static_modules rndlinux"
+      static_random_module="rndlinux"
   else
       case "${target}" in
           *-*-mingw32)
-              static_modules="$static_modules rndw32"
+              static_random_module="rndw32"
               AC_DEFINE(USE_STATIC_RNDW32)
               ;;
           i?86-emx-os2|i?86-*-os2*emx)
-              static_modules="$static_modules rndos2"
+              static_random_module="rndos2"
               ;;
           m68k-atari-mint)
-              static_modules="$static_modules rndatari"
+              static_random_module="rndatari"
               ;;
           i?86-*-msdosdjgpp*)
-              static_modules="$static_modules"
+              :
               ;;
           *)
-              static_modules="$static_modules rndunix"
+              static_random_module="rndunix"
               print_egd_notice=yes
              ;;
       esac
@@ -514,7 +523,7 @@ else
   if test "$use_static_rnd" = none; then
     :
   else
-    static_modules="$static_modules rnd$use_static_rnd"
+    static_random_module="rnd$use_static_rnd"
     if test "$use_static_rnd" = "unix"; then
         print_egd_notice=yes
     fi
@@ -547,23 +556,31 @@ dnl
 dnl Parse the modules list and build the list
 dnl of static and dymically linked modules
 dnl
+dnl (We always need a static rmd160)
+static_modules="$static_modules rmd160 $static_random_module"
 STATIC_CIPHER_NAMES=""
 STATIC_CIPHER_OBJS=""
 DYNAMIC_CIPHER_MODS=""
 GNUPG_MSG_PRINT([dynamically linked cipher modules:])
 for name in $MODULES_IN_CIPHER; do
-    x="no"
-    for i in $static_modules; do
-        if test "$name" = "$i" ; then
-            x="yes"
-        fi
+    x="yes"
+    for i in $disallowed_modules; do
+        if test "$name" = "$i" ; then x="no" ; fi
     done;
     if test $x = yes; then
-        STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
-        STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.lo"
-    else
-        DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
-        GNUPG_MSG_PRINT([$name])
+        x="no"
+        for i in $static_modules; do
+            if test "$name" = "$i" ; then
+                x="yes"
+            fi
+        done;
+        if test $x = yes; then
+            STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
+            STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.o"
+        else
+            DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
+            GNUPG_MSG_PRINT([$name])
+        fi
     fi
 done
 AC_MSG_RESULT()
@@ -663,6 +680,9 @@ fi
 AC_SUBST(ZLIBS)
 
 
+# Allow users to append something to the version string without
+# flagging it as development version.  The user version parts is
+# considered everything after a dash.
 changequote(,)dnl
 tmp_pat='[a-zA-Z]'
 changequote([,])dnl
@@ -678,12 +698,26 @@ AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
 
 GNUPG_DO_LINK_FILES
 
+GNUPG_CHECK_GNUMAKE
+
+if test "$GCC" = yes; then
+    if test "$MAINTAINER_MODE" = "yes"; then
+        CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+    else
+        CFLAGS="$CFLAGS -Wall"
+    fi
+fi
+
 dnl
 dnl Make the version number in gcrypt/gcrypt.h the same as the one here.
 dnl (this is easier than to have a .in file just for one substitution)
 dnl
 GNUPG_FIX_HDR_VERSION(gcrypt/gcrypt.h, GCRYPT_VERSION)
 
+GCRYPT_LIBS="-L${libdir} -lgcrypt"
+GCRYPT_CFLAGS=""
+AC_SUBST(GCRYPT_LIBS)
+AC_SUBST(GCRYPT_CFLAGS)
 
 AC_OUTPUT_COMMANDS([
 chmod +x scripts/db2html
index a41901b..5bb8faf 100644 (file)
@@ -1,3 +1,9 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  * argparse.c (default_strusage): Changed year of default copyright.
+
+  * dotlock.c (disable_dotlock): New.
+
 Mon Jan 24 13:04:28 CET 2000  Werner Koch  <wk@gnupg.de>
 
        * README: New.
index 3f77805..6293d3e 100644 (file)
@@ -1,5 +1,5 @@
 /* [argparse.c wk 17.06.97] Argument Parser for option handling
- *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *  This file is part of GnuPG.
  *
  *  GnuPG is free software; you can redistribute it and/or modify
@@ -899,7 +899,7 @@ strusage( int level )
     switch( level ) {
       case 11: p = "foo"; break;
       case 13: p = "0.0"; break;
-      case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break;
+      case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break;
       case 15: p =
 "This program comes with ABSOLUTELY NO WARRANTY.\n"
 "This is free software, and you are welcome to redistribute it\n"
index 8e61f7a..29ab65d 100644 (file)
@@ -1,5 +1,5 @@
 /* dotlock.c - dotfile locking
- *     Copyright (C) 1998,2000 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -42,14 +42,22 @@ struct dotlock_handle {
     char *tname;    /* name of lockfile template */
     char *lockname; /* name of the real lockfile */
     int locked;     /* lock status */
+    int disable;    /* locking */
 };
 
 
 static DOTLOCK all_lockfiles;
+static int never_lock;
 
 static int read_lockfile( const char *name );
 static void remove_lockfiles(void);
 
+void
+disable_dotlock(void)
+{
+    never_lock = 1;
+}
+
 /****************
  * Create a lockfile with the given name and return an object of
  * type DOTLOCK which may be used later to actually do the lock.
@@ -88,6 +96,16 @@ create_dotlock( const char *file_to_lock )
        return NULL;
 
     h = jnlib_xcalloc( 1, sizeof *h );
+    if( never_lock ) {
+       h->disable = 1;
+      #ifdef _REENTRANT
+       /* fixme: aquire mutex on all_lockfiles */
+      #endif
+       h->next = all_lockfiles;
+       all_lockfiles = h;
+       return h;
+    }
+
 #ifndef HAVE_DOSISH_SYSTEM
     sprintf( pidstr, "%10d\n", (int)getpid() );
     /* fixme: add the hostname to the second line (FQDN or IP addr?) */
@@ -191,6 +209,10 @@ make_dotlock( DOTLOCK h, long timeout )
     const char *maybe_dead="";
     int backoff=0;
 
+    if( h->disable ) {
+       return 0;
+    }
+
     if( h->locked ) {
        log_debug("oops, `%s' is already locked\n", h->lockname );
        return 0;
@@ -259,6 +281,10 @@ release_dotlock( DOTLOCK h )
 #else
     int pid;
 
+    if( h->disable ) {
+       return 0;
+    }
+
     if( !h->locked ) {
        log_debug("oops, `%s' is not locked\n", h->lockname );
        return 0;
@@ -333,11 +359,13 @@ remove_lockfiles()
 
     while( h ) {
        h2 = h->next;
-       if( h->locked )
-           unlink( h->lockname );
-       unlink(h->tname);
-       jnlib_free(h->tname);
-       jnlib_free(h->lockname);
+       if( !h->disable ) {
+           if( h->locked )
+               unlink( h->lockname );
+           unlink(h->tname);
+           jnlib_free(h->tname);
+           jnlib_free(h->lockname);
+       }
        jnlib_free(h);
        h = h2;
     }
index d54219e..74ac876 100644 (file)
@@ -24,6 +24,7 @@
 struct dotlock_handle;
 typedef struct dotlock_handle *DOTLOCK;
 
+void disable_dotlock(void);
 DOTLOCK create_dotlock( const char *file_to_lock );
 int make_dotlock( DOTLOCK h, long timeout );
 int release_dotlock( DOTLOCK h );
index dda6d39..83d1517 100644 (file)
@@ -1,3 +1,15 @@
+Fri Jul 14 19:38:23 CEST 2000  Werner Koch  <wk@>
+
+  * gcrypt.h (gcry_md_start_debug, gcry_md_stop_debug): New.
+  (gcry_ctl_cmds): New control values
+
+  * sexp.c (gcry_sexp_sscan): Add hex format parsing.
+
+  * secmem.c (lock_pool): Check for ENOSYS return my mlock() on old SCOs.
+  (pool_is_mmapped): Made volatile.
+  (lock_pool): No more warning for QNX. By Sam Roberts.
+  (lock_pool,secmem_init): Additional check for dropped privs.
+
 2000-03-21 09:18:48  Werner Koch  (wk@habibti.gnupg.de)
 
        * gcrypt.h (gcry_md_setkey): New.
index 0681e91..359bc1c 100644 (file)
@@ -12,9 +12,9 @@ bin_SCRIPTS = gcrypt-config
 m4datadir = $(datadir)/aclocal
 m4data_DATA = gcrypt.m4
 
-noinst_PROGRAMS = testapi
-#sexp_SOURCES = sexp.c mpiapi.c
-#sexp_LDADD =  ../cipher/libcipher.la ../mpi/libmpi.la ../util/libutil.la ./libgcrypt.la @INTLLIBS@
+noinst_PROGRAMS = testapi sexp
+sexp_SOURCES = sexp.c
+sexp_LDADD =  libgcrypt.la
 testapi_SOURCES = testapi.c
 testapi_LDADD = libgcrypt.la
 
index ab577a9..0f7fffd 100644 (file)
@@ -1,12 +1,12 @@
 #!/bin/sh
 
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
 
 gcrypt_libs="@GCRYPT_LIBS@"
 gcrypt_cflags="@GCRYPT_CFLAGS@"
 
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-exec_prefix_set=no
 
 usage()
 {
index 416505d..aaeb95b 100644 (file)
@@ -128,6 +128,8 @@ enum gcry_ctl_cmds {
     GCRYCTL_RESUME_SECMEM_WARN = 29,
     GCRYCTL_DROP_PRIVS         = 30,
     GCRYCTL_ENABLE_M_GUARD     = 31,
+    GCRYCTL_START_DUMP         = 32,
+    GCRYCTL_STOP_DUMP          = 33,
 };
 
 int gcry_control( enum gcry_ctl_cmds, ... );
@@ -411,6 +413,12 @@ int gcry_md_map_name( const char* name );
 #define gcry_md_test_algo(a) \
            gcry_md_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
 
+#define gcry_md_start_debug(a,b) \
+           gcry_md_ctl( (a), GCRYCTL_START_DUMP, (b), 0 )
+#define gcry_md_stop_debug(a,b) \
+           gcry_md_ctl( (a), GCRYCTL_STOP_DUMP, (b), 0 )
+
+
 /*********************************************
  *******  random generating functions  *******
  *********************************************/
index 388fa91..56df4f8 100644 (file)
@@ -1,5 +1,5 @@
 /* secmem.c  - memory allocation from a secure heap
- *     Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -56,7 +56,7 @@ struct memblock_struct {
 
 static void  *pool;
 static volatile int pool_okay; /* may be checked in an atexit function */
-static int   pool_is_mmapped;
+static volatile int pool_is_mmapped;
 static size_t poolsize; /* allocated length */
 static size_t poollen; /* used length */
 static MEMBLOCK *unused_blocks;
@@ -126,7 +126,9 @@ lock_pool( void *p, size_t n )
   #endif
 
     if( uid && !geteuid() ) {
-       if( setuid( uid ) || getuid() != geteuid()  )
+       /* check that we really dropped the privs.
+        * Note: setuid(0) should always fail */
+       if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
            log_fatal("failed to reset uid: %s\n", strerror(errno));
     }
 
@@ -143,6 +145,12 @@ lock_pool( void *p, size_t n )
        show_warning = 1;
     }
 
+  #elif defined ( __QNX__ )
+    /* QNX does not page at all, so the whole secure memory stuff does
+     * not make much sense.  However it is still of use because it
+     * wipes out the memory on a free().
+     * Therefore it is sufficient to suppress the warning
+     */
   #else
     log_info("Please note that you don't have secure memory on this system\n");
   #endif
@@ -252,7 +260,7 @@ secmem_init( size_t n )
        disable_secmem=1;
        uid = getuid();
        if( uid != geteuid() ) {
-           if( setuid( uid ) || getuid() != geteuid() )
+           if( setuid( uid ) || getuid() != geteuid()  || !setuid(0) )
                log_fatal("failed to drop setuid\n" );
        }
       #endif
index d720d4f..cd7af7a 100644 (file)
@@ -1,5 +1,5 @@
 /* sexp.c  -  S-Expression handling
- *     Copyright (C) 1999 Free Software Foundation, Inc.
+ *     Copyright (C) 1999, 2000 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -571,6 +571,34 @@ gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
 }
 
 
+
+
+
+static int
+hextobyte( const byte *s )
+{
+    int c=0;
+
+    if( *s >= '0' && *s <= '9' )
+       c = 16 * (*s - '0');
+    else if( *s >= 'A' && *s <= 'F' )
+       c = 16 * (10 + *s - 'A');
+    else if( *s >= 'a' && *s <= 'f' ) {
+       c = 16 * (10 + *s - 'a');
+    }
+    s++;
+    if( *s >= '0' && *s <= '9' )
+       c += *s - '0';
+    else if( *s >= 'A' && *s <= 'F' )
+       c += 10 + *s - 'A';
+    else if( *s >= 'a' && *s <= 'f' ) {
+       c += 10 + *s - 'a';
+    }
+    return c;
+}
+
+
+
 /****************
  * Scan the provided buffer and return the S expression in our internal
  * format.  Returns a newly allocated expression.  If erroff is not NULL and
@@ -592,6 +620,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
     const char *hexfmt=NULL;
     const char *base64=NULL;
     const char *disphint=NULL;
+    int hexcount=0;
     int quoted_esc=0;
     int datalen=0;
     int first;
@@ -603,7 +632,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
     tail = head = NULL;
     first = 0;
     for(p=buffer,n=length; n; p++, n-- ) {
-       if( tokenp ) {
+       if( tokenp && !hexfmt ) {
            if( strchr( tokenchars, *p ) )
                continue;
        }
@@ -657,8 +686,46 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
            }
        }
        else if( hexfmt ) {
-           if( *p == '#' )
-              hexfmt = NULL;
+           if( isxdigit( *p ) )
+               hexcount++;
+           else if( *p == '#' ) {
+               int i;
+
+               if( (hexcount & 1) ) {
+                   *erroff = p - buffer;
+                   return -12;  /* odd number of hex digits */
+               }
+
+               /* make a new list entry */
+               datalen = hexcount/2;
+               node = g10_xcalloc( 1, sizeof *node + datalen );
+               if( first ) { /* stuff it into the first node */
+                   first = 0;
+                   node->up = tail;
+                   tail->u.list = node;
+               }
+               else {
+                   node->up = tail->up;
+                   tail->next = node;
+               }
+               tail = node;
+               /* and fill in the value (we store the value in the node)*/
+               node->type = ntDATA;
+               node->u.data.len = datalen;
+               for(i=0, hexfmt++; hexfmt < p; hexfmt++ ) {
+                   if( isspace( *hexfmt ) )
+                       continue;
+                   node->u.data.d[i++] = hextobyte( hexfmt );
+                   hexfmt++;
+               }
+               assert( hexfmt == p );
+               assert( i == datalen );
+               hexfmt = NULL;
+           }
+           else if( !isspace( *p ) ) {
+               *erroff = p - buffer;
+               return -11;  /* invalid hex character */
+           }
        }
        else if( base64 ) {
            if( *p == '|' )
@@ -706,6 +773,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
            else if( *p == '#' ) {
                digptr = NULL; /* we ignore the optional length */
                hexfmt = p;
+               hexcount = 0;
            }
            else if( *p == '|' ) {
                digptr = NULL; /* we ignore the optional length */
@@ -751,8 +819,10 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
            quoted = p;
            quoted_esc = 0;
        }
-       else if( *p == '#' )
+       else if( *p == '#' ) {
            hexfmt = p;
+           hexcount = 0;
+       }
        else if( *p == '|' )
            base64 = p;
        else if( *p == '[' ) {
@@ -821,16 +891,17 @@ gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
 
 
 
-#if 0
+#if 1
 /***********************************************************/
 
 const char *
 strusage( int level )
 {
-    return default_strusage(level);
+    return "?";
 }
 
 
+#if 0
 static int
 sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
 {
@@ -909,7 +980,7 @@ sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
 
     return 0;
 }
-
+#endif
 
 
 int
@@ -921,7 +992,7 @@ main(int argc, char **argv)
     FILE *fp;
     GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp;
 
-  #if 0
+  #if 1
     fp = stdin;
     n = fread(buffer, 1, 5000, fp );
     rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff );
@@ -969,7 +1040,7 @@ main(int argc, char **argv)
            dump_sexp( s1 );
          }
 
-       #if 1
+       #if 0
        {  int i,rc, algo;
           GCRY_MPI *array;