diff options
Diffstat (limited to 'libgcrypt-1.4.6/random')
-rw-r--r-- | libgcrypt-1.4.6/random/ChangeLog | 139 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/Makefile.am | 49 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/Makefile.in | 519 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rand-internal.h | 137 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/random-csprng.c | 1397 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/random-daemon.c | 360 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/random-fips.c | 1118 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/random.c | 323 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/random.h | 72 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rndegd.c | 290 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rndhw.c | 138 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rndlinux.c | 167 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rndunix.c | 883 | ||||
-rw-r--r-- | libgcrypt-1.4.6/random/rndw32.c | 981 |
14 files changed, 6573 insertions, 0 deletions
diff --git a/libgcrypt-1.4.6/random/ChangeLog b/libgcrypt-1.4.6/random/ChangeLog new file mode 100644 index 0000000..b1639c4 --- /dev/null +++ b/libgcrypt-1.4.6/random/ChangeLog @@ -0,0 +1,139 @@ +2009-12-10 Werner Koch <wk@g10code.com> + + * rndw32.c (system_is_w2000): New. + (_gcry_rndw32_gather_random): Set it. + (slow_gatherer): Ignore SystemObjectInformation on W2000. Fixes + bug#1167. + +2009-06-24 Werner Koch <wk@g10code.com> + + * rndhw.c (poll_padlock): Asm change from Fedora. + +2009-01-22 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_deinit_external_test): Do not return a + value. Reported Albert Chin. + +2008-09-16 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_aes_driver): No re-seeding with test contexts. + (_gcry_rngfips_init_external_test): Fix setting of test_dt_ptr. + (struct rng_context): Add flag TEST_NO_DUP_CHECK. + (x931_aes_driver): Use that flag. + (_gcry_rngfips_init_external_test): Add arg FLAGS and use it to + modify the test. + * random.c (_gcry_random_init_external_test): Pass FLAGS. + +2008-09-15 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_init_external_test): New. + (_gcry_random_run_external_test): New. + (_gcry_random_deinit_external_test): New. + * random-fips.c (struct rng_context): Turn TEST_DT_COUNTER into a + 32 bit integer. + (x931_get_dt): Ditto. + (selftest_kat): Intialize it accordingly. + (_gcry_rngfips_init_external_test): New. + (_gcry_rngfips_run_external_test): New. + (_gcry_rngfips_deinit_external_test): New. + +2008-09-05 Werner Koch <wk@g10code.com> + + * random.c (_gcry_random_selftest): Return success if not in fips + mode. + +2008-09-01 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_get_dt) [W32]: Do not use getppid. + (get_entropy): Prepare for use under Windows. + (_gcry_rngfips_selftest): Ditto. + (entropy_collect_cb): Make sure that the gatherer never overflows + the buffers. + +2008-08-29 Werner Koch <wk@g10code.com> + + * random-fips.c (SEED_TTL): New. + (struct rng_context): Add USE_COUNTER, remove NEED_STRONG_ENTROPY. + (x931_aes_driver): Do re-seeding if required. + (x931_generate_key, x931_generate_seed): Factor common code out to .. + (get_entropy): .. new. Always use /dev/random. + (x931_generate_key): Seed key for nonce_context from std_rng_context. + (x931_reseed): New. Seed nonce context from std_rng_context. + (get_random): Use x931_reseed. + (_gcry_rngfips_selftest): Return an error if no /dev/radom support + has been compiled in. + (get_random): Remove locking. + (_gcry_rngfips_randomize, _gcry_rngfips_create_nonce): Lock here. + +2008-08-28 Werner Koch <wk@g10code.com> + + * random-daemon.c (connect_to_socket): Use GPG_ERR_ENAMETOOLONG. + +2008-08-25 Werner Koch <wk@g10code.com> + + * random-fips.c (x931_aes): Take datetime_GT from an arg. + (x931_aes_driver): Call x931_get_dt here. + (x931_get_dt): Implement the KAT hack. + (x931_generate_seed): Copy the seed value to the provided buffer. + (selftest_kat): New. + +2008-08-22 Werner Koch <wk@g10code.com> + + * random.c (_gcry_update_random_seed_file): Move operational check + to _gcry_vcontrol. + (_gcry_fast_random_poll): Ditto. + (_gcry_random_selftest): New. + * random-fips.c (_gcry_rngfips_selftest): New. + +2008-08-21 Werner Koch <wk@g10code.com> + + * random-fips.c: Finish implementation. + +2008-08-15 Werner Koch <wk@g10code.com> + + * random-fips.c: New. + + * random-csprng.c (process-cb, progress_cb_data): Move to + random.c. + (_gcry_register_random_progress, _gcry_random_progress): Ditto. + (_gcry_random_initialize): Rename to _gcry_rngcsprng_initialize. + (_gcry_random_dump_stats): Rename to _gcry_rngcsprng_dump_stats. + (_gcry_secure_random_alloc): Rename to + _gcry_rngcsprng_secure_alloc. + (_gcry_enable_quick_random_gen): Rename to + _gcry_rngcsprng_enable_quick_gen. + (_gcry_set_random_daemon_socket): Rename to + _gcry_rngcsprng_set_daemon_socket. + (_gcry_use_random_daemon): Rename to _gcry_rngcsprng_use_daemon. + (_gcry_random_is_faked): Rename to _gcry_rngcsprng_is_faked. + (gcry_random_add_bytes): Rename to _gcry_rngcsprng_add_bytes. + (gcry_random_bytes): Remove + (gcry_random_bytes_secure): Remove. + (gcry_randomize): Rename to _gcry_rngcsprng_randomize. + (_gcry_set_random_seed_file): Rename to + _gcry_rngcsprng_set_seed_file. + (_gcry_update_random_seed_file): Rename to + _gcry_rngcsprng_update_seed_file. + (_gcry_fast_random_poll): Rename to _gcry_rngcsprng_fast_poll. + (gcry_create_nonce): Rename to _gcry_rngcsprng_create_nonce. + + * random.c: Factor all code out to random-csprng.c and implement + wrapper functions. + +2008-07-05 Werner Koch <wk@g10code.com> + + * random-daemon.c, random.h, rndhw.c, rndunix.c, rand-internal.h * + random.c, rndegd.c, rndlinux.c, rndw32.c: Move from ../cipher/ to + here. + * Makefile.am: New. + + Copyright 2008 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + diff --git a/libgcrypt-1.4.6/random/Makefile.am b/libgcrypt-1.4.6/random/Makefile.am new file mode 100644 index 0000000..336109a --- /dev/null +++ b/libgcrypt-1.4.6/random/Makefile.am @@ -0,0 +1,49 @@ +# Makefile for cipher modules +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +# Process this file with automake to produce Makefile.in + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src +AM_CFLAGS = $(GPG_ERROR_CFLAGS) + +noinst_LTLIBRARIES = librandom.la + +GCRYPT_MODULES = @GCRYPT_RANDOM@ + +librandom_la_DEPENDENCIES = $(GCRYPT_MODULES) +librandom_la_LIBADD = $(GCRYPT_MODULES) + +librandom_la_SOURCES = \ +random.c random.h \ +rand-internal.h \ +random-csprng.c \ +random-fips.c \ +rndhw.c + +if USE_RANDOM_DAEMON +librandom_la_SOURCES += random-daemon.c +endif USE_RANDOM_DAEMON + + +EXTRA_librandom_la_SOURCES = \ +rndlinux.c \ +rndegd.c \ +rndunix.c \ +rndw32.c diff --git a/libgcrypt-1.4.6/random/Makefile.in b/libgcrypt-1.4.6/random/Makefile.in new file mode 100644 index 0000000..679abc8 --- /dev/null +++ b/libgcrypt-1.4.6/random/Makefile.in @@ -0,0 +1,519 @@ +# Makefile.in generated by automake 1.10.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Makefile for cipher modules +# Copyright (C) 2008 Free Software Foundation, Inc. +# +# This file is part of Libgcrypt. +# +# Libgcrypt is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of +# the License, or (at your option) any later version. +# +# Libgcrypt 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this program; if not, see <http://www.gnu.org/licenses/>. + +# Process this file with automake to produce Makefile.in + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@USE_RANDOM_DAEMON_TRUE@am__append_1 = random-daemon.c +subdir = random +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ChangeLog +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/noexecstack.m4 $(top_srcdir)/m4/onceonly.m4 \ + $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sys_socket_h.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__librandom_la_SOURCES_DIST = random.c random.h rand-internal.h \ + random-csprng.c random-fips.c rndhw.c random-daemon.c +@USE_RANDOM_DAEMON_TRUE@am__objects_1 = random-daemon.lo +am_librandom_la_OBJECTS = random.lo random-csprng.lo random-fips.lo \ + rndhw.lo $(am__objects_1) +librandom_la_OBJECTS = $(am_librandom_la_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(librandom_la_SOURCES) $(EXTRA_librandom_la_SOURCES) +DIST_SOURCES = $(am__librandom_la_SOURCES_DIST) \ + $(EXTRA_librandom_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUILD_FILEVERSION = @BUILD_FILEVERSION@ +BUILD_REVISION = @BUILD_REVISION@ +BUILD_TIMESTAMP = @BUILD_TIMESTAMP@ +CC = @CC@ +CCAS = @CCAS@ +CCASDEPMODE = @CCASDEPMODE@ +CCASFLAGS = @CCASFLAGS@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DL_LIBS = @DL_LIBS@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FALLBACK_SOCKLEN_T = @FALLBACK_SOCKLEN_T@ +FFLAGS = @FFLAGS@ +GCRYPT_CIPHERS = @GCRYPT_CIPHERS@ +GCRYPT_DIGESTS = @GCRYPT_DIGESTS@ +GCRYPT_PUBKEY_CIPHERS = @GCRYPT_PUBKEY_CIPHERS@ +GCRYPT_RANDOM = @GCRYPT_RANDOM@ +GPG_ERROR_CFLAGS = @GPG_ERROR_CFLAGS@ +GPG_ERROR_CONFIG = @GPG_ERROR_CONFIG@ +GPG_ERROR_LIBS = @GPG_ERROR_LIBS@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBGCRYPT_CIPHERS = @LIBGCRYPT_CIPHERS@ +LIBGCRYPT_CONFIG_API_VERSION = @LIBGCRYPT_CONFIG_API_VERSION@ +LIBGCRYPT_CONFIG_CFLAGS = @LIBGCRYPT_CONFIG_CFLAGS@ +LIBGCRYPT_CONFIG_LIBS = @LIBGCRYPT_CONFIG_LIBS@ +LIBGCRYPT_DIGESTS = @LIBGCRYPT_DIGESTS@ +LIBGCRYPT_LT_AGE = @LIBGCRYPT_LT_AGE@ +LIBGCRYPT_LT_CURRENT = @LIBGCRYPT_LT_CURRENT@ +LIBGCRYPT_LT_REVISION = @LIBGCRYPT_LT_REVISION@ +LIBGCRYPT_PUBKEY_CIPHERS = @LIBGCRYPT_PUBKEY_CIPHERS@ +LIBGCRYPT_THREAD_MODULES = @LIBGCRYPT_THREAD_MODULES@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MPI_SFLAGS = @MPI_SFLAGS@ +NOEXECSTACK_FLAGS = @NOEXECSTACK_FLAGS@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTH_CFLAGS = @PTH_CFLAGS@ +PTH_CONFIG = @PTH_CONFIG@ +PTH_LIBS = @PTH_LIBS@ +RANLIB = @RANLIB@ +RC = @RC@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SYS_SOCKET_H = @SYS_SOCKET_H@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Need to include ../src in addition to top_srcdir because gcrypt.h is +# a built header. +AM_CPPFLAGS = -I../src -I$(top_srcdir)/src +AM_CFLAGS = $(GPG_ERROR_CFLAGS) +noinst_LTLIBRARIES = librandom.la +GCRYPT_MODULES = @GCRYPT_RANDOM@ +librandom_la_DEPENDENCIES = $(GCRYPT_MODULES) +librandom_la_LIBADD = $(GCRYPT_MODULES) +librandom_la_SOURCES = random.c random.h rand-internal.h \ + random-csprng.c random-fips.c rndhw.c $(am__append_1) +EXTRA_librandom_la_SOURCES = \ +rndlinux.c \ +rndegd.c \ +rndunix.c \ +rndw32.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu random/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu random/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +librandom.la: $(librandom_la_OBJECTS) $(librandom_la_DEPENDENCIES) + $(LINK) $(librandom_la_OBJECTS) $(librandom_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-csprng.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-daemon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random-fips.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndegd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndhw.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndlinux.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndunix.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rndw32.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libgcrypt-1.4.6/random/rand-internal.h b/libgcrypt-1.4.6/random/rand-internal.h new file mode 100644 index 0000000..534d828 --- /dev/null +++ b/libgcrypt-1.4.6/random/rand-internal.h @@ -0,0 +1,137 @@ +/* rand-internal.h - header to glue the random functions + * Copyright (C) 1998, 2002 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser general Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef G10_RAND_INTERNAL_H +#define G10_RAND_INTERNAL_H + +#include "../src/cipher-proto.h" + +/* Constants used to define the origin of random added to the pool. + The code is sensitive to the order of the values. */ +enum random_origins + { + RANDOM_ORIGIN_INIT = 0, /* Used only for initialization. */ + RANDOM_ORIGIN_EXTERNAL = 1, /* Added from an external source. */ + RANDOM_ORIGIN_FASTPOLL = 2, /* Fast random poll function. */ + RANDOM_ORIGIN_SLOWPOLL = 3, /* Slow poll function. */ + RANDOM_ORIGIN_EXTRAPOLL = 4 /* Used to mark an extra pool seed + due to a GCRY_VERY_STRONG_RANDOM + random request. */ + }; + + + +/*-- random.c --*/ +void _gcry_random_progress (const char *what, int printchar, + int current, int total); + + +/*-- random-csprng.c --*/ +void _gcry_rngcsprng_initialize (int full); +void _gcry_rngcsprng_dump_stats (void); +void _gcry_rngcsprng_secure_alloc (void); +void _gcry_rngcsprng_enable_quick_gen (void); +void _gcry_rngcsprng_set_daemon_socket (const char *socketname); +int _gcry_rngcsprng_use_daemon (int onoff); +int _gcry_rngcsprng_is_faked (void); +gcry_error_t _gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, + int quality); +void *_gcry_rngcsprng_get_bytes (size_t nbytes, + enum gcry_random_level level); +void *_gcry_rngcsprng_get_bytes_secure (size_t nbytes, + enum gcry_random_level level); +void _gcry_rngcsprng_randomize (void *buffer, size_t length, + enum gcry_random_level level); +void _gcry_rngcsprng_set_seed_file (const char *name); +void _gcry_rngcsprng_update_seed_file (void); +void _gcry_rngcsprng_fast_poll (void); +void _gcry_rngcsprng_create_nonce (void *buffer, size_t length); + +/*-- random-rngcsprng.c --*/ +void _gcry_rngfips_initialize (int full); +void _gcry_rngfips_dump_stats (void); +int _gcry_rngfips_is_faked (void); +gcry_error_t _gcry_rngfips_add_bytes (const void *buf, size_t buflen, + int quality); +void *_gcry_rngfips_get_bytes (size_t nbytes, + enum gcry_random_level level); +void *_gcry_rngfips_get_bytes_secure (size_t nbytes, + enum gcry_random_level level); +void _gcry_rngfips_randomize (void *buffer, size_t length, + enum gcry_random_level level); +void _gcry_rngfips_create_nonce (void *buffer, size_t length); + +gcry_error_t _gcry_rngfips_selftest (selftest_report_func_t report); + +gcry_err_code_t _gcry_rngfips_init_external_test (void **r_context, + unsigned int flags, + const void *key, + size_t keylen, + const void *seed, + size_t seedlen, + const void *dt, + size_t dtlen); +gcry_err_code_t _gcry_rngfips_run_external_test (void *context, + char *buffer, size_t buflen); +void _gcry_rngfips_deinit_external_test (void *context); + + + + + +/*-- rndlinux.c --*/ +int _gcry_rndlinux_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); + +/*-- rndunix.c --*/ +int _gcry_rndunix_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); + +/*-- rndelg.c --*/ +int _gcry_rndegd_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); +int _gcry_rndegd_connect_socket (int nofail); + +/*-- rndw32.c --*/ +int _gcry_rndw32_gather_random (void (*add) (const void *, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level); +void _gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin ); + +/*-- rndhw.c --*/ +int _gcry_rndhw_failed_p (void); +void _gcry_rndhw_poll_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin); +size_t _gcry_rndhw_poll_slow (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin); + + + +#endif /*G10_RAND_INTERNAL_H*/ diff --git a/libgcrypt-1.4.6/random/random-csprng.c b/libgcrypt-1.4.6/random/random-csprng.c new file mode 100644 index 0000000..aca977e --- /dev/null +++ b/libgcrypt-1.4.6/random/random-csprng.c @@ -0,0 +1,1397 @@ +/* random-csprng.c - CSPRNG style random number generator (libgcrypt classic) + * Copyright (C) 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + * 2007, 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This random number generator is modelled after the one described in + Peter Gutmann's 1998 Usenix Security Symposium paper: "Software + Generation of Practically Strong Random Numbers". See also chapter + 6 in his book "Cryptographic Security Architecture", New York, + 2004, ISBN 0-387-95387-6. + + Note that the acronym CSPRNG stands for "Continuously Seeded + PseudoRandom Number Generator" as used in Peter's implementation of + the paper and not only for "Cryptographically Secure PseudoRandom + Number Generator". + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#ifdef HAVE_GETHRTIME +#include <sys/times.h> +#endif +#ifdef HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif +#ifdef HAVE_GETRUSAGE +#include <sys/resource.h> +#endif +#ifdef __MINGW32__ +#include <process.h> +#endif +#include "g10lib.h" +#include "../cipher/rmd.h" +#include "random.h" +#include "rand-internal.h" +#include "cipher.h" /* Required for the rmd160_hash_buffer() prototype. */ +#include "ath.h" + +#ifndef RAND_MAX /* For SunOS. */ +#define RAND_MAX 32767 +#endif + +/* Check whether we can lock the seed file read write. */ +#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM) +#define LOCK_SEED_FILE 1 +#else +#define LOCK_SEED_FILE 0 +#endif + +/* Define the constant we use for transforming the pool at read-out. */ +#if SIZEOF_UNSIGNED_LONG == 8 +#define ADD_VALUE 0xa5a5a5a5a5a5a5a5 +#elif SIZEOF_UNSIGNED_LONG == 4 +#define ADD_VALUE 0xa5a5a5a5 +#else +#error weird size for an unsigned long +#endif + +/* Contstants pertaining to the hash pool. */ +#define BLOCKLEN 64 /* Hash this amount of bytes... */ +#define DIGESTLEN 20 /* ... into a digest of this length (rmd160). */ +/* POOLBLOCKS is the number of digests which make up the pool. */ +#define POOLBLOCKS 30 +/* POOLSIZE must be a multiple of the digest length to make the AND + operations faster, the size should also be a multiple of unsigned + long. */ +#define POOLSIZE (POOLBLOCKS*DIGESTLEN) +#if (POOLSIZE % SIZEOF_UNSIGNED_LONG) +#error Please make sure that poolsize is a multiple of unsigned long +#endif +#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG) + + +/* RNDPOOL is the pool we use to collect the entropy and to stir it + up. Its allocated size is POOLSIZE+BLOCKLEN. Note that this is + also an indication on whether the module has been fully + initialized. */ +static unsigned char *rndpool; + +/* KEYPOOL is used as a scratch copy to read out random from RNDPOOL. + Its allocated size is also POOLSIZE+BLOCKLEN. */ +static unsigned char *keypool; + +/* This is the offset into RNDPOOL where the next random bytes are to + be mixed in. */ +static size_t pool_writepos; + +/* When reading data out of KEYPOOL, we start the read at different + positions. This variable keeps track on where to read next. */ +static size_t pool_readpos; + +/* This flag is set to true as soon as the pool has been completely + filled the first time. This may happen either by rereading a seed + file or by adding enough entropy. */ +static int pool_filled; + +/* This counter is used to track whether the initial seeding has been + done with enough bytes from a reliable entropy source. */ +static size_t pool_filled_counter; + +/* If random of level GCRY_VERY_STRONG_RANDOM has been requested we + have stricter requirements on what kind of entropy is in the pool. + In particular POOL_FILLED is not sufficient. Thus we add some + extra seeding and set this flag to true if the extra seeding has + been done. */ +static int did_initial_extra_seeding; + +/* This variable is used to estimated the amount of fresh entropy + available in RNDPOOL. */ +static int pool_balance; + +/* After a mixing operation this variable will be set to true and + cleared if new entropy has been added or a remix is required for + otehr reasons. */ +static int just_mixed; + +/* The name of the seed file or NULL if no seed file has been defined. + The seed file needs to be regsitered at initialiation time. We + keep a malloced copy here. */ +static char *seed_file_name; + +/* If a seed file has been registered and maybe updated on exit this + flag set. */ +static int allow_seed_file_update; + +/* Option flag set at initialiation time to force allocation of the + pool in secure memory. */ +static int secure_alloc; + +/* This function pointer is set to the actual entropy gathering + function during initailization. After initialization it is + guaranteed to point to function. (On systems without a random + gatherer module a dummy function is used).*/ +static int (*slow_gather_fnc)(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int); + +/* This function is set to the actual fast entropy gathering fucntion + during initialization. If it is NULL, no such function is + available. */ +static void (*fast_gather_fnc)(void (*)(const void*, size_t, + enum random_origins), + enum random_origins); + + +/* Option flag useful for debugging and the test suite. If set + requests for very strong random are degraded to strong random. Not + used by regular applications. */ +static int quick_test; + +/* On systems without entropy gathering modules, this flag is set to + indicate that the random generator is not working properly. A + warning message is issued as well. This is useful only for + debugging and during development. */ +static int faked_rng; + +/* This is the lock we use to protect all pool operations. */ +static ath_mutex_t pool_lock = ATH_MUTEX_INITIALIZER; + +/* This is a helper for assert calls. These calls are used to assert + that functions are called in a locked state. It is not meant to be + thread-safe but as a method to get aware of missing locks in the + test suite. */ +static int pool_is_locked; + +/* This is the lock we use to protect the buffer used by the nonce + generation. */ +static ath_mutex_t nonce_buffer_lock = ATH_MUTEX_INITIALIZER; + + +/* We keep some counters in this structure for the sake of the + _gcry_random_dump_stats () function. */ +static struct +{ + unsigned long mixrnd; + unsigned long mixkey; + unsigned long slowpolls; + unsigned long fastpolls; + unsigned long getbytes1; + unsigned long ngetbytes1; + unsigned long getbytes2; + unsigned long ngetbytes2; + unsigned long addbytes; + unsigned long naddbytes; +} rndstats; + + + +/* --- Stuff pertaining to the random daemon support. --- */ +#ifdef USE_RANDOM_DAEMON + +/* If ALLOW_DAEMON is true, the module will try to use the random + daemon first. If the daemon has failed, this variable is set to + back to false and the code continues as normal. Note, we don't + test this flag in a locked state because a wrong value does not + harm and the trhead will find out itself that the daemon does not + work and set it (again) to false. */ +static int allow_daemon; + +/* During initialization, the user may set a non-default socket name + for accessing the random daemon. If this value is NULL, the + default name will be used. */ +static char *daemon_socket_name; + +#endif /*USE_RANDOM_DAEMON*/ + + + +/* --- Prototypes --- */ +static void read_pool (byte *buffer, size_t length, int level ); +static void add_randomness (const void *buffer, size_t length, + enum random_origins origin); +static void random_poll (void); +static void do_fast_random_poll (void); +static int (*getfnc_gather_random (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int); +static void (*getfnc_fast_random_poll (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins); +static void read_random_source (enum random_origins origin, + size_t length, int level); +static int gather_faked (void (*add)(const void*, size_t, enum random_origins), + enum random_origins, size_t length, int level ); + + + +/* --- Functions --- */ + + +/* Basic initialization which is required to initialize mutexes and + such. It does not run a full initialization so that the filling of + the random pool can be delayed until it is actually needed. We + assume that this function is used before any concurrent access + happens. */ +static void +initialize_basics(void) +{ + static int initialized; + int err; + + if (!initialized) + { + initialized = 1; + err = ath_mutex_init (&pool_lock); + if (err) + log_fatal ("failed to create the pool lock: %s\n", strerror (err) ); + + err = ath_mutex_init (&nonce_buffer_lock); + if (err) + log_fatal ("failed to create the nonce buffer lock: %s\n", + strerror (err) ); + +#ifdef USE_RANDOM_DAEMON + _gcry_daemon_initialize_basics (); +#endif /*USE_RANDOM_DAEMON*/ + + /* Make sure that we are still using the values we have + traditionally used for the random levels. */ + gcry_assert (GCRY_WEAK_RANDOM == 0 + && GCRY_STRONG_RANDOM == 1 + && GCRY_VERY_STRONG_RANDOM == 2); + } +} + +/* Take the pool lock. */ +static void +lock_pool (void) +{ + int err; + + err = ath_mutex_lock (&pool_lock); + if (err) + log_fatal ("failed to acquire the pool lock: %s\n", strerror (err)); + pool_is_locked = 1; +} + +/* Release the pool lock. */ +static void +unlock_pool (void) +{ + int err; + + pool_is_locked = 0; + err = ath_mutex_unlock (&pool_lock); + if (err) + log_fatal ("failed to release the pool lock: %s\n", strerror (err)); +} + + +/* Full initialization of this module. */ +static void +initialize(void) +{ + /* Although the basic initialization should have happened already, + we call it here to make sure that all prerequisites are met. */ + initialize_basics (); + + /* Now we can look the pool and complete the initialization if + necessary. */ + lock_pool (); + if (!rndpool) + { + /* The data buffer is allocated somewhat larger, so that we can + use this extra space (which is allocated in secure memory) as + a temporary hash buffer */ + rndpool = (secure_alloc + ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : gcry_xcalloc (1, POOLSIZE + BLOCKLEN)); + keypool = (secure_alloc + ? gcry_xcalloc_secure (1, POOLSIZE + BLOCKLEN) + : gcry_xcalloc (1, POOLSIZE + BLOCKLEN)); + + /* Setup the slow entropy gathering function. The code requires + that this function exists. */ + slow_gather_fnc = getfnc_gather_random (); + if (!slow_gather_fnc) + { + faked_rng = 1; + slow_gather_fnc = gather_faked; + } + + /* Setup the fast entropy gathering function. */ + fast_gather_fnc = getfnc_fast_random_poll (); + + } + unlock_pool (); +} + + + + +/* Initialize this random subsystem. If FULL is false, this function + merely calls the initialize and does not do anything more. Doing + this is not really required but when running in a threaded + environment we might get a race condition otherwise. */ +void +_gcry_rngcsprng_initialize (int full) +{ + if (!full) + initialize_basics (); + else + initialize (); +} + + +void +_gcry_rngcsprng_dump_stats (void) +{ + /* In theory we would need to lock the stats here. However this + function is usually called during cleanup and then we _might_ run + into problems. */ + + log_info ("random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n" + " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu%s\n", + POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls, + rndstats.naddbytes, rndstats.addbytes, + rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1, + rndstats.ngetbytes2, rndstats.getbytes2, + _gcry_rndhw_failed_p()? " (hwrng failed)":""); +} + + +/* This function should be called during initialization and before + intialization of this module to place the random pools into secure + memory. */ +void +_gcry_rngcsprng_secure_alloc (void) +{ + secure_alloc = 1; +} + + +/* This may be called before full initialization to degrade the + quality of the RNG for the sake of a faster running test suite. */ +void +_gcry_rngcsprng_enable_quick_gen (void) +{ + quick_test = 1; +} + + +void +_gcry_rngcsprng_set_daemon_socket (const char *socketname) +{ +#ifdef USE_RANDOM_DAEMON + if (daemon_socket_name) + BUG (); + + daemon_socket_name = gcry_xstrdup (socketname); +#else /*!USE_RANDOM_DAEMON*/ + (void)socketname; +#endif /*!USE_RANDOM_DAEMON*/ +} + +/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set + to 0, disable the use of the daemon. With ONOF set to -1, return + whether the daemon has been enabled. */ +int +_gcry_rngcsprng_use_daemon (int onoff) +{ +#ifdef USE_RANDOM_DAEMON + int last; + + /* This is not really thread safe. However it is expected that this + function is being called during initialization and at that point + we are for other reasons not really thread safe. We do not want + to lock it because we might eventually decide that this function + may even be called prior to gcry_check_version. */ + last = allow_daemon; + if (onoff != -1) + allow_daemon = onoff; + + return last; +#else /*!USE_RANDOM_DAEMON*/ + (void)onoff; + return 0; +#endif /*!USE_RANDOM_DAEMON*/ +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_rngcsprng_is_faked (void) +{ + /* We need to initialize due to the runtime determination of + available entropy gather modules. */ + initialize(); + return (faked_rng || quick_test); +} + + +/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY + should be in the range of 0..100 to indicate the goodness of the + entropy added, or -1 for goodness not known. */ +gcry_error_t +_gcry_rngcsprng_add_bytes (const void *buf, size_t buflen, int quality) +{ + size_t nbytes; + const char *bufptr; + + if (quality == -1) + quality = 35; + else if (quality > 100) + quality = 100; + else if (quality < 0) + quality = 0; + + if (!buf) + return gpg_error (GPG_ERR_INV_ARG); + + if (!buflen || quality < 10) + return 0; /* Take a shortcut. */ + + /* Because we don't increment the entropy estimation with FASTPOLL, + we don't need to take lock that estimation while adding from an + external source. This limited entropy estimation also means that + we can't take QUALITY into account. */ + initialize_basics (); + bufptr = buf; + while (buflen) + { + nbytes = buflen > POOLSIZE? POOLSIZE : buflen; + lock_pool (); + if (rndpool) + add_randomness (bufptr, nbytes, RANDOM_ORIGIN_EXTERNAL); + unlock_pool (); + bufptr += nbytes; + buflen -= nbytes; + } + return 0; +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + not very strong, GCRY_STRONG_RANDOM is strong enough for most + usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but + may be very slow. */ +void +_gcry_rngcsprng_randomize (void *buffer, size_t length, + enum gcry_random_level level) +{ + unsigned char *p; + + /* Make sure we are initialized. */ + initialize (); + + /* Handle our hack used for regression tests of Libgcrypt. */ + if ( quick_test && level > GCRY_STRONG_RANDOM ) + level = GCRY_STRONG_RANDOM; + + /* Make sure the level is okay. */ + level &= 3; + +#ifdef USE_RANDOM_DAEMON + if (allow_daemon + && !_gcry_daemon_randomize (daemon_socket_name, buffer, length, level)) + return; /* The daemon succeeded. */ + allow_daemon = 0; /* Daemon failed - switch off. */ +#endif /*USE_RANDOM_DAEMON*/ + + /* Acquire the pool lock. */ + lock_pool (); + + /* Update the statistics. */ + if (level >= GCRY_VERY_STRONG_RANDOM) + { + rndstats.getbytes2 += length; + rndstats.ngetbytes2++; + } + else + { + rndstats.getbytes1 += length; + rndstats.ngetbytes1++; + } + + /* Read the random into the provided buffer. */ + for (p = buffer; length > 0;) + { + size_t n; + + n = length > POOLSIZE? POOLSIZE : length; + read_pool (p, n, level); + length -= n; + p += n; + } + + /* Release the pool lock. */ + unlock_pool (); +} + + + + +/* + Mix the pool: + + |........blocks*20byte........|20byte|..44byte..| + <..44byte..> <20byte> + | | + | +------+ + +---------------------------|----------+ + v v + |........blocks*20byte........|20byte|..44byte..| + <.....64bytes.....> + | + +----------------------------------+ + Hash + v + |.............................|20byte|..44byte..| + <20byte><20byte><..44byte..> + | | + | +---------------------+ + +-----------------------------+ | + v v + |.............................|20byte|..44byte..| + <.....64byte......> + | + +-------------------------+ + Hash + v + |.............................|20byte|..44byte..| + <20byte><20byte><..44byte..> + + and so on until we did this for all blocks. + + To better protect against implementation errors in this code, we + xor a digest of the entire pool into the pool before mixing. + + Note: this function must only be called with a locked pool. + */ +static void +mix_pool(unsigned char *pool) +{ + static unsigned char failsafe_digest[DIGESTLEN]; + static int failsafe_digest_valid; + + unsigned char *hashbuf = pool + POOLSIZE; + unsigned char *p, *pend; + int i, n; + RMD160_CONTEXT md; + +#if DIGESTLEN != 20 +#error must have a digest length of 20 for ripe-md-160 +#endif + + gcry_assert (pool_is_locked); + _gcry_rmd160_init( &md ); + + /* Loop over the pool. */ + pend = pool + POOLSIZE; + memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN ); + memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN); + _gcry_rmd160_mixblock( &md, hashbuf); + memcpy(pool, hashbuf, 20 ); + + if (failsafe_digest_valid && pool == rndpool) + { + for (i=0; i < 20; i++) + pool[i] ^= failsafe_digest[i]; + } + + p = pool; + for (n=1; n < POOLBLOCKS; n++) + { + memcpy (hashbuf, p, DIGESTLEN); + + p += DIGESTLEN; + if (p+DIGESTLEN+BLOCKLEN < pend) + memcpy (hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN); + else + { + unsigned char *pp = p + DIGESTLEN; + + for (i=DIGESTLEN; i < BLOCKLEN; i++ ) + { + if ( pp >= pend ) + pp = pool; + hashbuf[i] = *pp++; + } + } + + _gcry_rmd160_mixblock ( &md, hashbuf); + memcpy(p, hashbuf, 20 ); + } + + /* Our hash implementation does only leave small parts (64 bytes) + of the pool on the stack, so it is okay not to require secure + memory here. Before we use this pool, it will be copied to the + help buffer anyway. */ + if ( pool == rndpool) + { + _gcry_rmd160_hash_buffer (failsafe_digest, pool, POOLSIZE); + failsafe_digest_valid = 1; + } + + _gcry_burn_stack (384); /* for the rmd160_mixblock(), rmd160_hash_buffer */ +} + + +void +_gcry_rngcsprng_set_seed_file (const char *name) +{ + if (seed_file_name) + BUG (); + seed_file_name = gcry_xstrdup (name); +} + + +/* Lock an open file identified by file descriptor FD and wait a + reasonable time to succeed. With FOR_WRITE set to true a write + lock will be taken. FNAME is used only for diagnostics. Returns 0 + on success or -1 on error. */ +static int +lock_seed_file (int fd, const char *fname, int for_write) +{ +#if LOCK_SEED_FILE + struct flock lck; + struct timeval tv; + int backoff=0; + + /* We take a lock on the entire file. */ + memset (&lck, 0, sizeof lck); + lck.l_type = for_write? F_WRLCK : F_RDLCK; + lck.l_whence = SEEK_SET; + + while (fcntl (fd, F_SETLK, &lck) == -1) + { + if (errno != EAGAIN && errno != EACCES) + { + log_info (_("can't lock `%s': %s\n"), fname, strerror (errno)); + return -1; + } + + if (backoff > 2) /* Show the first message after ~2.25 seconds. */ + log_info( _("waiting for lock on `%s'...\n"), fname); + + tv.tv_sec = backoff; + tv.tv_usec = 250000; + select (0, NULL, NULL, NULL, &tv); + if (backoff < 10) + backoff++ ; + } +#endif /*LOCK_SEED_FILE*/ + return 0; +} + + +/* Read in a seed from the random_seed file and return true if this + was successful. + + Note: Multiple instances of applications sharing the same random + seed file can be started in parallel, in which case they will read + out the same pool and then race for updating it (the last update + overwrites earlier updates). They will differentiate only by the + weak entropy that is added in read_seed_file based on the PID and + clock, and up to 16 bytes of weak random non-blockingly. The + consequence is that the output of these different instances is + correlated to some extent. In the perfect scenario, the attacker + can control (or at least guess) the PID and clock of the + application, and drain the system's entropy pool to reduce the "up + to 16 bytes" above to 0. Then the dependencies of the inital + states of the pools are completely known. */ +static int +read_seed_file (void) +{ + int fd; + struct stat sb; + unsigned char buffer[POOLSIZE]; + int n; + + gcry_assert (pool_is_locked); + + 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 (lock_seed_file (fd, seed_file_name, 0)) + { + close (fd); + 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);/*NOTREACHED*/ + return 0; + } + + close(fd); + + add_randomness( buffer, POOLSIZE, RANDOM_ORIGIN_INIT ); + /* add some minor entropy to the pool now (this will also force a mixing) */ + { + pid_t x = getpid(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + { + time_t x = time(NULL); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + { + clock_t x = clock(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_INIT ); + } + + /* 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 too much as we + * want to be friendly to the scare system entropy resource. */ + read_random_source ( RANDOM_ORIGIN_INIT, 16, GCRY_WEAK_RANDOM ); + + allow_seed_file_update = 1; + return 1; +} + + +void +_gcry_rngcsprng_update_seed_file (void) +{ + unsigned long *sp, *dp; + int fd, i; + + /* We do only a basic initialization so that we can lock the pool. + This is required to cope with the case that this function is + called by some cleanup code at a point where the RNG has never + been initialized. */ + initialize_basics (); + lock_pool (); + + if ( !seed_file_name || !rndpool || !pool_filled ) + { + unlock_pool (); + return; + } + if ( !allow_seed_file_update ) + { + unlock_pool (); + log_info(_("note: random_seed file not updated\n")); + return; + } + + /* At this point we know that there is something in the pool and + thus we can conclude that the pool has been fully initialized. */ + + + /* Copy the entropy pool to a scratch pool and mix both of them. */ + for (i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool; + i < POOLWORDS; i++, dp++, sp++ ) + { + *dp = *sp + ADD_VALUE; + } + mix_pool(rndpool); rndstats.mixrnd++; + mix_pool(keypool); rndstats.mixkey++; + +#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) + fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, + S_IRUSR|S_IWUSR ); +#else +# if LOCK_SEED_FILE + fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR ); +# else + fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR ); +# endif +#endif + + if (fd == -1 ) + log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) ); + else if (lock_seed_file (fd, seed_file_name, 1)) + { + close (fd); + } +#if LOCK_SEED_FILE + else if (ftruncate (fd, 0)) + { + log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno)); + close (fd); + } +#endif /*LOCK_SEED_FILE*/ + else + { + 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)); + } + + unlock_pool (); +} + + +/* Read random out of the pool. This function is the core of the + public random functions. Note that Level GCRY_WEAK_RANDOM is not + anymore handled special and in fact is an alias in the API for + level GCRY_STRONG_RANDOM. Must be called with the pool already + locked. */ +static void +read_pool (byte *buffer, size_t length, int level) +{ + int i; + unsigned long *sp, *dp; + /* The volatile is there to make sure the compiler does not optimize + the code away in case the getpid function is badly attributed. + Note that we keep a pid in a static variable as well as in a + stack based one; the latter is to detect ill behaving thread + libraries, ignoring the pool mutexes. */ + static volatile pid_t my_pid = (pid_t)(-1); + volatile pid_t my_pid2; + + gcry_assert (pool_is_locked); + + retry: + /* Get our own pid, so that we can detect a fork. */ + my_pid2 = getpid (); + if (my_pid == (pid_t)(-1)) + my_pid = my_pid2; + if ( my_pid != my_pid2 ) + { + /* We detected a plain fork; i.e. we are now the child. Update + the static pid and add some randomness. */ + pid_t x; + + my_pid = my_pid2; + x = my_pid; + add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT); + just_mixed = 0; /* Make sure it will get mixed. */ + } + + gcry_assert (pool_is_locked); + + /* Our code does not allow to extract more than POOLSIZE. Better + check it here. */ + if (length > POOLSIZE) + { + log_bug("too many random bits requested\n"); + } + + if (!pool_filled) + { + if (read_seed_file() ) + pool_filled = 1; + } + + /* For level 2 quality (key generation) we always make sure that the + pool has been seeded enough initially. */ + if (level == GCRY_VERY_STRONG_RANDOM && !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 (RANDOM_ORIGIN_EXTRAPOLL, needed, + GCRY_VERY_STRONG_RANDOM); + pool_balance += needed; + did_initial_extra_seeding = 1; + } + + /* For level 2 make sure that there is enough random in the pool. */ + if (level == GCRY_VERY_STRONG_RANDOM && pool_balance < length) + { + size_t needed; + + if (pool_balance < 0) + pool_balance = 0; + needed = length - pool_balance; + if (needed > POOLSIZE) + BUG (); + read_random_source (RANDOM_ORIGIN_EXTRAPOLL, needed, + GCRY_VERY_STRONG_RANDOM); + pool_balance += needed; + } + + /* Make sure the pool is filled. */ + while (!pool_filled) + random_poll(); + + /* Always do a fast random poll (we have to use the unlocked version). */ + do_fast_random_poll(); + + /* Mix the pid in so that we for sure won't deliver the same random + after a fork. */ + { + pid_t apid = my_pid; + add_randomness (&apid, sizeof (apid), RANDOM_ORIGIN_INIT); + } + + /* Mix the pool (if add_randomness() didn't it). */ + if (!just_mixed) + { + mix_pool(rndpool); + rndstats.mixrnd++; + } + + /* Create a new pool. */ + for(i=0,dp=(unsigned long*)keypool, sp=(unsigned long*)rndpool; + i < POOLWORDS; i++, dp++, sp++ ) + *dp = *sp + ADD_VALUE; + + /* Mix both pools. */ + mix_pool(rndpool); rndstats.mixrnd++; + mix_pool(keypool); rndstats.mixkey++; + + /* Read the requested data. We use a read pointer to read from a + different position each time. */ + while (length--) + { + *buffer++ = keypool[pool_readpos++]; + if (pool_readpos >= POOLSIZE) + pool_readpos = 0; + pool_balance--; + } + + if (pool_balance < 0) + pool_balance = 0; + + /* Clear the keypool. */ + memset (keypool, 0, POOLSIZE); + + /* We need to detect whether a fork has happened. A fork might have + an identical pool and thus the child and the parent could emit + the very same random number. This test here is to detect forks + in a multi-threaded process. It does not work with all thread + implementations in particular not with pthreads. However it is + good enough for GNU Pth. */ + if ( getpid () != my_pid2 ) + { + pid_t x = getpid(); + add_randomness (&x, sizeof(x), RANDOM_ORIGIN_INIT); + just_mixed = 0; /* Make sure it will get mixed. */ + my_pid = x; /* Also update the static pid. */ + goto retry; + } +} + + + +/* Add LENGTH bytes of randomness from buffer to the pool. ORIGIN is + used to specify the randomness origin. This is one of the + RANDOM_ORIGIN_* values. */ +static void +add_randomness (const void *buffer, size_t length, enum random_origins origin) +{ + const unsigned char *p = buffer; + size_t count = 0; + + gcry_assert (pool_is_locked); + + rndstats.addbytes += length; + rndstats.naddbytes++; + while (length-- ) + { + rndpool[pool_writepos++] ^= *p++; + count++; + if (pool_writepos >= POOLSIZE ) + { + /* It is possible that we are invoked before the pool is + filled using an unreliable origin of entropy, for example + the fast random poll. To avoid flagging the pool as + filled in this case, we track the initial filling state + separately. See also the remarks about the seed file. */ + if (origin >= RANDOM_ORIGIN_SLOWPOLL && !pool_filled) + { + pool_filled_counter += count; + count = 0; + if (pool_filled_counter >= POOLSIZE) + pool_filled = 1; + } + pool_writepos = 0; + mix_pool(rndpool); rndstats.mixrnd++; + just_mixed = !length; + } + } +} + + + +static void +random_poll() +{ + rndstats.slowpolls++; + read_random_source (RANDOM_ORIGIN_SLOWPOLL, POOLSIZE/5, GCRY_STRONG_RANDOM); +} + + +/* Runtime determination of the slow entropy gathering module. */ +static int (* +getfnc_gather_random (void))(void (*)(const void*, size_t, + enum random_origins), + enum random_origins, size_t, int) +{ + int (*fnc)(void (*)(const void*, size_t, enum random_origins), + enum random_origins, size_t, int); + +#if USE_RNDLINUX + if ( !access (NAME_OF_DEV_RANDOM, R_OK) + && !access (NAME_OF_DEV_URANDOM, R_OK)) + { + fnc = _gcry_rndlinux_gather_random; + return fnc; + } +#endif + +#if USE_RNDEGD + if ( _gcry_rndegd_connect_socket (1) != -1 ) + { + fnc = _gcry_rndegd_gather_random; + return fnc; + } +#endif + +#if USE_RNDUNIX + fnc = _gcry_rndunix_gather_random; + return fnc; +#endif + +#if USE_RNDW32 + fnc = _gcry_rndw32_gather_random; + return fnc; +#endif + + log_fatal (_("no entropy gathering module detected\n")); + + return NULL; /*NOTREACHED*/ +} + +/* Runtime determination of the fast entropy gathering function. + (Currently a compile time method is used.) */ +static void (* +getfnc_fast_random_poll (void))( void (*)(const void*, size_t, + enum random_origins), + enum random_origins) +{ +#if USE_RNDW32 + return _gcry_rndw32_gather_random_fast; +#endif + return NULL; +} + + + +static void +do_fast_random_poll (void) +{ + gcry_assert (pool_is_locked); + + rndstats.fastpolls++; + + if (fast_gather_fnc) + fast_gather_fnc (add_randomness, RANDOM_ORIGIN_FASTPOLL); + + /* Continue with the generic functions. */ +#if HAVE_GETHRTIME + { + hrtime_t tv; + tv = gethrtime(); + add_randomness( &tv, sizeof(tv), RANDOM_ORIGIN_FASTPOLL ); + } +#elif HAVE_GETTIMEOFDAY + { + struct timeval tv; + if( gettimeofday( &tv, NULL ) ) + BUG(); + add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL ); + add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), RANDOM_ORIGIN_FASTPOLL ); + } +#elif HAVE_CLOCK_GETTIME + { struct timespec tv; + if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 ) + BUG(); + add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), RANDOM_ORIGIN_FASTPOLL ); + add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), RANDOM_ORIGIN_FASTPOLL ); + } +#else /* use times */ +# ifndef HAVE_DOSISH_SYSTEM + { struct tms buf; + times( &buf ); + add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL ); + } +# endif +#endif + +#ifdef HAVE_GETRUSAGE +# ifdef RUSAGE_SELF + { + struct rusage buf; + /* QNX/Neutrino does return ENOSYS - so we just ignore it and add + whatever is in buf. In a chroot environment it might not work + at all (i.e. because /proc/ is not accessible), so we better + ignore all error codes and hope for the best. */ + getrusage (RUSAGE_SELF, &buf ); + add_randomness( &buf, sizeof buf, RANDOM_ORIGIN_FASTPOLL ); + memset( &buf, 0, sizeof buf ); + } +# else /*!RUSAGE_SELF*/ +# ifdef __GCC__ +# warning There is no RUSAGE_SELF on this system +# endif +# endif /*!RUSAGE_SELF*/ +#endif /*HAVE_GETRUSAGE*/ + + /* 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), RANDOM_ORIGIN_FASTPOLL ); + } + { + clock_t x = clock(); + add_randomness( &x, sizeof(x), RANDOM_ORIGIN_FASTPOLL ); + } + + /* If the system features a fast hardware RNG, read some bytes from + there. */ + _gcry_rndhw_poll_fast (add_randomness, RANDOM_ORIGIN_FASTPOLL); +} + + +/* The fast random pool function as called at some places in + libgcrypt. This is merely a wrapper to make sure that this module + is initalized and to look the pool. Note, that this function is a + NOP unless a random function has been used or _gcry_initialize (1) + has been used. We use this hack so that the internal use of this + function in cipher_open and md_open won't start filling up the + random pool, even if no random will be required by the process. */ +void +_gcry_rngcsprng_fast_poll (void) +{ + initialize_basics (); + + lock_pool (); + if (rndpool) + { + /* Yes, we are fully initialized. */ + do_fast_random_poll (); + } + unlock_pool (); +} + + + +static void +read_random_source (enum random_origins orgin, size_t length, int level ) +{ + if ( !slow_gather_fnc ) + log_fatal ("Slow entropy gathering module not yet initialized\n"); + + if ( slow_gather_fnc (add_randomness, orgin, length, level) < 0) + log_fatal ("No way to gather entropy for the RNG\n"); +} + + +static int +gather_faked (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, size_t length, int level ) +{ + static int initialized=0; + size_t n; + char *buffer, *p; + + (void)add; + (void)level; + + if ( !initialized ) + { + log_info(_("WARNING: using insecure random number generator!!\n")); + initialized=1; +#ifdef HAVE_RAND + srand( time(NULL)*getpid()); +#else + srandom( time(NULL)*getpid()); +#endif + } + + p = buffer = gcry_xmalloc( length ); + n = length; +#ifdef HAVE_RAND + while ( n-- ) + *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1); +#else + while ( n-- ) + *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1); +#endif + add_randomness ( buffer, length, origin ); + gcry_free (buffer); + return 0; /* okay */ +} + + +/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ +void +_gcry_rngcsprng_create_nonce (void *buffer, size_t length) +{ + static unsigned char nonce_buffer[20+8]; + static int nonce_buffer_initialized = 0; + static volatile pid_t my_pid; /* The volatile is there to make sure the + compiler does not optimize the code away + in case the getpid function is badly + attributed. */ + volatile pid_t apid; + unsigned char *p; + size_t n; + int err; + + /* Make sure we are initialized. */ + initialize (); + +#ifdef USE_RANDOM_DAEMON + if (allow_daemon + && !_gcry_daemon_create_nonce (daemon_socket_name, buffer, length)) + return; /* The daemon succeeded. */ + allow_daemon = 0; /* Daemon failed - switch off. */ +#endif /*USE_RANDOM_DAEMON*/ + + /* Acquire the nonce buffer lock. */ + err = ath_mutex_lock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to acquire the nonce buffer lock: %s\n", + strerror (err)); + + apid = getpid (); + /* The first time intialize our buffer. */ + if (!nonce_buffer_initialized) + { + time_t atime = time (NULL); + pid_t xpid = apid; + + my_pid = apid; + + if ((sizeof apid + sizeof atime) > sizeof nonce_buffer) + BUG (); + + /* Initialize the first 20 bytes with a reasonable value so that + a failure of gcry_randomize won't affect us too much. Don't + care about the uninitialized remaining bytes. */ + p = nonce_buffer; + memcpy (p, &xpid, sizeof xpid); + p += sizeof xpid; + memcpy (p, &atime, sizeof atime); + + /* Initialize the never changing private part of 64 bits. */ + gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + + nonce_buffer_initialized = 1; + } + else if ( my_pid != apid ) + { + /* We forked. Need to reseed the buffer - doing this for the + private part should be sufficient. */ + gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM); + /* Update the pid so that we won't run into here again and + again. */ + my_pid = apid; + } + + /* Create the nonce by hashing the entire buffer, returning the hash + and updating the first 20 bytes of the buffer with this hash. */ + for (p = buffer; length > 0; length -= n, p += n) + { + _gcry_sha1_hash_buffer (nonce_buffer, + nonce_buffer, sizeof nonce_buffer); + n = length > 20? 20 : length; + memcpy (p, nonce_buffer, n); + } + + + /* Release the nonce buffer lock. */ + err = ath_mutex_unlock (&nonce_buffer_lock); + if (err) + log_fatal ("failed to release the nonce buffer lock: %s\n", + strerror (err)); + +} diff --git a/libgcrypt-1.4.6/random/random-daemon.c b/libgcrypt-1.4.6/random/random-daemon.c new file mode 100644 index 0000000..2e03ba0 --- /dev/null +++ b/libgcrypt-1.4.6/random/random-daemon.c @@ -0,0 +1,360 @@ +/* random-daemon.c - Access to the external random daemon + * Copyright (C) 2006 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 functions here are used by random.c to divert calls to an + external random number daemon. The actual daemon we use is + gcryptrnd. Such a daemon is useful to keep a persistent pool in + memory over invocations of a single application and to allow + prioritizing access to the actual entropy sources. The drawback is + that we need to use IPC (i.e. unix domain socket) to convey + sensitive data. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> +#include <unistd.h> + +#include "g10lib.h" +#include "random.h" +#include "ath.h" + + + +/* This is default socket name we use in case the provided socket name + is NULL. */ +#define RANDOM_DAEMON_SOCKET "/var/run/libgcrypt/S.gcryptrnd" + +/* The lock serializing access to the daemon. */ +static ath_mutex_t daemon_lock = ATH_MUTEX_INITIALIZER; + +/* The socket connected to the daemon. */ +static int daemon_socket = -1; + +/* Creates a socket connected to the daemon. On success, store the + socket fd in *SOCK. Returns error code. */ +static gcry_error_t +connect_to_socket (const char *socketname, int *sock) +{ + struct sockaddr_un *srvr_addr; + socklen_t addrlen; + gcry_error_t err; + int fd; + int rc; + + srvr_addr = NULL; + + /* Create a socket. */ + fd = socket (AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) + { + log_error ("can't create socket: %s\n", strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + + /* Set up address. */ + srvr_addr = gcry_malloc (sizeof *srvr_addr); + if (! srvr_addr) + { + log_error ("malloc failed: %s\n", strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + memset (srvr_addr, 0, sizeof *srvr_addr); + srvr_addr->sun_family = AF_UNIX; + if (strlen (socketname) + 1 >= sizeof (srvr_addr->sun_path)) + { + log_error ("socket name `%s' too long\n", socketname); + err = gcry_error (GPG_ERR_ENAMETOOLONG); + goto out; + } + strcpy (srvr_addr->sun_path, socketname); + addrlen = (offsetof (struct sockaddr_un, sun_path) + + strlen (srvr_addr->sun_path) + 1); + + /* Connect socket. */ + rc = connect (fd, (struct sockaddr *) srvr_addr, addrlen); + if (rc == -1) + { + log_error ("error connecting socket `%s': %s\n", + srvr_addr->sun_path, strerror (errno)); + err = gcry_error_from_errno (errno); + goto out; + } + + err = 0; + + out: + + gcry_free (srvr_addr); + if (err) + { + close (fd); + fd = -1; + } + *sock = fd; + + return err; +} + + +/* Initialize basics of this module. This should be viewed as a + constructor to prepare locking. */ +void +_gcry_daemon_initialize_basics (void) +{ + static int initialized; + int err; + + if (!initialized) + { + initialized = 1; + err = ath_mutex_init (&daemon_lock); + if (err) + log_fatal ("failed to create the daemon lock: %s\n", strerror (err) ); + } +} + + + +/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on + success or another value on write error. */ +static int +writen (int fd, const void *buffer, size_t length) +{ + ssize_t n; + + while (length) + { + do + n = ath_write (fd, buffer, length); + while (n < 0 && errno == EINTR); + if (n < 0) + { + log_error ("write error: %s\n", strerror (errno)); + return -1; /* write error */ + } + length -= n; + buffer = (const char*)buffer + n; + } + return 0; /* Okay */ +} + +static int +readn (int fd, void *buf, size_t buflen, size_t *ret_nread) +{ + size_t nleft = buflen; + int nread; + char *p; + + p = buf; + while (nleft > 0) + { + nread = ath_read (fd, buf, nleft); + if (nread < 0) + { + if (nread == EINTR) + nread = 0; + else + return -1; + } + else if (!nread) + break; /* EOF */ + nleft -= nread; + buf = (char*)buf + nread; + } + if (ret_nread) + *ret_nread = buflen - nleft; + return 0; +} + +/* This functions requests REQ_NBYTES from the daemon. If NONCE is + true, the data should be suited for a nonce. If NONCE is FALSE, + data of random level LEVEL will be generated. The retrieved random + data will be stored in BUFFER. Returns error code. */ +static gcry_error_t +call_daemon (const char *socketname, + void *buffer, size_t req_nbytes, int nonce, + enum gcry_random_level level) +{ + static int initialized; + unsigned char buf[255]; + gcry_error_t err = 0; + size_t nbytes; + size_t nread; + int rc; + + if (!req_nbytes) + return 0; + + ath_mutex_lock (&daemon_lock); + + /* Open the socket if that has not been done. */ + if (!initialized) + { + initialized = 1; + err = connect_to_socket (socketname ? socketname : RANDOM_DAEMON_SOCKET, + &daemon_socket); + if (err) + { + daemon_socket = -1; + log_info ("not using random daemon\n"); + ath_mutex_unlock (&daemon_lock); + return err; + } + } + + /* Check that we have a valid socket descriptor. */ + if ( daemon_socket == -1 ) + { + ath_mutex_unlock (&daemon_lock); + return gcry_error (GPG_ERR_INTERNAL); + } + + + /* Do the real work. */ + + do + { + /* Process in chunks. */ + nbytes = req_nbytes > sizeof (buf) ? sizeof (buf) : req_nbytes; + req_nbytes -= nbytes; + + /* Construct request. */ + buf[0] = 3; + if (nonce) + buf[1] = 10; + else if (level == GCRY_VERY_STRONG_RANDOM) + buf[1] = 12; + else if (level == GCRY_STRONG_RANDOM) + buf[1] = 11; + buf[2] = nbytes; + + /* Send request. */ + rc = writen (daemon_socket, buf, 3); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + break; + } + + /* Retrieve response. */ + + rc = readn (daemon_socket, buf, 2, &nread); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + log_error ("read error: %s\n", gcry_strerror (err)); + break; + } + if (nread && buf[0]) + { + log_error ("random daemon returned error code %d\n", buf[0]); + err = gcry_error (GPG_ERR_INTERNAL); /* ? */ + break; + } + if (nread != 2) + { + log_error ("response too small\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + + /* if (1)*/ /* Do this in verbose mode? */ + /* log_info ("received response with %d bytes of data\n", buf[1]);*/ + + if (buf[1] < nbytes) + { + log_error ("error: server returned less bytes than requested\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + else if (buf[1] > nbytes) + { + log_error ("warning: server returned more bytes than requested\n"); + err = gcry_error (GPG_ERR_PROTOCOL_VIOLATION); /* ? */ + break; + } + + assert (nbytes <= sizeof (buf)); + + rc = readn (daemon_socket, buf, nbytes, &nread); + if (rc == -1) + { + err = gcry_error_from_errno (errno); + log_error ("read error: %s\n", gcry_strerror (err)); + break; + } + + if (nread != nbytes) + { + log_error ("too little random data read\n"); + err = gcry_error (GPG_ERR_INTERNAL); + break; + } + + /* Successfuly read another chunk of data. */ + memcpy (buffer, buf, nbytes); + buffer = ((char *) buffer) + nbytes; + } + while (req_nbytes); + + ath_mutex_unlock (&daemon_lock); + + return err; +} + +/* Internal function to fill BUFFER with LENGTH bytes of random. We + support GCRY_STRONG_RANDOM and GCRY_VERY_STRONG_RANDOM here. + Return 0 on success. */ +int +_gcry_daemon_randomize (const char *socketname, + void *buffer, size_t length, + enum gcry_random_level level) +{ + gcry_error_t err; + + err = call_daemon (socketname, buffer, length, 0, level); + + return err ? -1 : 0; +} + + +/* Internal function to fill BUFFER with NBYTES of data usable for a + nonce. Returns 0 on success. */ +int +_gcry_daemon_create_nonce (const char *socketname, void *buffer, size_t length) +{ + gcry_error_t err; + + err = call_daemon (socketname, buffer, length, 1, 0); + + return err ? -1 : 0; +} + +/* END */ diff --git a/libgcrypt-1.4.6/random/random-fips.c b/libgcrypt-1.4.6/random/random-fips.c new file mode 100644 index 0000000..2667e71 --- /dev/null +++ b/libgcrypt-1.4.6/random/random-fips.c @@ -0,0 +1,1118 @@ +/* random-fips.c - FIPS style random number generator + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + The core of this deterministic random number generator is + implemented according to the document "NIST-Recommended Random + Number Generator Based on ANSI X9.31 Appendix A.2.4 Using the 3-Key + Triple DES and AES Algorithms" (2005-01-31). This implementation + uses the AES variant. + + There are 3 random context which map to the different levels of + random quality: + + Generator Seed and Key Kernel entropy (init/reseed) + ------------------------------------------------------------ + GCRY_VERY_STRONG_RANDOM /dev/random 256/128 bits + GCRY_STRONG_RANDOM /dev/random 256/128 bits + gcry_create_nonce GCRY_STRONG_RANDOM n/a + + All random generators return their data in 128 bit blocks. If the + caller requested less bits, the extra bits are not used. The key + for each generator is only set once at the first time a generator + is used. The seed value is set with the key and again after 1000 + (SEED_TTL) output blocks; the re-seeding is disabled in test mode. + + The GCRY_VERY_STRONG_RANDOM and GCRY_STRONG_RANDOM generators are + keyed and seeded from the /dev/random device. Thus these + generators may block until the kernel has collected enough entropy. + + The gcry_create_nonce generator is keyed and seeded from the + GCRY_STRONG_RANDOM generator. It may also block if the + GCRY_STRONG_RANDOM generator has not yet been used before and thus + gets initialized on the first use by gcry_create_nonce. This + special treatment is justified by the weaker requirements for a + nonce generator and to save precious kernel entropy for use by the + real random generators. + + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#ifdef HAVE_GETTIMEOFDAY +#include <sys/time.h> +#endif + +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" +#include "ath.h" + +/* This is the lock we use to serialize access to this RNG. The extra + integer variable is only used to check the locking state; that is, + it is not meant to be thread-safe but merely as a failsafe feature + to assert proper locking. */ +static ath_mutex_t fips_rng_lock = ATH_MUTEX_INITIALIZER; +static int fips_rng_is_locked; + + +/* The required size for the temporary buffer of the x931_aes_driver + function and the buffer itself which will be allocated in secure + memory. This needs to be global variable for proper initialization + and to allow shutting down the RNG without leaking memory. May + only be used while holding the FIPS_RNG_LOCK. + + This variable is also used to avoid duplicate initialization. */ +#define TEMPVALUE_FOR_X931_AES_DRIVER_SIZE 48 +static unsigned char *tempvalue_for_x931_aes_driver; + + +/* After having retrieved this number of blocks from the RNG, we want + to do a reseeding. */ +#define SEED_TTL 1000 + + +/* The length of the key we use: 16 bytes (128 bit) for AES128. */ +#define X931_AES_KEYLEN 16 +/* A global buffer used to communicate between the x931_generate_key + and x931_generate_seed functions and the entropy_collect_cb + function. It may only be used by these functions. */ +static unsigned char *entropy_collect_buffer; /* Buffer. */ +static size_t entropy_collect_buffer_len; /* Used length. */ +static size_t entropy_collect_buffer_size; /* Allocated length. */ + + +/* This random context type is used to track properties of one random + generator. Thee context are usually allocated in secure memory so + that the seed value is well protected. There are a couble of guard + fields to help detecting applications accidently overwriting parts + of the memory. */ +struct rng_context +{ + unsigned char guard_0[1]; + + /* The handle of the cipher used by the RNG. If this one is not + NULL a cipher handle along with a random key has been + established. */ + gcry_cipher_hd_t cipher_hd; + + /* If this flag is true, the SEED_V buffer below carries a valid + seed. */ + int is_seeded:1; + + /* The very first block generated is used to compare the result + against the last result. This flag indicates that such a block + is available. */ + int compare_value_valid:1; + + /* A counter used to trigger re-seeding. */ + unsigned int use_counter; + + unsigned char guard_1[1]; + + /* The buffer containing the seed value V. */ + unsigned char seed_V[16]; + + unsigned char guard_2[1]; + + /* The last result from the x931_aes fucntion. Only valid if + compare_value_valid is set. */ + unsigned char compare_value[16]; + + unsigned char guard_3[1]; + + /* The external test may want to suppress the duplicate bock check. + This is done if the this flag is set. */ + unsigned char test_no_dup_check; + /* To implement a KAT we need to provide a know DT value. To + accomplish this the x931_get_dt function checks whether this + field is not NULL and then uses the 16 bytes at this address for + the DT value. However the last 4 bytes are replaced by the + value of field TEST_DT_COUNTER which will be incremented after + each invocation of x931_get_dt. We use a pointer and not a buffer + because there is no need to put this value into secure memory. */ + const unsigned char *test_dt_ptr; + u32 test_dt_counter; + + /* We need to keep track of the process which did the initialization + so that we can detect a fork. The volatile modifier is required + so that the compiler does not optimize it away in case the getpid + function is badly attributed. */ + pid_t key_init_pid; + pid_t seed_init_pid; +}; +typedef struct rng_context *rng_context_t; + + +/* The random context used for the nonce generator. May only be used + while holding the FIPS_RNG_LOCK. */ +static rng_context_t nonce_context; +/* The random context used for the standard random generator. May + only be used while holding the FIPS_RNG_LOCK. */ +static rng_context_t std_rng_context; +/* The random context used for the very strong random generator. May + only be used while holding the FIPS_RNG_LOCK. */ +static rng_context_t strong_rng_context; + + +/* --- Local prototypes --- */ +static void x931_reseed (rng_context_t rng_ctx); +static void get_random (void *buffer, size_t length, rng_context_t rng_ctx); + + + + +/* --- Functions --- */ + +/* Basic initialization is required to initialize mutexes and + do a few checks on the implementation. */ +static void +basic_initialization (void) +{ + static int initialized; + int my_errno; + + if (!initialized) + return; + initialized = 1; + + my_errno = ath_mutex_init (&fips_rng_lock); + if (my_errno) + log_fatal ("failed to create the RNG lock: %s\n", strerror (my_errno)); + fips_rng_is_locked = 0; + + /* Make sure that we are still using the values we have + traditionally used for the random levels. */ + gcry_assert (GCRY_WEAK_RANDOM == 0 + && GCRY_STRONG_RANDOM == 1 + && GCRY_VERY_STRONG_RANDOM == 2); + +} + + +/* Acquire the fips_rng_lock. */ +static void +lock_rng (void) +{ + int my_errno; + + my_errno = ath_mutex_lock (&fips_rng_lock); + if (my_errno) + log_fatal ("failed to acquire the RNG lock: %s\n", strerror (my_errno)); + fips_rng_is_locked = 1; +} + + +/* Release the fips_rng_lock. */ +static void +unlock_rng (void) +{ + int my_errno; + + fips_rng_is_locked = 0; + my_errno = ath_mutex_unlock (&fips_rng_lock); + if (my_errno) + log_fatal ("failed to release the RNG lock: %s\n", strerror (my_errno)); +} + +static void +setup_guards (rng_context_t rng_ctx) +{ + /* Set the guards to some arbitrary values. */ + rng_ctx->guard_0[0] = 17; + rng_ctx->guard_1[0] = 42; + rng_ctx->guard_2[0] = 137; + rng_ctx->guard_3[0] = 252; +} + +static void +check_guards (rng_context_t rng_ctx) +{ + if ( rng_ctx->guard_0[0] != 17 + || rng_ctx->guard_1[0] != 42 + || rng_ctx->guard_2[0] != 137 + || rng_ctx->guard_3[0] != 252 ) + log_fatal ("memory corruption detected in RNG context %p\n", rng_ctx); +} + + +/* Get the DT vector for use with the core PRNG function. Buffer + needs to be provided by the caller with a size of at least LENGTH + bytes. RNG_CTX needs to be passed to allow for a KAT. The 16 byte + timestamp we construct is made up the real time and three counters: + + Buffer: 00112233445566778899AABBCCDDEEFF + !--+---!!-+-!!+!!--+---!!--+---! + seconds ---------/ | | | | + microseconds -----------/ | | | + counter2 -------------------/ | | + counter1 ------------------------/ | + counter0 --------------------------------/ + + Counter 2 is just 12 bits wide and used to track fractions of + milliseconds whereas counters 1 and 0 are combined to a free + running 64 bit counter. */ +static void +x931_get_dt (unsigned char *buffer, size_t length, rng_context_t rng_ctx) +{ + gcry_assert (length == 16); /* This length is required for use with AES. */ + gcry_assert (fips_rng_is_locked); + + /* If the random context indicates that a test DT should be used, + take the DT value from the context. For safety reasons we do + this only if the context is not one of the regular contexts. */ + if (rng_ctx->test_dt_ptr + && rng_ctx != nonce_context + && rng_ctx != std_rng_context + && rng_ctx != strong_rng_context) + { + memcpy (buffer, rng_ctx->test_dt_ptr, 16); + buffer[12] = (rng_ctx->test_dt_counter >> 24); + buffer[13] = (rng_ctx->test_dt_counter >> 16); + buffer[14] = (rng_ctx->test_dt_counter >> 8); + buffer[15] = rng_ctx->test_dt_counter; + rng_ctx->test_dt_counter++; + return; + } + + +#if HAVE_GETTIMEOFDAY + { + static u32 last_sec, last_usec; + static u32 counter1, counter0; + static u16 counter2; + + unsigned int usec; + struct timeval tv; + + if (!last_sec) + { + /* This is the very first time we are called: Set the counters + to an not so easy predictable value to avoid always + starting at 0. Not really needed but it doesn't harm. */ + counter1 = (u32)getpid (); +#ifndef HAVE_W32_SYSTEM + counter0 = (u32)getppid (); +#endif + } + + + if (gettimeofday (&tv, NULL)) + log_fatal ("gettimeofday() failed: %s\n", strerror (errno)); + + /* The microseconds part is always less than 1 millon (0x0f4240). + Thus we don't care about the MSB and in addition shift it to + the left by 4 bits. */ + usec = tv.tv_usec; + usec <<= 4; + /* If we got the same time as by the last invocation, bump up + counter2 and save the time for the next invocation. */ + if (tv.tv_sec == last_sec && usec == last_usec) + { + counter2++; + counter2 &= 0x0fff; + } + else + { + counter2 = 0; + last_sec = tv.tv_sec; + last_usec = usec; + } + /* Fill the buffer with the timestamp. */ + buffer[0] = ((tv.tv_sec >> 24) & 0xff); + buffer[1] = ((tv.tv_sec >> 16) & 0xff); + buffer[2] = ((tv.tv_sec >> 8) & 0xff); + buffer[3] = (tv.tv_sec & 0xff); + buffer[4] = ((usec >> 16) & 0xff); + buffer[5] = ((usec >> 8) & 0xff); + buffer[6] = ((usec & 0xf0) | ((counter2 >> 8) & 0x0f)); + buffer[7] = (counter2 & 0xff); + /* Add the free running counter. */ + buffer[8] = ((counter1 >> 24) & 0xff); + buffer[9] = ((counter1 >> 16) & 0xff); + buffer[10] = ((counter1 >> 8) & 0xff); + buffer[11] = ((counter1) & 0xff); + buffer[12] = ((counter0 >> 24) & 0xff); + buffer[13] = ((counter0 >> 16) & 0xff); + buffer[14] = ((counter0 >> 8) & 0xff); + buffer[15] = ((counter0) & 0xff); + /* Bump up that counter. */ + if (!++counter0) + ++counter1; + } +#else + log_fatal ("gettimeofday() not available on this system\n"); +#endif + + /* log_printhex ("x931_get_dt: ", buffer, 16); */ +} + + +/* XOR the buffers A and B which are each of LENGTH bytes and store + the result at R. R needs to be provided by the caller with a size + of at least LENGTH bytes. */ +static void +xor_buffer (unsigned char *r, + const unsigned char *a, const unsigned char *b, size_t length) +{ + for ( ; length; length--, a++, b++, r++) + *r = (*a ^ *b); +} + + +/* Encrypt LENGTH bytes of INPUT to OUTPUT using KEY. LENGTH + needs to be 16. */ +static void +encrypt_aes (gcry_cipher_hd_t key, + unsigned char *output, const unsigned char *input, size_t length) +{ + gpg_error_t err; + + gcry_assert (length == 16); + + err = gcry_cipher_encrypt (key, output, length, input, length); + if (err) + log_fatal ("AES encryption in RNG failed: %s\n", gcry_strerror (err)); +} + + +/* The core ANSI X9.31, Appendix A.2.4 function using AES. The caller + needs to pass a 16 byte buffer for the result, the 16 byte + datetime_DT value and the 16 byte seed value V. The caller also + needs to pass an appropriate KEY and make sure to pass a valid + seed_V. The caller also needs to provide two 16 bytes buffer for + intermediate results, they may be reused by the caller later. + + On return the result is stored at RESULT_R and the SEED_V is + updated. May only be used while holding the lock. */ +static void +x931_aes (unsigned char result_R[16], + unsigned char datetime_DT[16], unsigned char seed_V[16], + gcry_cipher_hd_t key, + unsigned char intermediate_I[16], unsigned char temp_xor[16]) +{ + /* Let ede*X(Y) represent the AES encryption of Y under the key *X. + + Let V be a 128-bit seed value which is also kept secret, and XOR + be the exclusive-or operator. Let DT be a date/time vector which + is updated on each iteration. I is a intermediate value. + + I = ede*K(DT) */ + encrypt_aes (key, intermediate_I, datetime_DT, 16); + + /* R = ede*K(I XOR V) */ + xor_buffer (temp_xor, intermediate_I, seed_V, 16); + encrypt_aes (key, result_R, temp_xor, 16); + + /* V = ede*K(R XOR I). */ + xor_buffer (temp_xor, result_R, intermediate_I, 16); + encrypt_aes (key, seed_V, temp_xor, 16); + + /* Zero out temporary values. */ + wipememory (intermediate_I, 16); + wipememory (temp_xor, 16); +} + + +/* The high level driver to x931_aes. This one does the required + tests and calls the core function until the entire buffer has been + filled. OUTPUT is a caller provided buffer of LENGTH bytes to + receive the random, RNG_CTX is the context of the RNG. The context + must be properly initialized. Returns 0 on success. */ +static int +x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx) +{ + unsigned char datetime_DT[16]; + unsigned char *intermediate_I, *temp_buffer, *result_buffer; + size_t nbytes; + + gcry_assert (fips_rng_is_locked); + gcry_assert (rng_ctx->cipher_hd); + gcry_assert (rng_ctx->is_seeded); + + gcry_assert (tempvalue_for_x931_aes_driver); + gcry_assert (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE == 48); + intermediate_I = tempvalue_for_x931_aes_driver; + temp_buffer = tempvalue_for_x931_aes_driver + 16; + result_buffer = tempvalue_for_x931_aes_driver + 32; + + while (length) + { + /* Unless we are running with a test context, we require a new + seed after some time. */ + if (!rng_ctx->test_dt_ptr && rng_ctx->use_counter > SEED_TTL) + { + x931_reseed (rng_ctx); + rng_ctx->use_counter = 0; + } + + /* Due to the design of the RNG, we always receive 16 bytes (128 + bit) of random even if we require less. The extra bytes + returned are not used. Intheory we could save them for the + next invocation, but that would make the control flow harder + to read. */ + nbytes = length < 16? length : 16; + + x931_get_dt (datetime_DT, 16, rng_ctx); + x931_aes (result_buffer, + datetime_DT, rng_ctx->seed_V, rng_ctx->cipher_hd, + intermediate_I, temp_buffer); + rng_ctx->use_counter++; + + if (rng_ctx->test_no_dup_check + && rng_ctx->test_dt_ptr + && rng_ctx != nonce_context + && rng_ctx != std_rng_context + && rng_ctx != strong_rng_context) + { + /* This is a test context which does not want the duplicate + block check. */ + } + else + { + /* Do a basic check on the output to avoid a stuck generator. */ + if (!rng_ctx->compare_value_valid) + { + /* First time used, only save the result. */ + memcpy (rng_ctx->compare_value, result_buffer, 16); + rng_ctx->compare_value_valid = 1; + continue; + } + if (!memcmp (rng_ctx->compare_value, result_buffer, 16)) + { + /* Ooops, we received the same 128 bit block - that should + in theory never happen. The FIPS requirement says that + we need to put ourself into the error state in such + case. */ + fips_signal_error ("duplicate 128 bit block returned by RNG"); + return -1; + } + memcpy (rng_ctx->compare_value, result_buffer, 16); + } + + /* Append to outbut. */ + memcpy (output, result_buffer, nbytes); + wipememory (result_buffer, 16); + output += nbytes; + length -= nbytes; + } + + return 0; +} + + +/* Callback for x931_generate_key. Note that this callback uses the + global ENTROPY_COLLECT_BUFFER which has been setup by get_entropy. + ORIGIN is not used but required due to the design of entropy + gathering module. */ +static void +entropy_collect_cb (const void *buffer, size_t length, + enum random_origins origin) +{ + const unsigned char *p = buffer; + + (void)origin; + + gcry_assert (fips_rng_is_locked); + gcry_assert (entropy_collect_buffer); + + /* Note that we need to protect against gatherers returning more + than the requested bytes (e.g. rndw32). */ + while (length-- && entropy_collect_buffer_len < entropy_collect_buffer_size) + { + entropy_collect_buffer[entropy_collect_buffer_len++] ^= *p++; + } +} + + +/* Get NBYTES of entropy from the kernel device. The callers needs to + free the returned buffer. The function either succeeds or + terminates the process in case of a fatal error. */ +static void * +get_entropy (size_t nbytes) +{ + void *result; + int rc; + + gcry_assert (!entropy_collect_buffer); + entropy_collect_buffer = gcry_xmalloc_secure (nbytes); + entropy_collect_buffer_size = nbytes; + entropy_collect_buffer_len = 0; + +#if USE_RNDLINUX + rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0, + X931_AES_KEYLEN, + GCRY_VERY_STRONG_RANDOM); +#elif USE_RNDW32 + do + { + rc = _gcry_rndw32_gather_random (entropy_collect_cb, 0, + X931_AES_KEYLEN, + GCRY_VERY_STRONG_RANDOM); + } + while (rc >= 0 && entropy_collect_buffer_len < entropy_collect_buffer_size); +#else + rc = -1; +#endif + + if (rc < 0 || entropy_collect_buffer_len != entropy_collect_buffer_size) + { + gcry_free (entropy_collect_buffer); + entropy_collect_buffer = NULL; + log_fatal ("error getting entropy data\n"); + } + result = entropy_collect_buffer; + entropy_collect_buffer = NULL; + return result; +} + + +/* Generate a key for use with x931_aes. The function returns a + handle to the cipher context readily prepared for ECB encryption. + If FOR_NONCE is true, the key is retrieved by readong random from + the standard generator. On error NULL is returned. */ +static gcry_cipher_hd_t +x931_generate_key (int for_nonce) +{ + gcry_cipher_hd_t hd; + gpg_error_t err; + void *buffer; + + gcry_assert (fips_rng_is_locked); + + /* Allocate a cipher context. */ + err = gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, + GCRY_CIPHER_SECURE); + if (err) + { + log_error ("error creating cipher context for RNG: %s\n", + gcry_strerror (err)); + return NULL; + } + + /* Get a key from the standard RNG or from the entropy source. */ + if (for_nonce) + { + buffer = gcry_xmalloc (X931_AES_KEYLEN); + get_random (buffer, X931_AES_KEYLEN, std_rng_context); + } + else + { + buffer = get_entropy (X931_AES_KEYLEN); + } + + /* Set the key and delete the buffer because the key is now part of + the cipher context. */ + err = gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN); + wipememory (buffer, X931_AES_KEYLEN); + gcry_free (buffer); + if (err) + { + log_error ("error creating key for RNG: %s\n", gcry_strerror (err)); + gcry_cipher_close (hd); + return NULL; + } + + return hd; +} + + +/* Generate a key for use with x931_aes. The function copies a seed + of LENGTH bytes into SEED_BUFFER. LENGTH needs to by given as 16. */ +static void +x931_generate_seed (unsigned char *seed_buffer, size_t length) +{ + void *buffer; + + gcry_assert (fips_rng_is_locked); + gcry_assert (length == 16); + + buffer = get_entropy (X931_AES_KEYLEN); + + memcpy (seed_buffer, buffer, X931_AES_KEYLEN); + wipememory (buffer, X931_AES_KEYLEN); + gcry_free (buffer); +} + + + +/* Reseed a generator. This is also used for the initial seeding. */ +static void +x931_reseed (rng_context_t rng_ctx) +{ + gcry_assert (fips_rng_is_locked); + + if (rng_ctx == nonce_context) + { + /* The nonce context is special. It will be seeded using the + standard random generator. */ + get_random (rng_ctx->seed_V, 16, std_rng_context); + rng_ctx->is_seeded = 1; + rng_ctx->seed_init_pid = getpid (); + } + else + { + /* The other two generators are seeded from /dev/random. */ + x931_generate_seed (rng_ctx->seed_V, 16); + rng_ctx->is_seeded = 1; + rng_ctx->seed_init_pid = getpid (); + } +} + + +/* Core random function. This is used for both nonce and random + generator. The actual RNG to be used depends on the random context + RNG_CTX passed. Note that this function is called with the RNG not + yet locked. */ +static void +get_random (void *buffer, size_t length, rng_context_t rng_ctx) +{ + gcry_assert (buffer); + gcry_assert (rng_ctx); + + check_guards (rng_ctx); + + /* Initialize the cipher handle and thus setup the key if needed. */ + if (!rng_ctx->cipher_hd) + { + if (rng_ctx == nonce_context) + rng_ctx->cipher_hd = x931_generate_key (1); + else + rng_ctx->cipher_hd = x931_generate_key (0); + if (!rng_ctx->cipher_hd) + goto bailout; + rng_ctx->key_init_pid = getpid (); + } + + /* Initialize the seed value if needed. */ + if (!rng_ctx->is_seeded) + x931_reseed (rng_ctx); + + if (rng_ctx->key_init_pid != getpid () + || rng_ctx->seed_init_pid != getpid ()) + { + /* We are in a child of us. Because we have no way yet to do + proper re-initialization (including self-checks etc), the + only chance we have is to bail out. Obviusly a fork/exec + won't harm because the exec overwrites the old image. */ + fips_signal_error ("fork without proper re-initialization " + "detected in RNG"); + goto bailout; + } + + if (x931_aes_driver (buffer, length, rng_ctx)) + goto bailout; + + check_guards (rng_ctx); + return; + + bailout: + log_fatal ("severe error getting random\n"); + /*NOTREACHED*/ +} + + + +/* --- Public Functions --- */ + +/* Initialize this random subsystem. If FULL is false, this function + merely calls the basic initialization of the module and does not do + anything more. Doing this is not really required but when running + in a threaded environment we might get a race condition + otherwise. */ +void +_gcry_rngfips_initialize (int full) +{ + basic_initialization (); + if (!full) + return; + + /* Allocate temporary buffers. If that buffer already exists we + know that we are already initialized. */ + lock_rng (); + if (!tempvalue_for_x931_aes_driver) + { + tempvalue_for_x931_aes_driver + = gcry_xmalloc_secure (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE); + + /* Allocate the random contexts. Note that we do not need to use + secure memory for the nonce context. */ + nonce_context = gcry_xcalloc (1, sizeof *nonce_context); + setup_guards (nonce_context); + + std_rng_context = gcry_xcalloc_secure (1, sizeof *std_rng_context); + setup_guards (std_rng_context); + + strong_rng_context = gcry_xcalloc_secure (1, sizeof *strong_rng_context); + setup_guards (strong_rng_context); + } + else + { + /* Already initialized. Do some sanity checks. */ + gcry_assert (!nonce_context->test_dt_ptr); + gcry_assert (!std_rng_context->test_dt_ptr); + gcry_assert (!strong_rng_context->test_dt_ptr); + check_guards (nonce_context); + check_guards (std_rng_context); + check_guards (strong_rng_context); + } + unlock_rng (); +} + + +/* Print some statistics about the RNG. */ +void +_gcry_rngfips_dump_stats (void) +{ + /* Not yet implemented. */ +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_rngfips_is_faked (void) +{ + return 0; /* Faked random is not allowed. */ +} + + +/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY + should be in the range of 0..100 to indicate the goodness of the + entropy added, or -1 for goodness not known. */ +gcry_error_t +_gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality) +{ + (void)buf; + (void)buflen; + (void)quality; + return 0; /* Not implemented. */ +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong + enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key + generation stuff but may be very slow. */ +void +_gcry_rngfips_randomize (void *buffer, size_t length, + enum gcry_random_level level) +{ + _gcry_rngfips_initialize (1); /* Auto-initialize if needed. */ + + lock_rng (); + if (level == GCRY_VERY_STRONG_RANDOM) + get_random (buffer, length, strong_rng_context); + else + get_random (buffer, length, std_rng_context); + unlock_rng (); +} + + +/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ +void +_gcry_rngfips_create_nonce (void *buffer, size_t length) +{ + _gcry_rngfips_initialize (1); /* Auto-initialize if needed. */ + + lock_rng (); + get_random (buffer, length, nonce_context); + unlock_rng (); +} + + +/* Run a Know-Answer-Test using a dedicated test context. Note that + we can't use the samples from the NISR RNGVS document because they + don't take the requirement to throw away the first block and use + that for duplicate check in account. Thus we made up our own test + vectors. */ +static gcry_err_code_t +selftest_kat (selftest_report_func_t report) +{ + static struct + { + const unsigned char key[16]; + const unsigned char dt[16]; + const unsigned char v[16]; + const unsigned char r[3][16]; + } tv[] = + { + { { 0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42, + 0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe }, + { 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00, + 0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00 }, + { 0x52, 0x17, 0x8d, 0x29, 0xa2, 0xd5, 0x84, 0x12, + 0x9d, 0x89, 0x9a, 0x45, 0x82, 0x02, 0xf7, 0x77 }, + { { 0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40, + 0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3 }, + { 0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73, + 0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa }, + { 0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46, + 0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d } } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { { 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7, + 0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc }, + { 0xc8, 0xd1, 0xe5, 0x11, 0x59, 0x52, 0xf7, 0xfa, + 0x37, 0x38, 0xb4, 0xc5, 0xce, 0xb2, 0xb0, 0x9a }, + { 0x0d, 0x9c, 0xc5, 0x0d, 0x16, 0xe1, 0xbc, 0xed, + 0xcf, 0x60, 0x62, 0x09, 0x9d, 0x20, 0x83, 0x7e } } }, + { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x80, 0x00, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03, + 0xa0, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xa3, 0x23 }, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + { { 0x96, 0xed, 0xcc, 0xc3, 0xdd, 0x04, 0x7f, 0x75, + 0x63, 0x19, 0x37, 0x6f, 0x15, 0x22, 0x57, 0x56 }, + { 0x7a, 0x14, 0x76, 0x77, 0x95, 0x17, 0x7e, 0xc8, + 0x92, 0xe8, 0xdd, 0x15, 0xcb, 0x1f, 0xbc, 0xb1 }, + { 0x25, 0x3e, 0x2e, 0xa2, 0x41, 0x1b, 0xdd, 0xf5, + 0x21, 0x48, 0x41, 0x71, 0xb3, 0x8d, 0x2f, 0x4c } } } + }; + int tvidx, ridx; + rng_context_t test_ctx; + gpg_error_t err; + const char *errtxt = NULL; + unsigned char result[16]; + + gcry_assert (tempvalue_for_x931_aes_driver); + + test_ctx = gcry_xcalloc (1, sizeof *test_ctx); + setup_guards (test_ctx); + + lock_rng (); + + for (tvidx=0; tvidx < DIM (tv); tvidx++) + { + /* Setup the key. */ + err = gcry_cipher_open (&test_ctx->cipher_hd, + GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, + GCRY_CIPHER_SECURE); + if (err) + { + errtxt = "error creating cipher context for RNG"; + goto leave; + } + + err = gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16); + if (err) + { + errtxt = "error setting key for RNG"; + goto leave; + } + test_ctx->key_init_pid = getpid (); + + /* Setup the seed. */ + memcpy (test_ctx->seed_V, tv[tvidx].v, 16); + test_ctx->is_seeded = 1; + test_ctx->seed_init_pid = getpid (); + + /* Setup a DT value. */ + test_ctx->test_dt_ptr = tv[tvidx].dt; + test_ctx->test_dt_counter = ( (tv[tvidx].dt[12] << 24) + |(tv[tvidx].dt[13] << 16) + |(tv[tvidx].dt[14] << 8) + |(tv[tvidx].dt[15]) ); + + /* Get and compare the first three results. */ + for (ridx=0; ridx < 3; ridx++) + { + /* Compute the next value. */ + if (x931_aes_driver (result, 16, test_ctx)) + { + errtxt = "X9.31 RNG core function failed"; + goto leave; + } + + /* Compare it to the known value. */ + if (memcmp (result, tv[tvidx].r[ridx], 16)) + { + /* log_printhex ("x931_aes got: ", result, 16); */ + /* log_printhex ("x931_aes exp: ", tv[tvidx].r[ridx], 16); */ + errtxt = "RNG output does not match known value"; + goto leave; + } + } + + /* This test is actual pretty pointless because we use a local test + context. */ + if (test_ctx->key_init_pid != getpid () + || test_ctx->seed_init_pid != getpid ()) + { + errtxt = "fork detection failed"; + goto leave; + } + + gcry_cipher_close (test_ctx->cipher_hd); + test_ctx->cipher_hd = NULL; + test_ctx->is_seeded = 0; + check_guards (test_ctx); + } + + leave: + unlock_rng (); + gcry_cipher_close (test_ctx->cipher_hd); + check_guards (test_ctx); + gcry_free (test_ctx); + if (report && errtxt) + report ("random", 0, "KAT", errtxt); + return errtxt? GPG_ERR_SELFTEST_FAILED : 0; +} + + +/* Run the self-tests. */ +gcry_error_t +_gcry_rngfips_selftest (selftest_report_func_t report) +{ + gcry_err_code_t ec; + +#if defined(USE_RNDLINUX) || defined(USE_RNDW32) + { + char buffer[8]; + + /* Do a simple test using the public interface. This will also + enforce full intialization of the RNG. We need to be fully + initialized due to the global requirement of the + tempvalue_for_x931_aes_driver stuff. */ + gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM); + } + + ec = selftest_kat (report); + +#else /*!(USE_RNDLINUX||USE_RNDW32)*/ + report ("random", 0, "setup", "no entropy gathering module"); + ec = GPG_ERR_SELFTEST_FAILED; +#endif + return gpg_error (ec); +} + + +/* Create a new test context for an external RNG test driver. On + success the test context is stored at R_CONTEXT; on failure NULL is + stored at R_CONTEXT and an error code is returned. */ +gcry_err_code_t +_gcry_rngfips_init_external_test (void **r_context, unsigned int flags, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + gpg_error_t err; + rng_context_t test_ctx; + + _gcry_rngfips_initialize (1); /* Auto-initialize if needed. */ + + if (!r_context + || !key || keylen != 16 + || !seed || seedlen != 16 + || !dt || dtlen != 16 ) + return GPG_ERR_INV_ARG; + + test_ctx = gcry_calloc (1, sizeof *test_ctx + dtlen); + if (!test_ctx) + return gpg_err_code_from_syserror (); + setup_guards (test_ctx); + + /* Setup the key. */ + err = gcry_cipher_open (&test_ctx->cipher_hd, + GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, + GCRY_CIPHER_SECURE); + if (err) + goto leave; + + err = gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen); + if (err) + goto leave; + + test_ctx->key_init_pid = getpid (); + + /* Setup the seed. */ + memcpy (test_ctx->seed_V, seed, seedlen); + test_ctx->is_seeded = 1; + test_ctx->seed_init_pid = getpid (); + + /* Setup a DT value. Because our context structure only stores a + pointer we copy the DT value to the extra space we allocated in + the test_ctx and set the pointer to that address. */ + memcpy ((unsigned char*)test_ctx + sizeof *test_ctx, dt, dtlen); + test_ctx->test_dt_ptr = (unsigned char*)test_ctx + sizeof *test_ctx; + test_ctx->test_dt_counter = ( (test_ctx->test_dt_ptr[12] << 24) + |(test_ctx->test_dt_ptr[13] << 16) + |(test_ctx->test_dt_ptr[14] << 8) + |(test_ctx->test_dt_ptr[15]) ); + + if ( (flags & 1) ) + test_ctx->test_no_dup_check = 1; + + check_guards (test_ctx); + /* All fine. */ + err = 0; + + leave: + if (err) + { + gcry_cipher_close (test_ctx->cipher_hd); + gcry_free (test_ctx); + *r_context = NULL; + } + else + *r_context = test_ctx; + return gcry_err_code (err); +} + + +/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them + at BUFFER. Return 0 on success or an error code. */ +gcry_err_code_t +_gcry_rngfips_run_external_test (void *context, char *buffer, size_t buflen) +{ + rng_context_t test_ctx = context; + + if (!test_ctx || !buffer || buflen != 16) + return GPG_ERR_INV_ARG; + + lock_rng (); + get_random (buffer, buflen, test_ctx); + unlock_rng (); + return 0; +} + +/* Release the test CONTEXT. */ +void +_gcry_rngfips_deinit_external_test (void *context) +{ + rng_context_t test_ctx = context; + + if (test_ctx) + { + gcry_cipher_close (test_ctx->cipher_hd); + gcry_free (test_ctx); + } +} + + diff --git a/libgcrypt-1.4.6/random/random.c b/libgcrypt-1.4.6/random/random.c new file mode 100644 index 0000000..8df87e2 --- /dev/null +++ b/libgcrypt-1.4.6/random/random.c @@ -0,0 +1,323 @@ +/* random.c - Random number switch + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + This module switches between different implementations of random + number generators and provides a few help functions. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "g10lib.h" +#include "random.h" +#include "rand-internal.h" +#include "ath.h" + + +/* If not NULL a progress function called from certain places and the + opaque value passed along. Registred by + _gcry_register_random_progress (). */ +static void (*progress_cb) (void *,const char*,int,int, int ); +static void *progress_cb_data; + + + + +/* --- Functions --- */ + + +/* Used to register a progress callback. This needs to be called + before any threads are created. */ +void +_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int), + void *cb_data ) +{ + progress_cb = cb; + progress_cb_data = cb_data; +} + + +/* This progress function is currently used by the random modules to + give hints on how much more entropy is required. */ +void +_gcry_random_progress (const char *what, int printchar, int current, int total) +{ + if (progress_cb) + progress_cb (progress_cb_data, what, printchar, current, total); +} + + + +/* Initialize this random subsystem. If FULL is false, this function + merely calls the basic initialization of the module and does not do + anything more. Doing this is not really required but when running + in a threaded environment we might get a race condition + otherwise. */ +void +_gcry_random_initialize (int full) +{ + if (fips_mode ()) + _gcry_rngfips_initialize (full); + else + _gcry_rngcsprng_initialize (full); +} + + +void +_gcry_random_dump_stats (void) +{ + if (fips_mode ()) + _gcry_rngfips_dump_stats (); + else + _gcry_rngcsprng_dump_stats (); +} + + +/* This function should be called during initialization and beore + intialization of this module to place the random pools into secure + memory. */ +void +_gcry_secure_random_alloc (void) +{ + if (fips_mode ()) + ; /* Not used; the fips rng is allows in secure mode. */ + else + _gcry_rngcsprng_secure_alloc (); +} + + +/* This may be called before full initialization to degrade the + quality of the RNG for the sake of a faster running test suite. */ +void +_gcry_enable_quick_random_gen (void) +{ + if (fips_mode ()) + ; /* Not used. */ + else + _gcry_rngcsprng_enable_quick_gen (); +} + + +void +_gcry_set_random_daemon_socket (const char *socketname) +{ + if (fips_mode ()) + ; /* Not used. */ + else + _gcry_rngcsprng_set_daemon_socket (socketname); +} + +/* With ONOFF set to 1, enable the use of the daemon. With ONOFF set + to 0, disable the use of the daemon. With ONOF set to -1, return + whether the daemon has been enabled. */ +int +_gcry_use_random_daemon (int onoff) +{ + if (fips_mode ()) + return 0; /* Never enabled in fips mode. */ + else + return _gcry_rngcsprng_use_daemon (onoff); +} + + +/* This function returns true if no real RNG is available or the + quality of the RNG has been degraded for test purposes. */ +int +_gcry_random_is_faked (void) +{ + if (fips_mode ()) + return _gcry_rngfips_is_faked (); + else + return _gcry_rngcsprng_is_faked (); +} + + +/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY + should be in the range of 0..100 to indicate the goodness of the + entropy added, or -1 for goodness not known. */ +gcry_error_t +gcry_random_add_bytes (const void *buf, size_t buflen, int quality) +{ + if (fips_mode ()) + return 0; /* No need for this in fips mode. */ + else + return _gcry_rngcsprng_add_bytes (buf, buflen, quality); +} + + +/* Helper function. */ +static void +do_randomize (void *buffer, size_t length, enum gcry_random_level level) +{ + if (fips_mode ()) + _gcry_rngfips_randomize (buffer, length, level); + else + _gcry_rngcsprng_randomize (buffer, length, level); +} + +/* The public function to return random data of the quality LEVEL. + Returns a pointer to a newly allocated and randomized buffer of + LEVEL and NBYTES length. Caller must free the buffer. */ +void * +gcry_random_bytes (size_t nbytes, enum gcry_random_level level) +{ + void *buffer; + + buffer = gcry_xmalloc (nbytes); + do_randomize (buffer, nbytes, level); + return buffer; +} + + +/* The public function to return random data of the quality LEVEL; + this version of the function returns the random in a buffer allocated + in secure memory. Caller must free the buffer. */ +void * +gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level) +{ + void *buffer; + + /* Historical note (1.3.0--1.4.1): The buffer was only allocated + in secure memory if the pool in random-csprng.c was also set to + use secure memory. */ + buffer = gcry_xmalloc_secure (nbytes); + do_randomize (buffer, nbytes, level); + return buffer; +} + + +/* Public function to fill the buffer with LENGTH bytes of + cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is + not very strong, GCRY_STRONG_RANDOM is strong enough for most + usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but + may be very slow. */ +void +gcry_randomize (void *buffer, size_t length, enum gcry_random_level level) +{ + do_randomize (buffer, length, level); +} + + +/* This function may be used to specify the file to be used as a seed + file for the PRNG. This fucntion should be called prior to the + initialization of the random module. NAME may not be NULL. */ +void +_gcry_set_random_seed_file (const char *name) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else + _gcry_rngcsprng_set_seed_file (name); +} + + +/* If a seed file has been setup, this function may be used to write + back the random numbers entropy pool. */ +void +_gcry_update_random_seed_file (void) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else + _gcry_rngcsprng_update_seed_file (); +} + + + +/* The fast random pool function as called at some places in + libgcrypt. This is merely a wrapper to make sure that this module + is initalized and to lock the pool. Note, that this function is a + NOP unless a random function has been used or _gcry_initialize (1) + has been used. We use this hack so that the internal use of this + function in cipher_open and md_open won't start filling up the + random pool, even if no random will be required by the process. */ +void +_gcry_fast_random_poll (void) +{ + if (fips_mode ()) + ; /* No need for this in fips mode. */ + else + _gcry_rngcsprng_fast_poll (); +} + + + +/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */ +void +gcry_create_nonce (void *buffer, size_t length) +{ + if (fips_mode ()) + _gcry_rngfips_create_nonce (buffer, length); + else + _gcry_rngcsprng_create_nonce (buffer, length); +} + + +/* Run the self-tests for the RNG. This is currently only implemented + for the FIPS generator. */ +gpg_error_t +_gcry_random_selftest (selftest_report_func_t report) +{ + if (fips_mode ()) + return _gcry_rngfips_selftest (report); + else + return 0; /* No selftests yet. */ +} + + +/* Create a new test context for an external RNG test driver. On + success the test context is stored at R_CONTEXT; on failure NULL is + stored at R_CONTEXT and an error code is returned. */ +gcry_err_code_t +_gcry_random_init_external_test (void **r_context, + unsigned int flags, + const void *key, size_t keylen, + const void *seed, size_t seedlen, + const void *dt, size_t dtlen) +{ + (void)flags; + if (fips_mode ()) + return _gcry_rngfips_init_external_test (r_context, flags, key, keylen, + seed, seedlen, + dt, dtlen); + else + return GPG_ERR_NOT_SUPPORTED; +} + +/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them + at BUFFER. Return 0 on success or an error code. */ +gcry_err_code_t +_gcry_random_run_external_test (void *context, char *buffer, size_t buflen) +{ + if (fips_mode ()) + return _gcry_rngfips_run_external_test (context, buffer, buflen); + else + return GPG_ERR_NOT_SUPPORTED; +} + +/* Release the test CONTEXT. */ +void +_gcry_random_deinit_external_test (void *context) +{ + if (fips_mode ()) + _gcry_rngfips_deinit_external_test (context); +} diff --git a/libgcrypt-1.4.6/random/random.h b/libgcrypt-1.4.6/random/random.h new file mode 100644 index 0000000..9075d9a --- /dev/null +++ b/libgcrypt-1.4.6/random/random.h @@ -0,0 +1,72 @@ +/* random.h - random functions + * Copyright (C) 1998, 2002, 2006 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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_RANDOM_H +#define G10_RANDOM_H + +#include "types.h" + +/*-- random.c --*/ +void _gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int), + void *cb_data ); + +void _gcry_random_initialize (int full); +void _gcry_random_dump_stats(void); +void _gcry_secure_random_alloc(void); +void _gcry_enable_quick_random_gen (void); +int _gcry_random_is_faked(void); +void _gcry_set_random_daemon_socket (const char *socketname); +int _gcry_use_random_daemon (int onoff); +void _gcry_set_random_seed_file (const char *name); +void _gcry_update_random_seed_file (void); + +byte *_gcry_get_random_bits( size_t nbits, int level, int secure ); +void _gcry_fast_random_poll( void ); + +gcry_err_code_t _gcry_random_init_external_test (void **r_context, + unsigned int flags, + const void *key, + size_t keylen, + const void *seed, + size_t seedlen, + const void *dt, + size_t dtlen); +gcry_err_code_t _gcry_random_run_external_test (void *context, + char *buffer, size_t buflen); +void _gcry_random_deinit_external_test (void *context); + + +/*-- rndegd.c --*/ +gpg_error_t _gcry_rndegd_set_socket_name (const char *name); + +/*-- random-daemon.c (only used from random.c) --*/ +#ifdef USE_RANDOM_DAEMON +void _gcry_daemon_initialize_basics (void); +int _gcry_daemon_randomize (const char *socketname, + void *buffer, size_t length, + enum gcry_random_level level); +int _gcry_daemon_create_nonce (const char *socketname, + void *buffer, size_t length); +#endif /*USE_RANDOM_DAEMON*/ + +#endif /*G10_RANDOM_H*/ + + + + diff --git a/libgcrypt-1.4.6/random/rndegd.c b/libgcrypt-1.4.6/random/rndegd.c new file mode 100644 index 0000000..63a5e0f --- /dev/null +++ b/libgcrypt-1.4.6/random/rndegd.c @@ -0,0 +1,290 @@ +/* rndegd.c - interface to the EGD + * Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 <errno.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "types.h" +#include "g10lib.h" +#include "cipher.h" +#include "rand-internal.h" + +#ifndef offsetof +#define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif + +static int egd_socket = -1; + +/* Allocated name of the socket if supplied at runtime. */ +static char *user_socket_name; + + +/* Allocate a new filename from FIRST_PART and SECOND_PART and to + tilde expansion for first_part. SECOND_PART might be NULL. + */ +static char * +my_make_filename (const char *first_part, const char *second_part) +{ + size_t n; + char *name, *home, *p; + + n = strlen(first_part)+1; + if (second_part) + n += strlen (second_part) + 1; + + home = NULL; + if( *first_part == '~' && first_part[1] == '/' + && (home = getenv("HOME")) && *home ) + n += strlen(home); + + name = gcry_xmalloc(n); + p = (home + ? stpcpy (stpcpy (name, home), first_part+1 ) + : stpcpy (name, first_part) ); + + if (second_part) + strcpy (stpcpy(p,"/"), second_part); + + return name; +} + + +static int +do_write( int fd, void *buf, size_t nbytes ) +{ + size_t nleft = nbytes; + int nwritten; + + while( nleft > 0 ) + { + nwritten = write( fd, buf, nleft); + if( nwritten < 0 ) + { + if( errno == EINTR ) + continue; + return -1; + } + nleft -= nwritten; + buf = (char*)buf + nwritten; + } + return 0; +} + +static int +do_read( int fd, void *buf, size_t nbytes ) +{ + int n, nread = 0; + + do + { + do + { + n = read(fd, (char*)buf + nread, nbytes ); + } + while( n == -1 && errno == EINTR ); + if( n == -1) + return nread? nread:-1; + if( n == 0) + return -1; + nread += n; + nbytes -= n; + } + while( nread < nbytes ); + return nread; +} + + +/* Note that his fucntion is not thread-safe. */ +gpg_error_t +_gcry_rndegd_set_socket_name (const char *name) +{ + char *newname; + struct sockaddr_un addr; + + newname = my_make_filename (name, NULL); + if (strlen (newname)+1 >= sizeof addr.sun_path) + { + gcry_free (newname); + return gpg_error_from_syserror (); + } + gcry_free (user_socket_name); + user_socket_name = newname; + return 0; +} + + +/* Connect to the EGD and return the file descriptor. Return -1 on + error. With NOFAIL set to true, silently fail and return the + error, otherwise print an error message and die. */ +int +_gcry_rndegd_connect_socket (int nofail) +{ + int fd; + const char *bname = NULL; + char *name; + struct sockaddr_un addr; + int addr_len; + + if (egd_socket != -1) + { + close (egd_socket); + egd_socket = -1; + } + +#ifdef EGD_SOCKET_NAME + bname = EGD_SOCKET_NAME; +#endif + if (user_socket_name) + { + name = gcry_strdup (user_socket_name); + if (!name) + { + if (!nofail) + log_fatal ("error allocating memory in rndegd: %s\n", + strerror(errno) ); + return -1; + } + } + else if ( !bname || !*bname ) + name = my_make_filename ("~/.gnupg", "entropy"); + else + name = my_make_filename (bname, NULL); + + if (strlen(name)+1 >= sizeof addr.sun_path) + log_fatal ("EGD socketname is too long\n"); + + memset( &addr, 0, sizeof addr ); + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, name ); + addr_len = (offsetof( struct sockaddr_un, sun_path ) + + strlen( addr.sun_path )); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1 && !nofail) + log_fatal("can't create unix domain socket: %s\n", strerror(errno) ); + else if (connect (fd, (struct sockaddr*)&addr, addr_len) == -1) + { + if (!nofail) + log_fatal("can't connect to EGD socket `%s': %s\n", + name, strerror(errno) ); + close (fd); + fd = -1; + } + gcry_free(name); + if (fd != -1) + egd_socket = fd; + return fd; +} + +/**************** + * 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. + */ +int +_gcry_rndegd_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + int fd = egd_socket; + int n; + byte buffer[256+2]; + int nbytes; + int do_restart = 0; + + if( !length ) + return 0; + if( !level ) + return 0; + + restart: + if (fd == -1 || do_restart) + fd = _gcry_rndegd_connect_socket (0); + + do_restart = 0; + + nbytes = length < 255? length : 255; + /* First time we do it with a non blocking request */ + buffer[0] = 1; /* non blocking */ + buffer[1] = nbytes; + if( do_write( fd, buffer, 2 ) == -1 ) + log_fatal("can't write to the EGD: %s\n", strerror(errno) ); + n = do_read( fd, buffer, 1 ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + n = buffer[0]; + if( n ) + { + n = do_read( fd, buffer, n ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + (*add)( buffer, n, origin ); + length -= n; + } + + if( length ) + { + log_info ( + _("Please wait, entropy is being gathered. Do some work if it would\n" + "keep you from getting bored, because it will improve the quality\n" + "of the entropy.\n") ); + } + while( length ) + { + nbytes = length < 255? length : 255; + + buffer[0] = 2; /* blocking */ + buffer[1] = nbytes; + if( do_write( fd, buffer, 2 ) == -1 ) + log_fatal("can't write to the EGD: %s\n", strerror(errno) ); + n = do_read( fd, buffer, nbytes ); + if( n == -1 ) + { + log_error("read error on EGD: %s\n", strerror(errno)); + do_restart = 1; + goto restart; + } + (*add)( buffer, n, origin ); + length -= n; + } + memset(buffer, 0, sizeof(buffer) ); + + return 0; /* success */ +} diff --git a/libgcrypt-1.4.6/random/rndhw.c b/libgcrypt-1.4.6/random/rndhw.c new file mode 100644 index 0000000..0961d10 --- /dev/null +++ b/libgcrypt-1.4.6/random/rndhw.c @@ -0,0 +1,138 @@ +/* rndhw.c - Access to the external random daemon + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + +#undef USE_PADLOCK +#ifdef ENABLE_PADLOCK_SUPPORT +# if defined (__i386__) && SIZEOF_UNSIGNED_LONG == 4 && defined (__GNUC__) +# define USE_PADLOCK +# endif +#endif /*ENABLE_PADLOCK_SUPPORT*/ + +/* Keep track on whether the RNG has problems. */ +static volatile int rng_failed; + + +#ifdef USE_PADLOCK +static size_t +poll_padlock (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin, int fast) +{ + volatile char buffer[64+8] __attribute__ ((aligned (8))); + volatile char *p; + unsigned int nbytes, status; + + /* Peter Gutmann's cryptlib tests again whether the RNG is enabled + but we don't do so. We would have to do this also for our AES + implementaion and that is definitely too time consuming. There + would be a race condition anyway. Thus we assume that the OS + does not change the Padlock initialization while a user process + is running. */ + p = buffer; + nbytes = 0; + while (nbytes < 64) + { + asm volatile + ("movl %1, %%edi\n\t" /* Set buffer. */ + "xorl %%edx, %%edx\n\t" /* Request up to 8 bytes. */ + ".byte 0x0f, 0xa7, 0xc0\n\t" /* XSTORE RNG. */ + : "=a" (status) + : "g" (p) + : "%edx", "%edi", "cc" + ); + if ((status & (1<<6)) /* RNG still enabled. */ + && !(status & (1<<13)) /* von Neumann corrector is enabled. */ + && !(status & (1<<14)) /* String filter is disabled. */ + && !(status & 0x1c00) /* BIAS voltage at default. */ + && (!(status & 0x1f) || (status & 0x1f) == 8) /* Sanity check. */ + ) + { + nbytes += (status & 0x1f); + if (fast) + break; /* Don't get into the loop with the fast flag set. */ + p += (status & 0x1f); + } + else + { + /* If there was an error we need to break the loop and + record that there is something wrong with the padlock + RNG. */ + rng_failed = 1; + break; + } + } + + if (nbytes) + { + (*add) ((void*)buffer, nbytes, origin); + wipememory (buffer, nbytes); + } + return nbytes; +} +#endif /*USE_PADLOCK*/ + + +int +_gcry_rndhw_failed_p (void) +{ + return rng_failed; +} + + +/* Try to read random from a hardware RNG if a fast one is + available. */ +void +_gcry_rndhw_poll_fast (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin) +{ + (void)add; + (void)origin; + +#ifdef USE_PADLOCK + if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) + poll_padlock (add, origin, 1); +#endif +} + + +/* Read 64 bytes from a hardware RNG and return the number of bytes + actually read. */ +size_t +_gcry_rndhw_poll_slow (void (*add)(const void*, size_t, enum random_origins), + enum random_origins origin) +{ + size_t nbytes = 0; + + (void)add; + (void)origin; + +#ifdef USE_PADLOCK + if ((_gcry_get_hw_features () & HWF_PADLOCK_RNG)) + nbytes += poll_padlock (add, origin, 0); +#endif + + return nbytes; +} diff --git a/libgcrypt-1.4.6/random/rndlinux.c b/libgcrypt-1.4.6/random/rndlinux.c new file mode 100644 index 0000000..574ef6d --- /dev/null +++ b/libgcrypt-1.4.6/random/rndlinux.c @@ -0,0 +1,167 @@ +/* rndlinux.c - raw random number for OSes with /dev/random + * Copyright (C) 1998, 2001, 2002, 2003, 2007 Free Software Foundation, Inc. + * + * This file is part of Libgcrypt. + * + * Libgcrypt is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * Libgcrypt 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_GETTIMEOFDAY +# include <sys/times.h> +#endif +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + +static int open_device ( const char *name ); + + +static int +set_cloexec_flag (int fd) +{ + int oldflags; + + oldflags= fcntl (fd, F_GETFD, 0); + if (oldflags < 0) + return oldflags; + oldflags |= FD_CLOEXEC; + return fcntl (fd, F_SETFD, oldflags); +} + + + +/* + * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). + */ +static int +open_device ( const char *name ) +{ + int fd; + + fd = open ( name, O_RDONLY ); + if ( fd == -1 ) + log_fatal ("can't open %s: %s\n", name, strerror(errno) ); + + if (set_cloexec_flag (fd)) + log_error ("error setting FD_CLOEXEC on fd %d: %s\n", + fd, strerror (errno)); + + /* We used to do the following check, however it turned out that this + is not portable since more OSes provide a random device which is + sometimes implemented as another device type. + + struct stat sb; + + if( fstat( fd, &sb ) ) + log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); + if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) + log_fatal("invalid random device!\n" ); + */ + return fd; +} + + +int +_gcry_rndlinux_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static int fd_urandom = -1; + static int fd_random = -1; + int fd; + int n; + int warn=0; + byte buffer[768]; + size_t n_hw; + + /* First read from a hardware source. However let it account only + for up to 50% of the requested bytes. */ + n_hw = _gcry_rndhw_poll_slow (add, origin); + if (n_hw > length/2) + n_hw = length/2; + if (length > 1) + length -= n_hw; + + /* Open the requested device. */ + if (level >= 2) + { + if( fd_random == -1 ) + fd_random = open_device ( NAME_OF_DEV_RANDOM ); + fd = fd_random; + } + else + { + if( fd_urandom == -1 ) + fd_urandom = open_device ( NAME_OF_DEV_URANDOM ); + fd = fd_urandom; + } + + /* And enter the read loop. */ + while (length) + { + fd_set rfds; + struct timeval tv; + int rc; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = 3; + tv.tv_usec = 0; + if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) + { + if( !warn ) + { + _gcry_random_progress ("need_entropy", 'X', 0, (int)length); + warn = 1; + } + continue; + } + else if( rc == -1 ) + { + log_error ("select() error: %s\n", strerror(errno)); + continue; + } + + do + { + int nbytes = length < sizeof(buffer)? length : sizeof(buffer); + n = read(fd, buffer, nbytes ); + if( n >= 0 && n > nbytes ) + { + log_error("bogus read from random device (n=%d)\n", n ); + n = nbytes; + } + } + while( n == -1 && errno == EINTR ); + if( n == -1 ) + log_fatal("read error on random device: %s\n", strerror(errno)); + (*add)( buffer, n, origin ); + length -= n; + } + memset(buffer, 0, sizeof(buffer) ); + + return 0; /* success */ +} diff --git a/libgcrypt-1.4.6/random/rndunix.c b/libgcrypt-1.4.6/random/rndunix.c new file mode 100644 index 0000000..1faf9ab --- /dev/null +++ b/libgcrypt-1.4.6/random/rndunix.c @@ -0,0 +1,883 @@ +/**************************************************************************** + * * + * * + * Unix Randomness-Gathering Code * + * * + * Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1999. * + * Heavily modified for GnuPG by Werner Koch * + * * + * * + ****************************************************************************/ + +/* 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:] + + 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 Lesser General Public License, version 2.1 or any later version + published by the Free Software Foundation, in which case the + provisions of the GNU LGPL are required INSTEAD OF the above + restrictions. + + Although not required under the terms of the LGPL, it would still be + nice if you could make any changes available to the author to allow + a consistent code base to be maintained. */ +/************************************************************************* + The above alternative was changed from GPL to LGPL on 2007-08-22 with + permission from Peter Gutmann: + ========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 03:05:42 +1200 + + Hi, + + >As of now libgcrypt is GPL under Windows due to that module and some people + >would really like to see it under LGPL too. Can you do such a license change + >to LGPL version 2? Note that LGPL give the user the option to relicense it + >under GPL, so the change would be pretty easy and backwar compatible. + + Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy + code as well, but Ian asked for LGPL as an option so as of the next release + I'll have LGPL in there. You can consider it to be retroactive, so your + current version will be LGPLd as well. + + Peter. + ========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 20:50:08 +1200 + + >Would you mind to extend this also to the Unix entropy gatherer which is + >still used on systems without /dev/random and when EGD is not installed? That + >would be the last GPLed piece in Libgcrypt. + + Sure, it covers the entire entropy-gathering subsystem. + + Peter. + ========= +*/ + +/* General includes */ + +#include <config.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* OS-specific includes */ + +#ifdef __osf__ + /* Somewhere in the morass of system-specific cruft which OSF/1 pulls in + * via the following includes are various endianness defines, so we + * undefine the cryptlib ones, which aren't really needed for this module + * anyway */ +#undef BIG_ENDIAN +#undef LITTLE_ENDIAN +#endif /* __osf__ */ + +#include <unistd.h> +#include <fcntl.h> +#include <pwd.h> +#ifndef __QNX__ +#include <sys/errno.h> +#include <sys/ipc.h> +#endif /* __QNX__ */ +#include <sys/time.h> /* SCO and SunOS need this before resource.h */ +#ifndef __QNX__ +#include <sys/resource.h> +#endif /* __QNX__ */ +#if defined( _AIX ) || defined( __QNX__ ) +#include <sys/select.h> +#endif /* _AIX */ +#ifndef __QNX__ +#include <sys/shm.h> +#include <signal.h> +#include <sys/signal.h> +#endif /* __QNX__ */ +#include <sys/stat.h> +#include <sys/types.h> /* Verschiedene komische Typen */ +#if defined( __hpux ) && ( OS_VERSION == 9 ) +#include <vfork.h> +#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" +#include "rand-internal.h" + +#ifndef EAGAIN +#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 */ + +/* The structure containing information on random-data sources. Each + * record contains the source and a relative estimate of its usefulness + * (weighting) which is used to scale the number of kB of output from the + * source (total = data_bytes / usefulness). Usually the weighting is in the + * range 1-3 (or 0 for especially useless sources), resulting in a usefulness + * rating of 1...3 for each kB of source output (or 0 for the useless + * sources). + * + * If the source is constantly changing (certain types of network statistics + * have this characteristic) but the amount of output is small, the weighting + * is given as a negative value to indicate that the output should be treated + * as if a minimum of 1K of output had been obtained. If the source produces + * a lot of output then the scale factor is fractional, resulting in a + * usefulness rating of < 1 for each kB of source output. + * + * In order to provide enough randomness to satisfy the requirements for a + * slow poll, we need to accumulate at least 20 points of usefulness (a + * typical system should get about 30 points). + * + * Some potential options are missed out because of special considerations. + * pstat -i and pstat -f can produce amazing amounts of output (the record + * is 600K on an Oracle server) which floods the buffer and doesn't yield + * anything useful (apart from perhaps increasing the entropy of the vmstat + * output a bit), so we don't bother with this. pstat in general produces + * quite a bit of output, but it doesn't change much over time, so it gets + * very low weightings. netstat -s produces constantly-changing output but + * also produces quite a bit of it, so it only gets a weighting of 2 rather + * than 3. The same holds for netstat -in, which gets 1 rather than 2. + * + * Some binaries are stored in different locations on different systems so + * alternative paths are given for them. The code sorts out which one to + * run by itself, once it finds an exectable somewhere it moves on to the + * next source. The sources are arranged roughly in their order of + * usefulness, occasionally sources which provide a tiny amount of + * relatively useless data are placed ahead of ones which provide a large + * amount of possibly useful data because another 100 bytes can't hurt, and + * it means the buffer won't be swamped by one or two high-output sources. + * All the high-output sources are clustered towards the end of the list + * for this reason. Some binaries are checked for in a certain order, for + * example under Slowaris /usr/ucb/ps understands aux as an arg, but the + * others don't. Some systems have conditional defines enabling alternatives + * to commands which don't understand the usual options but will provide + * enough output (in the form of error messages) to look like they're the + * real thing, causing alternative options to be skipped (we can't check the + * return either because some commands return peculiar, non-zero status even + * when they're working correctly). + * + * In order to maximise use of the buffer, the code performs a form of run- + * length compression on its input where a repeated sequence of bytes is + * replaced by the occurrence count mod 256. Some commands output an awful + * lot of whitespace, this measure greatly increases the amount of data we + * can fit in the buffer. + * + * When we scale the weighting using the SC() macro, some preprocessors may + * give a division by zero warning for the most obvious expression + * 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero + * trap), so we define a value SC_0 which evaluates to zero when fed to + * '1024 / SC_0' */ + +#define SC( weight ) ( 1024 / weight ) /* Scale factor */ +#define SC_0 16384 /* SC( SC_0 ) evalutes to 0 */ + +static struct RI { + const char *path; /* Path to check for existence of source */ + const char *arg; /* Args for source */ + const int usefulness; /* Usefulness of source */ + FILE *pipe; /* Pipe to source as FILE * */ + int pipeFD; /* Pipe to source as FD */ + pid_t pid; /* pid of child for waitpid() */ + int length; /* Quantity of output produced */ + const int hasAlternative; /* Whether source has alt.location */ +} dataSources[] = { + + { "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 0}, + { "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, 0}, + { "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, 0 }, + { "/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, 0}, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP in */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP out */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* IP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/bin/df", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 0 }, +#if defined( __sgi ) || defined( __hpux ) + { "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, 1 }, +#endif /* __sgi || __hpux */ + { "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/bin/ps", "-A", SC(0.3), NULL, 0, 0, 0, 0 }, /*QNX*/ + { "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0 }, + /* Unreliable source, depends on system usage */ + { "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + /* pstat is your friend */ + { "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 1 }, +#ifdef __sgi + { "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __sgi */ +#ifdef __hpux + { "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __hpux */ + { "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/ripquery", "-nw 1 127.0.0.1", + SC(0.1), NULL, 0, 0, 0, 0 }, + { "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, 0 }, + /* This is very environment-dependant. If network traffic is low, it'll + * probably time out before delivering 5 packets, which is OK because + * it'll probably be fixed stuff like ARP anyway */ + { "/usr/sbin/advfsstat", "-b usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-l 2 usr_domain", + SC(0.5), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-p usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + /* This is a complex and screwball program. Some systems have things + * like rX_dmn, x = integer, for RAID systems, but the statistics are + * pretty dodgy */ +#ifdef __QNXNTO__ + { "/bin/pidin", "-F%A%B%c%d%E%I%J%K%m%M%n%N%p%P%S%s%T", SC(0.3), + NULL, 0, 0, 0, 0 }, +#endif +#if 0 + /* The following aren't enabled since they're somewhat slow and not very + * unpredictable, however they give an indication of the sort of sources + * you can use (for example the finger might be more useful on a + * firewalled internal network) */ + { "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, 0 }, + { "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html", + SC(0.9), NULL, 0, 0, 0, 0 }, + { "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, 0 }, +#endif /* 0 */ + { NULL, NULL, 0, NULL, 0, 0, 0, 0 } +}; + +static byte *gather_buffer; /* buffer for gathering random noise */ +static int gather_buffer_size; /* size of the memory buffer */ +static uid_t gatherer_uid; + +/* The message structure used to communicate with the parent */ +typedef struct { + int usefulness; /* usefulness of data */ + int ndata; /* valid bytes in data */ + char data[500]; /* gathered data */ +} GATHER_MSG; + +#ifndef HAVE_WAITPID +static 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 + * that this reaps any other children that happen to have died at that + * moment, and when their pclose() comes along, the process hangs forever. + * The fix is to use a wrapper for popen()/pclose() which saves the pid in + * the dataSources structure (code adapted from GNU-libc's popen() call). + * + * Aut viam inveniam aut faciam */ + +static FILE * +my_popen(struct RI *entry) +{ + int pipedes[2]; + FILE *stream; + + /* Create the pipe */ + if (pipe(pipedes) < 0) + return (NULL); + + /* Fork off the child ("vfork() is like an OS orgasm. All OS's want to + * do it, but most just end up faking it" - Chris Wedgwood). If your OS + * supports it, you should try to use vfork() here because it's somewhat + * more efficient */ +#if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ ) || \ + defined(__hpux) + entry->pid = vfork(); +#else /* */ + entry->pid = fork(); +#endif /* Unixen which have vfork() */ + if (entry->pid == (pid_t) - 1) { + /* The fork failed */ + close(pipedes[0]); + close(pipedes[1]); + return (NULL); + } + + if (entry->pid == (pid_t) 0) { + struct passwd *passwd; + + /* We are the child. Make the read side of the pipe be stdout */ + if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0) + exit(127); + + /* Now that everything is set up, give up our permissions to make + * sure we don't read anything sensitive. If the getpwnam() fails, + * we default to -1, which is usually nobody */ + if (gatherer_uid == (uid_t)-1 && \ + (passwd = getpwnam("nobody")) != NULL) + gatherer_uid = passwd->pw_uid; + + setuid(gatherer_uid); + + /* Close the pipe descriptors */ + close(pipedes[STDIN_FILENO]); + close(pipedes[STDOUT_FILENO]); + + /* Try and exec the program */ + execl(entry->path, entry->path, entry->arg, NULL); + + /* Die if the exec failed */ + exit(127); + } + + /* We are the parent. Close the irrelevant side of the pipe and open + * the relevant side as a new stream. Mark our side of the pipe to + * 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"); + + if (stream == NULL) { + int savedErrno = errno; + + /* The stream couldn't be opened or the child structure couldn't be + * allocated. Kill the child and close the other side of the pipe */ + kill(entry->pid, SIGKILL); + if (stream == NULL) + close(pipedes[STDOUT_FILENO]); + else + fclose(stream); + + waitpid(entry->pid, NULL, 0); + + entry->pid = 0; + errno = savedErrno; + return (NULL); + } + + return (stream); +} + +static int +my_pclose(struct RI *entry) +{ + int status = 0; + + if (fclose(entry->pipe)) + return (-1); + + /* We ignore the return value from the process because some + programs return funny values which would result in the input + being discarded even if they executed successfully. This isn't + a problem because the result data size threshold will filter + out any programs which exit with a usage message without + producing useful output. */ + if (waitpid(entry->pid, NULL, 0) != entry->pid) + status = -1; + + entry->pipe = NULL; + entry->pid = 0; + return (status); +} + + +/* Unix slow poll (without special support for Linux) + * + * If a few of the randomness sources create a large amount of output then + * the slowPoll() stops once the buffer has been filled (but before all the + * randomness sources have been sucked dry) so that the 'usefulness' factor + * remains below the threshold. For this reason the gatherer buffer has to + * be fairly sizeable on moderately loaded systems. This is something of a + * bug since the usefulness should be influenced by the amount of output as + * well as the source type */ + + +static int +slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes ) +{ + int moreSources; + struct timeval tv; + fd_set fds; +#if defined( __hpux ) + size_t maxFD = 0; +#else + int maxFD = 0; +#endif /* OS-specific brokenness */ + int bufPos, i, usefulness = 0; + + + /* Fire up each randomness source */ + FD_ZERO(&fds); + for (i = 0; dataSources[i].path != NULL; i++) { + /* Since popen() is a fairly heavy function, we check to see whether + * the executable exists before we try to run it */ + if (access(dataSources[i].path, X_OK)) { + if( dbgfp && dbgall ) + fprintf(dbgfp, "%s not present%s\n", dataSources[i].path, + dataSources[i].hasAlternative ? + ", has alternatives" : ""); + dataSources[i].pipe = NULL; + } + else + dataSources[i].pipe = my_popen(&dataSources[i]); + + if (dataSources[i].pipe != NULL) { + dataSources[i].pipeFD = fileno(dataSources[i].pipe); + if (dataSources[i].pipeFD > maxFD) + maxFD = dataSources[i].pipeFD; + +#ifdef O_NONBLOCK /* Ohhh what a hack (used for Atari) */ + fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK); +#else +#error O_NONBLOCK is missing +#endif + + FD_SET(dataSources[i].pipeFD, &fds); + dataSources[i].length = 0; + + /* If there are alternatives for this command, don't try and + * execute them */ + while (dataSources[i].hasAlternative) { + if( dbgfp && dbgall ) + fprintf(dbgfp, "Skipping %s\n", dataSources[i + 1].path); + i++; + } + } + } + + + /* Suck all the data we can get from each of the sources */ + bufPos = 0; + moreSources = 1; + while (moreSources && bufPos <= gather_buffer_size) { + /* Wait for data to become available from any of the sources, with a + * timeout of 10 seconds. This adds even more randomness since data + * becomes available in a nondeterministic fashion. Kudos to HP's QA + * department for managing to ship a select() which breaks its own + * prototype */ + tv.tv_sec = 10; + tv.tv_usec = 0; + +#if defined( __hpux ) && ( OS_VERSION == 9 ) + if (select(maxFD + 1, (int *)&fds, NULL, NULL, &tv) == -1) +#else /* */ + if (select(maxFD + 1, &fds, NULL, NULL, &tv) == -1) +#endif /* __hpux */ + break; + + /* One of the sources has data available, read it into the buffer */ + for (i = 0; dataSources[i].path != NULL; i++) { + if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) { + size_t noBytes; + + if ((noBytes = fread(gather_buffer + bufPos, 1, + gather_buffer_size - bufPos, + dataSources[i].pipe)) == 0) { + if (my_pclose(&dataSources[i]) == 0) { + int total = 0; + + /* Try and estimate how much entropy we're getting + * from a data source */ + if (dataSources[i].usefulness) { + if (dataSources[i].usefulness < 0) + total = (dataSources[i].length + 999) + / -dataSources[i].usefulness; + else + total = dataSources[i].length + / dataSources[i].usefulness; + } + if( dbgfp ) + fprintf(dbgfp, + "%s %s contributed %d bytes, " + "usefulness = %d\n", dataSources[i].path, + (dataSources[i].arg != NULL) ? + dataSources[i].arg : "", + dataSources[i].length, total); + if( dataSources[i].length ) + usefulness += total; + } + dataSources[i].pipe = NULL; + } + else { + int currPos = bufPos; + int endPos = bufPos + noBytes; + + /* Run-length compress the input byte sequence */ + while (currPos < endPos) { + int ch = gather_buffer[currPos]; + + /* If it's a single byte, just copy it over */ + if (ch != gather_buffer[currPos + 1]) { + gather_buffer[bufPos++] = ch; + currPos++; + } + else { + int count = 0; + + /* It's a run of repeated bytes, replace them + * with the byte count mod 256 */ + while ((ch == gather_buffer[currPos]) + && currPos < endPos) { + count++; + currPos++; + } + gather_buffer[bufPos++] = count; + noBytes -= count - 1; + } + } + + /* Remember the number of (compressed) bytes of input we + * obtained */ + dataSources[i].length += noBytes; + } + } + } + + /* Check if there is more input available on any of the sources */ + moreSources = 0; + FD_ZERO(&fds); + for (i = 0; dataSources[i].path != NULL; i++) { + if (dataSources[i].pipe != NULL) { + FD_SET(dataSources[i].pipeFD, &fds); + moreSources = 1; + } + } + } + + if( dbgfp ) { + fprintf(dbgfp, "Got %d bytes, usefulness = %d\n", bufPos, usefulness); + fflush(dbgfp); + } + *nbytes = bufPos; + return usefulness; +} + +/**************** + * Start the gatherer process which writes messages of + * type GATHERER_MSG to pipedes + */ +static void +start_gatherer( int pipefd ) +{ + FILE *dbgfp = NULL; + int dbgall; + + { + const char *s = getenv("GNUPG_RNDUNIX_DBG"); + if( s ) { + dbgfp = (*s=='-' && !s[1])? stdout : fopen(s, "a"); + if( !dbgfp ) + log_info("can't open debug file `%s': %s\n", + s, strerror(errno) ); + else + fprintf(dbgfp,"\nSTART RNDUNIX DEBUG pid=%d\n", (int)getpid()); + } + dbgall = !!getenv("GNUPG_RNDUNIX_DBGALL"); + } + /* 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; +#else + nmax = 20; /* assume a reasonable value */ +#endif + } +#else /*!_SC_OPEN_MAX*/ + nmax = 20; /* assume a reasonable value */ +#endif /*!_SC_OPEN_MAX*/ + n1 = fileno( stderr ); + n2 = dbgfp? fileno( dbgfp ) : -1; + for(i=0; i < nmax; i++ ) { + if( i != n1 && i != n2 && i != pipefd ) + close(i); + } + errno = 0; + } + + + /* Set up the buffer. Not ethat we use a plain standard malloc here. */ + gather_buffer_size = GATHER_BUFSIZE; + gather_buffer = malloc( gather_buffer_size ); + if( !gather_buffer ) { + log_error("out of core while allocating the gatherer buffer\n"); + exit(2); + } + + /* Reset the SIGC(H)LD handler to the system default. This is necessary + * because if the program which cryptlib is a part of installs its own + * SIGC(H)LD handler, it will end up reaping the cryptlib children before + * cryptlib can. As a result, my_pclose() will call waitpid() on a + * process which has already been reaped by the installed handler and + * return an error, so the read data won't be added to the randomness + * pool. There are two types of SIGC(H)LD naming, the SysV SIGCLD and + * the BSD/Posix SIGCHLD, so we need to handle either possibility */ +#ifdef SIGCLD + signal(SIGCLD, SIG_DFL); +#else + signal(SIGCHLD, SIG_DFL); +#endif + + fclose(stderr); /* Arrghh!! It's Stuart code!! */ + + for(;;) { + GATHER_MSG msg; + size_t nbytes; + const char *p; + + msg.usefulness = slow_poll( dbgfp, dbgall, &nbytes ); + p = gather_buffer; + while( nbytes ) { + msg.ndata = nbytes > sizeof(msg.data)? sizeof(msg.data) : nbytes; + memcpy( msg.data, p, msg.ndata ); + nbytes -= msg.ndata; + p += msg.ndata; + + while( write( pipefd, &msg, sizeof(msg) ) != sizeof(msg) ) { + if( errno == EINTR ) + continue; + if( errno == EAGAIN ) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 50000; + select(0, NULL, NULL, NULL, &tv); + continue; + } + if( errno == EPIPE ) /* parent has exited, so give up */ + exit(0); + + /* we can't do very much here because stderr is closed */ + if( dbgfp ) + fprintf(dbgfp, "gatherer can't write to pipe: %s\n", + strerror(errno) ); + /* we start a new poll to give the system some time */ + nbytes = 0; + break; + } + } + } + /* we are killed when the parent dies */ +} + + +static int +read_a_msg( int fd, GATHER_MSG *msg ) +{ + char *buffer = (char*)msg; + size_t length = sizeof( *msg ); + int n; + + do { + do { + n = read(fd, buffer, length ); + } while( n == -1 && errno == EINTR ); + if( n == -1 ) + return -1; + buffer += n; + length -= n; + } while( length ); + return 0; +} + + +/**************** + * Using a level of 0 should never block and better add nothing + * to the pool. So this is just a dummy for this gatherer. + */ +int +_gcry_rndunix_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static pid_t gatherer_pid = 0; + static int pipedes[2]; + GATHER_MSG msg; + size_t n; + + if( !level ) + return 0; + + if( !gatherer_pid ) { + /* Make sure we are not setuid. */ + if ( getuid() != geteuid() ) + BUG(); + /* time to start the gatherer process */ + if( pipe( pipedes ) ) { + log_error("pipe() failed: %s\n", strerror(errno)); + return -1; + } + gatherer_pid = fork(); + if( gatherer_pid == -1 ) { + log_error("can't for gatherer process: %s\n", strerror(errno)); + return -1; + } + if( !gatherer_pid ) { + start_gatherer( pipedes[1] ); + /* oops, can't happen */ + return -1; + } + } + + /* now read from the gatherer */ + while( length ) { + int goodness; + ulong subtract; + + if( read_a_msg( pipedes[0], &msg ) ) { + log_error("reading from gatherer pipe failed: %s\n", + strerror(errno)); + return -1; + } + + + if( level > 1 ) { + if( msg.usefulness > 30 ) + goodness = 100; + else if ( msg.usefulness ) + goodness = msg.usefulness * 100 / 30; + else + goodness = 0; + } + else if( level ) { + if( msg.usefulness > 15 ) + goodness = 100; + else if ( msg.usefulness ) + goodness = msg.usefulness * 100 / 15; + else + goodness = 0; + } + else + goodness = 100; /* goodness of level 0 is always 100 % */ + + n = msg.ndata; + if( n > length ) + n = length; + (*add)( msg.data, n, origin ); + + /* this is the trick how we cope with the goodness */ + subtract = (ulong)n * goodness / 100; + /* subtract at least 1 byte to avoid infinite loops */ + length -= subtract ? subtract : 1; + } + + return 0; +} diff --git a/libgcrypt-1.4.6/random/rndw32.c b/libgcrypt-1.4.6/random/rndw32.c new file mode 100644 index 0000000..a41cb46 --- /dev/null +++ b/libgcrypt-1.4.6/random/rndw32.c @@ -0,0 +1,981 @@ +/* rndw32.c - W32 entropy gatherer + * Copyright (C) 1999, 2000, 2002, 2003, 2007 Free Software Foundation, Inc. + * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-2006 + * + * This file is part of Libgcrypt. + * + ************************************************************************* + * 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 Lesser General Public License, version 2.1 or any later version + * published by the Free Software Foundation, in which case the + * provisions of the GNU LGPL are required INSTEAD OF the above + * restrictions. + * + * Although not required under the terms of the LGPL, it would still + * be nice if you could make any changes available to the author to + * allow a consistent code base to be maintained. + ************************************************************************* + * The above alternative was changed from GPL to LGPL on 2007-08-22 with + * permission from Peter Gutmann: + *========== + From: pgut001 <pgut001@cs.auckland.ac.nz> + Subject: Re: LGPL for the windows entropy gatherer + To: wk@gnupg.org + Date: Wed, 22 Aug 2007 03:05:42 +1200 + + Hi, + + >As of now libgcrypt is GPL under Windows due to that module and some people + >would really like to see it under LGPL too. Can you do such a license change + >to LGPL version 2? Note that LGPL give the user the option to relicense it + >under GPL, so the change would be pretty easy and backwar compatible. + + Sure. I assumed that since GPG was GPLd, you'd prefer the GPL for the entropy + code as well, but Ian asked for LGPL as an option so as of the next release + I'll have LGPL in there. You can consider it to be retroactive, so your + current version will be LGPLd as well. + + Peter. + *========== + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#ifdef __GNUC__ +#include <stdint.h> +#endif + +#include <winsock2.h> +#include <windows.h> + + +#include "types.h" +#include "g10lib.h" +#include "rand-internal.h" + + +/* Definitions which are missing from the current GNU Windows32Api. */ +#ifndef IOCTL_DISK_PERFORMANCE +#define IOCTL_DISK_PERFORMANCE 0x00070020 +#endif + +/* This used to be (6*8+5*4+8*2), but Peter Gutmann figured a larger + value in a newer release. So we use a far larger value. */ +#define SIZEOF_DISK_PERFORMANCE_STRUCT 256 + +/* We don't include wincrypt.h so define it here. */ +#define HCRYPTPROV HANDLE + + +/* 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 */ + + +/* The number of bytes to read from the system RNG on each slow poll. */ +#define SYSTEMRNG_BYTES 64 + +/* Intel Chipset CSP type and name */ +#define PROV_INTEL_SEC 22 +#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider" + + + + +/* 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); + +/* Type definitions for function pointers to call native NT functions. */ +typedef DWORD (WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD systemInformationClass, + PVOID systemInformation, + ULONG systemInformationLength, + PULONG returnLength); +typedef DWORD (WINAPI *NTQUERYINFORMATIONPROCESS) + (HANDLE processHandle, DWORD processInformationClass, + PVOID processInformation, ULONG processInformationLength, + PULONG returnLength); +typedef DWORD (WINAPI *NTPOWERINFORMATION) + (DWORD powerInformationClass, PVOID inputBuffer, + ULONG inputBufferLength, PVOID outputBuffer, ULONG outputBufferLength ); + +/* Type definitions for function pointers to call CryptoAPI functions. */ +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *phProv, + LPCTSTR pszContainer, + LPCTSTR pszProvider, + DWORD dwProvType, + DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, + BYTE *pbBuffer); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +/* Somewhat alternative functionality available as a direct call, for + Windows XP and newer. This is the CryptoAPI RNG, which isn't anywhere + near as good as the HW RNG, but we use it if it's present on the basis + that at least it can't make things any worse. This direct access version + is only available under Windows XP, we don't go out of our way to access + the more general CryptoAPI one since the main purpose of using it is to + take advantage of any possible future hardware RNGs that may be added, + for example via TCPA devices. */ +typedef BOOL (WINAPI *RTLGENRANDOM)(PVOID RandomBuffer, + ULONG RandomBufferLength); + + + +/* MBM data structures, originally by Alexander van Kaam, converted to C by + Anders@Majland.org, finally updated by Chris Zahrt <techn0@iastate.edu> */ +#define BusType char +#define SMBType char +#define SensorType char + +typedef struct +{ + SensorType iType; /* Type of sensor. */ + int Count; /* Number of sensor for that type. */ +} SharedIndex; + +typedef struct +{ + SensorType ssType; /* Type of sensor */ + unsigned char ssName[12]; /* Name of sensor */ + char sspadding1[3]; /* Padding of 3 bytes */ + double ssCurrent; /* Current value */ + double ssLow; /* Lowest readout */ + double ssHigh; /* Highest readout */ + long ssCount; /* Total number of readout */ + char sspadding2[4]; /* Padding of 4 bytes */ + long double ssTotal; /* Total amout of all readouts */ + char sspadding3[6]; /* Padding of 6 bytes */ + double ssAlarm1; /* Temp & fan: high alarm; voltage: % off */ + double ssAlarm2; /* Temp: low alarm */ +} SharedSensor; + +typedef struct +{ + short siSMB_Base; /* SMBus base address */ + BusType siSMB_Type; /* SMBus/Isa bus used to access chip */ + SMBType siSMB_Code; /* SMBus sub type, Intel, AMD or ALi */ + char siSMB_Addr; /* Address of sensor chip on SMBus */ + unsigned char siSMB_Name[41]; /* Nice name for SMBus */ + short siISA_Base; /* ISA base address of sensor chip on ISA */ + int siChipType; /* Chip nr, connects with Chipinfo.ini */ + char siVoltageSubType; /* Subvoltage option selected */ +} SharedInfo; + +typedef struct +{ + double sdVersion; /* Version number (example: 51090) */ + SharedIndex sdIndex[10]; /* Sensor index */ + SharedSensor sdSensor[100]; /* Sensor info */ + SharedInfo sdInfo; /* Misc.info */ + unsigned char sdStart[41]; /* Start time */ + + /* We don't use the next two fields both because they're not random + and because it provides a nice safety margin in case of data size + mis- estimates (we always under-estimate the buffer size). */ +#if 0 + unsigned char sdCurrent[41]; /* Current time */ + unsigned char sdPath[256]; /* MBM path */ +#endif /*0*/ +} SharedData; + + + +/* One time intialized handles and function pointers. We use dynamic + loading of the DLLs to do without them in case libgcrypt does not + need any random. */ +static HANDLE hNetAPI32; +static NETSTATISTICSGET pNetStatisticsGet; +static NETAPIBUFFERSIZE pNetApiBufferSize; +static NETAPIBUFFERFREE pNetApiBufferFree; + +static HANDLE hNTAPI; +static NTQUERYSYSTEMINFORMATION pNtQuerySystemInformation; +static NTQUERYINFORMATIONPROCESS pNtQueryInformationProcess; +static NTPOWERINFORMATION pNtPowerInformation; + +static HANDLE hAdvAPI32; +static CRYPTACQUIRECONTEXT pCryptAcquireContext; +static CRYPTGENRANDOM pCryptGenRandom; +static CRYPTRELEASECONTEXT pCryptReleaseContext; +static RTLGENRANDOM pRtlGenRandom; + + +/* Other module global variables. */ +static int system_rng_available; /* Whether a system RNG is available. */ +static HCRYPTPROV hRNGProv; /* Handle to Intel RNG CSP. */ + +static int debug_me; /* Debug flag. */ + +static int system_is_w2000; /* True if running on W2000. */ + + + + +/* Try and connect to the system RNG if there's one present. */ +static void +init_system_rng (void) +{ + system_rng_available = 0; + hRNGProv = NULL; + + hAdvAPI32 = GetModuleHandle ("AdvAPI32.dll"); + if (!hAdvAPI32) + return; + + pCryptAcquireContext = (CRYPTACQUIRECONTEXT) + GetProcAddress (hAdvAPI32, "CryptAcquireContextA"); + pCryptGenRandom = (CRYPTGENRANDOM) + GetProcAddress (hAdvAPI32, "CryptGenRandom"); + pCryptReleaseContext = (CRYPTRELEASECONTEXT) + GetProcAddress (hAdvAPI32, "CryptReleaseContext"); + + /* Get a pointer to the native randomness function if it's available. + This isn't exported by name, so we have to get it by ordinal. */ + pRtlGenRandom = (RTLGENRANDOM) + GetProcAddress (hAdvAPI32, "SystemFunction036"); + + /* Try and connect to the PIII RNG CSP. The AMD 768 southbridge (from + the 760 MP chipset) also has a hardware RNG, but there doesn't appear + to be any driver support for this as there is for the Intel RNG so we + can't do much with it. OTOH the Intel RNG is also effectively dead + as well, mostly due to virtually nonexistant support/marketing by + Intel, it's included here mostly for form's sake. */ + if ( (!pCryptAcquireContext || !pCryptGenRandom || !pCryptReleaseContext + || !pCryptAcquireContext (&hRNGProv, NULL, INTEL_DEF_PROV, + PROV_INTEL_SEC, 0) ) + && !pRtlGenRandom) + { + hAdvAPI32 = NULL; + } + else + system_rng_available = 1; +} + + +/* Read data from the system RNG if availavle. */ +static void +read_system_rng (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + BYTE buffer[ SYSTEMRNG_BYTES + 8 ]; + int quality = 0; + + if (!system_rng_available) + return; + + /* Read SYSTEMRNG_BYTES bytes from the system RNG. We don't rely on + this for all our randomness requirements (particularly the + software RNG) in case it's broken in some way. */ + if (hRNGProv) + { + if (pCryptGenRandom (hRNGProv, SYSTEMRNG_BYTES, buffer)) + quality = 80; + } + else if (pRtlGenRandom) + { + if ( pRtlGenRandom (buffer, SYSTEMRNG_BYTES)) + quality = 50; + } + if (quality > 0) + { + if (debug_me) + log_debug ("rndw32#read_system_rng: got %d bytes of quality %d\n", + SYSTEMRNG_BYTES, quality); + (*add) (buffer, SYSTEMRNG_BYTES, requester); + wipememory (buffer, SYSTEMRNG_BYTES); + } +} + + +/* Read data from MBM. This communicates via shared memory, so all we + need to do is map a file and read the data out. */ +static void +read_mbm_data (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + HANDLE hMBMData; + SharedData *mbmDataPtr; + + hMBMData = OpenFileMapping (FILE_MAP_READ, FALSE, "$M$B$M$5$S$D$" ); + if (hMBMData) + { + mbmDataPtr = (SharedData*)MapViewOfFile (hMBMData, FILE_MAP_READ,0,0,0); + if (mbmDataPtr) + { + if (debug_me) + log_debug ("rndw32#read_mbm_data: got %d bytes\n", + (int)sizeof (SharedData)); + (*add) (mbmDataPtr, sizeof (SharedData), requester); + UnmapViewOfFile (mbmDataPtr); + } + CloseHandle (hMBMData); + } +} + + +/* Fallback method using the registry to poll the statistics. */ +static void +registry_poll (void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester) +{ + static int cbPerfData = PERFORMANCE_BUFFER_SIZE; + int iterations; + DWORD dwSize, status; + PERF_DATA_BLOCK *pPerfData; + + /* 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, in + some cases 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. MS knowledge base article Q178887 covers + this type of problem, it's typically caused by an external driver or + other program that adds its own values under the + HKEY_PERFORMANCE_DATA key. The NT kernel, via Advapi32.dll, calls the + required external module to map in the data inside an SEH try/except + block, so problems in the module's collect function don't pop up until + after it has finished, so the fault appears to occur in Advapi32.dll. + There may be problems in the NT kernel as well though, 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). + OTOH this could be coming from the external module calling back into + the kernel, which eventually causes the problem described above. + + Possibly as an extension of the problem that the krnlWaitSemaphore() + call above works around, running two instances of cryptlib (e.g. two + applications that use it) under NT4 can result in one of them hanging + in the RegQueryValueEx() call. This happens only under NT4 and is + hard to reproduce in any consistent manner. + + One workaround that helps a bit is to read the registry as a remote + (rather than local) registry, it's possible that the use of a network + RPC call isolates the calling app from the problem in that whatever + service handles the RPC is taking the hit and not affecting the + calling app. Since this would require another round of extensive + testing to verify and the NT native API call is working fine, we'll + stick with the native API call for now. + + Some versions of NT4 had a problem where the amount of data returned + was mis-reported and would never settle down, because of this the code + below includes a safety-catch that bails out after 10 attempts have + been made, this results in no data being returned but at does ensure + that the thread will terminate. + + In addition to these problems the code in RegQueryValueEx() that + estimates the amount of memory required to return the performance + counter information isn't very accurate (it's much worse than the + "slightly-inaccurate" level that the MS docs warn about, it's usually + wildly off) 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. + + Even worse than the registry-based performance counters is the + performance data helper (PDH) shim that tries to make the counters + look like the old Win16 API (which is also used by Win95). Under NT + this can consume tens of MB of memory and huge amounts of CPU time + while it gathers its data, and even running once can still consume + about 1/2MB of memory */ + pPerfData = gcry_xmalloc (cbPerfData); + for (iterations=0; iterations < 10; iterations++) + { + 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 + log_debug ("rndw32: no PERF signature\n"); + break; + } + else if (status == ERROR_MORE_DATA) + { + cbPerfData += PERFORMANCE_BUFFER_STEP; + pPerfData = gcry_xrealloc (pPerfData, cbPerfData); + } + else + { + static int been_here; + + /* Silence the error message. In particular under Wine (as + of 2008) we would get swamped with such diagnotiscs. One + such diagnotiscs should be enough. */ + if (been_here != status) + { + been_here = status; + log_debug ("rndw32: get performance data problem: ec=%ld\n", + status); + } + break; + } + } + gcry_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 void +slow_gatherer ( void (*add)(const void*, size_t, enum random_origins), + enum random_origins requester ) +{ + static int is_initialized = 0; + static int is_workstation = 1; + HANDLE hDevice; + DWORD dwType, dwSize, dwResult; + ULONG ulSize; + int drive_no, status; + int no_results = 0; + void *buffer; + + if ( !is_initialized ) + { + HKEY hKey; + + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: 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 + 8]; + dwSize = 32; + + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: 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); + } + + /* The following are fixed for the lifetime of the process so we + only add them once */ + /* readPnPData (); - we have not implemented that. */ + + /* Initialize the NetAPI32 function pointers if necessary */ + hNetAPI32 = LoadLibrary ("NETAPI32.DLL"); + if (hNetAPI32) + { + if (debug_me) + log_debug ("rndw32#slow_gatherer: 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; + log_debug ("rndw32: No NETAPI found\n" ); + } + } + + /* Initialize the NT kernel native API function pointers if necessary */ + hNTAPI = GetModuleHandle ("NTDll.dll"); + if (hNTAPI) + { + /* Get a pointer to the NT native information query functions */ + pNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) + GetProcAddress (hNTAPI, "NtQuerySystemInformation"); + pNtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS) + GetProcAddress (hNTAPI, "NtQueryInformationProcess"); + pNtPowerInformation = (NTPOWERINFORMATION) + GetProcAddress(hNTAPI, "NtPowerInformation"); + + if (!pNtQuerySystemInformation || !pNtQueryInformationProcess) + hNTAPI = NULL; + } + + + is_initialized = 1; + } + + read_system_rng ( add, requester ); + read_mbm_data ( add, requester ); + + /* 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: get netstats\n" ); + pNetApiBufferSize (lpBuffer, &dwSize); + (*add) ( lpBuffer, dwSize, requester ); + pNetApiBufferFree (lpBuffer); + } + } + + /* Get disk I/O statistics for all the hard drives. 100 is an + arbitrary failsafe limit. */ + for (drive_no = 0; drive_no < 100 ; drive_no++) + { + char diskPerformance[SIZEOF_DISK_PERFORMANCE_STRUCT + 8]; + char szDevice[50]; + + /* Check whether we can access this device. */ + snprintf (szDevice, sizeof szDevice, "\\\\.\\PhysicalDrive%d", + drive_no); + hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) + break; /* No more drives. */ + + /* Note: This only works if you have turned on the disk performance + counters with 'diskperf -y'. These counters are off by default. */ + dwSize = sizeof diskPerformance; + if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, + diskPerformance, SIZEOF_DISK_PERFORMANCE_STRUCT, + &dwSize, NULL)) + { + if ( debug_me ) + log_debug ("rndw32#slow_gatherer: iostat drive %d\n", + drive_no); + (*add) (diskPerformance, dwSize, requester); + } + else + { + log_info ("NOTE: you should run 'diskperf -y' " + "to enable the disk statistics\n"); + } + CloseHandle (hDevice); + } + + /* In theory we should be using the Win32 performance query API to obtain + unpredictable data from the system, however this is so unreliable (see + the multiple sets of comments in registryPoll()) that it's too risky + to rely on it except as a fallback in emergencies. Instead, we rely + mostly on the NT native API function NtQuerySystemInformation(), which + has the dual advantages that it doesn't have as many (known) problems + as the Win32 equivalent and that it doesn't access the data indirectly + via pseudo-registry keys, which means that it's much faster. Note + that the Win32 equivalent actually works almost all of the time, the + problem is that on one or two systems it can fail in strange ways that + are never the same and can't be reproduced on any other system, which + is why we use the native API here. Microsoft officially documented + this function in early 2003, so it'll be fairly safe to use. */ + if ( !hNTAPI ) + { + registry_poll (add, requester); + return; + } + + + /* Scan the first 64 possible information types (we don't bother with + increasing the buffer size as we do with the Win32 version of the + performance data read, we may miss a few classes but it's no big deal). + This scan typically yields around 20 pieces of data, there's nothing + in the range 65...128 so chances are there won't be anything above + there either. */ + buffer = gcry_xmalloc (PERFORMANCE_BUFFER_SIZE); + for (dwType = 0; dwType < 64; dwType++) + { + switch (dwType) + { + /* ID 17 = SystemObjectInformation hangs on some win2k systems. */ + case 17: + if (system_is_w2000) + continue; + break; + + /* Some information types are write-only (the IDs are shared with + a set-information call), we skip these. */ + case 26: case 27: case 38: case 46: case 47: case 48: case 52: + continue; + + /* ID 53 = SystemSessionProcessInformation reads input from the + output buffer, which has to contain a session ID and pointer + to the actual buffer in which to store the session information. + Because this isn't a standard query, we skip this. */ + case 53: + continue; + } + + /* Query the info for this ID. Some results (for example for + ID = 6, SystemCallCounts) are only available in checked builds + of the kernel. A smaller subcless of results require that + certain system config flags be set, for example + SystemObjectInformation requires that the + FLG_MAINTAIN_OBJECT_TYPELIST be set in NtGlobalFlags. To avoid + having to special-case all of these, we try reading each one and + only use those for which we get a success status. */ + dwResult = pNtQuerySystemInformation (dwType, buffer, + PERFORMANCE_BUFFER_SIZE - 2048, + &ulSize); + if (dwResult != ERROR_SUCCESS) + continue; + + /* Some calls (e.g. ID = 23, SystemProcessorStatistics, and ID = 24, + SystemDpcInformation) incorrectly return a length of zero, so we + manually adjust the length to the correct value. */ + if ( !ulSize ) + { + if (dwType == 23) + ulSize = 6 * sizeof (ULONG); + else if (dwType == 24) + ulSize = 5 * sizeof (ULONG); + } + + /* If we got some data back, add it to the entropy pool. */ + if (ulSize > 0 && ulSize <= PERFORMANCE_BUFFER_SIZE - 2048) + { + if (debug_me) + log_debug ("rndw32#slow_gatherer: %lu bytes from sysinfo %ld\n", + ulSize, dwType); + (*add) (buffer, ulSize, requester); + no_results++; + } + } + + /* Now we would do the same for the process information. This + call would rather ugly in that it requires an exact length + match for the data returned, failing with a + STATUS_INFO_LENGTH_MISMATCH error code (0xC0000004) if the + length isn't an exact match. It requires a compiler to handle + complex nested structs, alignment issues, and so on, and + without the headers in which the entries are declared it's + almost impossible to do. Thus we don't. */ + + + /* Finally, do the same for the system power status information. There + are only a limited number of useful information types available so we + restrict ourselves to the useful types. In addition since this + function doesn't return length information, we have to hardcode in + length data. */ + if (pNtPowerInformation) + { + static const struct { int type; int size; } powerInfo[] = { + { 0, 128 }, /* SystemPowerPolicyAc */ + { 1, 128 }, /* SystemPowerPolicyDc */ + { 4, 64 }, /* SystemPowerCapabilities */ + { 5, 48 }, /* SystemBatteryState */ + { 11, 48 }, /* ProcessorInformation */ + { 12, 24 }, /* SystemPowerInformation */ + { -1, -1 } + }; + int i; + + /* The 100 is a failsafe limit. */ + for (i = 0; powerInfo[i].type != -1 && i < 100; i++ ) + { + /* Query the info for this ID */ + dwResult = pNtPowerInformation (powerInfo[i].type, NULL, 0, buffer, + PERFORMANCE_BUFFER_SIZE - 2048); + if (dwResult != ERROR_SUCCESS) + continue; + if (debug_me) + log_debug ("rndw32#slow_gatherer: %u bytes from powerinfo %d\n", + powerInfo[i].size, i); + (*add) (buffer, powerInfo[i].size, requester); + no_results++; + } + gcry_assert (i < 100); + } + gcry_free (buffer); + + /* We couldn't get enough results from the kernel, fall back to the + somewhat troublesome registry poll. */ + if (no_results < 15) + registry_poll (add, requester); +} + + +int +_gcry_rndw32_gather_random (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin, + size_t length, int level ) +{ + static int is_initialized; + + if (!level) + return 0; + + /* We don't differentiate between level 1 and 2 here because there + is no internal 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 ) }; + + GetVersionEx( &osvi ); + if ( osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) + log_fatal ("can only run on a Windows NT platform\n" ); + system_is_w2000 = (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0); + init_system_rng (); + is_initialized = 1; + } + + if (debug_me) + log_debug ("rndw32#gather_random: ori=%d len=%u lvl=%d\n", + origin, (unsigned int)length, level ); + + slow_gatherer (add, origin); + + return 0; +} + + + +void +_gcry_rndw32_gather_random_fast (void (*add)(const void*, size_t, + enum random_origins), + enum random_origins origin) +{ + static int addedFixedItems = 0; + + if ( debug_me ) + log_debug ("rndw32#gather_random_fast: ori=%d\n", origin ); + + /* 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 ()); + + gcry_assert ( bufptr-buffer < sizeof (buffer) ); + (*add) ( buffer, bufptr-buffer, origin ); +#undef ADD + } + + /* Get multiword system information: Current caret position, current + mouse cursor position. */ + { + POINT point; + + GetCaretPos (&point); + (*add) ( &point, sizeof (point), origin ); + GetCursorPos (&point); + (*add) ( &point, sizeof (point), origin ); + } + + /* 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), origin ); + } + + /* 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), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + handle = GetCurrentProcess (); + GetProcessTimes (handle, &creationTime, &exitTime, + &kernelTime, &userTime); + (*add) ( &creationTime, sizeof (creationTime), origin ); + (*add) ( &exitTime, sizeof (exitTime), origin ); + (*add) ( &kernelTime, sizeof (kernelTime), origin ); + (*add) ( &userTime, sizeof (userTime), origin ); + + /* Get the minimum and maximum working set size for the current + process. */ + GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, + &maximumWorkingSetSize); + (*add) ( &minimumWorkingSetSize, + sizeof (minimumWorkingSetSize), origin ); + (*add) ( &maximumWorkingSetSize, + sizeof (maximumWorkingSetSize), origin ); + } + + + /* 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), origin ); + addedFixedItems = 1; + } + + /* The performance of QPC varies depending on the architecture it's + running on and on the OS, the MS documentation is vague about the + details because it varies so much. Under Win9x/ME it reads the + 1.193180 MHz PIC timer. Under NT/Win2K/XP it may or may not read the + 64-bit TSC depending on the HAL and assorted other circumstances, + generally on machines with a uniprocessor HAL + KeQueryPerformanceCounter() uses a 3.579545MHz timer and on machines + with a multiprocessor or APIC HAL it uses the TSC (the exact time + source is controlled by the HalpUse8254 flag in the kernel). That + choice of time sources is somewhat peculiar because on a + multiprocessor machine it's theoretically possible to get completely + different TSC readings depending on which CPU you're currently + running on, while for uniprocessor machines it's not a problem. + However, the kernel appears to synchronise the TSCs across CPUs at + boot time (it resets the TSC as part of its system init), so this + shouldn't really be a problem. Under WinCE it's completely platform- + dependant, if there's no hardware performance counter available, it + uses the 1ms system timer. + + Another feature of the TSC (although it doesn't really affect us here) + is that mobile CPUs will turn off the TSC when they idle, Pentiums + will change the rate of the counter when they clock-throttle (to + match the current CPU speed), and hyperthreading Pentiums will turn + it off when both threads are idle (this more or less makes sense, + since the CPU will be in the halted state and not executing any + instructions to count). + + To make things unambiguous, we detect a CPU new enough to call RDTSC + directly by checking for CPUID capabilities, and fall back to QPC if + this isn't present. */ +#ifdef __GNUC__ +/* FIXME: We would need to implement the CPU feature tests first. */ +/* if (cpu_has_feature_rdtsc) */ +/* { */ +/* uint32_t lo, hi; */ + /* We cannot use "=A", since this would use %rax on x86_64. */ +/* __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); */ + /* Ignore high 32 bits, hwich are >1s res. */ +/* (*add) (&lo, 4, origin ); */ +/* } */ +/* else */ +#endif /*!__GNUC__*/ + { + LARGE_INTEGER performanceCount; + + if (QueryPerformanceCounter (&performanceCount)) + { + if ( debug_me ) + log_debug ("rndw32#gather_random_fast: perf data\n"); + (*add) (&performanceCount, sizeof (performanceCount), origin); + } + else + { + /* Millisecond accuracy at best... */ + DWORD aword = GetTickCount (); + (*add) (&aword, sizeof (aword), origin ); + } + } + + +} |