Page MenuHome GnuPG

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
This document is not UTF8. It was detected as Shift JIS and converted to UTF8 for display.
diff --git a/ChangeLog b/ChangeLog
index e0091e20..d33da812 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,419 +1,482 @@
+Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+
+ The big merge between this one and the stable branch 1.0. Still need
+ to merge TNANKS, AUTHORS and such. It probaly does not compile yet.
+
+ * acinclude.m4 (GNUPG_CHECK_MLOCK): Fixed syntax error in C code.
+
+ * configure.in: Add check for termio.h, wait unctiosn and sigaction.
+
+ * acinclude.m4, configure.in (GNUPG_CHECK_GNUMAKE): New.
+
+ * acinclude.m4 (MKDIR_TAKES_ONE_ARG): Check some headers. By Ga? Qu駻i.
+
+ * configure.in (AM_INIT_AUTOMAKE): Use this now. By Ga?.
+
+ * acinclude.m4 (GNUPG_CHECK_EXPORTDYNAMIC): Replacement for
+ GNUPG_CHECK_RDYNAMIC which should handle gcc with non GNU ld nicer.
+ Contributed by Dave Dykstra.
+ * configure.in (GNYPG_CHECK_RDYNAMIC): Replaced by the new check.
+
+ * configure.in: Add a test for unisgned long long.
+
+ * configure.in (DYNLINK_MOD_CFLAGS): Set different for NetBSD.
+
+ * configure.in: Add check for clock_gettime
+
+ * configure.in (ALL_LINGUAS): Add nl.
+ * configure.in (ALL_LINGUAS): Add Esperanto.
+ * configure.in (ALL_LINGUAS): Add sv and ja.
+
+ * configure.in: Use /usr/local for CFLAGS and LDFLAGS when
+ target is freebsd. By R駑i.
+
+ * configure.in: Do not set development version when the version has
+ a dash in it. Suggested by Dave Dykstra.
+
+ * configure.in: Removed substitution for doc/gph/Makefile.
+ Do all the gcc warning only in maintainer mode.
+
+ * configure.in (dlopen): Use CHECK_FUNC for a test of dlopen in libc.
+ Suggested by Alexandre Oliva.
+ (-Wall): Moved the settting of gcc warning options near to the end
+ so that tests don't get confused. Suggested by Paul D. Smith.
+
+ * acinclude.m4 (GNUPG_SYS_NM_PARSE): Added BSDI support.
+ (GNUPG_CHECK_RDYNAMIC): Ditto.
+
+ * acinclude.m4 (GNUPG_CHECK_MLOCK): Changed the way to test for
+ librt. Test suggested by Jeff Long.
+
+ * acinclude.m4 (GNUPG_CHECK_MLOCK): Do librt check only when
+ we can't link a test program. This way GNU systems don't need
+ to link against linrt.
+ (GNUPG_CHECK_IPC): Fixed use of TRY_COMPILE macro. From Tim Mooney.
+
+ * acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add support for
+ DJGPP.
+ (GNUPG_CHECK_MLOCK): Check whether mlock sits in librt.
+
+ * acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Add NetBSD. By Thomas Klausner.
+
+ * acconfig.h (HAVE_MLOCK): Added
+
Mon Mar 13 19:22:46 CET 2000 Werner Koch <wk@openit.de>
- * configure.in: Now uses the Docbook M$s from GPH.
+ * configure.in: Now uses the Docbook M4s from GPH.
Mon Jan 31 17:46:35 CET 2000 Werner Koch <wk@>
* Makefile.am: Re-added tools. By R駑i.
Mon Jan 31 16:37:34 CET 2000 Werner Koch <wk@gnupg.de>
* configure.in: Create a symlink for types.h in gcrypt/.
Thu Jan 27 18:00:44 CET 2000 Werner Koch <wk@gnupg.de>
* configure.in (g10defs.h): Replaced by gnupg-defs.h
Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
* jnlib/ : New.
* configure.in: Do set development version when the version has
a dash in it. Suggested by Dave Dykstra.
Thu Dec 9 17:22:27 CET 1999 Werner Koch <wk@gnupg.de>
* acinclude.m4 (GNUPG_FIX_HDR_VERSION): New.
* configure.in: Check and fix the version number of gcrypt/gcrypt.h
so that it is always the save as VERSION.
Thu Oct 28 16:17:46 CEST 1999 Werner Koch <wk@gnupg.de>
* Started with development series 1.1 on 1999-10-26
Tue Oct 26 14:10:21 CEST 1999 Werner Koch <wk@gnupg.de>
* README-alpha: New
* configure.in: Fixed quoting in test for development version.
* THANKS: Add entries for Michael, Brenno and J Horacio who did
very nice Howto documents - I apoligize for forgetting to mention them
earlier.
Fri Sep 17 12:56:42 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Add "-lcap" when capabilities are requested.
Add the conditional CROSS_COMPILING.
* Makefile.am: Don't use checks when CROSS_COMPILING.
Wed Sep 15 16:22:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (ALL_LINGUAS): Add pt_PT.
* configure.in: Some tweaks for cross compiling under MingW32
* acconfig.h (USE_STATIC_RNDW32): New.
Tue Sep 7 17:08:10 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Set to 1.0.0.
Mon Sep 6 19:59:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Create makefile in doc/gph
* acinclude.m4 (GNUPG_FUNC_MKDIR_TAKES_ONE_ARG): New
* configure.in: use the above.
Thu Sep 2 16:40:55 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Set to 0.9.11.
Tue Aug 31 17:20:44 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Minor changes to the OS/2 and Mingw32 system labels.
Add a printable name for Hurd.
Mon Aug 30 20:38:33 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Some support for DJGPP (Mark Elbrecht)
Wed Aug 4 10:34:46 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Set to 0.9.10.
Mon Jul 26 09:34:46 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): remove init of ac_cv_...
* Makefile.am (DISCLEANFILES): New
Fri Jul 23 13:53:03 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Set to 0.9.9.
* configure.in: Print a notice when rndunix is used.
Thu Jul 15 10:15:35 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Fixed last modification.
Wed Jul 7 13:08:40 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* Makefile.am: Support for libtool.
* configure.in: Ditto.
Tue Jun 29 21:44:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (use_local_zlib): The lost dollar is back.
* acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): Add EMX case.
* configure.in: Another variant of the MX vendor string
* configure.in (--with-capabilities): Some test code (Remi).
Sat Jun 26 12:15:59 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Support for HPUX and IRIX.
* configure.in (HAVE_DL_SHL_LOAD): New for HPUX (Dave Dykstra).
* VERSION: Now 0.9.8
Wed Jun 16 20:16:21 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Add test for docbook-to-man
Tue Jun 15 12:21:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_SYS_NM_PARSE): Support for {net,free}bsd,
Thu Jun 10 14:18:23 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (ZLIB,GDBM): Check both, header and lib.
Sat Jun 5 15:30:33 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* pkclist.c (key_present_in_pk_list): New (Michael).
Tue May 25 19:50:32 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (IS_DEVELOPMENT_VERSION): Fixed detection.
Sun May 23 14:20:22 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_SYS_SYMBOL_UNDERSCORE): assume yes when
cross-compiling.
Mon May 17 21:54:43 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (socket): Fix for Unisys by Katsuhiro Kondou.
Sat May 8 19:28:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* NEWS: Add a marker line which I forgot to do for 0.9.6.
Thu May 6 14:18:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* README: Minor updates
* VERSION: Now 0.9.6
Thu Apr 8 09:35:53 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for
amiga-openbsd (Peter Reich)
(GNUPG_PROG_NM): Ditto
Wed Apr 7 20:51:39 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* Makefile.am (g10defs.h): Removed.
* configure.in (AC_OUTPUT_COMMANDS): Create g10defs.h
Sat Mar 20 12:55:33 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Now 0.9.5
Sun Mar 14 19:34:36 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (AM_SYS_SYMBOL_UNDERSCORE): Removed because it is
now in the latest libtool.
Thu Mar 11 16:39:46 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Removed the need for libtool
Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (DLSYM_NEEDS_UNDERSCORE): Replaced.
* acinclude.in (AM_SYS_SYMBOL_UNDERSCORE): New.
* VERSION: Now 0.9.4
Sun Feb 28 19:11:00 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (dld): Test disabled.
Fri Feb 26 17:55:41 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* encode.c (encode_simple): temporary fix.
Wed Feb 24 11:07:27 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: New option --enable-static-rnd.
Mon Feb 22 20:04:00 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* BUGS: Now we assign bug numbers.
* OBUGS: New to keep rack o fixed bugs (CVS only)
Fri Feb 19 18:01:54 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Released 0.9.3
Fri Feb 19 15:49:15 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4: Removed gettext macros.
Tue Feb 16 14:10:02 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in (socket): Check for -lsocket and -lnsl.
(osf4): Disable all warnings for DEC's cc.
(-Wall): Add more warning options for gcc
Sat Feb 13 12:04:43 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Changed detection of compiler flags.
* intl/ : Removed directory
Wed Feb 10 17:15:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_CHECK_RDYNAMIC): Fix for freebsd 2.2
* configure.in: a lot of changes to allow selection of modules.
Add support for OS/2.
* acinclude.m4: add some more caching
* README: Spelling and grammar corrections (John A. Martin)
* INSTALL: Ditto.
Wed Jan 20 21:40:21 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: --enable-m-guard is now default
Wed Jan 13 12:49:36 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* INSTALL: Applied new information how to build rpms by Fabio Coatti
* Makefile.in (gnupg.spec): Changed the names.
Tue Jan 12 11:17:18 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* config.links (m68k-atari-mint): New
Tue Jan 12 09:17:19 CET 1999 Ga? Qu駻i <gqueri@mail.dotcom.fr>
* all: Fixed typos all over the place
Sat Jan 9 16:02:23 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Add a way to statically link rndunix
Sun Jan 3 15:28:44 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m4 (GNUPG_CHECK_RDYNAMIC): New.
* configure.in (DYNLOAD_CFLAGS): Use result from CHECK_RDYNAMIC
Wed Dec 23 13:18:14 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* README: Replaced the command overview with a short intro.
Sat Dec 12 18:40:32 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* configure.in: Add check for dlopen in libc (Greg Troxel)
and a new define
* acconfig.h (DLSYM_NEEDS_UNDERSCORE): New.
Thu Dec 10 20:15:36 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* acinclude.m (GNUPG_CHECK_PIC): New
* configure.in, acinclude.m4: Renamed all WK_ to GNUPG_
Tue Dec 8 15:09:29 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* VERSION: Set to 0.4.5
Wed Nov 25 12:38:29 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (USE_RNDLINUX): New.
Fri Nov 20 19:34:57 1998 Werner Koch (wk@isil.d.shuttle.de)
* VERSION: Released 0.4.4
* configure.in (try_asm_modules): For option --disable-asm
Tue Nov 10 19:32:40 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (MPI_SFLAGS): New.
Tue Nov 10 13:44:53 1998 Werner Koch (wk@isil.d.shuttle.de)
* ABOUT-NLS: New
* configure.in (AC_REVISION): New.
Sun Nov 8 18:20:35 1998 Werner Koch (wk@isil.d.shuttle.de)
* VERSION: Set to 0.4.3
Sun Oct 25 19:49:37 1998 Werner Koch (wk@isil.d.shuttle.de)
* Makefile.am (g10defs.h): New macro GNUPG_DATADIR.
Wed Oct 21 17:24:24 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in: Removed gettext kludge
* acinclude.m4: Add patched AM_WITH_NKS macro
Tue Oct 20 19:03:36 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in: Kludge to make AM_GNU_GETTEXT work,
changed some macors to more modern versions. Also
changeg the all makefiles to remove duplicate ../intl.
* acinclude.m4: Removed the gettext stuff, as this
already comes with automake now.
Wed Oct 14 12:11:34 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (NAME_OF_DEV_RANDOM): New.
(DYNLINK_MOD_CFLAGS): New.
Thu Oct 8 10:55:15 1998 Werner Koch (wk@isil.d.shuttle.de)
* Makefile.am (g10defs.h): creates include file
* acconfig.h: now includes g10defs.h
* configure.in: Removed G10_LOCALEDIR and GNUPG_LIB
Thu Sep 17 18:49:40 1998 Werner Koch (wk@(none))
* Makefile.am (dist-hook): Now creates RPM file.
* scripts/gnupg.spec: New template file for RPMs
Thu Jul 30 19:17:07 1998 Werner Koch (wk@(none))
* acinclude.h (WK_CHECK_IPC): New
* configure.in : Add checks for SysV IPC
Thu Jun 25 11:18:49 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (--disable-dynload): New.
Wed Jun 10 07:48:59 1998 Werner Koch,mobil,,, (wk@tobold)
* configure.in (GNUPG_LIBDIR): New.
Mon May 25 19:10:59 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-unix.c (fast_random_poll): fixed syntax bug.
Mon May 11 10:21:31 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (PRINTABLE_OS_NAME): Linux is now GNU/Linux
Tue Apr 14 19:08:05 1998 Werner Koch (wk@isil.d.shuttle.de)
* [all files]: Applied Matthew Skala's typo and grammar fixes.
Wed Mar 4 10:32:40 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (getrusage,gettimeofday): New tests.
Fri Feb 27 13:14:17 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (--disable-m-guard): New.
Thu Feb 26 17:09:27 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in, acinclude.m4, intl/, po/: New macros taken
from GNOME, switched to automake 1.2f
Thu Feb 26 09:05:46 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (doc/Makefile): New
Thu Feb 26 07:40:47 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in: Changed gettext stuff
Wed Feb 25 11:44:10 1998 Werner Koch (wk@isil.d.shuttle.de)
* checks/*test : restructured the directory.
Tue Feb 24 15:59:12 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in: Changed the name of the package to GNUPG and
chnaged several other names too.
Wed Feb 18 17:36:45 1998 Werner Koch (wk@isil.d.shuttle.de)
* Makefile.am (checks): New.
Sat Feb 14 15:37:55 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (mpi_config_done): Removed asm links caching.
Sat Feb 14 14:02:20 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in (PRINTABLE_OS_NAME): New.
* acconfig.h: Likewise.
Fri Feb 13 19:43:41 1998 Werner Koch (wk@isil.d.shuttle.de)
* configure.in : Fixed zlib stuff
* Makefile.am: Likewise
diff --git a/acconfig.h b/acconfig.h
index d364c7b7..a2c91283 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -1,112 +1,114 @@
/* acconfig.h - used by autoheader to make config.h.in
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GNUPG.
*
* GNUPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GNUPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef GNUPG_CONFIG_H
#define GNUPG_CONFIG_H
/* need this, because some autoconf tests rely on this (e.g. stpcpy)
* and it should be used for new programs
*/
#define _GNU_SOURCE 1
@TOP@
#undef M_DEBUG
#undef M_GUARD
#undef VERSION
#undef PACKAGE
#undef PRINTABLE_OS_NAME
#undef IS_DEVELOPMENT_VERSION
/* Define if your locale.h file contains LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
/* Define to 1 if NLS is requested. */
#undef ENABLE_NLS
/* Define as 1 if you have catgets and don't want to use GNU gettext. */
#undef HAVE_CATGETS
/* Define as 1 if you have gettext and don't want to use GNU gettext. */
#undef HAVE_GETTEXT
/* libintl.h is available; this is obsolete because if we don't have
* this header we use a symlink to the one in intl/ */
#undef HAVE_LIBINTL_H
#undef HAVE_STPCPY
+#undef HAVE_MLOCK
+
#undef BIG_ENDIAN_HOST
#undef LITTLE_ENDIAN_HOST
#undef HAVE_BYTE_TYPEDEF
#undef HAVE_USHORT_TYPEDEF
#undef HAVE_ULONG_TYPEDEF
#undef HAVE_U16_TYPEDEF
#undef HAVE_U32_TYPEDEF
#undef HAVE_BROKEN_MLOCK
/* defined if we have a /dev/random and /dev/urandom */
#undef HAVE_DEV_RANDOM
/* and the real names of the random devices */
#undef NAME_OF_DEV_RANDOM
#undef NAME_OF_DEV_URANDOM
/* Linux has an ioctl */
#undef HAVE_DEV_RANDOM_IOCTL
#undef USE_DYNAMIC_LINKING
#undef HAVE_DL_DLOPEN
#undef HAVE_DL_SHL_LOAD
#undef HAVE_DLD_DLD_LINK
#undef USE_SHM_COPROCESSING
#undef IPC_HAVE_SHM_LOCK
#undef IPC_RMID_DEFERRED_RELEASE
/* set this to limit filenames to the 8.3 format */
#undef USE_ONLY_8DOT3
/* defined if we must run on a stupid file system */
#undef HAVE_DRIVE_LETTERS
/* defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2)
* with special properties like no file modes */
#undef HAVE_DOSISH_SYSTEM
/* because the Unix gettext has to much overhead on MingW32 systems
* and these systems lack Posix functions, we use a simplified version
* of gettext */
#undef USE_SIMPLE_GETTEXT
/* At some point in the system we need to know that we use the Windows
* random module. */
#undef USE_STATIC_RNDW32
#undef USE_CAPABILITIES
/* Some systems have mkdir that takes a single argument. */
#undef MKDIR_TAKES_ONE_ARG
@BOTTOM@
#include "gnupg-defs.h"
#endif /*GNUPG_CONFIG_H*/
diff --git a/acinclude.m4 b/acinclude.m4
index 20c92be5..9f8bfd01 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -1,778 +1,833 @@
dnl macros to configure g10
dnl GNUPG_MSG_PRINT(STRING)
dnl print a message
dnl
define(GNUPG_MSG_PRINT,
[ echo $ac_n "$1"" $ac_c" 1>&AC_FD_MSG
])
dnl GNUPG_CHECK_TYPEDEF(TYPE, HAVE_NAME)
dnl Check whether a typedef exists and create a #define $2 if it exists
dnl
AC_DEFUN(GNUPG_CHECK_TYPEDEF,
[ AC_MSG_CHECKING(for $1 typedef)
AC_CACHE_VAL(gnupg_cv_typedef_$1,
[AC_TRY_COMPILE([#include <stdlib.h>
#include <sys/types.h>], [
#undef $1
int a = sizeof($1);
], gnupg_cv_typedef_$1=yes, gnupg_cv_typedef_$1=no )])
AC_MSG_RESULT($gnupg_cv_typedef_$1)
if test "$gnupg_cv_typedef_$1" = yes; then
AC_DEFINE($2)
fi
])
dnl GNUPG_FIX_HDR_VERSION(FILE, NAME)
dnl Make the version number in gcrypt/gcrypt.h the same as the one here.
dnl (this is easier than to have a .in file just for one substitution)
dnl
AC_DEFUN(GNUPG_FIX_HDR_VERSION,
[ sed "s/^#define $2 \".*/#define $2 \"$VERSION\"/" $1 > $1.tmp
if cmp -s $1 $1.tmp 2>/dev/null; then
rm -f $1.tmp
else
rm -f $1
if mv $1.tmp $1 ; then
:
else
AC_MSG_ERROR([[
*** Failed to fix the version string macro $2 in $1.
*** The old file has been saved as $1.tmp
]])
fi
AC_MSG_WARN([fixed the $2 macro in $1])
fi
])
+dnl GNUPG_CHECK_GNUMAKE
+dnl
+AC_DEFUN(GNUPG_CHECK_GNUMAKE,
+ [
+ if ${MAKE-make} --version 2>/dev/null | grep '^GNU ' >/dev/null 2>&1; then
+ :
+ else
+ AC_MSG_WARN([[
+***
+*** It seems that you are not using GNU make. Some make tools have serious
+*** flaws and you may not be able to build this software at all. Before you
+*** complain, please try GNU make: GNU make is easy to build and available
+*** at all GNU archives. It is always available from ftp.gnu.org:/gnu/make.
+***]])
+ fi
+ ])
+
+
+
dnl GNUPG_LINK_FILES( SRC, DEST )
dnl same as AC_LINK_FILES, but collect the files to link in
dnl some special variables and do the link
dnl when GNUPG_DO_LINK_FILES is called
dnl This is a workaround for AC_LINK_FILES, because it does not work
dnl correct when using a caching scheme
dnl
define(GNUPG_LINK_FILES,
[ if test "x$wk_link_files_src" = "x"; then
wk_link_files_src="$1"
wk_link_files_dst="$2"
else
wk_link_files_src="$wk_link_files_src $1"
wk_link_files_dst="$wk_link_files_dst $2"
fi
])
define(GNUPG_DO_LINK_FILES,
[ AC_LINK_FILES( $wk_link_files_src, $wk_link_files_dst )
])
dnl GNUPG_CHECK_ENDIAN
dnl define either LITTLE_ENDIAN_HOST or BIG_ENDIAN_HOST
dnl
define(GNUPG_CHECK_ENDIAN,
[ if test "$cross_compiling" = yes; then
AC_MSG_WARN(cross compiling; assuming little endianess)
fi
AC_MSG_CHECKING(endianess)
AC_CACHE_VAL(gnupg_cv_c_endian,
[ gnupg_cv_c_endian=unknown
# See if sys/param.h defines the BYTE_ORDER macro.
AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/param.h>], [
#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
bogus endian macros
#endif], [# It does; now see whether it defined to BIG_ENDIAN or not.
AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/param.h>], [
#if BYTE_ORDER != BIG_ENDIAN
not big endian
#endif], gnupg_cv_c_endian=big, gnupg_cv_c_endian=little)])
if test "$gnupg_cv_c_endian" = unknown; then
AC_TRY_RUN([main () {
/* Are we little or big endian? From Harbison&Steele. */
union
{
long l;
char c[sizeof (long)];
} u;
u.l = 1;
exit (u.c[sizeof (long) - 1] == 1);
}],
gnupg_cv_c_endian=little,
gnupg_cv_c_endian=big,
gnupg_cv_c_endian=little
)
fi
])
AC_MSG_RESULT([$gnupg_cv_c_endian])
if test "$gnupg_cv_c_endian" = little; then
AC_DEFINE(LITTLE_ENDIAN_HOST)
else
AC_DEFINE(BIG_ENDIAN_HOST)
fi
])
dnl GNUPG_CHECK_CACHE
dnl
define(GNUPG_CHECK_CACHE,
[ AC_MSG_CHECKING(cached information)
gnupg_hostcheck="$target"
AC_CACHE_VAL(gnupg_cv_hostcheck, [ gnupg_cv_hostcheck="$gnupg_hostcheck" ])
if test "$gnupg_cv_hostcheck" != "$gnupg_hostcheck"; then
AC_MSG_RESULT(changed)
AC_MSG_WARN(config.cache exists!)
AC_MSG_ERROR(you must do 'make distclean' first to compile for
different target or different parameters.)
else
AC_MSG_RESULT(ok)
fi
])
######################################################################
# Check for -fPIC etc (taken from libtool)
# This sets CFLAGS_PIC to the required flags
# NO_PIC to yes if it is not possible to
# generate PIC
######################################################################
dnl GNUPG_CHECK_PIC
dnl
define(GNUPG_CHECK_PIC,
[ AC_MSG_CHECKING(for option to create PIC)
CFLAGS_PIC=
NO_PIC=no
if test "$cross_compiling" = yes; then
AC_MSG_RESULT(assume none)
else
if test "$GCC" = yes; then
CFLAGS_PIC="-fPIC"
else
case "$host_os" in
aix3* | aix4*)
# All rs/6000 code is PIC
# but is there any non-rs/6000 AIX platform?
;;
hpux9* | hpux10*)
CFLAGS_PIC="+Z"
;;
irix5* | irix6*)
# PIC (with -KPIC) is the default.
;;
osf3* | osf4*)
# FIXME - pic_flag is probably required for
# hppa*-osf* and i860-osf*
;;
sco3.2v5*)
CFLAGS_PIC='-Kpic'
;;
solaris2* | solaris7* )
CFLAGS_PIC='-KPIC'
;;
sunos4*)
CFLAGS_PIC='-PIC'
;;
*)
NO_PIC=yes
;;
esac
fi
case "$host_cpu" in
rs6000 | powerpc | powerpcle)
# Yippee! All RS/6000 and PowerPC code is position-independent.
CFLAGS_PIC=""
;;
esac
if test "$NO_PIC" = yes; then
AC_MSG_RESULT(not possible)
else
if test -z "$CFLAGS_PIC"; then
AC_MSG_RESULT(none)
else
AC_MSG_RESULT($CFLAGS_PIC)
fi
fi
fi
])
######################################################################
-# Check for rdynamic flag
-# This sets CFLAGS_RDYNAMIC to the required flags
+# Check for export-dynamic flag
+# This sets CFLAGS_EXPORTDYNAMIC to the required flags
######################################################################
-dnl GNUPG_CHECK_RDYNAMIC
+dnl GNUPG_CHECK_EXPORTDYNAMIC
dnl
-define(GNUPG_CHECK_RDYNAMIC,
- [ AC_MSG_CHECKING(how to specify -rdynamic)
- CFLAGS_RDYNAMIC=
+define(GNUPG_CHECK_EXPORTDYNAMIC,
+ [ AC_MSG_CHECKING(how to specify -export-dynamic)
if test "$cross_compiling" = yes; then
- AC_MSG_RESULT(assume none)
+ AC_MSG_RESULT(assume none)
+ CFLAGS_EXPORTDYNAMIC=""
else
- case "$host_os" in
- solaris* )
- CFLAGS_RDYNAMIC="-Wl,-dy"
- ;;
-
- hpux* )
- CFLAGS_RDYNAMIC="-Wl,-E"
- ;;
-
- openbsd* | freebsd2* | osf4* | irix* )
- CFLAGS_RDYNAMIC=""
- ;;
-
- * )
- CFLAGS_RDYNAMIC="-Wl,-export-dynamic"
- ;;
- esac
- AC_MSG_RESULT($CFLAGS_RDYNAMIC)
+ AC_CACHE_VAL(gnupg_cv_export_dynamic,[
+ if AC_TRY_COMMAND([${CC-cc} $CFLAGS -Wl,--version 2>&1 |
+ grep "GNU ld" >/dev/null]); then
+ # using gnu's linker
+ gnupg_cv_export_dynamic="-Wl,-export-dynamic"
+ else
+ case "$host_os" in
+ hpux* )
+ gnupg_cv_export_dynamic="-Wl,-E"
+ ;;
+ * )
+ gnupg_cv_export_dynamic=""
+ ;;
+ esac
+ fi
+ ])
+ AC_MSG_RESULT($gnupg_cv_export_dynamic)
+ CFLAGS_EXPORTDYNAMIC="$gnupg_cv_export_dynamic"
fi
])
-
#####################################################################
# Check for SysV IPC (from GIMP)
# And see whether we have a SHM_LOCK (FreeBSD does not have it).
#####################################################################
dnl GNUPG_CHECK_IPC
dnl
define(GNUPG_CHECK_IPC,
[ AC_CHECK_HEADERS(sys/ipc.h sys/shm.h)
if test "$ac_cv_header_sys_shm_h" = "yes"; then
AC_MSG_CHECKING(whether IPC_RMID allowes subsequent attaches)
AC_CACHE_VAL(gnupg_cv_ipc_rmid_deferred_release,
AC_TRY_RUN([
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int id;
char *shmaddr;
id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0777);
if (id == -1)
exit (2);
shmaddr = shmat (id, 0, 0);
shmctl (id, IPC_RMID, 0);
if ((char*) shmat (id, 0, 0) == (char*) -1)
{
shmdt (shmaddr);
exit (1);
}
shmdt (shmaddr);
shmdt (shmaddr);
exit (0);
}
],
gnupg_cv_ipc_rmid_deferred_release="yes",
gnupg_cv_ipc_rmid_deferred_release="no",
gnupg_cv_ipc_rmid_deferred_release="assume-no")
)
if test "$gnupg_cv_ipc_rmid_deferred_release" = "yes"; then
AC_DEFINE(IPC_RMID_DEFERRED_RELEASE)
AC_MSG_RESULT(yes)
else
if test "$gnupg_cv_ipc_rmid_deferred_release" = "no"; then
AC_MSG_RESULT(no)
else
AC_MSG_RESULT([assuming no])
fi
fi
AC_MSG_CHECKING(whether SHM_LOCK is available)
AC_CACHE_VAL(gnupg_cv_ipc_have_shm_lock,
AC_TRY_COMPILE([#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>],[
- int foo( int shm_id ) { shmctl(shm_id, SHM_LOCK, 0); }
+ int shm_id;
+ shmctl(shm_id, SHM_LOCK, 0);
],
gnupg_cv_ipc_have_shm_lock="yes",
gnupg_cv_ipc_have_shm_lock="no"
)
)
if test "$gnupg_cv_ipc_have_shm_lock" = "yes"; then
AC_DEFINE(IPC_HAVE_SHM_LOCK)
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
fi
])
######################################################################
# Check whether mlock is broken (hpux 10.20 raises a SIGBUS if mlock
# is not called from uid 0 (not tested whether uid 0 works)
+# For DECs Tru64 we have also to check whether mlock is in librt
+# mlock is there a macro using memlk()
######################################################################
dnl GNUPG_CHECK_MLOCK
dnl
define(GNUPG_CHECK_MLOCK,
[ AC_CHECK_FUNCS(mlock)
+ if test "$ac_cv_func_mlock" = "no"; then
+ AC_CHECK_HEADERS(sys/mman.h)
+ if test "$ac_cv_header_sys_mman_h" = "yes"; then
+ # Add librt to LIBS:
+ AC_CHECK_LIB(rt, memlk)
+ AC_CACHE_CHECK([whether mlock is in sys/mman.h],
+ gnupg_cv_mlock_is_in_sys_mman,
+ [AC_TRY_LINK([
+ #include <assert.h>
+ #ifdef HAVE_SYS_MMAN_H
+ #include <sys/mman.h>
+ #endif
+ ], [
+ int i;
+ mkdir ("foo", 0);
+ /* glibc defines this for functions which it implements
+ * to always fail with ENOSYS. Some functions are actually
+ * named something starting with __ and the normal name
+ * is an alias. */
+ #if defined (__stub_mlock) || defined (__stub___mlock)
+ choke me
+ #else
+ mlock(&i, 4);
+ #endif
+ ; return 0;
+ ],
+ gnupg_cv_mlock_is_in_sys_mman=yes,
+ gnupg_cv_mlock_is_in_sys_mman=no)])
+ if test "$gnupg_cv_mlock_is_in_sys_mman" = "yes"; then
+ AC_DEFINE(HAVE_MLOCK)
+ fi
+ fi
+ fi
if test "$ac_cv_func_mlock" = "yes"; then
AC_MSG_CHECKING(whether mlock is broken)
AC_CACHE_VAL(gnupg_cv_have_broken_mlock,
AC_TRY_RUN([
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
char *pool;
int err;
long int pgsize = getpagesize();
pool = malloc( 4096 + pgsize );
if( !pool )
return 2;
pool += (pgsize - ((long int)pool % pgsize));
err = mlock( pool, 4096 );
if( !err || errno == EPERM )
return 0; /* okay */
return 1; /* hmmm */
}
],
gnupg_cv_have_broken_mlock="no",
gnupg_cv_have_broken_mlock="yes",
gnupg_cv_have_broken_mlock="assume-no"
)
)
if test "$gnupg_cv_have_broken_mlock" = "yes"; then
AC_DEFINE(HAVE_BROKEN_MLOCK)
AC_MSG_RESULT(yes)
else
if test "$gnupg_cv_have_broken_mlock" = "no"; then
AC_MSG_RESULT(no)
else
AC_MSG_RESULT(assuming no)
fi
fi
fi
])
-################################################################
+################################################################
# GNUPG_PROG_NM - find the path to a BSD-compatible name lister
+################################################################
AC_DEFUN(GNUPG_PROG_NM,
[AC_MSG_CHECKING([for BSD-compatible nm])
AC_CACHE_VAL(ac_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
ac_cv_path_NM="$NM"
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/nm; then
# Check to see if the nm accepts a BSD-compat flag.
# Adding the `sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -B"
elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -p"
else
ac_cv_path_NM="$ac_dir/nm"
fi
break
fi
done
IFS="$ac_save_ifs"
test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
fi])
NM="$ac_cv_path_NM"
AC_MSG_RESULT([$NM])
AC_SUBST(NM)
])
# GNUPG_SYS_NM_PARSE - Check for command ro grab the raw symbol name followed
# by C symbol name from nm.
AC_DEFUN(GNUPG_SYS_NM_PARSE,
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([GNUPG_PROG_NM])dnl
# Check for command to grab the raw symbol name followed by C symbol from nm.
AC_MSG_CHECKING([command to parse $NM output])
AC_CACHE_VAL(ac_cv_sys_global_symbol_pipe,
[# These are sane defaults that work on at least a few old systems.
# {They come from Ultrix. What could be older than Ultrix?!! ;)}
changequote(,)dnl
# Character class describing NM global symbol codes.
ac_symcode='[BCDEGRSTU]'
# Regexp to match symbols that can be accessed directly from C.
ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
# Transform the above into a raw symbol and a C symbol.
ac_symxfrm='\1 \1'
# Define system-specific variables.
case "$host_os" in
aix*)
ac_symcode='[BCDTU]'
;;
-freebsd* | netbsd* | openbsd* | sunos* | cygwin32* | mingw32*)
+freebsd* | netbsd* | openbsd* | bsdi* | sunos* | cygwin32* | mingw32*)
ac_sympat='_\([_A-Za-z][_A-Za-z0-9]*\)'
ac_symxfrm='_\1 \1'
;;
irix*)
# Cannot use undefined symbols on IRIX because inlined functions mess us up.
ac_symcode='[BCDEGRST]'
;;
solaris*)
ac_symcode='[BDTU]'
;;
esac
# If we're using GNU nm, then use its standard symbol codes.
if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
ac_symcode='[ABCDGISTUW]'
fi
case "$host_os" in
cygwin32* | mingw32*)
# We do not want undefined symbols on cygwin32. The user must
# arrange to define them via -l arguments.
ac_symcode='[ABCDGISTW]'
;;
esac
changequote([,])dnl
# Write the raw and C identifiers.
ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.* $ac_symcode $ac_sympat$/$ac_symxfrm/p'"
# Check to see that the pipe works correctly.
ac_pipe_works=no
cat > conftest.$ac_ext <<EOF
#ifdef __cplusplus
extern "C" {
#endif
char nm_test_var;
void nm_test_func(){}
#ifdef __cplusplus
}
#endif
int main(){nm_test_var='a';nm_test_func;return 0;}
EOF
if AC_TRY_EVAL(ac_compile); then
# Now try to grab the symbols.
ac_nlist=conftest.nm
if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
# Try sorting and uniquifying the output.
if sort "$ac_nlist" | uniq > "$ac_nlist"T; then
mv -f "$ac_nlist"T "$ac_nlist"
ac_wcout=`wc "$ac_nlist" 2>/dev/null`
changequote(,)dnl
ac_count=`echo "X$ac_wcout" | sed -e 's,^X,,' -e 's/^[ ]*\([0-9][0-9]*\).*$/\1/'`
changequote([,])dnl
(test "$ac_count" -ge 0) 2>/dev/null || ac_count=-1
else
rm -f "$ac_nlist"T
ac_count=-1
fi
# Make sure that we snagged all the symbols we need.
if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then
if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then
cat <<EOF > conftest.c
#ifdef __cplusplus
extern "C" {
#endif
EOF
# Now generate the symbol file.
sed 's/^.* \(.*\)$/extern char \1;/' < "$ac_nlist" >> conftest.c
cat <<EOF >> conftest.c
#if defined (__STDC__) && __STDC__
# define __ptr_t void *
#else
# define __ptr_t char *
#endif
/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */
int dld_preloaded_symbol_count = $ac_count;
/* The mapping between symbol names and symbols. */
struct {
char *name;
__ptr_t address;
}
changequote(,)dnl
dld_preloaded_symbols[] =
changequote([,])dnl
{
EOF
sed 's/^\(.*\) \(.*\)$/ {"\1", (__ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c
cat <<\EOF >> conftest.c
{0, (__ptr_t) 0}
};
#ifdef __cplusplus
}
#endif
EOF
# Now try linking the two files.
mv conftest.$ac_objext conftestm.$ac_objext
ac_save_LIBS="$LIBS"
ac_save_CFLAGS="$CFLAGS"
LIBS="conftestm.$ac_objext"
CFLAGS="$CFLAGS$no_builtin_flag"
if AC_TRY_EVAL(ac_link) && test -s conftest; then
ac_pipe_works=yes
else
echo "configure: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
LIBS="$ac_save_LIBS"
CFLAGS="$ac_save_CFLAGS"
else
echo "cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
fi
else
echo "cannot find nm_test_var in $ac_nlist" >&AC_FD_CC
fi
else
echo "cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
fi
else
echo "$progname: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
rm -rf conftest*
# Do not use the global_symbol_pipe unless it works.
test "$ac_pipe_works" = yes || ac_cv_sys_global_symbol_pipe=
])
ac_result=yes
if test -z "$ac_cv_sys_global_symbol_pipe"; then
ac_result=no
fi
AC_MSG_RESULT($ac_result)
])
# GNUPG_SYS_LIBTOOL_CYGWIN32 - find tools needed on cygwin32
AC_DEFUN(GNUPG_SYS_LIBTOOL_CYGWIN32,
[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(AS, as, false)
])
# GNUPG_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols
# with an underscore?
AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE,
[tmp_do_check="no"
case "${target}" in
- i386-emx-os2 | i[3456]86-pc-os2*emx )
+ i386-emx-os2 | i[3456]86-pc-os2*emx | i386-pc-msdosdjgpp)
ac_cv_sys_symbol_underscore=yes
;;
*)
if test "$cross_compiling" = yes; then
ac_cv_sys_symbol_underscore=yes
else
tmp_do_check="yes"
fi
;;
esac
if test "$tmp_do_check" = "yes"; then
AC_REQUIRE([GNUPG_PROG_NM])dnl
AC_REQUIRE([GNUPG_SYS_NM_PARSE])dnl
AC_MSG_CHECKING([for _ prefix in compiled symbols])
AC_CACHE_VAL(ac_cv_sys_symbol_underscore,
[ac_cv_sys_symbol_underscore=no
cat > conftest.$ac_ext <<EOF
void nm_test_func(){}
int main(){nm_test_func;return 0;}
EOF
if AC_TRY_EVAL(ac_compile); then
# Now try to grab the symbols.
ac_nlist=conftest.nm
if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
# See whether the symbols have a leading underscore.
if egrep '^_nm_test_func' "$ac_nlist" >/dev/null; then
ac_cv_sys_symbol_underscore=yes
else
if egrep '^nm_test_func ' "$ac_nlist" >/dev/null; then
:
else
echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
fi
fi
else
echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
fi
else
echo "configure: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
rm -rf conftest*
])
else
AC_MSG_CHECKING([for _ prefix in compiled symbols])
fi
AC_MSG_RESULT($ac_cv_sys_symbol_underscore)
if test x$ac_cv_sys_symbol_underscore = xyes; then
AC_DEFINE(WITH_SYMBOL_UNDERSCORE,1,
[define if compiled symbols have a leading underscore])
fi
])
dnl Stolen from gcc
dnl Define MKDIR_TAKES_ONE_ARG if mkdir accepts only one argument instead
dnl of the usual 2.
AC_DEFUN(GNUPG_FUNC_MKDIR_TAKES_ONE_ARG,
-[AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
+[AC_CHECK_HEADERS(sys/stat.h unistd.h direct.h)
+AC_CACHE_CHECK([if mkdir takes one argument], gnupg_cv_mkdir_takes_one_arg,
[AC_TRY_COMPILE([
#include <sys/types.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_DIRECT_H
# include <direct.h>
#endif], [mkdir ("foo", 0);],
gnupg_cv_mkdir_takes_one_arg=no, gnupg_cv_mkdir_takes_one_arg=yes)])
if test $gnupg_cv_mkdir_takes_one_arg = yes ; then
AC_DEFINE(MKDIR_TAKES_ONE_ARG)
fi
])
-
dnl GPH_PROG_DOCBOOK()
dnl Check whether we have the needed Docbook environment
dnl and issue a warning if this is not the case.
dnl
dnl This test defines these variables for substitution:
dnl DB2HTML - command used to convert Docbook to HTML
dnl DB2TEX - command used to convert Docbook to TeX
dnl DB2MAN - command used to convert Docbook to man pages
dnl JADE - command to invoke jade
dnl JADETEX - command to invoke jadetex
dnl DSL_FOR_HTML - the stylesheet used to for the Docbook->HTML conversion
dnl The following make conditionals are defined
dnl HAVE_DB2MAN - defined when db2man is available
dnl HAVE_DB2TEX - defined when db2tex is available
dnl HAVE_DB2HTML - defined when db2html is available
dnl HAVE_DOCBOOK - defined when the entire Docbook environment is present
dnl HAVE_JADE - defined when jade is installed
dnl HAVE_JADETEX - defined when jadetex is installed
dnl
dnl (wk 2000-02-17)
dnl
AC_DEFUN(GPH_PROG_DOCBOOK,
[ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
all=yes
AC_PATH_PROG(DB2MAN, docbook-to-man, no)
test "$DB2MAN" = no && all=no
AM_CONDITIONAL(HAVE_DB2MAN, test "$DB2MAN" != no )
AC_PATH_PROG(JADE, jade, no)
test "$JADE" = no && all=no
AM_CONDITIONAL(HAVE_JADE, test "$JADE" != no )
AC_PATH_PROG(JADETEX, jadetex, no)
test "$JADETEX" = no && all=no
AM_CONDITIONAL(HAVE_JADETEX, test "$JADETEX" != no )
stylesheet_dirs='
/usr/local/lib/dsssl/stylesheets/docbook
/usr/local/share/dsssl/stylesheets/docbook
/usr/local/lib/sgml/stylesheet/dsssl/docbook/nwalsh
/usr/local/share/sgml/stylesheet/dsssl/docbook/nwalsh
/usr/lib/dsssl/stylesheets/docbook
/usr/share/dsssl/stylesheets/docbook
/usr/lib/sgml/stylesheet/dsssl/docbook/nwalsh
/usr/share/sgml/stylesheet/dsssl/docbook/nwalsh
'
AC_MSG_CHECKING(for TeX stylesheet)
dsl=none
for d in ${stylesheet_dirs}; do
file=${d}/print/docbook.dsl
if test -f $file; then
dsl=$file
break
fi
done
AC_MSG_RESULT([$dsl])
okay=no
if test $dsl = none ; then
DB2TEX="$missing_dir/missing db2tex"
all=no
else
DB2TEX="$JADE -t tex -i tex -d $dsl"
okay=yes
fi
AC_SUBST(DB2TEX)
AM_CONDITIONAL(HAVE_DB2TEX, test $okay = yes )
if ( $ac_aux_dir/db2html.in --version) < /dev/null > /dev/null 2>&1; then
:
else
AC_ERROR([needed $ac_aux_dir/db2html.in not found])
fi
AC_MSG_CHECKING(for HTML stylesheet)
DSL_FOR_HTML="none"
for d in ${stylesheet_dirs}; do
file=${d}/html/docbook.dsl
if test -f $file; then
DSL_FOR_HTML=$file
break
fi
done
AC_MSG_RESULT([$DSL_FOR_HTML])
okay=no
if test $DSL_FOR_HTML = none ; then
DB2HTML="$missing_dir/missing db2html"
all=no
else
DB2HTML="`cd $ac_aux_dir && pwd`/db2html --copyfiles"
okay=yes
fi
AC_SUBST(DB2HTML)
AC_SUBST(DSL_FOR_HTML)
AM_CONDITIONAL(HAVE_DB2HTML, test $okay = yes )
AM_CONDITIONAL(HAVE_DOCBOOK, test "$all" != yes )
if test $all = no ; then
AC_MSG_WARN([[
***
*** It seems that the Docbook environment is not installed as required.
*** We will try to build everything, but if you either touch some files
*** or use a bogus make tool, you may run into problems.
*** Docbook is normally only needed to build the documentation.
***]])
fi
])
dnl *-*wedit:notab*-* Please keep this as the last line.
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 49595a93..877a2ad2 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,650 +1,732 @@
+Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+
+ * md.c (gcry_md_ctl): Support GCRYCTL_{START,STOP}_DUMP.
+
+ * Makefile.am: Never compile mingw32 as module.
+
+ * Makefile.am: Tweaked module build and removed libtool
+
+ * Makefile.am: Replaced -O1 by -O. Suggested by Alec Habig.
+
+ * elgamal.c (sign): Removed inactive code.
+
+ * rsa.c, rsa.h: New based on the old module version (only in CVS for now).
+ * pubkey.c (setup_pubkey_table): Added commented support for RSA.
+
+ * rndunix.c (waitpid): New. For UTS 2.1. All by Dave Dykstra.
+ (my_popen): Do the FD_CLOEXEC only if it is available
+ (start_gatherer): Cope with missing _SC_OPEN_MAX
+
+ * rndunix.c: Add some more headers for QNX. By Sam Roberts.
+
+ * rndegd.c (gather_random): Shortcut level 0.
+ * rndunix.c (gather_random): Ditto.
+ * rndw32.c (gather_random): Ditto.
+
+ * rndw32.c: Replaced with code from Cryptlib and commented the old stuff.
+ * rndw32.c: Add some debuging code enabled by an environment variable.
+
+ * random.c (read_seed_file): Binary open for DOSish system
+ (update_random_seed_file): Ditto.
+ * random.c [MINGW32]: Include process.h for getpid.
+ * random.c (fast_random_poll): Add clock_gettime() as fallback for
+ system which support this POSIX.4 fucntion. By Sam Roberts.
+
+ * random.c (read_seed_file): Removed the S_ISLNK test becuase it
+ is already covered by !S_ISREG and is not defined in Unixware.
+ Reported by Dave Dykstra.
+ (update_random_seed_file): Silently ignore update request when pool
+ is not filled.
+
+ * random.c (read_seed_file): New.
+ (set_random_seed_file): New.
+ (read_pool): Try to read the seeding file.
+ (update_random_seed_file): New.
+
+ (read_pool): Do an initial extra seeding when level 2 quality random
+ is requested the first time. This requestes at least POOLSIZE/2 bytes
+ of entropy. Compined with the seeding file this should make normal
+ random bytes cheaper and increase the quality of the random bytes
+ used for key generation.
+
+ * random.c (read_pool): Print a more friendly error message in
+ cases when too much random is requested in one call.
+
+ * random.c (fast_random_poll): Check whether RUSAGE_SELF is defined;
+ this is not the case for some ESIX and Unixware, although they have
+ getrusage().
+
+ * primegen.c (generate_elg_prime): All primes are now generated with
+ the lowest random quality level. Because they are public anyway we
+ don't need stronger random and by this we do not drain the systems
+ entropy so much.
+
+ * primegen.c (register_primegen_progress): New.
+ * dsa.c (register_pk_dsa_progress): New.
+ * elgamal.c (register_pk_elg_progress): New.
+
+ * elgamal.c (wiener_map): New.
+ (gen_k): Use a much smaller k.
+ (generate): Calculate the qbits using the wiener map and
+ choose an x at a size comparable to the one choosen in gen_k
+
+ * rmd160.c (rmd160_get_info): Moved casting to the left side due to a
+ problem with UTS4.3. Suggested by Dave Dykstra.
+ * sha1.c (sha1_get_info): Ditto.
+ * tiger.c (tiger_get_info): Ditto.
+ * md5.c (md5_get_info): Ditto
+ * des.c (des_get_info): Ditto.
+ * blowfish.c (blowfish_get_info): Ditto.
+ * cast5.c (cast5_get_info): Ditto.
+ * twofish.c (twofish_get_info): Ditto.
+
Fri Mar 24 11:25:45 CET 2000 Werner Koch <wk@openit.de>
* md.c (md_open): Add hmac arg and allocate space for the pads.
(md_finalize): Add HMAC support.
(md_copy): Ditto.
(md_close): Ditto.
(gcry_md_reset): Ditto.
(gcry_md_ctl): Ditto.
(prepare_macpdas): New.
Mon Mar 13 19:22:46 CET 2000 Werner Koch <wk@openit.de>
* md.c (gcry_md_hash_buffer): Add support for the other algorithms.
Mon Jan 31 16:37:34 CET 2000 Werner Koch <wk@gnupg.de>
* genprime.c (generate_elg_prime): Fixed returned factors which never
worked for non-DSA keys.
Thu Jan 27 18:00:44 CET 2000 Werner Koch <wk@gnupg.de>
* pubkey.c (sexp_to_key): Fixed mem leaks in case of errors.
Mon Jan 24 22:24:38 CET 2000 Werner Koch <wk@gnupg.de>
* pubkey.c (gcry_pk_decrypt): Implemented.
(gcry_pk_encrypt): Implemented.
(gcry_pk_testkey): New.
(gcry_pk_genkey): New.
(pubkey_decrypt): Made static.
(pubkey_encrypt): Ditto.
(pubkey_check_secret_key): Ditto.
(pubkey_generate): Ditto.
Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
* pubkey.c (pubkey_nbits): Removed and replaced by ...
(gcry_pk_get_nbits): this new one.
Wed Dec 8 21:58:32 CET 1999 Werner Koch <wk@gnupg.de>
* dsa.c: s/mpi_powm/gcry_mpi_powm/g
* elgamal.c: Ditto.
* primegen.c: Ditto.
* : Replaced g10_opt_verbose by g10_log_verbosity().
* Makefile.am (INCLUDES): removed intl, add ../gcrypt
Fri Nov 19 17:15:20 CET 1999 Werner Koch <wk@gnupg.de>
* dynload.c (cmp_filenames): New to replaced compare_filename() in
module.
(register_cipher_extension): Removed the tilde expansion stuff.
* rndeg.c (my_make_filename): New.
* : Replaced header util.h by g10lib.h
* random.c (gather_faked): Replaced make_timestamp by time(2).
Disabled wrning printed with tty_printf.
* rndlinux.c (gather_random): Always use fprintf instead of tty_xxx;
this should be replaced by a callback function.
* primegen.c (gen_prime): Use gcry_mpi_randomize.
(is_prime): Ditto.
* elgamal.c (test_keys): Ditto.
* dsa.c (test_keys): Ditto.
* cipher.c (gcry_cipher_close): Die on invalid handle.
Mon Nov 15 21:36:02 CET 1999 Werner Koch <wk@gnupg.de>
* elgamal.c (gen_k): Use the new random API.
(generate): Ditto.
* dsa.c (gen_k): Ditto.
(generate): Ditto.
Sat Nov 13 17:44:23 CET 1999 Werner Koch <wk@gnupg.de>
* pubkey.c (disable_pubkey_algo): Made static.
(gcry_pk_ctl): New.
* random.c (get_random_bits): Renamed to ...
(get_random_bytes): ... this and made static.
(gcry_random_bytes): New.
(gcry_random_bytes_secure): New.
(randomize_buffer): Renamed to ...
(gcry_randomize): ...this.
* md.c (gcry_md_hash_buffer): New.
* pubkey.c (gcry_pk_algo_info): 4 new commands.
(pubkey_get_npkey): Made static.
(pubkey_get_nskey): Made static.
(pubkey_get_nsig): Made static.
(pubkey_get_nenc): Made static.
* pubkey.c: Removed all G10ERR_xxx.
* cipher.c: Changed all GCRYERR_INV_ALGO to GCRYERR_INV_CIPHER_ALGO.
* md.c: Changed all GCRYERR_INV_ALGO to GCRYERR_INV_MD_ALGO.
* cast5.c (cast_setkey): Changed errocodes to GCRYERR_xxx.
* blowfish.c: Ditto.
* des.c: Ditto.
* twofish.c: Ditto.
* dsa.c: Ditto.
* elgamal.c: Ditto.
* g10c.c: Removed
* cipher.c (gcry_cipher_open): Replaced alloc functions and return NULL
if we are out of core.
* dynload.c: Replaced all memory allocation functions.
* md.c: Ditto.
* primegen.c: Ditto.
* pubkey.c: Ditto.
* random.c: Ditto.
* rndw32.c: Ditto.
* elgamal.c: Ditto.
* dsa.c: Ditto.
Tue Oct 26 14:10:21 CEST 1999 Werner Koch <wk@gnupg.de>
* elgamal.c (sign): Hugh found strange code here. Replaced by BUG().
* cipher.c: Merged with gcrypt/symapi.c.
* pubkey.c (string_to_pubkey_algo): Renamed function to ...
(gcry_pk_map_name): ... this.
(pubkey_algo_to_string): Renamed function to ...
(gcry_pk_algo_name): ... this.
(gcry_pk_algo_info): New.
* pubkey.c: Merged with gcrypt/pkapi.c.
* md.c (md_reset): Clear finalized; thanks to Ulf Moeller for
fixing this bug.
* md.c: Merged with gcrypt/mdapi.c
Wed Sep 15 14:39:59 CEST 1999 Michael Roth <mroth@nessie.de>
* des.c: Various speed improvements: One bit pre rotation
trick after initial permutation (Richard Outerbridge).
Finished test of SSLeay Tripple-DES patterns.
Wed Sep 15 16:22:17 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndw32.c: New.
Mon Sep 13 10:51:29 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* bithelp.h: New.
* rmd160.h, sha1.h, md5.h: Use the rol macro from bithelp.h
Tue Sep 7 16:23:36 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* Makefile.am: Fixed seds for latest egcc. By Ollivier Robert.
Mon Sep 6 19:59:08 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* des.c (selftest): Add some testpattern
Mon Aug 30 20:38:33 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* cipher.c (do_cbc_encrypt): Fixed serious bug occuring when not using
in place encryption. Pointed out by Frank Stajano.
Mon Jul 26 09:34:46 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* md5.c (md5_final): Fix for a SCO cpp bug.
Thu Jul 15 10:15:35 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* elgamal.c (elg_check_secret_key,elg_encrypt
elg_decrypt,elg_sign,elg_verify): Sanity check on the args.
* dsa.c (dsa_check_secret_key,dsa_sign,dsa_verify): Ditto.
* pubkey.c (disable_pubkey_algo): New.
(check_pubkey_algo2): Look at disabled algo table.
* cipher.c (disable_cipher_algo): New.
(check_cipher_algo): Look at disabled algo table.
Wed Jul 7 13:08:40 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* Makefile.am: Support for libtool.
Fri Jul 2 11:45:54 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* dsa.c (gen_k): Changed algorithm to consume less random bytes
* elgamal.c (gen_k): Ditto.
* random.c (random_dump_stats): New.
Thu Jul 1 12:47:31 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* primegen.c, elgamal.c, dsa.c (progess): New and replaced all
fputc with a call to this function.
Sat Jun 26 12:15:59 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndegd.c (do_write): s/ssize_t/int/ due to SunOS 4.1 probs.
* cipher.c (do_cbc_encrypt, do_cbc_decrypt): New.
* dynload.c (HAVE_DL_SHL_LOAD): Map hpux API to dlopen (Dave Dykstra).
* Makefile.am (install-exec-hook): Removed.
Sun May 23 14:20:22 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* cipher.c (setup_cipher_table): Enable Twofish
* random.c (fast_random_poll): Disable use of times() for mingw32.
Mon May 17 21:54:43 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* dynload.c (register_internal_cipher_extension): Minor init fix.
Tue May 4 15:47:53 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* primegen.c (gen_prime): Readded the Fermat test. Fixed the bug
that we didn't correct for step when passing the prime to the
Rabin-Miller test which led to bad performance (Stefan Keller).
(check_prime): Add a first Fermat test.
Sun Apr 18 10:11:28 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* cipher.c (cipher_setiv): Add ivlen arg, changed all callers.
* random.c (randomize_buffer): alway use secure memory because
we can't use m_is_secure() on a statically allocated buffer.
* twofish.c: Replaced some macros by a loop to reduce text size.
* Makefile.am (twofish): No more need for sed editing.
Fri Apr 9 12:26:25 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* cipher.c (cipher_open): Reversed the changes for AUTO_CFB.
* blowfish.c: Dropped the Blowfish 160 mode.
* cipher.c (cipher_open): Ditto.
(setup_cipher_table): Ditto. And removed support of twofish128
Wed Apr 7 20:51:39 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* random.c (get_random_bits): Can now handle requests > POOLSIZE
* cipher.c (cipher_open): Now uses standard CFB for automode if
the blocksize is gt 8 (according to rfc2440).
* twofish.c: Applied Matthew Skala's patches for 256 bit key.
Tue Apr 6 19:58:12 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* random.c (get_random_bits): Can now handle requests > POOLSIZE
* cipher.c (cipher_open): Now uses standard CFB for automode if
the blocksize is gt 8 (according to rfc2440).
Sat Mar 20 11:44:21 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndlinux.c (tty_printf) [IS_MODULE]: Removed.
* rndegd.c (gather_random): Some fixes.
Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndegd.c (do_read): New.
(gather_random): Changed the implementation.
Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* dynload.c (DLSYM_NEEDS_UNDERSCORE): Renamed.
Fri Feb 26 17:55:41 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* md.c: Nearly a total rewrote.
Wed Feb 24 11:07:27 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* cipher.c (context): Fixed alignment
* md.c: Ditto.
* rndegd.c: New
Mon Feb 22 20:04:00 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndegd.c: New.
Wed Feb 10 17:15:39 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* Makefile.am: Modules are now figured out by configure
* construct.c: New. Generated by configure. Changed all modules
to work with that.
* sha1.h: Removed.
* md5.h: Removed.
* twofish.c: Changed interface to allow Twofish/256
* rndunix.c (start_gatherer): Die on SIGPIPE.
Wed Jan 20 18:59:49 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndunix.c (gather_random): Fix to avoid infinite loop.
Sun Jan 17 11:04:33 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* des.c (is_weak_key): Replace system memcmp due to bugs
in SunOS's memcmp.
(des_get_info): Return error on failed selftest.
* twofish.c (twofish_setkey): Return error on failed selftest or
invalid keylength.
* cast5.c (cast_setkey): Ditto.
* blowfish.c (bf_setkey): Return error on failed selftest.
Tue Jan 12 11:17:18 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* random.c (random_is_faked): New.
* tiger.c: Only compile if we have the u64 type
Sat Jan 9 16:02:23 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndunix.c (gather_random): check for setuid.
* Makefile.am: Add a way to staically link random modules
Thu Jan 7 18:00:58 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* md.c (md_stop_debug): Do a flush first.
(md_open): size of buffer now depends on the secure parameter
Sun Jan 3 15:28:44 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndunix.c (start_gatherer): Fixed stupid ==/= bug
1998-12-31 Geoff Keating <geoffk@ozemail.com.au>
* des.c (is_weak_key): Rewrite loop end condition.
Tue Dec 29 14:41:47 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* random.c: add unistd.h for getpid().
(RAND_MAX): Fallback value for Sun.
Wed Dec 23 17:12:24 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* md.c (md_copy): Reset debug.
Mon Dec 14 21:18:49 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* random.c (read_random_source): Changed the interface to the
random gathering function.
(gather_faked): Use new interface.
* dynload.c (dynload_getfnc_fast_random_poll): Ditto.
(dynload_getfnc_gather_random): Ditto.
* rndlinux.c (gather_random): Ditto.
* rndunix.c (gather_random): Ditto.
Sat Dec 12 18:40:32 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* dynload.c (SYMBOL_VERSION): New to cope with system which needs
underscores.
* rndunix.c: Rewrote large parts
Thu Dec 10 20:15:36 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* dynload.c (load_extension): increased needed verbosity level.
* random.c (fast_random_poll): Fallback to a default fast random
poll function.
(read_random_source): Always use the faked entroy gatherer if no
gather module is available.
* rndlinux.c (fast_poll): Removed.
* rndunix.c (fast_poll): Removed.
Wed Nov 25 12:33:41 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-*.c: Removed.
* rndlinux.c : New.
* rndunix.c : New.
* random.c : Restructured the interface to the gather modules.
(intialize): Call constructor functions
(read_radnom_source): Moved to here.
* dynload.c (dynload_getfnc_gather_random): New.
(dynload_getfnc_fast_random_poll): New.
(register_internal_cipher_extension): New.
(register_cipher_extension): Support of internal modules.
Sun Nov 8 17:44:36 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-unix.c (read_random_source): Removed the assert.
Mon Oct 19 18:34:30 1998 me,,, (wk@tobold)
* pubkey.c: Hack to allow us to give some info about RSA keys back.
Thu Oct 15 11:47:57 1998 Werner Koch (wk@isil.d.shuttle.de)
* dynload.c: Support for DLD
Wed Oct 14 12:13:07 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-unix.c: Now uses names from configure for /dev/random.
1998-10-10 SL Baur <steve@altair.xemacs.org>
* Makefile.am: fix sed -O substitutions to catch -O6, etc.
Tue Oct 6 10:06:32 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-unix.c (HAVE_GETTIMEOFDAY): Fixed (was ..GETTIMEOFTIME :-)
* rand-dummy.c (HAVE_GETTIMEOFDAY): Ditto.
Mon Sep 28 13:23:09 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c (md_digest): New.
(md_reset): New.
Wed Sep 23 12:27:02 1998 Werner Koch (wk@isil.d.shuttle.de)
* tiger.c (TIGER_CONTEXT): moved "buf", so that it is 64 bit aligned.
Mon Sep 21 06:22:53 1998 Werner Koch (wk@(none))
* des.c: Some patches from Michael.
Thu Sep 17 19:00:06 1998 Werner Koch (wk@(none))
* des.c : New file from Michael Roth <mroth@nessie.de>
Mon Sep 14 11:10:55 1998 Werner Koch (wk@(none))
* blowfish.c (bf_setkey): Niklas Hernaeus patch to detect weak keys.
Mon Sep 14 09:19:25 1998 Werner Koch (wk@(none))
* dynload.c (RTLD_NOW): Now defined to 1 if it is undefined.
Mon Sep 7 17:04:33 1998 Werner Koch (wk@(none))
* Makefile.am: Fixes to allow a different build directory
Thu Aug 6 17:25:38 1998 Werner Koch,mobil,,, (wk@tobold)
* random.c (get_random_byte): Removed and changed all callers
to use get_random_bits()
Mon Jul 27 10:30:22 1998 Werner Koch (wk@(none))
* cipher.c : Support for other blocksizes
(cipher_get_blocksize): New.
* twofish.c: New.
* Makefile.am: Add twofish module.
Mon Jul 13 21:30:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (read_pool): Simple alloc if secure_alloc is not set.
(get_random_bits): Ditto.
Thu Jul 9 13:01:14 1998 Werner Koch (wk@isil.d.shuttle.de)
* dynload.c (load_extension): Function now nbails out if
the program is run setuid.
Wed Jul 8 18:58:23 1998 Werner Koch (wk@isil.d.shuttle.de)
* rmd160.c (rmd160_hash_buffer): New.
Thu Jul 2 10:50:30 1998 Werner Koch (wk@isil.d.shuttle.de)
* cipher.c (cipher_open): algos >=100 use standard CFB
Thu Jun 25 11:18:25 1998 Werner Koch (wk@isil.d.shuttle.de)
* Makefile.am: Support for extensions
Thu Jun 18 12:09:38 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (mix_pool): simpler handling for level 0
Mon Jun 15 14:40:48 1998 Werner Koch (wk@isil.d.shuttle.de)
* tiger.c: Removed from dist, will reappear as dynload module
Sat Jun 13 14:16:57 1998 Werner Koch (wk@isil.d.shuttle.de)
* pubkey.c: Major changes to allow extensions. Changed the inteface
of all public key ciphers and added the ability to load extensions
on demand.
* misc.c: Removed.
Wed Jun 10 07:52:08 1998 Werner Koch,mobil,,, (wk@tobold)
* dynload.c: New.
* cipher.c: Major changes to allow extensions.
Mon Jun 8 22:43:00 1998 Werner Koch (wk@isil.d.shuttle.de)
* cipher.c: Major internal chnages to support extensions.
* blowfish.c (blowfish_get_info): New and made all internal
functions static, changed heder.
* cast5.c (cast5_get_info): Likewise.
Mon Jun 8 12:27:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* tiger.c (transform): Fix for big endian
* cipher.c (do_cfb_decrypt): Big endian fix.
Fri May 22 07:30:39 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c (md_get_oid): Add a new one for TIGER.
Thu May 21 13:24:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* cipher.c: Add support for a dummy cipher
Thu May 14 15:40:36 1998 Werner Koch (wk@isil.d.shuttle.de)
* rmd160.c (transform): fixed sigbus - I should better
add Christian von Roques's new implemenation of rmd160_write.
Fri May 8 18:07:44 1998 Werner Koch (wk@isil.d.shuttle.de)
* rand-internal.h, rand-unix.c, rand-w32.c, rand_dummy.c: New
* random.c: Moved system specific functions to rand-****.c
Fri May 8 14:01:17 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (fast_random_poll): add call to gethrtime.
Tue May 5 21:28:55 1998 Werner Koch (wk@isil.d.shuttle.de)
* elgamal.c (elg_generate): choosing x was not correct, could
yield 6 bytes which are not from the random pool, tsss, tsss..
Tue May 5 14:09:06 1998 Werner Koch (wk@isil.d.shuttle.de)
* primegen.c (generate_elg_prime): Add arg mode, changed all
callers and implemented mode 1.
Mon Apr 27 14:41:58 1998 Werner Koch (wk@isil.d.shuttle.de)
* cipher.c (cipher_get_keylen): New.
Sun Apr 26 14:44:52 1998 Werner Koch (wk@isil.d.shuttle.de)
* tiger.c, tiger.h: New.
Wed Apr 8 14:57:11 1998 Werner Koch (wk@isil.d.shuttle.de)
* misc.c (check_pubkey_algo2): New.
Tue Apr 7 18:46:49 1998 Werner Koch (wk@isil.d.shuttle.de)
* cipher.c: New
* misc.c (check_cipher_algo): Moved to cipher.c
* cast5.c: Moved many functions to cipher.c
* blowfish.c: Likewise.
Sat Apr 4 19:52:08 1998 Werner Koch (wk@isil.d.shuttle.de)
* cast5.c: Implemented and tested.
Wed Apr 1 16:38:27 1998 Werner Koch (wk@isil.d.shuttle.de)
* elgamal.c (elg_generate): Faster generation of x in some cases.
Thu Mar 19 13:54:48 1998 Werner Koch (wk@isil.d.shuttle.de)
* blowfish.c (blowfish_decode_cfb): changed XOR operation
(blowfish_encode_cfb): Ditto.
Thu Mar 12 14:04:05 1998 Werner Koch (wk@isil.d.shuttle.de)
* sha1.c (transform): Rewrote
* blowfish.c (encrypt): Unrolled for rounds == 16
(decrypt): Ditto.
Tue Mar 10 16:32:08 1998 Werner Koch (wk@isil.d.shuttle.de)
* rmd160.c (transform): Unrolled the loop.
Tue Mar 10 13:05:14 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (read_pool): Add pool_balance stuff.
(get_random_bits): New.
* elgamal.c (elg_generate): Now uses get_random_bits to generate x.
Tue Mar 10 11:33:51 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c (md_digest_length): New.
Tue Mar 10 11:27:41 1998 Werner Koch (wk@isil.d.shuttle.de)
* dsa.c (dsa_verify): Works.
Mon Mar 9 12:59:08 1998 Werner Koch (wk@isil.d.shuttle.de)
* dsa.c, dsa.h: Removed some unused code.
Wed Mar 4 10:39:22 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c (md_open): Add call to fast_random_poll.
blowfish.c (blowfish_setkey): Ditto.
Tue Mar 3 13:32:54 1998 Werner Koch (wk@isil.d.shuttle.de)
* rmd160.c (rmd160_mixblock): New.
* random.c: Restructured to start with a new RNG implementation.
* random.h: New.
Mon Mar 2 19:21:46 1998 Werner Koch (wk@isil.d.shuttle.de)
* gost.c, gost.h: Removed because they did only conatin trash.
Sun Mar 1 16:42:29 1998 Werner Koch (wk@isil.d.shuttle.de)
* random.c (fill_buffer): removed error message if n == -1.
Fri Feb 27 16:39:34 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c (md_enable): No init if called twice.
Thu Feb 26 07:57:02 1998 Werner Koch (wk@isil.d.shuttle.de)
* primegen.c (generate_elg_prime): Changed the progress printing.
(gen_prime): Ditto.
Tue Feb 24 12:28:42 1998 Werner Koch (wk@isil.d.shuttle.de)
* md5.c, md.5 : Replaced by a modified version of md5.c from
GNU textutils 1.22.
Wed Feb 18 14:08:30 1998 Werner Koch (wk@isil.d.shuttle.de)
* md.c, md.h : New debugging support
Mon Feb 16 10:08:47 1998 Werner Koch (wk@isil.d.shuttle.de)
* misc.c (cipher_algo_to_string): New
(pubkey_algo_to_string): New.
(digest_algo_to_string): New.
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index aa766bbc..9792419f 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -1,106 +1,93 @@
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_srcdir)/gcrypt
noinst_LTLIBRARIES = libcipher.la
-# The configure script greps the module names from the following lines.
-# You must also add all these names to EXTRA_PROGRAMS some lines below
-# and EXTRA_foo_SOURCES entries.
-# Hmmm is there a more easy way to do this? (EXTRA_PROGRAMS
-# might also list programs which are not modules)
-# MODULES: rndunix rndlinux rndegd rndw32
-# MODULES: sha1 rmd160 md5 tiger
-EXTRA_PROGRAMS = rndunix rndlinux rndegd rndw32 \
- sha1 rmd160 md5 tiger
+# The configure script greps the module names from the EXTRA_PROGRAMS line
+EXTRA_PROGRAMS = rndlinux rndunix rndegd rndw32 sha1 rmd160 md5 tiger
EXTRA_rndlinux_SOURCES = rndlinux.c
EXTRA_rndunix_SOURCES = rndunix.c
EXTRA_rndegd_SOURCES = rndegd.c
EXTRA_rndw32_SOURCES = rndw32.c
EXTRA_md5_SOURCES = md5.c
EXTRA_rmd160_SOURCES = rmd160.c
EXTRA_sha1_SOURCES = sha1.c
EXTRA_tiger_SOURCES = tiger.c
if ENABLE_GNUPG_EXTENSIONS
pkglib_PROGRAMS = @DYNAMIC_CIPHER_MODS@
else
pkglib_PROGRAMS =
endif
DYNLINK_MOD_CFLAGS = -DIS_MODULE @DYNLINK_MOD_CFLAGS@
libcipher_la_LDFLAGS =
libcipher_la_SOURCES = cipher.c \
pubkey.c \
md.c \
dynload.c \
dynload.h \
bithelp.h \
des.c \
des.h \
twofish.c \
blowfish.c \
blowfish.h \
cast5.c \
cast5.h \
elgamal.c \
elgamal.h \
primegen.c \
random.h \
random.c \
rand-internal.h \
rmd.h \
dsa.h \
dsa.c \
smallprime.c \
construct.c
# configure creates the constructor file
BUILT_SOURCES = construct.c
libcipher_la_DEPENDENCIES = @STATIC_CIPHER_OBJS@
libcipher_la_LIBADD = @STATIC_CIPHER_OBJS@
# If I remember it correct, automake 1.4 has a feature to set
# fooFLAGS depending on the program. So we should check it out.
tiger: $(srcdir)/tiger.c
`echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o tiger $(srcdir)/tiger.c | \
- sed -e 's/-O[2-9s]*/-O1/g' `
+ sed -e 's/-O[2-9s]*/-O/g' `
tiger.o: $(srcdir)/tiger.c
`echo $(COMPILE) -c $(srcdir)/tiger.c | sed -e 's/-O[2-9s]*/-O1/g' `
#twofish: $(srcdir)/twofish.c
# `echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o twofish $(srcdir)/twofish.c | \
# sed -e 's/-O[0-9s]*/ /g' `
twofish: $(srcdir)/twofish.c
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o twofish $(srcdir)/twofish.c
#twofish.o: $(srcdir)/twofish.c
# `echo $(COMPILE) -c $(srcdir)/twofish.c | sed -e 's/-O[0-9s]*/ /g' `
rndunix: $(srcdir)/rndunix.c
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndunix $(srcdir)/rndunix.c
rndlinux: $(srcdir)/rndlinux.c
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndlinux $(srcdir)/rndlinux.c
rndegd: $(srcdir)/rndegd.c
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c
-# We need to have a better system for selection which modules
-# to compile. For now this works.
-rndw32: $(srcdir)/rndw32.c
- echo "#!/bin/sh" >rndw32
- echo "Not usable as a module" >>rndw32
-
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index e7f047ff..2bdb3b5e 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -1,595 +1,598 @@
/* blowfish.c - Blowfish encryption
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 336 ff.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Test values:
* key "abcdefghijklmnopqrstuvwxyz";
* plain "BLOWFISH"
* cipher 32 4E D0 FE F4 13 A2 03
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "types.h"
#include "g10lib.h"
#include "blowfish.h"
#include "dynload.h"
#define CIPHER_ALGO_BLOWFISH 4 /* blowfish 128 bit key */
#define FNCCAST_SETKEY(f) (int(*)(void*, byte*, unsigned))(f)
#define FNCCAST_CRYPT(f) (void(*)(void*, byte*, byte*))(f)
#define BLOWFISH_BLOCKSIZE 8
#define BLOWFISH_ROUNDS 16
typedef struct {
u32 s0[256];
u32 s1[256];
u32 s2[256];
u32 s3[256];
u32 p[BLOWFISH_ROUNDS+2];
} BLOWFISH_context;
static int bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen );
static void encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
static void decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf );
/* precomputed S boxes */
static const u32 ks0[256] = {
0xD1310BA6,0x98DFB5AC,0x2FFD72DB,0xD01ADFB7,0xB8E1AFED,0x6A267E96,
0xBA7C9045,0xF12C7F99,0x24A19947,0xB3916CF7,0x0801F2E2,0x858EFC16,
0x636920D8,0x71574E69,0xA458FEA3,0xF4933D7E,0x0D95748F,0x728EB658,
0x718BCD58,0x82154AEE,0x7B54A41D,0xC25A59B5,0x9C30D539,0x2AF26013,
0xC5D1B023,0x286085F0,0xCA417918,0xB8DB38EF,0x8E79DCB0,0x603A180E,
0x6C9E0E8B,0xB01E8A3E,0xD71577C1,0xBD314B27,0x78AF2FDA,0x55605C60,
0xE65525F3,0xAA55AB94,0x57489862,0x63E81440,0x55CA396A,0x2AAB10B6,
0xB4CC5C34,0x1141E8CE,0xA15486AF,0x7C72E993,0xB3EE1411,0x636FBC2A,
0x2BA9C55D,0x741831F6,0xCE5C3E16,0x9B87931E,0xAFD6BA33,0x6C24CF5C,
0x7A325381,0x28958677,0x3B8F4898,0x6B4BB9AF,0xC4BFE81B,0x66282193,
0x61D809CC,0xFB21A991,0x487CAC60,0x5DEC8032,0xEF845D5D,0xE98575B1,
0xDC262302,0xEB651B88,0x23893E81,0xD396ACC5,0x0F6D6FF3,0x83F44239,
0x2E0B4482,0xA4842004,0x69C8F04A,0x9E1F9B5E,0x21C66842,0xF6E96C9A,
0x670C9C61,0xABD388F0,0x6A51A0D2,0xD8542F68,0x960FA728,0xAB5133A3,
0x6EEF0B6C,0x137A3BE4,0xBA3BF050,0x7EFB2A98,0xA1F1651D,0x39AF0176,
0x66CA593E,0x82430E88,0x8CEE8619,0x456F9FB4,0x7D84A5C3,0x3B8B5EBE,
0xE06F75D8,0x85C12073,0x401A449F,0x56C16AA6,0x4ED3AA62,0x363F7706,
0x1BFEDF72,0x429B023D,0x37D0D724,0xD00A1248,0xDB0FEAD3,0x49F1C09B,
0x075372C9,0x80991B7B,0x25D479D8,0xF6E8DEF7,0xE3FE501A,0xB6794C3B,
0x976CE0BD,0x04C006BA,0xC1A94FB6,0x409F60C4,0x5E5C9EC2,0x196A2463,
0x68FB6FAF,0x3E6C53B5,0x1339B2EB,0x3B52EC6F,0x6DFC511F,0x9B30952C,
0xCC814544,0xAF5EBD09,0xBEE3D004,0xDE334AFD,0x660F2807,0x192E4BB3,
0xC0CBA857,0x45C8740F,0xD20B5F39,0xB9D3FBDB,0x5579C0BD,0x1A60320A,
0xD6A100C6,0x402C7279,0x679F25FE,0xFB1FA3CC,0x8EA5E9F8,0xDB3222F8,
0x3C7516DF,0xFD616B15,0x2F501EC8,0xAD0552AB,0x323DB5FA,0xFD238760,
0x53317B48,0x3E00DF82,0x9E5C57BB,0xCA6F8CA0,0x1A87562E,0xDF1769DB,
0xD542A8F6,0x287EFFC3,0xAC6732C6,0x8C4F5573,0x695B27B0,0xBBCA58C8,
0xE1FFA35D,0xB8F011A0,0x10FA3D98,0xFD2183B8,0x4AFCB56C,0x2DD1D35B,
0x9A53E479,0xB6F84565,0xD28E49BC,0x4BFB9790,0xE1DDF2DA,0xA4CB7E33,
0x62FB1341,0xCEE4C6E8,0xEF20CADA,0x36774C01,0xD07E9EFE,0x2BF11FB4,
0x95DBDA4D,0xAE909198,0xEAAD8E71,0x6B93D5A0,0xD08ED1D0,0xAFC725E0,
0x8E3C5B2F,0x8E7594B7,0x8FF6E2FB,0xF2122B64,0x8888B812,0x900DF01C,
0x4FAD5EA0,0x688FC31C,0xD1CFF191,0xB3A8C1AD,0x2F2F2218,0xBE0E1777,
0xEA752DFE,0x8B021FA1,0xE5A0CC0F,0xB56F74E8,0x18ACF3D6,0xCE89E299,
0xB4A84FE0,0xFD13E0B7,0x7CC43B81,0xD2ADA8D9,0x165FA266,0x80957705,
0x93CC7314,0x211A1477,0xE6AD2065,0x77B5FA86,0xC75442F5,0xFB9D35CF,
0xEBCDAF0C,0x7B3E89A0,0xD6411BD3,0xAE1E7E49,0x00250E2D,0x2071B35E,
0x226800BB,0x57B8E0AF,0x2464369B,0xF009B91E,0x5563911D,0x59DFA6AA,
0x78C14389,0xD95A537F,0x207D5BA2,0x02E5B9C5,0x83260376,0x6295CFA9,
0x11C81968,0x4E734A41,0xB3472DCA,0x7B14A94A,0x1B510052,0x9A532915,
0xD60F573F,0xBC9BC6E4,0x2B60A476,0x81E67400,0x08BA6FB5,0x571BE91F,
0xF296EC6B,0x2A0DD915,0xB6636521,0xE7B9F9B6,0xFF34052E,0xC5855664,
0x53B02D5D,0xA99F8FA1,0x08BA4799,0x6E85076A };
static const u32 ks1[256] = {
0x4B7A70E9,0xB5B32944,0xDB75092E,0xC4192623,0xAD6EA6B0,0x49A7DF7D,
0x9CEE60B8,0x8FEDB266,0xECAA8C71,0x699A17FF,0x5664526C,0xC2B19EE1,
0x193602A5,0x75094C29,0xA0591340,0xE4183A3E,0x3F54989A,0x5B429D65,
0x6B8FE4D6,0x99F73FD6,0xA1D29C07,0xEFE830F5,0x4D2D38E6,0xF0255DC1,
0x4CDD2086,0x8470EB26,0x6382E9C6,0x021ECC5E,0x09686B3F,0x3EBAEFC9,
0x3C971814,0x6B6A70A1,0x687F3584,0x52A0E286,0xB79C5305,0xAA500737,
0x3E07841C,0x7FDEAE5C,0x8E7D44EC,0x5716F2B8,0xB03ADA37,0xF0500C0D,
0xF01C1F04,0x0200B3FF,0xAE0CF51A,0x3CB574B2,0x25837A58,0xDC0921BD,
0xD19113F9,0x7CA92FF6,0x94324773,0x22F54701,0x3AE5E581,0x37C2DADC,
0xC8B57634,0x9AF3DDA7,0xA9446146,0x0FD0030E,0xECC8C73E,0xA4751E41,
0xE238CD99,0x3BEA0E2F,0x3280BBA1,0x183EB331,0x4E548B38,0x4F6DB908,
0x6F420D03,0xF60A04BF,0x2CB81290,0x24977C79,0x5679B072,0xBCAF89AF,
0xDE9A771F,0xD9930810,0xB38BAE12,0xDCCF3F2E,0x5512721F,0x2E6B7124,
0x501ADDE6,0x9F84CD87,0x7A584718,0x7408DA17,0xBC9F9ABC,0xE94B7D8C,
0xEC7AEC3A,0xDB851DFA,0x63094366,0xC464C3D2,0xEF1C1847,0x3215D908,
0xDD433B37,0x24C2BA16,0x12A14D43,0x2A65C451,0x50940002,0x133AE4DD,
0x71DFF89E,0x10314E55,0x81AC77D6,0x5F11199B,0x043556F1,0xD7A3C76B,
0x3C11183B,0x5924A509,0xF28FE6ED,0x97F1FBFA,0x9EBABF2C,0x1E153C6E,
0x86E34570,0xEAE96FB1,0x860E5E0A,0x5A3E2AB3,0x771FE71C,0x4E3D06FA,
0x2965DCB9,0x99E71D0F,0x803E89D6,0x5266C825,0x2E4CC978,0x9C10B36A,
0xC6150EBA,0x94E2EA78,0xA5FC3C53,0x1E0A2DF4,0xF2F74EA7,0x361D2B3D,
0x1939260F,0x19C27960,0x5223A708,0xF71312B6,0xEBADFE6E,0xEAC31F66,
0xE3BC4595,0xA67BC883,0xB17F37D1,0x018CFF28,0xC332DDEF,0xBE6C5AA5,
0x65582185,0x68AB9802,0xEECEA50F,0xDB2F953B,0x2AEF7DAD,0x5B6E2F84,
0x1521B628,0x29076170,0xECDD4775,0x619F1510,0x13CCA830,0xEB61BD96,
0x0334FE1E,0xAA0363CF,0xB5735C90,0x4C70A239,0xD59E9E0B,0xCBAADE14,
0xEECC86BC,0x60622CA7,0x9CAB5CAB,0xB2F3846E,0x648B1EAF,0x19BDF0CA,
0xA02369B9,0x655ABB50,0x40685A32,0x3C2AB4B3,0x319EE9D5,0xC021B8F7,
0x9B540B19,0x875FA099,0x95F7997E,0x623D7DA8,0xF837889A,0x97E32D77,
0x11ED935F,0x16681281,0x0E358829,0xC7E61FD6,0x96DEDFA1,0x7858BA99,
0x57F584A5,0x1B227263,0x9B83C3FF,0x1AC24696,0xCDB30AEB,0x532E3054,
0x8FD948E4,0x6DBC3128,0x58EBF2EF,0x34C6FFEA,0xFE28ED61,0xEE7C3C73,
0x5D4A14D9,0xE864B7E3,0x42105D14,0x203E13E0,0x45EEE2B6,0xA3AAABEA,
0xDB6C4F15,0xFACB4FD0,0xC742F442,0xEF6ABBB5,0x654F3B1D,0x41CD2105,
0xD81E799E,0x86854DC7,0xE44B476A,0x3D816250,0xCF62A1F2,0x5B8D2646,
0xFC8883A0,0xC1C7B6A3,0x7F1524C3,0x69CB7492,0x47848A0B,0x5692B285,
0x095BBF00,0xAD19489D,0x1462B174,0x23820E00,0x58428D2A,0x0C55F5EA,
0x1DADF43E,0x233F7061,0x3372F092,0x8D937E41,0xD65FECF1,0x6C223BDB,
0x7CDE3759,0xCBEE7460,0x4085F2A7,0xCE77326E,0xA6078084,0x19F8509E,
0xE8EFD855,0x61D99735,0xA969A7AA,0xC50C06C2,0x5A04ABFC,0x800BCADC,
0x9E447A2E,0xC3453484,0xFDD56705,0x0E1E9EC9,0xDB73DBD3,0x105588CD,
0x675FDA79,0xE3674340,0xC5C43465,0x713E38D8,0x3D28F89E,0xF16DFF20,
0x153E21E7,0x8FB03D4A,0xE6E39F2B,0xDB83ADF7 };
static const u32 ks2[256] = {
0xE93D5A68,0x948140F7,0xF64C261C,0x94692934,0x411520F7,0x7602D4F7,
0xBCF46B2E,0xD4A20068,0xD4082471,0x3320F46A,0x43B7D4B7,0x500061AF,
0x1E39F62E,0x97244546,0x14214F74,0xBF8B8840,0x4D95FC1D,0x96B591AF,
0x70F4DDD3,0x66A02F45,0xBFBC09EC,0x03BD9785,0x7FAC6DD0,0x31CB8504,
0x96EB27B3,0x55FD3941,0xDA2547E6,0xABCA0A9A,0x28507825,0x530429F4,
0x0A2C86DA,0xE9B66DFB,0x68DC1462,0xD7486900,0x680EC0A4,0x27A18DEE,
0x4F3FFEA2,0xE887AD8C,0xB58CE006,0x7AF4D6B6,0xAACE1E7C,0xD3375FEC,
0xCE78A399,0x406B2A42,0x20FE9E35,0xD9F385B9,0xEE39D7AB,0x3B124E8B,
0x1DC9FAF7,0x4B6D1856,0x26A36631,0xEAE397B2,0x3A6EFA74,0xDD5B4332,
0x6841E7F7,0xCA7820FB,0xFB0AF54E,0xD8FEB397,0x454056AC,0xBA489527,
0x55533A3A,0x20838D87,0xFE6BA9B7,0xD096954B,0x55A867BC,0xA1159A58,
0xCCA92963,0x99E1DB33,0xA62A4A56,0x3F3125F9,0x5EF47E1C,0x9029317C,
0xFDF8E802,0x04272F70,0x80BB155C,0x05282CE3,0x95C11548,0xE4C66D22,
0x48C1133F,0xC70F86DC,0x07F9C9EE,0x41041F0F,0x404779A4,0x5D886E17,
0x325F51EB,0xD59BC0D1,0xF2BCC18F,0x41113564,0x257B7834,0x602A9C60,
0xDFF8E8A3,0x1F636C1B,0x0E12B4C2,0x02E1329E,0xAF664FD1,0xCAD18115,
0x6B2395E0,0x333E92E1,0x3B240B62,0xEEBEB922,0x85B2A20E,0xE6BA0D99,
0xDE720C8C,0x2DA2F728,0xD0127845,0x95B794FD,0x647D0862,0xE7CCF5F0,
0x5449A36F,0x877D48FA,0xC39DFD27,0xF33E8D1E,0x0A476341,0x992EFF74,
0x3A6F6EAB,0xF4F8FD37,0xA812DC60,0xA1EBDDF8,0x991BE14C,0xDB6E6B0D,
0xC67B5510,0x6D672C37,0x2765D43B,0xDCD0E804,0xF1290DC7,0xCC00FFA3,
0xB5390F92,0x690FED0B,0x667B9FFB,0xCEDB7D9C,0xA091CF0B,0xD9155EA3,
0xBB132F88,0x515BAD24,0x7B9479BF,0x763BD6EB,0x37392EB3,0xCC115979,
0x8026E297,0xF42E312D,0x6842ADA7,0xC66A2B3B,0x12754CCC,0x782EF11C,
0x6A124237,0xB79251E7,0x06A1BBE6,0x4BFB6350,0x1A6B1018,0x11CAEDFA,
0x3D25BDD8,0xE2E1C3C9,0x44421659,0x0A121386,0xD90CEC6E,0xD5ABEA2A,
0x64AF674E,0xDA86A85F,0xBEBFE988,0x64E4C3FE,0x9DBC8057,0xF0F7C086,
0x60787BF8,0x6003604D,0xD1FD8346,0xF6381FB0,0x7745AE04,0xD736FCCC,
0x83426B33,0xF01EAB71,0xB0804187,0x3C005E5F,0x77A057BE,0xBDE8AE24,
0x55464299,0xBF582E61,0x4E58F48F,0xF2DDFDA2,0xF474EF38,0x8789BDC2,
0x5366F9C3,0xC8B38E74,0xB475F255,0x46FCD9B9,0x7AEB2661,0x8B1DDF84,
0x846A0E79,0x915F95E2,0x466E598E,0x20B45770,0x8CD55591,0xC902DE4C,
0xB90BACE1,0xBB8205D0,0x11A86248,0x7574A99E,0xB77F19B6,0xE0A9DC09,
0x662D09A1,0xC4324633,0xE85A1F02,0x09F0BE8C,0x4A99A025,0x1D6EFE10,
0x1AB93D1D,0x0BA5A4DF,0xA186F20F,0x2868F169,0xDCB7DA83,0x573906FE,
0xA1E2CE9B,0x4FCD7F52,0x50115E01,0xA70683FA,0xA002B5C4,0x0DE6D027,
0x9AF88C27,0x773F8641,0xC3604C06,0x61A806B5,0xF0177A28,0xC0F586E0,
0x006058AA,0x30DC7D62,0x11E69ED7,0x2338EA63,0x53C2DD94,0xC2C21634,
0xBBCBEE56,0x90BCB6DE,0xEBFC7DA1,0xCE591D76,0x6F05E409,0x4B7C0188,
0x39720A3D,0x7C927C24,0x86E3725F,0x724D9DB9,0x1AC15BB4,0xD39EB8FC,
0xED545578,0x08FCA5B5,0xD83D7CD3,0x4DAD0FC4,0x1E50EF5E,0xB161E6F8,
0xA28514D9,0x6C51133C,0x6FD5C7E7,0x56E14EC4,0x362ABFCE,0xDDC6C837,
0xD79A3234,0x92638212,0x670EFA8E,0x406000E0 };
static const u32 ks3[256] = {
0x3A39CE37,0xD3FAF5CF,0xABC27737,0x5AC52D1B,0x5CB0679E,0x4FA33742,
0xD3822740,0x99BC9BBE,0xD5118E9D,0xBF0F7315,0xD62D1C7E,0xC700C47B,
0xB78C1B6B,0x21A19045,0xB26EB1BE,0x6A366EB4,0x5748AB2F,0xBC946E79,
0xC6A376D2,0x6549C2C8,0x530FF8EE,0x468DDE7D,0xD5730A1D,0x4CD04DC6,
0x2939BBDB,0xA9BA4650,0xAC9526E8,0xBE5EE304,0xA1FAD5F0,0x6A2D519A,
0x63EF8CE2,0x9A86EE22,0xC089C2B8,0x43242EF6,0xA51E03AA,0x9CF2D0A4,
0x83C061BA,0x9BE96A4D,0x8FE51550,0xBA645BD6,0x2826A2F9,0xA73A3AE1,
0x4BA99586,0xEF5562E9,0xC72FEFD3,0xF752F7DA,0x3F046F69,0x77FA0A59,
0x80E4A915,0x87B08601,0x9B09E6AD,0x3B3EE593,0xE990FD5A,0x9E34D797,
0x2CF0B7D9,0x022B8B51,0x96D5AC3A,0x017DA67D,0xD1CF3ED6,0x7C7D2D28,
0x1F9F25CF,0xADF2B89B,0x5AD6B472,0x5A88F54C,0xE029AC71,0xE019A5E6,
0x47B0ACFD,0xED93FA9B,0xE8D3C48D,0x283B57CC,0xF8D56629,0x79132E28,
0x785F0191,0xED756055,0xF7960E44,0xE3D35E8C,0x15056DD4,0x88F46DBA,
0x03A16125,0x0564F0BD,0xC3EB9E15,0x3C9057A2,0x97271AEC,0xA93A072A,
0x1B3F6D9B,0x1E6321F5,0xF59C66FB,0x26DCF319,0x7533D928,0xB155FDF5,
0x03563482,0x8ABA3CBB,0x28517711,0xC20AD9F8,0xABCC5167,0xCCAD925F,
0x4DE81751,0x3830DC8E,0x379D5862,0x9320F991,0xEA7A90C2,0xFB3E7BCE,
0x5121CE64,0x774FBE32,0xA8B6E37E,0xC3293D46,0x48DE5369,0x6413E680,
0xA2AE0810,0xDD6DB224,0x69852DFD,0x09072166,0xB39A460A,0x6445C0DD,
0x586CDECF,0x1C20C8AE,0x5BBEF7DD,0x1B588D40,0xCCD2017F,0x6BB4E3BB,
0xDDA26A7E,0x3A59FF45,0x3E350A44,0xBCB4CDD5,0x72EACEA8,0xFA6484BB,
0x8D6612AE,0xBF3C6F47,0xD29BE463,0x542F5D9E,0xAEC2771B,0xF64E6370,
0x740E0D8D,0xE75B1357,0xF8721671,0xAF537D5D,0x4040CB08,0x4EB4E2CC,
0x34D2466A,0x0115AF84,0xE1B00428,0x95983A1D,0x06B89FB4,0xCE6EA048,
0x6F3F3B82,0x3520AB82,0x011A1D4B,0x277227F8,0x611560B1,0xE7933FDC,
0xBB3A792B,0x344525BD,0xA08839E1,0x51CE794B,0x2F32C9B7,0xA01FBAC9,
0xE01CC87E,0xBCC7D1F6,0xCF0111C3,0xA1E8AAC7,0x1A908749,0xD44FBD9A,
0xD0DADECB,0xD50ADA38,0x0339C32A,0xC6913667,0x8DF9317C,0xE0B12B4F,
0xF79E59B7,0x43F5BB3A,0xF2D519FF,0x27D9459C,0xBF97222C,0x15E6FC2A,
0x0F91FC71,0x9B941525,0xFAE59361,0xCEB69CEB,0xC2A86459,0x12BAA8D1,
0xB6C1075E,0xE3056A0C,0x10D25065,0xCB03A442,0xE0EC6E0E,0x1698DB3B,
0x4C98A0BE,0x3278E964,0x9F1F9532,0xE0D392DF,0xD3A0342B,0x8971F21E,
0x1B0A7441,0x4BA3348C,0xC5BE7120,0xC37632D8,0xDF359F8D,0x9B992F2E,
0xE60B6F47,0x0FE3F11D,0xE54CDA54,0x1EDAD891,0xCE6279CF,0xCD3E7E6F,
0x1618B166,0xFD2C1D05,0x848FD2C5,0xF6FB2299,0xF523F357,0xA6327623,
0x93A83531,0x56CCCD02,0xACF08162,0x5A75EBB5,0x6E163697,0x88D273CC,
0xDE966292,0x81B949D0,0x4C50901B,0x71C65614,0xE6C6C7BD,0x327A140A,
0x45E1D006,0xC3F27B9A,0xC9AA53FD,0x62A80F00,0xBB25BFE2,0x35BDD2F6,
0x71126905,0xB2040222,0xB6CBCF7C,0xCD769C2B,0x53113EC0,0x1640E3D3,
0x38ABBD60,0x2547ADF0,0xBA38209C,0xF746CE76,0x77AFA1C5,0x20756060,
0x85CBFE4E,0x8AE88DD8,0x7AAAF9B0,0x4CF9AA7E,0x1948C25C,0x02FB8A8C,
0x01C36AE4,0xD6EBE1F9,0x90D4F869,0xA65CDEA0,0x3F09252D,0xC208E69F,
0xB74E6132,0xCE77E25B,0x578FDFE3,0x3AC372E6 };
static const u32 ps[BLOWFISH_ROUNDS+2] = {
0x243F6A88,0x85A308D3,0x13198A2E,0x03707344,0xA4093822,0x299F31D0,
0x082EFA98,0xEC4E6C89,0x452821E6,0x38D01377,0xBE5466CF,0x34E90C6C,
0xC0AC29B7,0xC97C50DD,0x3F84D5B5,0xB5470917,0x9216D5D9,0x8979FB1B };
#if BLOWFISH_ROUNDS != 16
static inline u32
function_F( BLOWFISH_context *bc, u32 x )
{
u16 a, b, c, d;
#ifdef BIG_ENDIAN_HOST
a = ((byte*)&x)[0];
b = ((byte*)&x)[1];
c = ((byte*)&x)[2];
d = ((byte*)&x)[3];
#else
a = ((byte*)&x)[3];
b = ((byte*)&x)[2];
c = ((byte*)&x)[1];
d = ((byte*)&x)[0];
#endif
return ((bc->s0[a] + bc->s1[b]) ^ bc->s2[c] ) + bc->s3[d];
}
#endif
#ifdef BIG_ENDIAN_HOST
#define F(x) ((( s0[((byte*)&x)[0]] + s1[((byte*)&x)[1]]) \
^ s2[((byte*)&x)[2]]) + s3[((byte*)&x)[3]] )
#else
#define F(x) ((( s0[((byte*)&x)[3]] + s1[((byte*)&x)[2]]) \
^ s2[((byte*)&x)[1]]) + s3[((byte*)&x)[0]] )
#endif
#define R(l,r,i) do { l ^= p[i]; r ^= F(l); } while(0)
static void
encrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 0);
R( xr, xl, 1);
R( xl, xr, 2);
R( xr, xl, 3);
R( xl, xr, 4);
R( xr, xl, 5);
R( xl, xr, 6);
R( xr, xl, 7);
R( xl, xr, 8);
R( xr, xl, 9);
R( xl, xr, 10);
R( xr, xl, 11);
R( xl, xr, 12);
R( xr, xl, 13);
R( xl, xr, 14);
R( xr, xl, 15);
xl ^= p[BLOWFISH_ROUNDS];
xr ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for(i=0; i < BLOWFISH_ROUNDS; i++ ) {
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[BLOWFISH_ROUNDS];
xl ^= p[BLOWFISH_ROUNDS+1];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
static void
decrypt( BLOWFISH_context *bc, u32 *ret_xl, u32 *ret_xr )
{
#if BLOWFISH_ROUNDS == 16
u32 xl, xr, *s0, *s1, *s2, *s3, *p;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
s0 = bc->s0;
s1 = bc->s1;
s2 = bc->s2;
s3 = bc->s3;
R( xl, xr, 17);
R( xr, xl, 16);
R( xl, xr, 15);
R( xr, xl, 14);
R( xl, xr, 13);
R( xr, xl, 12);
R( xl, xr, 11);
R( xr, xl, 10);
R( xl, xr, 9);
R( xr, xl, 8);
R( xl, xr, 7);
R( xr, xl, 6);
R( xl, xr, 5);
R( xr, xl, 4);
R( xl, xr, 3);
R( xr, xl, 2);
xl ^= p[1];
xr ^= p[0];
*ret_xl = xr;
*ret_xr = xl;
#else
u32 xl, xr, temp, *p;
int i;
xl = *ret_xl;
xr = *ret_xr;
p = bc->p;
for(i=BLOWFISH_ROUNDS+1; i > 1; i-- ) {
xl ^= p[i];
xr ^= function_F(bc, xl);
temp = xl;
xl = xr;
xr = temp;
}
temp = xl;
xl = xr;
xr = temp;
xr ^= p[1];
xl ^= p[0];
*ret_xl = xl;
*ret_xr = xr;
#endif
}
#undef F
#undef R
static void
encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
encrypt( bc, &d1, &d2 );
outbuf[0] = (d1 >> 24) & 0xff;
outbuf[1] = (d1 >> 16) & 0xff;
outbuf[2] = (d1 >> 8) & 0xff;
outbuf[3] = d1 & 0xff;
outbuf[4] = (d2 >> 24) & 0xff;
outbuf[5] = (d2 >> 16) & 0xff;
outbuf[6] = (d2 >> 8) & 0xff;
outbuf[7] = d2 & 0xff;
}
static void
decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf )
{
u32 d1, d2;
d1 = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
d2 = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
decrypt( bc, &d1, &d2 );
outbuf[0] = (d1 >> 24) & 0xff;
outbuf[1] = (d1 >> 16) & 0xff;
outbuf[2] = (d1 >> 8) & 0xff;
outbuf[3] = d1 & 0xff;
outbuf[4] = (d2 >> 24) & 0xff;
outbuf[5] = (d2 >> 16) & 0xff;
outbuf[6] = (d2 >> 8) & 0xff;
outbuf[7] = d2 & 0xff;
}
static const char*
selftest(void)
{
BLOWFISH_context c;
byte plain[] = "BLOWFISH";
byte buffer[8];
byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
bf_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, "\x32\x4E\xD0\xFE\xF4\x13\xA2\x03", 8 ) )
return "Blowfish selftest failed (1).";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "Blowfish selftest failed (2).";
bf_setkey( &c, key3, 8 );
encrypt_block( &c, buffer, plain3 );
if( memcmp( buffer, cipher3, 8 ) )
return "Blowfish selftest failed (3).";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain3, 8 ) )
return "Blowfish selftest failed (4).";
return NULL;
}
static int
bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen )
{
int i, j;
u32 data, datal, datar;
static int initialized;
static const char *selftest_failed;
if( !initialized ) {
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
fprintf(stderr,"%s\n", selftest_failed );
}
if( selftest_failed )
return GCRYERR_SELFTEST;
for(i=0; i < BLOWFISH_ROUNDS+2; i++ )
c->p[i] = ps[i];
for(i=0; i < 256; i++ ) {
c->s0[i] = ks0[i];
c->s1[i] = ks1[i];
c->s2[i] = ks2[i];
c->s3[i] = ks3[i];
}
for(i=j=0; i < BLOWFISH_ROUNDS+2; i++ ) {
#ifdef BIG_ENDIAN_HOST
((byte*)&data)[0] = key[j];
((byte*)&data)[1] = key[(j+1)%keylen];
((byte*)&data)[2] = key[(j+2)%keylen];
((byte*)&data)[3] = key[(j+3)%keylen];
#else
((byte*)&data)[3] = key[j];
((byte*)&data)[2] = key[(j+1)%keylen];
((byte*)&data)[1] = key[(j+2)%keylen];
((byte*)&data)[0] = key[(j+3)%keylen];
#endif
c->p[i] ^= data;
j = (j+4) % keylen;
}
datal = datar = 0;
for(i=0; i < BLOWFISH_ROUNDS+2; i += 2 ) {
encrypt( c, &datal, &datar );
c->p[i] = datal;
c->p[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s0[i] = datal;
c->s0[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s1[i] = datal;
c->s1[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s2[i] = datal;
c->s2[i+1] = datar;
}
for(i=0; i < 256; i += 2 ) {
encrypt( c, &datal, &datar );
c->s3[i] = datal;
c->s3[i+1] = datar;
}
/* Check for weak key. A weak key is a key in which a value in */
/* the P-array (here c) occurs more than once per table. */
for(i=0; i < 255; i++ ) {
for( j=i+1; j < 256; j++) {
if( (c->s0[i] == c->s0[j]) || (c->s1[i] == c->s1[j]) ||
(c->s2[i] == c->s2[j]) || (c->s3[i] == c->s3[j]) )
return GCRYERR_WEAK_KEY;
}
}
return 0;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
blowfish_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
)
{
*keylen = 128;
*blocksize = BLOWFISH_BLOCKSIZE;
*contextsize = sizeof(BLOWFISH_context);
- *r_setkey = FNCCAST_SETKEY(bf_setkey);
- *r_encrypt= FNCCAST_CRYPT(encrypt_block);
- *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+ *(int (**)(BLOWFISH_context*, byte*, unsigned))r_setkey
+ = bf_setkey;
+ *(void (**)(BLOWFISH_context*, byte*, byte*))r_encrypt
+ = encrypt_block;
+ *(void (**)(BLOWFISH_context*, byte*, byte*))r_decrypt
+ = decrypt_block;
if( algo == CIPHER_ALGO_BLOWFISH )
return "BLOWFISH";
return NULL;
}
diff --git a/cipher/cast5.c b/cipher/cast5.c
index aaa0a42e..64f6bb0e 100644
--- a/cipher/cast5.c
+++ b/cipher/cast5.c
@@ -1,621 +1,625 @@
/* cast5.c - CAST5 cipher (RFC2144)
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Test vectors:
*
* 128-bit key = 01 23 45 67 12 34 56 78 23 45 67 89 34 56 78 9A
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 23 8B 4F E5 84 7E 44 B2
*
* 80-bit key = 01 23 45 67 12 34 56 78 23 45
* = 01 23 45 67 12 34 56 78 23 45 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = EB 6A 71 1A 2C 02 27 1B
*
* 40-bit key = 01 23 45 67 12
* = 01 23 45 67 12 00 00 00 00 00 00 00 00 00 00 00
* plaintext = 01 23 45 67 89 AB CD EF
* ciphertext = 7A C8 16 D1 6E 9B 30 2E
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "types.h"
#include "cast5.h"
#define CIPHER_ALGO_CAST5 3
#define FNCCAST_SETKEY(f) (int(*)(void*, byte*, unsigned))(f)
#define FNCCAST_CRYPT(f) (void(*)(void*, byte*, byte*))(f)
#define CAST5_BLOCKSIZE 8
typedef struct {
u32 Km[16];
byte Kr[16];
} CAST5_context;
static int cast_setkey( CAST5_context *c, byte *key, unsigned keylen );
static void encrypt_block( CAST5_context *bc, byte *outbuf, byte *inbuf );
static void decrypt_block( CAST5_context *bc, byte *outbuf, byte *inbuf );
static const u32 s1[256] = {
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
};
static const u32 s2[256] = {
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1
};
static const u32 s3[256] = {
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783
};
static const u32 s4[256] = {
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
};
static const u32 s5[256] = {
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4
};
static const u32 s6[256] = {
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f
};
static const u32 s7[256] = {
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3
};
static const u32 s8[256] = {
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e
};
#if defined(__GNUC__) && defined(__i386__)
static inline u32
rol(int n, u32 x)
{
__asm__("roll %%cl,%0"
:"=r" (x)
:"0" (x),"c" (n));
return x;
}
#else
#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
#endif
#define F1(D,m,r) ( (I = ((m) + (D))), (I=rol((r),I)), \
(((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
#define F2(D,m,r) ( (I = ((m) ^ (D))), (I=rol((r),I)), \
(((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
#define F3(D,m,r) ( (I = ((m) - (D))), (I=rol((r),I)), \
(((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
static void
encrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf )
{
u32 l, r, t;
u32 I; /* used by the Fx macros */
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
/* (L0,R0) <-- (m1...m64). (Split the plaintext into left and
* right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
*/
l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
/* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
* Li = Ri-1;
* Ri = Li-1 ^ f(Ri-1,Kmi,Kri), where f is defined in Section 2.2
* Rounds 1, 4, 7, 10, 13, and 16 use f function Type 1.
* Rounds 2, 5, 8, 11, and 14 use f function Type 2.
* Rounds 3, 6, 9, 12, and 15 use f function Type 3.
*/
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
/* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
* concatenate to form the ciphertext.) */
outbuf[0] = (r >> 24) & 0xff;
outbuf[1] = (r >> 16) & 0xff;
outbuf[2] = (r >> 8) & 0xff;
outbuf[3] = r & 0xff;
outbuf[4] = (l >> 24) & 0xff;
outbuf[5] = (l >> 16) & 0xff;
outbuf[6] = (l >> 8) & 0xff;
outbuf[7] = l & 0xff;
}
static void
decrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf )
{
u32 l, r, t;
u32 I;
u32 *Km;
byte *Kr;
Km = c->Km;
Kr = c->Kr;
l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
t = l; l = r; r = t ^ F2(r, Km[13], Kr[13]);
t = l; l = r; r = t ^ F1(r, Km[12], Kr[12]);
t = l; l = r; r = t ^ F3(r, Km[11], Kr[11]);
t = l; l = r; r = t ^ F2(r, Km[10], Kr[10]);
t = l; l = r; r = t ^ F1(r, Km[ 9], Kr[ 9]);
t = l; l = r; r = t ^ F3(r, Km[ 8], Kr[ 8]);
t = l; l = r; r = t ^ F2(r, Km[ 7], Kr[ 7]);
t = l; l = r; r = t ^ F1(r, Km[ 6], Kr[ 6]);
t = l; l = r; r = t ^ F3(r, Km[ 5], Kr[ 5]);
t = l; l = r; r = t ^ F2(r, Km[ 4], Kr[ 4]);
t = l; l = r; r = t ^ F1(r, Km[ 3], Kr[ 3]);
t = l; l = r; r = t ^ F3(r, Km[ 2], Kr[ 2]);
t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
outbuf[0] = (r >> 24) & 0xff;
outbuf[1] = (r >> 16) & 0xff;
outbuf[2] = (r >> 8) & 0xff;
outbuf[3] = r & 0xff;
outbuf[4] = (l >> 24) & 0xff;
outbuf[5] = (l >> 16) & 0xff;
outbuf[6] = (l >> 8) & 0xff;
outbuf[7] = l & 0xff;
}
static const char*
selftest(void)
{
CAST5_context c;
byte key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A };
byte plain[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
byte cipher[8]= { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
byte buffer[8];
cast_setkey( &c, key, 16 );
encrypt_block( &c, buffer, plain );
if( memcmp( buffer, cipher, 8 ) )
return "1";
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
return "2";
#if 0 /* full maintenance test */
{
int i;
byte a0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte b0[16] = { 0x01,0x23,0x45,0x67,0x12,0x34,0x56,0x78,
0x23,0x45,0x67,0x89,0x34,0x56,0x78,0x9A };
byte a1[16] = { 0xEE,0xA9,0xD0,0xA2,0x49,0xFD,0x3B,0xA6,
0xB3,0x43,0x6F,0xB8,0x9D,0x6D,0xCA,0x92 };
byte b1[16] = { 0xB2,0xC9,0x5E,0xB0,0x0C,0x31,0xAD,0x71,
0x80,0xAC,0x05,0xB8,0xE8,0x3D,0x69,0x6E };
for(i=0; i < 1000000; i++ ) {
cast_setkey( &c, b0, 16 );
encrypt_block( &c, a0, a0 );
encrypt_block( &c, a0+8, a0+8 );
cast_setkey( &c, a0, 16 );
encrypt_block( &c, b0, b0 );
encrypt_block( &c, b0+8, b0+8 );
}
if( memcmp( a0, a1, 16 ) || memcmp( b0, b1, 16 ) )
return "3";
}
#endif
return NULL;
}
static void
key_schedule( u32 *x, u32 *z, u32 *k )
{
#define xi(i) ((x[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
#define zi(i) ((z[(i)/4] >> (8*(3-((i)%4)))) & 0xff)
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[0] = s5[zi( 8)]^s6[zi( 9)]^s7[zi( 7)]^s8[zi( 6)]^s5[zi( 2)];
k[1] = s5[zi(10)]^s6[zi(11)]^s7[zi( 5)]^s8[zi( 4)]^s6[zi( 6)];
k[2] = s5[zi(12)]^s6[zi(13)]^s7[zi( 3)]^s8[zi( 2)]^s7[zi( 9)];
k[3] = s5[zi(14)]^s6[zi(15)]^s7[zi( 1)]^s8[zi( 0)]^s8[zi(12)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[4] = s5[xi( 3)]^s6[xi( 2)]^s7[xi(12)]^s8[xi(13)]^s5[xi( 8)];
k[5] = s5[xi( 1)]^s6[xi( 0)]^s7[xi(14)]^s8[xi(15)]^s6[xi(13)];
k[6] = s5[xi( 7)]^s6[xi( 6)]^s7[xi( 8)]^s8[xi( 9)]^s7[xi( 3)];
k[7] = s5[xi( 5)]^s6[xi( 4)]^s7[xi(10)]^s8[xi(11)]^s8[xi( 7)];
z[0] = x[0] ^ s5[xi(13)]^s6[xi(15)]^s7[xi(12)]^s8[xi(14)]^s7[xi( 8)];
z[1] = x[2] ^ s5[zi( 0)]^s6[zi( 2)]^s7[zi( 1)]^s8[zi( 3)]^s8[xi(10)];
z[2] = x[3] ^ s5[zi( 7)]^s6[zi( 6)]^s7[zi( 5)]^s8[zi( 4)]^s5[xi( 9)];
z[3] = x[1] ^ s5[zi(10)]^s6[zi( 9)]^s7[zi(11)]^s8[zi( 8)]^s6[xi(11)];
k[8] = s5[zi( 3)]^s6[zi( 2)]^s7[zi(12)]^s8[zi(13)]^s5[zi( 9)];
k[9] = s5[zi( 1)]^s6[zi( 0)]^s7[zi(14)]^s8[zi(15)]^s6[zi(12)];
k[10]= s5[zi( 7)]^s6[zi( 6)]^s7[zi( 8)]^s8[zi( 9)]^s7[zi( 2)];
k[11]= s5[zi( 5)]^s6[zi( 4)]^s7[zi(10)]^s8[zi(11)]^s8[zi( 6)];
x[0] = z[2] ^ s5[zi( 5)]^s6[zi( 7)]^s7[zi( 4)]^s8[zi( 6)]^s7[zi( 0)];
x[1] = z[0] ^ s5[xi( 0)]^s6[xi( 2)]^s7[xi( 1)]^s8[xi( 3)]^s8[zi( 2)];
x[2] = z[1] ^ s5[xi( 7)]^s6[xi( 6)]^s7[xi( 5)]^s8[xi( 4)]^s5[zi( 1)];
x[3] = z[3] ^ s5[xi(10)]^s6[xi( 9)]^s7[xi(11)]^s8[xi( 8)]^s6[zi( 3)];
k[12]= s5[xi( 8)]^s6[xi( 9)]^s7[xi( 7)]^s8[xi( 6)]^s5[xi( 3)];
k[13]= s5[xi(10)]^s6[xi(11)]^s7[xi( 5)]^s8[xi( 4)]^s6[xi( 7)];
k[14]= s5[xi(12)]^s6[xi(13)]^s7[xi( 3)]^s8[xi( 2)]^s7[xi( 8)];
k[15]= s5[xi(14)]^s6[xi(15)]^s7[xi( 1)]^s8[xi( 0)]^s8[xi(13)];
#undef xi
#undef zi
}
static int
cast_setkey( CAST5_context *c, byte *key, unsigned keylen )
{
static int initialized;
static const char* selftest_failed;
int i;
u32 x[4];
u32 z[4];
u32 k[16];
if( !initialized ) {
initialized = 1;
selftest_failed = selftest();
if( selftest_failed )
fprintf(stderr,"CAST5 selftest failed (%s).\n", selftest_failed );
}
if( selftest_failed )
return GCRYERR_SELFTEST;
if( keylen != 16 )
return GCRYERR_INV_KEYLEN;
x[0] = key[0] << 24 | key[1] << 16 | key[2] << 8 | key[3];
x[1] = key[4] << 24 | key[5] << 16 | key[6] << 8 | key[7];
x[2] = key[8] << 24 | key[9] << 16 | key[10] << 8 | key[11];
x[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15];
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Km[i] = k[i];
key_schedule( x, z, k );
for(i=0; i < 16; i++ )
c->Kr[i] = k[i] & 0x1f;
memset(&x,0, sizeof x);
memset(&z,0, sizeof z);
memset(&k,0, sizeof k);
#undef xi
#undef zi
return 0;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
cast5_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
)
{
*keylen = 128;
*blocksize = CAST5_BLOCKSIZE;
*contextsize = sizeof(CAST5_context);
- *r_setkey = FNCCAST_SETKEY(cast_setkey);
- *r_encrypt= FNCCAST_CRYPT(encrypt_block);
- *r_decrypt= FNCCAST_CRYPT(decrypt_block);
+ *(int (**)(CAST5_context*, byte*, unsigned))r_setkey
+ = cast_setkey;
+ *(void (**)(CAST5_context*, byte*, byte*))r_encrypt
+ = encrypt_block;
+ *(void (**)(CAST5_context*, byte*, byte*))r_decrypt
+ = decrypt_block;
+
if( algo == CIPHER_ALGO_CAST5 )
return "CAST5";
return NULL;
}
diff --git a/cipher/des.c b/cipher/des.c
index af5b5845..9c3c5419 100644
--- a/cipher/des.c
+++ b/cipher/des.c
@@ -1,1011 +1,1014 @@
/* des.c - DES and Triple-DES encryption/decryption Algorithm
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
*
* Please see below for more legal information!
*
* According to the definition of DES in FIPS PUB 46-2 from December 1993.
* For a description of triple encryption, see:
* Bruce Schneier: Applied Cryptography. Second Edition.
* John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/*
* Written by Michael Roth <mroth@nessie.de>, September 1998
*/
/*
* U S A G E
* ===========
*
* For DES or Triple-DES encryption/decryption you must initialize a proper
* encryption context with a key.
*
* A DES key is 64bit wide but only 56bits of the key are used. The remaining
* bits are parity bits and they will _not_ checked in this implementation, but
* simply ignored.
*
* For Tripple-DES you could use either two 64bit keys or three 64bit keys.
* The parity bits will _not_ checked, too.
*
* After initializing a context with a key you could use this context to
* encrypt or decrypt data in 64bit blocks in Electronic Codebook Mode.
*
* (In the examples below the slashes at the beginning and ending of comments
* are omited.)
*
* DES Example
* -----------
* unsigned char key[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* des_ctx context;
*
* * Fill 'key' and 'plaintext' with some data *
* ....
*
* * Set up the DES encryption context *
* des_setkey(context, key);
*
* * Encrypt the plaintext *
* des_ecb_encrypt(context, plaintext, ciphertext);
*
* * To recover the orginal plaintext from ciphertext use: *
* des_ecb_decrypt(context, ciphertext, recoverd);
*
*
* Triple-DES Example
* ------------------
* unsigned char key1[8];
* unsigned char key2[8];
* unsigned char key3[8];
* unsigned char plaintext[8];
* unsigned char ciphertext[8];
* unsigned char recoverd[8];
* tripledes_ctx context;
*
* * If you would like to use two 64bit keys, fill 'key1' and'key2'
* then setup the encryption context: *
* tripledes_set2keys(context, key1, key2);
*
* * To use three 64bit keys with Triple-DES use: *
* tripledes_set3keys(context, key1, key2, key3);
*
* * Encrypting plaintext with Triple-DES *
* tripledes_ecb_encrypt(context, plaintext, ciphertext);
*
* * Decrypting ciphertext to recover the plaintext with Triple-DES *
* tripledes_ecb_decrypt(context, ciphertext, recoverd);
*
*
* Selftest
* --------
* char *error_msg;
*
* * To perform a selftest of this DES/Triple-DES implementation use the
* function selftest(). It will return an error string if their are
* some problems with this library. *
*
* if ( (error_msg = selftest()) )
* {
* fprintf(stderr, "An error in the DES/Tripple-DES implementation occured: %s\n", error_msg);
* abort();
* }
*/
#include <config.h>
#include <stdio.h>
#include <string.h> /* memcpy, memcmp */
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "des.h"
#if defined(__GNUC__) && defined(__GNU_LIBRARY__)
#define working_memcmp memcmp
#else
/*
* According to the SunOS man page, memcmp returns indeterminate sign
* depending on whether characters are signed or not.
*/
int
working_memcmp( const char *a, const char *b, size_t n )
{
for( ; n; n--, a++, b++ )
if( *a != *b )
return (int)(*(byte*)a) - (int)(*(byte*)b);
return 0;
}
#endif
/* Some defines/checks to support standalone modules */
#ifndef CIPHER_ALGO_3DES
#define CIPHER_ALGO_3DES 2
#elif CIPHER_ALGO_3DES != 2
#error CIPHER_ALGO_3DES is defined to a wrong value.
#endif
/* Macros used by the info function. */
#define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned))(f))
#define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f))
/*
* Encryption/Decryption context of DES
*/
typedef struct _des_ctx
{
u32 encrypt_subkeys[32];
u32 decrypt_subkeys[32];
}
des_ctx[1];
/*
* Encryption/Decryption context of Triple-DES
*/
typedef struct _tripledes_ctx
{
u32 encrypt_subkeys[96];
u32 decrypt_subkeys[96];
}
tripledes_ctx[1];
static const char *selftest_failed;
static void des_key_schedule (const byte *, u32 *);
static int des_setkey (struct _des_ctx *, const byte *);
static int des_ecb_crypt (struct _des_ctx *, const byte *, byte *, int);
static int tripledes_set2keys (struct _tripledes_ctx *, const byte *, const byte *);
static int tripledes_set3keys (struct _tripledes_ctx *, const byte *, const byte *, const byte *);
static int tripledes_ecb_crypt (struct _tripledes_ctx *, const byte *, byte *, int);
static int is_weak_key ( const byte *key );
static const char *selftest (void);
/*
* The s-box values are permuted according to the 'primitive function P'
* and are rotated one bit to the left.
*/
static u32 sbox1[64] =
{
0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004, 0x00010000,
0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,
0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404,
0x00010004, 0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000,
0x00010000, 0x01010404, 0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400,
0x01010004, 0x00010000, 0x00010400, 0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404,
0x01010404, 0x00010004, 0x01010000, 0x01000404, 0x01000004, 0x00000404, 0x00010404, 0x01010400,
0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004, 0x00010400, 0x00000000, 0x01010004
};
static u32 sbox2[64] =
{
0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020, 0x80008020,
0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,
0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000,
0x00100020, 0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020,
0x00000000, 0x00108020, 0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000,
0x80100000, 0x80008000, 0x00000020, 0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000,
0x00008020, 0x80108000, 0x00100000, 0x80000020, 0x00100020, 0x80008020, 0x80000020, 0x00100020,
0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000, 0x80100020, 0x80108020, 0x00108000
};
static u32 sbox3[64] =
{
0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208, 0x08000200,
0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,
0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208,
0x08000208, 0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000,
0x08020200, 0x08000000, 0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000,
0x00000200, 0x00020008, 0x08020208, 0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008,
0x08000208, 0x00020000, 0x08000000, 0x08020208, 0x00000008, 0x00020208, 0x00020200, 0x08000008,
0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208, 0x00000008, 0x08020008, 0x00020200
};
static u32 sbox4[64] =
{
0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001, 0x00002001,
0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,
0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080,
0x00800081, 0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081,
0x00800080, 0x00800001, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000,
0x00002080, 0x00800080, 0x00800081, 0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080,
0x00802081, 0x00000081, 0x00000001, 0x00002000, 0x00800001, 0x00002001, 0x00802080, 0x00800081,
0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002000, 0x00802080
};
static u32 sbox5[64] =
{
0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000, 0x02080000,
0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,
0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100,
0x42080000, 0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100,
0x00080000, 0x42000100, 0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100,
0x02000100, 0x40000000, 0x42080000, 0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000,
0x42080100, 0x00080100, 0x42000000, 0x42080100, 0x02080000, 0x00000000, 0x40080000, 0x42000000,
0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000, 0x40080000, 0x02080100, 0x40000100
};
static u32 sbox6[64] =
{
0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010, 0x00400000,
0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,
0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010,
0x20400010, 0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000,
0x20004000, 0x00000010, 0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010,
0x00400000, 0x20004000, 0x20000000, 0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000,
0x00404010, 0x20404000, 0x00000000, 0x20400010, 0x00000010, 0x00004000, 0x20400000, 0x00404010,
0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000, 0x20000000, 0x00400010, 0x20004010
};
static u32 sbox7[64] =
{
0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802, 0x04200800,
0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,
0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002,
0x04200000, 0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800,
0x04000000, 0x00200800, 0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002,
0x00200002, 0x04000000, 0x04000800, 0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800,
0x00000802, 0x04000002, 0x04200802, 0x04200000, 0x00200800, 0x00000000, 0x00000002, 0x04200802,
0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002, 0x04000800, 0x00000800, 0x00200002
};
static u32 sbox8[64] =
{
0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040, 0x10000000,
0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,
0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000,
0x00001040, 0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000,
0x00041040, 0x00040000, 0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040,
0x10001000, 0x00000040, 0x10000040, 0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040,
0x00000000, 0x10041040, 0x00040040, 0x10000040, 0x10040000, 0x10001000, 0x10001040, 0x00000000,
0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040, 0x00040040, 0x10000000, 0x10041000
};
/*
* These two tables are part of the 'permuted choice 1' function.
* In this implementation several speed improvements are done.
*/
u32 leftkey_swap[16] =
{
0x00000000, 0x00000001, 0x00000100, 0x00000101,
0x00010000, 0x00010001, 0x00010100, 0x00010101,
0x01000000, 0x01000001, 0x01000100, 0x01000101,
0x01010000, 0x01010001, 0x01010100, 0x01010101
};
u32 rightkey_swap[16] =
{
0x00000000, 0x01000000, 0x00010000, 0x01010000,
0x00000100, 0x01000100, 0x00010100, 0x01010100,
0x00000001, 0x01000001, 0x00010001, 0x01010001,
0x00000101, 0x01000101, 0x00010101, 0x01010101,
};
/*
* Numbers of left shifts per round for encryption subkeys.
* To calculate the decryption subkeys we just reverse the
* ordering of the calculated encryption subkeys. So their
* is no need for a decryption rotate tab.
*/
static byte encrypt_rotate_tab[16] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
/*
* Table with weak DES keys sorted in ascending order.
* In DES their are 64 known keys wich are weak. They are weak
* because they produce only one, two or four different
* subkeys in the subkey scheduling process.
* The keys in this table have all their parity bits cleared.
*/
static byte weak_keys[64][8] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e },
{ 0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0 }, { 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe },
{ 0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e }, { 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00 },
{ 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe }, { 0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0 },
{ 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0 }, { 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe },
{ 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00 }, { 0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e },
{ 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe }, { 0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0 },
{ 0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e }, { 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00 },
{ 0x0e, 0x0e, 0x0e, 0x0e, 0xf0, 0xf0, 0xf0, 0xf0 }, { 0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e },
{ 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00 }, { 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe },
{ 0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0 }, { 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00 },
{ 0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e }, { 0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0 },
{ 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe }, { 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe },
{ 0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0 }, { 0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e },
{ 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00 }, { 0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0 },
{ 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe }, { 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00 },
{ 0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e }, { 0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0 },
{ 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe }, { 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00 },
{ 0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e }, { 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe },
{ 0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0 }, { 0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e },
{ 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00 }, { 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00 },
{ 0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e }, { 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe },
{ 0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e }, { 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00 },
{ 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe }, { 0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0 },
{ 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe }, { 0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0 },
{ 0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e }, { 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00 },
{ 0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0 }, { 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe },
{ 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00 }, { 0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e },
{ 0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e }, { 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00 },
{ 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe }, { 0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0 },
{ 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00 }, { 0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e },
{ 0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0 }, { 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe }
};
/*
* Macro to swap bits across two words.
*/
#define DO_PERMUTATION(a, temp, b, offset, mask) \
temp = ((a>>offset) ^ b) & mask; \
b ^= temp; \
a ^= temp<<offset;
/*
* This performs the 'initial permutation' of the data to be encrypted
* or decrypted. Additionally the resulting two words are rotated one bit
* to the left.
*/
#define INITIAL_PERMUTATION(left, temp, right) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
right = (right << 1) | (right >> 31); \
temp = (left ^ right) & 0xaaaaaaaa; \
right ^= temp; \
left ^= temp; \
left = (left << 1) | (left >> 31);
/*
* The 'inverse initial permutation'.
*/
#define FINAL_PERMUTATION(left, temp, right) \
left = (left << 31) | (left >> 1); \
temp = (left ^ right) & 0xaaaaaaaa; \
left ^= temp; \
right ^= temp; \
right = (right << 31) | (right >> 1); \
DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff) \
DO_PERMUTATION(right, temp, left, 2, 0x33333333) \
DO_PERMUTATION(left, temp, right, 16, 0x0000ffff) \
DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)
/*
* A full DES round including 'expansion function', 'sbox substitution'
* and 'primitive function P' but without swapping the left and right word.
* Please note: The data in 'from' and 'to' is already rotated one bit to
* the left, done in the initial permutation.
*/
#define DES_ROUND(from, to, work, subkey) \
work = from ^ *subkey++; \
to ^= sbox8[ work & 0x3f ]; \
to ^= sbox6[ (work>>8) & 0x3f ]; \
to ^= sbox4[ (work>>16) & 0x3f ]; \
to ^= sbox2[ (work>>24) & 0x3f ]; \
work = ((from << 28) | (from >> 4)) ^ *subkey++; \
to ^= sbox7[ work & 0x3f ]; \
to ^= sbox5[ (work>>8) & 0x3f ]; \
to ^= sbox3[ (work>>16) & 0x3f ]; \
to ^= sbox1[ (work>>24) & 0x3f ];
/*
* Macros to convert 8 bytes from/to 32bit words.
*/
#define READ_64BIT_DATA(data, left, right) \
left = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; \
right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
#define WRITE_64BIT_DATA(data, left, right) \
data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff; \
data[2] = (left >> 8) &0xff; data[3] = left &0xff; \
data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff; \
data[6] = (right >> 8) &0xff; data[7] = right &0xff;
/*
* Handy macros for encryption and decryption of data
*/
#define des_ecb_encrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 0)
#define des_ecb_decrypt(ctx, from, to) des_ecb_crypt(ctx, from, to, 1)
#define tripledes_ecb_encrypt(ctx, from, to) tripledes_ecb_crypt(ctx, from, to, 0)
#define tripledes_ecb_decrypt(ctx, from, to) tripledes_ecb_crypt(ctx, from, to, 1)
/*
* des_key_schedule(): Calculate 16 subkeys pairs (even/odd) for
* 16 encryption rounds.
* To calculate subkeys for decryption the caller
* have to reorder the generated subkeys.
*
* rawkey: 8 Bytes of key data
* subkey: Array of at least 32 u32s. Will be filled
* with calculated subkeys.
*
*/
static void
des_key_schedule (const byte * rawkey, u32 * subkey)
{
u32 left, right, work;
int round;
READ_64BIT_DATA (rawkey, left, right)
DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
DO_PERMUTATION (right, work, left, 0, 0x10101010)
left = (leftkey_swap[(left >> 0) & 0xf] << 3) | (leftkey_swap[(left >> 8) & 0xf] << 2)
| (leftkey_swap[(left >> 16) & 0xf] << 1) | (leftkey_swap[(left >> 24) & 0xf])
| (leftkey_swap[(left >> 5) & 0xf] << 7) | (leftkey_swap[(left >> 13) & 0xf] << 6)
| (leftkey_swap[(left >> 21) & 0xf] << 5) | (leftkey_swap[(left >> 29) & 0xf] << 4);
left &= 0x0fffffff;
right = (rightkey_swap[(right >> 1) & 0xf] << 3) | (rightkey_swap[(right >> 9) & 0xf] << 2)
| (rightkey_swap[(right >> 17) & 0xf] << 1) | (rightkey_swap[(right >> 25) & 0xf])
| (rightkey_swap[(right >> 4) & 0xf] << 7) | (rightkey_swap[(right >> 12) & 0xf] << 6)
| (rightkey_swap[(right >> 20) & 0xf] << 5) | (rightkey_swap[(right >> 28) & 0xf] << 4);
right &= 0x0fffffff;
for (round = 0; round < 16; ++round)
{
left = ((left << encrypt_rotate_tab[round]) | (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
right = ((right << encrypt_rotate_tab[round]) | (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
*subkey++ = ((left << 4) & 0x24000000)
| ((left << 28) & 0x10000000)
| ((left << 14) & 0x08000000)
| ((left << 18) & 0x02080000)
| ((left << 6) & 0x01000000)
| ((left << 9) & 0x00200000)
| ((left >> 1) & 0x00100000)
| ((left << 10) & 0x00040000)
| ((left << 2) & 0x00020000)
| ((left >> 10) & 0x00010000)
| ((right >> 13) & 0x00002000)
| ((right >> 4) & 0x00001000)
| ((right << 6) & 0x00000800)
| ((right >> 1) & 0x00000400)
| ((right >> 14) & 0x00000200)
| (right & 0x00000100)
| ((right >> 5) & 0x00000020)
| ((right >> 10) & 0x00000010)
| ((right >> 3) & 0x00000008)
| ((right >> 18) & 0x00000004)
| ((right >> 26) & 0x00000002)
| ((right >> 24) & 0x00000001);
*subkey++ = ((left << 15) & 0x20000000)
| ((left << 17) & 0x10000000)
| ((left << 10) & 0x08000000)
| ((left << 22) & 0x04000000)
| ((left >> 2) & 0x02000000)
| ((left << 1) & 0x01000000)
| ((left << 16) & 0x00200000)
| ((left << 11) & 0x00100000)
| ((left << 3) & 0x00080000)
| ((left >> 6) & 0x00040000)
| ((left << 15) & 0x00020000)
| ((left >> 4) & 0x00010000)
| ((right >> 2) & 0x00002000)
| ((right << 8) & 0x00001000)
| ((right >> 14) & 0x00000808)
| ((right >> 9) & 0x00000400)
| ((right) & 0x00000200)
| ((right << 7) & 0x00000100)
| ((right >> 7) & 0x00000020)
| ((right >> 3) & 0x00000011)
| ((right << 2) & 0x00000004)
| ((right >> 21) & 0x00000002);
}
}
/*
* Fill a DES context with subkeys calculated from a 64bit key.
* Does not check parity bits, but simply ignore them.
* Does not check for weak keys.
*/
static int
des_setkey (struct _des_ctx *ctx, const byte * key)
{
int i;
if( selftest_failed )
return GCRYERR_SELFTEST;
des_key_schedule (key, ctx->encrypt_subkeys);
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
}
return 0;
}
/*
* Electronic Codebook Mode DES encryption/decryption of data according
* to 'mode'.
*/
static int
des_ecb_crypt (struct _des_ctx *ctx, const byte * from, byte * to, int mode)
{
u32 left, right, work;
u32 *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left)
WRITE_64BIT_DATA (to, right, left)
return 0;
}
/*
* Fill a Triple-DES context with subkeys calculated from two 64bit keys.
* Does not check the parity bits of the keys, but simply ignore them.
* Does not check for weak keys.
*/
static int
tripledes_set2keys (struct _tripledes_ctx *ctx,
const byte * key1,
const byte * key2)
{
int i;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[31-i];
ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i];
ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i];
ctx->encrypt_subkeys[i+64] = ctx->encrypt_subkeys[i];
ctx->encrypt_subkeys[i+65] = ctx->encrypt_subkeys[i+1];
ctx->decrypt_subkeys[i+64] = ctx->decrypt_subkeys[i];
ctx->decrypt_subkeys[i+65] = ctx->decrypt_subkeys[i+1];
}
return 0;
}
/*
* Fill a Triple-DES context with subkeys calculated from three 64bit keys.
* Does not check the parity bits of the keys, but simply ignore them.
* Does not check for weak keys.
*/
static int
tripledes_set3keys (struct _tripledes_ctx *ctx,
const byte * key1,
const byte * key2,
const byte * key3)
{
int i;
des_key_schedule (key1, ctx->encrypt_subkeys);
des_key_schedule (key2, &(ctx->decrypt_subkeys[32]));
des_key_schedule (key3, &(ctx->encrypt_subkeys[64]));
for(i=0; i<32; i+=2)
{
ctx->decrypt_subkeys[i] = ctx->encrypt_subkeys[94-i];
ctx->decrypt_subkeys[i+1] = ctx->encrypt_subkeys[95-i];
ctx->encrypt_subkeys[i+32] = ctx->decrypt_subkeys[62-i];
ctx->encrypt_subkeys[i+33] = ctx->decrypt_subkeys[63-i];
ctx->decrypt_subkeys[i+64] = ctx->encrypt_subkeys[30-i];
ctx->decrypt_subkeys[i+65] = ctx->encrypt_subkeys[31-i];
}
return 0;
}
/*
* Electronic Codebook Mode Triple-DES encryption/decryption of data according to 'mode'.
* Sometimes this mode is named 'EDE' mode (Encryption-Decryption-Encryption).
*/
static int
tripledes_ecb_crypt (struct _tripledes_ctx *ctx, const byte * from, byte * to, int mode)
{
u32 left, right, work;
u32 *keys;
keys = mode ? ctx->decrypt_subkeys : ctx->encrypt_subkeys;
READ_64BIT_DATA (from, left, right)
INITIAL_PERMUTATION (left, work, right)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (left, right, work, keys) DES_ROUND (right, left, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
FINAL_PERMUTATION (right, work, left)
WRITE_64BIT_DATA (to, right, left)
return 0;
}
/*
* Check whether the 8 byte key is weak.
* Dose not check the parity bits of the key but simple ignore them.
*/
static int
is_weak_key ( const byte *key )
{
byte work[8];
int i, left, right, middle, cmp_result;
/* clear parity bits */
for(i=0; i<8; ++i)
work[i] = key[i] & 0xfe;
/* binary search in the weak key table */
left = 0;
right = 63;
while(left <= right)
{
middle = (left + right) / 2;
if ( !(cmp_result=working_memcmp(work, weak_keys[middle], 8)) )
return -1;
if ( cmp_result > 0 )
left = middle + 1;
else
right = middle - 1;
}
return 0;
}
/*
* Performs a selftest of this DES/Triple-DES implementation.
* Returns an string with the error text on failure.
* Returns NULL if all is ok.
*/
static const char *
selftest (void)
{
/*
* Check if 'u32' is really 32 bits wide. This DES / 3DES implementation
* need this.
*/
if (sizeof (u32) != 4)
return "Wrong word size for DES configured.";
/*
* DES Maintenance Test
*/
{
int i;
byte key[8] =
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
byte input[8] =
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
byte result[8] =
{0x24, 0x6e, 0x9d, 0xb9, 0xc5, 0x50, 0x38, 0x1a};
byte temp1[8], temp2[8], temp3[8];
des_ctx des;
for (i = 0; i < 64; ++i)
{
des_setkey (des, key);
des_ecb_encrypt (des, input, temp1);
des_ecb_encrypt (des, temp1, temp2);
des_setkey (des, temp2);
des_ecb_decrypt (des, temp1, temp3);
memcpy (key, temp3, 8);
memcpy (input, temp1, 8);
}
if (memcmp (temp3, result, 8))
return "DES maintenance test failed.";
}
/*
* Self made Triple-DES test (Does somebody known an official test?)
*/
{
int i;
byte input[8] =
{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
byte key1[8] =
{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
byte key2[8] =
{0x11, 0x22, 0x33, 0x44, 0xff, 0xaa, 0xcc, 0xdd};
byte result[8] =
{0x7b, 0x38, 0x3b, 0x23, 0xa2, 0x7d, 0x26, 0xd3};
tripledes_ctx des3;
for (i = 0; i < 16; ++i)
{
tripledes_set2keys (des3, key1, key2);
tripledes_ecb_encrypt (des3, input, key1);
tripledes_ecb_decrypt (des3, input, key2);
tripledes_set3keys (des3, key1, input, key2);
tripledes_ecb_encrypt (des3, input, input);
}
if (memcmp (input, result, 8))
return "Triple-DES test failed.";
}
/*
* More Triple-DES test. These are testvectors as used by SSLeay,
* thanks to Jeroen C. van Gelderen.
*/
{ struct { byte key[24]; byte plain[8]; byte cipher[8]; } testdata[] = {
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
{ 0x95,0xF8,0xA5,0xE5,0xDD,0x31,0xD9,0x00 },
{ 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
},
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 },
{ 0x9D,0x64,0x55,0x5A,0x9A,0x10,0xB8,0x52, },
{ 0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00 }
},
{ { 0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E,
0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E,
0x38,0x49,0x67,0x4C,0x26,0x02,0x31,0x9E },
{ 0x51,0x45,0x4B,0x58,0x2D,0xDF,0x44,0x0A },
{ 0x71,0x78,0x87,0x6E,0x01,0xF1,0x9B,0x2A }
},
{ { 0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6,
0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6,
0x04,0xB9,0x15,0xBA,0x43,0xFE,0xB5,0xB6 },
{ 0x42,0xFD,0x44,0x30,0x59,0x57,0x7F,0xA2 },
{ 0xAF,0x37,0xFB,0x42,0x1F,0x8C,0x40,0x95 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0x3D,0x12,0x4F,0xE2,0x19,0x8B,0xA3,0x18 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0xFB,0xAB,0xA1,0xFF,0x9D,0x05,0xE9,0xB1 }
},
{ { 0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,
0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
0xFE,0xDC,0xBA,0x98,0x76,0x54,0x32,0x10 },
{ 0x73,0x6F,0x6D,0x65,0x64,0x61,0x74,0x61 },
{ 0x18,0xd7,0x48,0xe5,0x63,0x62,0x05,0x72 }
},
{ { 0x03,0x52,0x02,0x07,0x67,0x20,0x82,0x17,
0x86,0x02,0x87,0x66,0x59,0x08,0x21,0x98,
0x64,0x05,0x6A,0xBD,0xFE,0xA9,0x34,0x57 },
{ 0x73,0x71,0x75,0x69,0x67,0x67,0x6C,0x65 },
{ 0xc0,0x7d,0x2a,0x0f,0xa5,0x66,0xfa,0x30 }
},
{ { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x80,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0xe6,0xe6,0xdd,0x5b,0x7e,0x72,0x29,0x74 }
},
{ { 0x10,0x46,0x10,0x34,0x89,0x98,0x80,0x20,
0x91,0x07,0xD0,0x15,0x89,0x19,0x01,0x01,
0x19,0x07,0x92,0x10,0x98,0x1A,0x01,0x01 },
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
{ 0xe1,0xef,0x62,0xc3,0x32,0xfe,0x82,0x5b }
}
};
byte result[8];
int i;
static char error[80];
tripledes_ctx des3;
for (i=0; i<sizeof(testdata)/sizeof(*testdata); ++i) {
tripledes_set3keys (des3, testdata[i].key, testdata[i].key + 8, testdata[i].key + 16);
tripledes_ecb_encrypt (des3, testdata[i].plain, result);
if (memcmp (testdata[i].cipher, result, 8)) {
sprintf (error, "Triple-DES SSLeay test pattern no. %d failend on encryption.", i+1);
return error;
}
tripledes_ecb_decrypt (des3, testdata[i].cipher, result);
if (memcmp (testdata[i].plain, result, 8)) {
sprintf (error, "Triple-DES SSLeay test pattern no. %d failend on decryption.", i+1);
return error;
}
}
}
/*
* Check the weak key detection. We simply assume that the table
* with weak keys is ok and check every key in the table if it is
* detected... (This test is a little bit stupid)
*/
{
int i;
for (i = 0; i < 64; ++i)
if (!is_weak_key(weak_keys[i]))
return "DES weak key detection failed";
}
return 0;
}
static int
do_tripledes_setkey ( struct _tripledes_ctx *ctx, byte *key, unsigned keylen )
{
if( selftest_failed )
return GCRYERR_SELFTEST;
if( keylen != 24 )
return GCRYERR_INV_KEYLEN;
tripledes_set3keys ( ctx, key, key+8, key+16);
if( is_weak_key( key ) || is_weak_key( key+8 ) || is_weak_key( key+16 ) )
return GCRYERR_WEAK_KEY;
return 0;
}
static void
do_tripledes_encrypt( struct _tripledes_ctx *ctx, byte *outbuf, byte *inbuf )
{
tripledes_ecb_encrypt ( ctx, inbuf, outbuf );
}
static void
do_tripledes_decrypt( struct _tripledes_ctx *ctx, byte *outbuf, byte *inbuf )
{
tripledes_ecb_decrypt ( ctx, inbuf, outbuf );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
const char *
des_get_info( int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey)( void *c, byte *key, unsigned keylen ),
void (**r_encrypt)( void *c, byte *outbuf, byte *inbuf ),
void (**r_decrypt)( void *c, byte *outbuf, byte *inbuf )
)
{
static int did_selftest = 0;
if( !did_selftest ) {
const char *s = selftest();
did_selftest = 1;
if( s ) {
fprintf(stderr,"%s\n", s );
selftest_failed = s;
return NULL;
}
}
if( algo == CIPHER_ALGO_3DES ) {
*keylen = 192;
*blocksize = 8;
*contextsize = sizeof(struct _tripledes_ctx);
- *r_setkey = FNCCAST_SETKEY(do_tripledes_setkey);
- *r_encrypt= FNCCAST_CRYPT(do_tripledes_encrypt);
- *r_decrypt= FNCCAST_CRYPT(do_tripledes_decrypt);
+ *(int (**)(struct _tripledes_ctx*, byte*, unsigned))r_setkey
+ = do_tripledes_setkey;
+ *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_encrypt
+ = do_tripledes_encrypt;
+ *(void (**)(struct _tripledes_ctx*, byte*, byte*))r_decrypt
+ = do_tripledes_decrypt;
return "3DES";
}
return NULL;
}
diff --git a/cipher/dsa.c b/cipher/dsa.c
index 1f132ae0..255fa372 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -1,460 +1,475 @@
/* dsa.c - DSA signature scheme
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "dsa.h"
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} DSA_public_key;
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
} DSA_secret_key;
static MPI gen_k( MPI q );
static void test_keys( DSA_secret_key *sk, unsigned qbits );
static int check_secret_key( DSA_secret_key *sk );
static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
+
/****************
* Generate a random secret exponent k less than q
*/
static MPI
gen_k( MPI q )
{
MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
unsigned int nbits = mpi_get_nbits(q);
unsigned int nbytes = (nbits+7)/8;
char *rndbuf = NULL;
if( DBG_CIPHER )
log_debug("choosing a random k ");
for(;;) {
if( DBG_CIPHER )
progress('.');
if( !rndbuf || nbits < 32 ) {
g10_free(rndbuf);
rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
GCRY_STRONG_RANDOM );
}
else { /* change only some of the higher bits */
/* we could imporove this by directly requesting more memory
* at the first call to get_random_bytes() and use this the here
* maybe it is easier to do this directly in random.c */
char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
memcpy( rndbuf,pp, 4 );
g10_free(pp);
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
if( mpi_test_bit( k, nbits-1 ) )
mpi_set_highbit( k, nbits-1 );
else {
mpi_set_highbit( k, nbits-1 );
mpi_clear_bit( k, nbits-1 );
}
if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */
if( DBG_CIPHER )
progress('+');
continue; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
if( DBG_CIPHER )
progress('-');
continue; /* no */
}
break; /* okay */
}
g10_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
return k;
}
static void
test_keys( DSA_secret_key *sk, unsigned qbits )
{
DSA_public_key pk;
MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
pk.p = sk->p;
pk.q = sk->q;
pk.g = sk->g;
pk.y = sk->y;
gcry_mpi_randomize( test, qbits, GCRY_WEAK_RANDOM );
sign( out1_a, out1_b, test, sk );
if( !verify( out1_a, out1_b, test, &pk ) )
log_fatal("DSA:: sign, verify failed\n");
mpi_free( test );
mpi_free( out1_a );
mpi_free( out1_b );
}
/****************
* Generate a DSA key pair with a key of size NBITS
* Returns: 2 structures filled with all needed values
* and an array with the n-1 factors of (p-1)
*/
static void
generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI q; /* the 160 bit prime factor */
MPI g; /* the generator */
MPI y; /* g^x mod p */
MPI x; /* the secret exponent */
MPI h, e; /* helper */
unsigned qbits;
byte *rndbuf;
assert( nbits >= 512 && nbits <= 1024 );
qbits = 160;
p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
/* get q out of factors */
q = mpi_copy((*ret_factors)[0]);
if( mpi_get_nbits(q) != qbits )
BUG();
/* find a generator g (h and e are helpers)*/
/* e = (p-1)/q */
e = mpi_alloc( mpi_get_nlimbs(p) );
mpi_sub_ui( e, p, 1 );
mpi_fdiv_q( e, e, q );
g = mpi_alloc( mpi_get_nlimbs(p) );
h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
do {
mpi_add_ui( h, h, 1 );
/* g = h^e mod p */
gcry_mpi_powm( g, h, e, p );
} while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */
/* select a random number which has these properties:
* 0 < x < q-1
* This must be a very good random number because this
* is the secret part. */
if( DBG_CIPHER )
log_debug("choosing a random x ");
assert( qbits >= 160 );
x = mpi_alloc_secure( mpi_get_nlimbs(q) );
mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( !rndbuf )
rndbuf = gcry_random_bytes_secure( (qbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
else { /* change only some of the higher bits (= 2 bytes)*/
char *r = gcry_random_bytes_secure( 2,
GCRY_VERY_STRONG_RANDOM );
memcpy(rndbuf, r, 2 );
g10_free(r);
}
mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
mpi_clear_highbit( x, qbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
g10_free(rndbuf);
mpi_free( e );
mpi_free( h );
/* y = g^x mod p */
y = mpi_alloc( mpi_get_nlimbs(p) );
gcry_mpi_powm( y, g, x, p );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump("dsa p= ", p );
log_mpidump("dsa q= ", q );
log_mpidump("dsa g= ", g );
log_mpidump("dsa y= ", y );
log_mpidump("dsa x= ", x );
}
/* copy the stuff to the key structures */
sk->p = p;
sk->q = q;
sk->g = g;
sk->y = y;
sk->x = x;
/* now we can test our keys (this should never fail!) */
test_keys( sk, qbits );
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( DSA_secret_key *sk )
{
int rc;
MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
gcry_mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
/****************
* Make a DSA signature from HASH and put it into r and s.
*/
static void
sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
{
MPI k;
MPI kinv;
MPI tmp;
/* select a random k with 0 < k < q */
k = gen_k( skey->q );
/* r = (a^k mod p) mod q */
gcry_mpi_powm( r, skey->g, k, skey->p );
mpi_fdiv_r( r, r, skey->q );
/* kinv = k^(-1) mod q */
kinv = mpi_alloc( mpi_get_nlimbs(k) );
mpi_invm(kinv, k, skey->q );
/* s = (kinv * ( hash + x * r)) mod q */
tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
mpi_mul( tmp, skey->x, r );
mpi_add( tmp, tmp, hash );
mpi_mulm( s , kinv, tmp, skey->q );
mpi_free(k);
mpi_free(kinv);
mpi_free(tmp);
}
/****************
* Returns true if the signature composed from R and S is valid.
*/
static int
verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
{
int rc;
MPI w, u1, u2, v;
MPI base[3];
MPI exp[3];
if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
return 0; /* assertion 0 < r < q failed */
if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
return 0; /* assertion 0 < s < q failed */
w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
/* w = s^(-1) mod q */
mpi_invm( w, s, pkey->q );
/* u1 = (hash * w) mod q */
mpi_mulm( u1, hash, w, pkey->q );
/* u2 = r * w mod q */
mpi_mulm( u2, r, w, pkey->q );
/* v = g^u1 * y^u2 mod p mod q */
base[0] = pkey->g; exp[0] = u1;
base[1] = pkey->y; exp[1] = u2;
base[2] = NULL; exp[2] = NULL;
mpi_mulpowm( v, base, exp, pkey->p );
mpi_fdiv_r( v, v, pkey->q );
rc = !mpi_cmp( v, r );
mpi_free(w);
mpi_free(u1);
mpi_free(u2);
mpi_free(v);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
int
dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return GCRYERR_INV_PK_ALGO;
generate( &sk, nbits, retfactors );
skey[0] = sk.p;
skey[1] = sk.q;
skey[2] = sk.g;
skey[3] = sk.y;
skey[4] = sk.x;
return 0;
}
int
dsa_check_secret_key( int algo, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return GCRYERR_INV_PK_ALGO;
if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return GCRYERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
if( !check_secret_key( &sk ) )
return GCRYERR_BAD_SECRET_KEY;
return 0;
}
int
dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return GCRYERR_INV_PK_ALGO;
if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return GCRYERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
sign( resarr[0], resarr[1], data, &sk );
return 0;
}
int
dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev )
{
DSA_public_key pk;
if( algo != PUBKEY_ALGO_DSA )
return GCRYERR_INV_PK_ALGO;
if( !data[0] || !data[1] || !hash
|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
return GCRYERR_BAD_MPI;
pk.p = pkey[0];
pk.q = pkey[1];
pk.g = pkey[2];
pk.y = pkey[3];
if( !verify( data[0], data[1], hash, &pk ) )
return GCRYERR_BAD_SIGNATURE;
return 0;
}
unsigned
dsa_get_nbits( int algo, MPI *pkey )
{
if( algo != PUBKEY_ALGO_DSA )
return 0;
return mpi_get_nbits( pkey[0] );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
* Usage: Bit 0 set : allows signing
* 1 set : allows encryption
*/
const char *
dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
int *use )
{
*npkey = 4;
*nskey = 5;
*nenc = 0;
*nsig = 2;
switch( algo ) {
case PUBKEY_ALGO_DSA: *use = GCRY_PK_USAGE_SIGN; return "DSA";
default: *use = 0; return NULL;
}
}
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 02995e02..f2c029b3 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -1,600 +1,661 @@
/* elgamal.c - ElGamal Public Key encryption
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 476 ff.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "elgamal.h"
typedef struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} ELG_public_key;
typedef struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
} ELG_secret_key;
static void test_keys( ELG_secret_key *sk, unsigned nbits );
static MPI gen_k( MPI p );
static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors );
static int check_secret_key( ELG_secret_key *sk );
static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey );
static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey );
static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
+/****************
+ * Michael Wiener's table on subgroup sizes to match field sizes
+ * (floating around somewhere - Fixme: need a reference)
+ */
+static unsigned int
+wiener_map( unsigned int n )
+{
+ static struct { unsigned int p_n, q_n; } t[] =
+ { /* p q attack cost */
+ { 512, 119 }, /* 9 x 10^17 */
+ { 768, 145 }, /* 6 x 10^21 */
+ { 1024, 165 }, /* 7 x 10^24 */
+ { 1280, 183 }, /* 3 x 10^27 */
+ { 1536, 198 }, /* 7 x 10^29 */
+ { 1792, 212 }, /* 9 x 10^31 */
+ { 2048, 225 }, /* 8 x 10^33 */
+ { 2304, 237 }, /* 5 x 10^35 */
+ { 2560, 249 }, /* 3 x 10^37 */
+ { 2816, 259 }, /* 1 x 10^39 */
+ { 3072, 269 }, /* 3 x 10^40 */
+ { 3328, 279 }, /* 8 x 10^41 */
+ { 3584, 288 }, /* 2 x 10^43 */
+ { 3840, 296 }, /* 4 x 10^44 */
+ { 4096, 305 }, /* 7 x 10^45 */
+ { 4352, 313 }, /* 1 x 10^47 */
+ { 4608, 320 }, /* 2 x 10^48 */
+ { 4864, 328 }, /* 2 x 10^49 */
+ { 5120, 335 }, /* 3 x 10^50 */
+ { 0, 0 }
+ };
+ int i;
+
+ for(i=0; t[i].p_n; i++ ) {
+ if( n <= t[i].p_n )
+ return t[i].q_n;
+ }
+ /* not in table - use some arbitrary high number ;-) */
+ return n / 8 + 200;
+}
+
static void
test_keys( ELG_secret_key *sk, unsigned nbits )
{
ELG_public_key pk;
MPI test = mpi_alloc( 0 );
MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
pk.p = sk->p;
pk.g = sk->g;
pk.y = sk->y;
gcry_mpi_randomize( test, nbits, GCRY_WEAK_RANDOM );
encrypt( out1_a, out1_b, test, &pk );
decrypt( out2, out1_a, out1_b, sk );
if( mpi_cmp( test, out2 ) )
log_fatal("ElGamal operation: encrypt, decrypt failed\n");
sign( out1_a, out1_b, test, sk );
if( !verify( out1_a, out1_b, test, &pk ) )
log_fatal("ElGamal operation: sign, verify failed\n");
mpi_free( test );
mpi_free( out1_a );
mpi_free( out1_b );
mpi_free( out2 );
}
/****************
* generate a random secret exponent k from prime p, so
* that k is relatively prime to p-1
*/
static MPI
gen_k( MPI p )
{
MPI k = mpi_alloc_secure( 0 );
MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
MPI p_1 = mpi_copy(p);
- unsigned int nbits = mpi_get_nbits(p);
- unsigned int nbytes = (nbits+7)/8;
+ unsigned int orig_nbits = mpi_get_nbits(p);
+ unsigned int nbits, nbytes;
char *rndbuf = NULL;
+ /* IMO using a k much lesser than p is sufficient and it greatly
+ * improves the encryption performance. We use Wiener's table
+ * and add a large safety margin.
+ */
+ nbits = wiener_map( orig_nbits ) * 3 / 2;
+ if( nbits >= orig_nbits )
+ BUG();
+
+ nbytes = (nbits+7)/8;
if( DBG_CIPHER )
log_debug("choosing a random k ");
mpi_sub_ui( p_1, p, 1);
for(;;) {
- if( DBG_CIPHER )
- progress('.');
if( !rndbuf || nbits < 32 ) {
g10_free(rndbuf);
rndbuf = gcry_random_bytes_secure( nbytes, GCRY_STRONG_RANDOM );
}
else { /* change only some of the higher bits */
- /* we could imporove this by directly requesting more memory
+ /* we could improve this by directly requesting more memory
* at the first call to get_random_bytes() and use this the here
- * maybe it is easier to do this directly in random.c */
+ * maybe it is easier to do this directly in random.c
+ * Anyway, it is highly inlikely that we will ever reach this code
+ */
char *pp = gcry_random_bytes_secure( 4, GCRY_STRONG_RANDOM );
memcpy( rndbuf, pp, 4 );
g10_free(pp);
+ log_debug("gen_k: tsss, never expected to reach this\n");
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
for(;;) {
- /* make sure that the number is of the exact lenght */
- if( mpi_test_bit( k, nbits-1 ) )
- mpi_set_highbit( k, nbits-1 );
- else {
- mpi_set_highbit( k, nbits-1 );
- mpi_clear_bit( k, nbits-1 );
- }
+ /* Hmm, actually we don't need this step here
+ * because we use k much smaller than p - we do it anyway
+ * just in case the keep on adding a one to k ;) */
if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */
if( DBG_CIPHER )
progress('+');
break; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
if( DBG_CIPHER )
progress('-');
break; /* no */
}
if( mpi_gcd( temp, k, p_1 ) )
goto found; /* okay, k is relatively prime to (p-1) */
mpi_add_ui( k, k, 1 );
+ if( DBG_CIPHER )
+ progress('.');
}
}
found:
g10_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
mpi_free(p_1);
mpi_free(temp);
return k;
}
/****************
* Generate a key pair with a key of size NBITS
* Returns: 2 structures filles with all needed values
* and an array with n-1 factors of (p-1)
*/
static void
-generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
+generate( ELG_secret_key *sk, unsigned int nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI p_min1;
MPI g;
MPI x; /* the secret exponent */
MPI y;
MPI temp;
- unsigned qbits;
+ unsigned int qbits;
+ unsigned int xbits;
byte *rndbuf;
p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
- if( nbits < 512 )
- qbits = 120;
- else if( nbits <= 1024 )
- qbits = 160;
- else if( nbits <= 2048 )
- qbits = 200;
- else
- qbits = 240;
+ qbits = wiener_map( nbits );
+ if( qbits & 1 ) /* better have a even one */
+ qbits++;
g = mpi_alloc(1);
p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
mpi_sub_ui(p_min1, p, 1);
/* select a random number which has these properties:
* 0 < x < p-1
* This must be a very good random number because this is the
* secret part. The prime is public and may be shared anyway,
* so a random generator level of 1 is used for the prime.
+ *
+ * I don't see a reason to have a x of about the same size
+ * as the p. It should be sufficient to have one about the size
+ * of q or the later used k plus a large safety margin. Decryption
+ * will be much faster with such an x.
*/
- x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
+ xbits = qbits * 3 / 2;
+ if( xbits >= nbits )
+ BUG();
+ x = mpi_alloc_secure( xbits/BITS_PER_MPI_LIMB );
if( DBG_CIPHER )
- log_debug("choosing a random x ");
+ log_debug("choosing a random x of size %u", xbits );
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( rndbuf ) { /* change only some of the higher bits */
- if( nbits < 16 ) {/* should never happen ... */
+ if( xbits < 16 ) {/* should never happen ... */
g10_free(rndbuf);
- rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+ rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
else {
char *r = gcry_random_bytes_secure( 2,
GCRY_VERY_STRONG_RANDOM );
memcpy(rndbuf, r, 2 );
g10_free(r);
}
}
else {
- rndbuf = gcry_random_bytes_secure( (nbits+7)/8,
+ rndbuf = gcry_random_bytes_secure( (xbits+7)/8,
GCRY_VERY_STRONG_RANDOM );
}
- mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
- mpi_clear_highbit( x, nbits+1 );
+ mpi_set_buffer( x, rndbuf, (xbits+7)/8, 0 );
+ mpi_clear_highbit( x, xbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
g10_free(rndbuf);
y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
gcry_mpi_powm( y, g, x, p );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump("elg p= ", p );
log_mpidump("elg g= ", g );
log_mpidump("elg y= ", y );
log_mpidump("elg x= ", x );
}
/* copy the stuff to the key structures */
sk->p = p;
sk->g = g;
sk->y = y;
sk->x = x;
/* now we can test our keys (this should never fail!) */
test_keys( sk, nbits - 64 );
mpi_free( p_min1 );
mpi_free( temp );
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( ELG_secret_key *sk )
{
int rc;
MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
gcry_mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
static void
encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey )
{
MPI k;
/* Note: maybe we should change the interface, so that it
* is possible to check that input is < p and return an
* error code.
*/
k = gen_k( pkey->p );
gcry_mpi_powm( a, pkey->g, k, pkey->p );
/* b = (y^k * input) mod p
* = ((y^k mod p) * (input mod p)) mod p
* and because input is < p
* = ((y^k mod p) * input) mod p
*/
gcry_mpi_powm( b, pkey->y, k, pkey->p );
mpi_mulm( b, b, input, pkey->p );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg encrypted y= ", pkey->y);
log_mpidump("elg encrypted p= ", pkey->p);
log_mpidump("elg encrypted k= ", k);
log_mpidump("elg encrypted M= ", input);
log_mpidump("elg encrypted a= ", a);
log_mpidump("elg encrypted b= ", b);
}
#endif
mpi_free(k);
}
static void
decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
{
MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
/* output = b/(a^x) mod p */
-
gcry_mpi_powm( t1, a, skey->x, skey->p );
mpi_invm( t1, t1, skey->p );
mpi_mulm( output, b, t1, skey->p );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg decrypted x= ", skey->x);
log_mpidump("elg decrypted p= ", skey->p);
log_mpidump("elg decrypted a= ", a);
log_mpidump("elg decrypted b= ", b);
log_mpidump("elg decrypted M= ", output);
}
#endif
mpi_free(t1);
}
/****************
* Make an Elgamal signature out of INPUT
*/
static void
sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
{
MPI k;
MPI t = mpi_alloc( mpi_get_nlimbs(a) );
MPI inv = mpi_alloc( mpi_get_nlimbs(a) );
MPI p_1 = mpi_copy(skey->p);
/*
* b = (t * inv) mod (p-1)
* b = (t * inv(k,(p-1),(p-1)) mod (p-1)
* b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
*
*/
mpi_sub_ui(p_1, p_1, 1);
k = gen_k( skey->p );
gcry_mpi_powm( a, skey->g, k, skey->p );
mpi_mul(t, skey->x, a );
mpi_subm(t, input, t, p_1 );
- while( mpi_is_neg(t) ) {
- BUG(); /* That is nonsense code - left over from a very early test?*/
- mpi_add(t, t, p_1);
- }
mpi_invm(inv, k, p_1 );
mpi_mulm(b, t, inv, p_1 );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg sign p= ", skey->p);
log_mpidump("elg sign g= ", skey->g);
log_mpidump("elg sign y= ", skey->y);
log_mpidump("elg sign x= ", skey->x);
log_mpidump("elg sign k= ", k);
log_mpidump("elg sign M= ", input);
log_mpidump("elg sign a= ", a);
log_mpidump("elg sign b= ", b);
}
#endif
mpi_free(k);
mpi_free(t);
mpi_free(inv);
mpi_free(p_1);
}
/****************
* Returns true if the signature composed of A and B is valid.
*/
static int
verify(MPI a, MPI b, MPI input, ELG_public_key *pkey )
{
int rc;
MPI t1;
MPI t2;
MPI base[4];
MPI exp[4];
if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
return 0; /* assertion 0 < a < p failed */
t1 = mpi_alloc( mpi_get_nlimbs(a) );
t2 = mpi_alloc( mpi_get_nlimbs(a) );
#if 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
gcry_mpi_powm( t1, pkey->y, a, pkey->p );
gcry_mpi_powm( t2, a, b, pkey->p );
mpi_mulm( t1, t1, t2, pkey->p );
/* t2 = g ^ input mod p */
gcry_mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#elif 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
base[0] = pkey->y; exp[0] = a;
base[1] = a; exp[1] = b;
base[2] = NULL; exp[2] = NULL;
mpi_mulpowm( t1, base, exp, pkey->p );
/* t2 = g ^ input mod p */
gcry_mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#else
/* t1 = g ^ - input * y ^ a * a ^ b mod p */
mpi_invm(t2, pkey->g, pkey->p );
base[0] = t2 ; exp[0] = input;
base[1] = pkey->y; exp[1] = a;
base[2] = a; exp[2] = b;
base[3] = NULL; exp[3] = NULL;
mpi_mulpowm( t1, base, exp, pkey->p );
rc = !mpi_cmp_ui( t1, 1 );
#endif
mpi_free(t1);
mpi_free(t2);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
int
elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
generate( &sk, nbits, retfactors );
skey[0] = sk.p;
skey[1] = sk.g;
skey[2] = sk.y;
skey[3] = sk.x;
return 0;
}
int
elg_check_secret_key( int algo, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
if( !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return GCRYERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
if( !check_secret_key( &sk ) )
return GCRYERR_BAD_SECRET_KEY;
return 0;
}
int
elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{
ELG_public_key pk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
if( !data || !pkey[0] || !pkey[1] || !pkey[2] )
return GCRYERR_BAD_MPI;
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
encrypt( resarr[0], resarr[1], data, &pk );
return 0;
}
int
elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
if( !data[0] || !data[1]
|| !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return GCRYERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
*result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
decrypt( *result, data[0], data[1], &sk );
return 0;
}
int
elg_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return GCRYERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
sign( resarr[0], resarr[1], data, &sk );
return 0;
}
int
elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev )
{
ELG_public_key pk;
if( !is_ELGAMAL(algo) )
return GCRYERR_INV_PK_ALGO;
if( !data[0] || !data[1] || !hash
|| !pkey[0] || !pkey[1] || !pkey[2] )
return GCRYERR_BAD_MPI;
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
if( !verify( data[0], data[1], hash, &pk ) )
return GCRYERR_BAD_SIGNATURE;
return 0;
}
-unsigned
+unsigned int
elg_get_nbits( int algo, MPI *pkey )
{
if( !is_ELGAMAL(algo) )
return 0;
return mpi_get_nbits( pkey[0] );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
* Usage: Bit 0 set : allows signing
* 1 set : allows encryption
* NOTE: This function allows signing also for ELG-E, which is not
* okay but a bad hack to allow to work with old gpg keys. The real check
* is done in the gnupg ocde depending on the packet version.
*/
const char *
elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
int *use )
{
*npkey = 3;
*nskey = 4;
*nenc = 2;
*nsig = 2;
switch( algo ) {
- case PUBKEY_ALGO_ELGAMAL:
+ case GCRY_PK_ELG:
*use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
return "ELG";
- case PUBKEY_ALGO_ELGAMAL_E:
+ case GCRY_PK_ELG_E:
*use = GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR;
return "ELG-E";
default: *use = 0; return NULL;
}
}
diff --git a/cipher/md.c b/cipher/md.c
index 98795206..e8ac8ac2 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -1,894 +1,900 @@
/* md.c - message digest dispatcher
* Copyright (C) 1998,1999 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "g10lib.h"
#include "cipher.h"
#include "dynload.h"
#include "rmd.h"
struct md_digest_list_s;
/* this structure is put right after the GCRY_MD_HD buffer, so that
* only one memory block is needed. */
struct gcry_md_context {
int magic;
int secure;
FILE *debug;
int finalized;
struct md_digest_list_s *list;
byte *macpads;
};
#define CTX_MAGIC_NORMAL 0x11071961
#define CTX_MAGIC_SECURE 0x16917011
static const char * digest_algo_to_string( int algo );
static int check_digest_algo( int algo );
static GCRY_MD_HD md_open( int algo, int secure, int hmac );
static int md_enable( GCRY_MD_HD hd, int algo );
static GCRY_MD_HD md_copy( GCRY_MD_HD a );
static void md_close(GCRY_MD_HD a);
static void md_write( GCRY_MD_HD a, byte *inbuf, size_t inlen);
static void md_final(GCRY_MD_HD a);
static byte *md_read( GCRY_MD_HD a, int algo );
static int md_get_algo( GCRY_MD_HD a );
static int md_digest_length( int algo );
static const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen );
static void md_start_debug( GCRY_MD_HD a, const char *suffix );
static void md_stop_debug( GCRY_MD_HD a );
/****************
* This structure is used for the list of available algorithms
* and for the list of algorithms in GCRY_MD_HD.
*/
struct md_digest_list_s {
struct md_digest_list_s *next;
const char *name;
int algo;
byte *asnoid;
int asnlen;
int mdlen;
void (*init)( void *c );
void (*write)( void *c, byte *buf, size_t nbytes );
void (*final)( void *c );
byte *(*read)( void *c );
size_t contextsize; /* allocate this amount of context */
PROPERLY_ALIGNED_TYPE context;
};
static struct md_digest_list_s *digest_list;
static struct md_digest_list_s *
new_list_item( int algo,
const char *(*get_info)( int, size_t*,byte**, int*, int*,
void (**)(void*),
void (**)(void*,byte*,size_t),
void (**)(void*),byte *(**)(void*)) )
{
struct md_digest_list_s *r;
r = g10_xcalloc( 1, sizeof *r );
r->algo = algo,
r->name = (*get_info)( algo, &r->contextsize,
&r->asnoid, &r->asnlen, &r->mdlen,
&r->init, &r->write, &r->final, &r->read );
if( !r->name ) {
g10_free(r);
r = NULL;
}
return r;
}
/****************
* Try to load the modules with the requeste algorithm
* and return true if new modules are available
* If req_alog is -1 try to load all digest algorithms.
*/
static int
load_digest_module( int req_algo )
{
static int initialized = 0;
static u32 checked_algos[256/32];
static int checked_all = 0;
struct md_digest_list_s *r;
void *context = NULL;
int algo;
int any = 0;
const char *(*get_info)( int, size_t*,byte**, int*, int*,
void (**)(void*),
void (**)(void*,byte*,size_t),
void (**)(void*),byte *(**)(void*));
if( !initialized ) {
cipher_modules_constructor();
initialized = 1;
}
algo = req_algo;
if( algo > 255 || !algo )
return 0; /* algorithm number too high (does not fit into out bitmap)*/
if( checked_all )
return 0; /* already called with -1 */
if( algo < 0 )
checked_all = 1;
else if( (checked_algos[algo/32] & (1 << (algo%32))) )
return 0; /* already checked and not found */
else
checked_algos[algo/32] |= (1 << (algo%32));
while( enum_gnupgext_digests( &context, &algo, &get_info ) ) {
if( req_algo != -1 && algo != req_algo )
continue;
for(r=digest_list; r; r = r->next )
if( r->algo == algo )
break;
if( r ) {
log_info("skipping digest %d: already loaded\n", algo );
continue;
}
r = new_list_item( algo, get_info );
if( ! r ) {
log_info("skipping digest %d: no name\n", algo );
continue;
}
/* put it into the list */
if( g10_log_verbosity( 2 ) )
log_info("loaded digest %d\n", algo);
r->next = digest_list;
digest_list = r;
any = 1;
if( req_algo != -1 )
break;
}
enum_gnupgext_digests( &context, NULL, NULL );
return any;
}
/****************
* Map a string to the digest algo
*/
int
gcry_md_map_name( const char *string )
{
struct md_digest_list_s *r;
do {
for(r = digest_list; r; r = r->next )
if( !stricmp( r->name, string ) )
return r->algo;
} while( !r && load_digest_module(-1) );
return 0;
}
/****************
* Map a digest algo to a string
*/
static const char *
digest_algo_to_string( int algo )
{
struct md_digest_list_s *r;
do {
for(r = digest_list; r; r = r->next )
if( r->algo == algo )
return r->name;
} while( !r && load_digest_module( algo ) );
return NULL;
}
/****************
* This function simply returns the name of the algorithm or some constant
* string when there is no algo. It will never return NULL.
* Use the macro gcry_md_test_algo() to check whether the algorithm
* is valid.
*/
const char *
gcry_md_algo_name( int algo )
{
const char *s = digest_algo_to_string( algo );
return s? s: "?";
}
static int
check_digest_algo( int algo )
{
struct md_digest_list_s *r;
do {
for(r = digest_list; r; r = r->next )
if( r->algo == algo )
return 0;
} while( !r && load_digest_module(algo) );
return GCRYERR_INV_MD_ALGO;
}
/****************
* Open a message digest handle for use with algorithm ALGO.
* More algorithms may be added by md_enable(). The initial algorithm
* may be 0.
*/
static GCRY_MD_HD
md_open( int algo, int secure, int hmac )
{
GCRY_MD_HD hd;
struct gcry_md_context *ctx;
int bufsize = secure? 512 : 1024;
size_t n;
/* Allocate a memory area to hold the caller visible buffer with it's
* control information and the data required by this module. Set the
* context pointer at the beginning to this area.
* We have to use this strange scheme because we want to hide the
* internal data but have a variable sized buffer.
*
* +---+------+---........------+-------------+
* !ctx! bctl ! buffer ! private !
* +---+------+---........------+-------------+
* ! ^
* !---------------------------!
*
* We have to make sture that private is well aligned.
*/
n = sizeof( struct gcry_md_handle ) + bufsize;
n = ((n + sizeof(PROPERLY_ALIGNED_TYPE)-1)
/ sizeof(PROPERLY_ALIGNED_TYPE) ) * sizeof(PROPERLY_ALIGNED_TYPE);
/* allocate and set the Context pointer to the private data */
hd = secure ? g10_malloc_secure( n + sizeof( struct gcry_md_context ) )
: g10_malloc( n + sizeof( struct gcry_md_context ) );
if( !hd ) {
set_lasterr( GCRYERR_NO_MEM );
return NULL;
}
hd->ctx = ctx = (struct gcry_md_context*)( (char*)hd + n );
/* setup the globally visible data (bctl in the diagram)*/
hd->bufsize = n - sizeof( struct gcry_md_handle ) + 1;
hd->bufpos = 0;
/* initialize the private data */
memset( hd->ctx, 0, sizeof *hd->ctx );
ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
ctx->secure = secure;
if( hmac ) {
ctx->macpads = g10_malloc_secure( 128 );
if( !ctx->macpads ) {
md_close( hd );
set_lasterr( GCRYERR_NO_MEM );
return NULL;
}
}
fast_random_poll(); /* FIXME: should we really do that? */
if( algo && md_enable( hd, algo ) ) {
md_close( hd );
return NULL;
}
return hd;
}
GCRY_MD_HD
gcry_md_open( int algo, unsigned int flags )
{
GCRY_MD_HD hd;
/* fixme: check that algo is available and that only valid
* flag values are used */
hd = md_open( algo, (flags & GCRY_MD_FLAG_SECURE),
(flags & GCRY_MD_FLAG_HMAC) );
return hd;
}
static int
md_enable( GCRY_MD_HD hd, int algo )
{
struct gcry_md_context *h = hd->ctx;
struct md_digest_list_s *r, *ac;
for( ac=h->list; ac; ac = ac->next )
if( ac->algo == algo )
return 0; /* already enabled */
/* find the algorithm */
do {
for(r = digest_list; r; r = r->next )
if( r->algo == algo )
break;
} while( !r && load_digest_module( algo ) );
if( !r ) {
log_debug("md_enable: algorithm %d not available\n", algo );
return set_lasterr( GCRYERR_INV_MD_ALGO );
}
/* and allocate a new list entry */
ac = h->secure? g10_malloc_secure( sizeof *ac + r->contextsize
- sizeof(r->context) )
: g10_malloc( sizeof *ac + r->contextsize
- sizeof(r->context) );
if( !ac )
return set_lasterr( GCRYERR_NO_MEM );
*ac = *r;
ac->next = h->list;
h->list = ac;
/* and init this instance */
(*ac->init)( &ac->context.c );
return 0;
}
int
gcry_md_enable( GCRY_MD_HD hd, int algo )
{
return md_enable( hd, algo );
}
static GCRY_MD_HD
md_copy( GCRY_MD_HD ahd )
{
struct gcry_md_context *a = ahd->ctx;
struct gcry_md_context *b;
GCRY_MD_HD bhd;
struct md_digest_list_s *ar, *br;
size_t n;
if( ahd->bufpos )
md_write( ahd, NULL, 0 );
n = (char*)ahd->ctx - (char*)ahd;
bhd = a->secure ? g10_malloc_secure( n + sizeof( struct gcry_md_context ) )
: g10_malloc( n + sizeof( struct gcry_md_context ) );
if( !bhd ) {
set_lasterr( GCRYERR_NO_MEM );
return NULL;
}
bhd->ctx = b = (struct gcry_md_context*)( (char*)bhd + n );
/* no need to copy the buffer due to the write above */
assert( ahd->bufsize == (n - sizeof( struct gcry_md_handle ) + 1) );
bhd->bufsize = ahd->bufsize;
bhd->bufpos = 0; assert( !ahd->bufpos );
memcpy( b, a, sizeof *a );
b->list = NULL;
b->debug = NULL;
if( a->macpads ) {
b->macpads = g10_malloc_secure( 128 );
memcpy( b->macpads, a->macpads, 128 );
}
/* and now copy the complete list of algorithms */
/* I know that the copied list is reversed, but that doesn't matter */
for( ar=a->list; ar; ar = ar->next ) {
br = a->secure ? g10_xmalloc_secure( sizeof *br + ar->contextsize
- sizeof(ar->context) )
: g10_xmalloc( sizeof *br + ar->contextsize
- sizeof(ar->context) );
memcpy( br, ar, sizeof(*br) + ar->contextsize
- sizeof(ar->context) );
br->next = b->list;
b->list = br;
}
if( a->debug )
md_start_debug( bhd, "unknown" );
return bhd;
}
GCRY_MD_HD
gcry_md_copy( GCRY_MD_HD hd )
{
return md_copy( hd );
}
/****************
* Reset all contexts and discard any buffered stuff. This may be used
* instead of a md_close(); md_open().
*/
void
gcry_md_reset( GCRY_MD_HD a )
{
struct md_digest_list_s *r;
a->bufpos = a->ctx->finalized = 0;
for( r=a->ctx->list; r; r = r->next ) {
memset( r->context.c, 0, r->contextsize );
(*r->init)( &r->context.c );
}
if( a->ctx->macpads ) {
md_write( a, a->ctx->macpads, 64 ); /* inner pad */
}
}
static void
md_close(GCRY_MD_HD a)
{
struct md_digest_list_s *r, *r2;
if( !a )
return;
if( a->ctx->debug )
md_stop_debug(a);
for(r=a->ctx->list; r; r = r2 ) {
r2 = r->next;
g10_free(r);
}
g10_free(a->ctx->macpads);
g10_free(a);
}
void
gcry_md_close( GCRY_MD_HD hd )
{
md_close( hd );
}
static void
md_write( GCRY_MD_HD a, byte *inbuf, size_t inlen)
{
struct md_digest_list_s *r;
if( a->ctx->debug ) {
if( a->bufpos && fwrite(a->buf, a->bufpos, 1, a->ctx->debug ) != 1 )
BUG();
if( inlen && fwrite(inbuf, inlen, 1, a->ctx->debug ) != 1 )
BUG();
}
for(r=a->ctx->list; r; r = r->next ) {
if( a->bufpos )
(*r->write)( &r->context.c, a->buf, a->bufpos );
(*r->write)( &r->context.c, inbuf, inlen );
}
a->bufpos = 0;
}
void
gcry_md_write( GCRY_MD_HD hd, const byte *inbuf, size_t inlen)
{
md_write( hd, (byte*)inbuf, inlen );
}
static void
md_final(GCRY_MD_HD a)
{
struct md_digest_list_s *r;
if( a->ctx->finalized )
return;
if( a->bufpos )
md_write( a, NULL, 0 );
for(r=a->ctx->list; r; r = r->next ) {
(*r->final)( &r->context.c );
}
a->ctx->finalized = 1;
if( a->ctx->macpads ) { /* finish the hmac */
int algo = md_get_algo( a );
byte *p = md_read( a, algo );
size_t dlen = md_digest_length(algo);
GCRY_MD_HD om = md_open( algo, a->ctx->secure, 0 );
if( !om )
g10_fatal_error( gcry_errno(), NULL );
md_write( om, a->ctx->macpads+64, 64 );
md_write( om, p, dlen );
md_final( om );
/* replace our digest with the mac (they have the same size) */
memcpy( p, md_read( om, algo ), dlen );
md_close( om );
}
}
static int
prepare_macpads( GCRY_MD_HD hd, byte *key, size_t keylen)
{
int i;
int algo = md_get_algo( hd );
byte *helpkey = NULL;
byte *ipad, *opad;
if( !algo )
return GCRYERR_INV_MD_ALGO; /* i.e. no algo enabled */
if( keylen > 64 ) {
helpkey = g10_malloc_secure( md_digest_length( algo ) );
if( !helpkey )
return GCRYERR_NO_MEM;
gcry_md_hash_buffer( algo, helpkey, key, keylen );
key = helpkey;
keylen = md_digest_length( algo );
assert( keylen <= 64 );
}
memset( hd->ctx->macpads, 0, 128 );
ipad = hd->ctx->macpads;
opad = hd->ctx->macpads+64;
memcpy( ipad, key, keylen );
memcpy( opad, key, keylen );
for(i=0; i < 64; i++ ) {
ipad[i] ^= 0x36;
opad[i] ^= 0x5c;
}
g10_free( helpkey );
return 0;
}
int
gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen)
{
int rc = 0;
if( cmd == GCRYCTL_FINALIZE )
md_final( hd );
else if( cmd == GCRYCTL_SET_KEY ) {
if( !(hd->ctx->macpads ) )
rc = GCRYERR_CONFLICT;
else if ( !(rc = prepare_macpads( hd, buffer, buflen )) )
gcry_md_reset( hd );
}
+ else if( cmd == GCRYCTL_START_DUMP ) {
+ md_start_debug( hd, buffer );
+ }
+ else if( cmd == GCRYCTL_STOP_DUMP ) {
+ md_stop_debug( hd );
+ }
else
rc = GCRYERR_INV_OP;
return set_lasterr( rc );
}
/****************
* if ALGO is null get the digest for the used algo (which should be only one)
*/
static byte *
md_read( GCRY_MD_HD a, int algo )
{
struct md_digest_list_s *r;
if( !algo ) { /* return the first algorithm */
if( (r=a->ctx->list) ) {
if( r->next )
log_debug("more than algorithm in md_read(0)\n");
return (*r->read)( &r->context.c );
}
}
else {
for(r=a->ctx->list; r; r = r->next )
if( r->algo == algo )
return (*r->read)( &r->context.c );
}
BUG();
return NULL;
}
/****************
* Read out the complete digest, this function implictly finalizes
* the hash.
*/
byte *
gcry_md_read( GCRY_MD_HD hd, int algo )
{
gcry_md_ctl( hd, GCRYCTL_FINALIZE, NULL, 0 );
return md_read( hd, algo);
}
/****************
* This function combines md_final and md_read but keeps the context
* intact. This function can be used to calculate intermediate
* digests. The digest is copied into buffer and the digestlength is
* returned. If buffer is NULL only the needed size for buffer is returned.
* buflen gives the max size of buffer. If the buffer is too shourt to
* hold the complete digest, the buffer is filled with as many bytes are
* possible and this value is returned.
*/
#if 0
static int
md_digest( GCRY_MD_HD a, int algo, byte *buffer, int buflen )
{
struct md_digest_list_s *r = NULL;
char *context;
char *digest;
if( a->bufpos )
md_write( a, NULL, 0 );
if( !algo ) { /* return digest for the first algorithm */
if( (r=a->ctx->list) && r->next )
log_debug("more than algorithm in md_digest(0)\n");
}
else {
for(r=a->ctx->list; r; r = r->next )
if( r->algo == algo )
break;
}
if( !r )
BUG();
if( !buffer )
return r->mdlen;
/* I don't want to change the interface, so I simply work on a copy
* of the context (extra overhead - should be fixed)*/
context = a->ctx->secure ? g10_xmalloc_secure( r->contextsize )
: g10_xmalloc( r->contextsize );
memcpy( context, r->context.c, r->contextsize );
(*r->final)( context );
digest = (*r->read)( context );
if( buflen > r->mdlen )
buflen = r->mdlen;
memcpy( buffer, digest, buflen );
g10_free(context);
return buflen;
}
#endif
/****************
* Read out an intermediate digest.
*/
int
gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen )
{
/*md_digest ... */
return GCRYERR_INTERNAL;
}
/****************
* Shortcut function to hash a buffer with a given algo. The only supported
* algorithm is RIPE-MD. The supplied digest buffer must be large enough
* to store the resulting hash. No error is returned, the function will
* abort on an invalid algo. DISABLED_ALGOS are ignored here.
*/
void
gcry_md_hash_buffer( int algo, char *digest, const char *buffer, size_t length)
{
if( algo == GCRY_MD_RMD160 )
rmd160_hash_buffer( digest, buffer, length );
else { /* for the others we do not have a fast function, so
* we use the normal functions to do it */
GCRY_MD_HD h = md_open( algo, 0, 0 );
if( !h )
BUG(); /* algo not available */
md_write( h, (byte*)buffer, length );
md_final( h );
memcpy( digest, md_read( h, algo ), md_digest_length( algo ) );
}
}
static int
md_get_algo( GCRY_MD_HD a )
{
struct md_digest_list_s *r;
if( (r=a->ctx->list) ) {
if( r->next )
log_error("WARNING: more than algorithm in md_get_algo()\n");
return r->algo;
}
return 0;
}
int
gcry_md_get_algo( GCRY_MD_HD hd )
{
return md_get_algo( hd ); /* fixme: we need error handling */
}
/****************
* Return the length of the digest
*/
static int
md_digest_length( int algo )
{
struct md_digest_list_s *r;
do {
for(r = digest_list; r; r = r->next ) {
if( r->algo == algo )
return r->mdlen;
}
} while( !r && load_digest_module( algo ) );
return 0;
}
/****************
* Return the length of the digest in bytes.
* This function will return 0 in case of errors.
*/
unsigned int
gcry_md_get_algo_dlen( int algo )
{
/* we do some very quick checks here */
switch( algo )
{
case GCRY_MD_MD5: return 16;
case GCRY_MD_SHA1:
case GCRY_MD_RMD160: return 20;
default: {
int len = md_digest_length( algo );
if( !len )
set_lasterr( GCRYERR_INV_MD_ALGO );
return 0;
}
}
}
/* Hmmm: add a mode to enumerate the OIDs
* to make g10/sig-check.c more portable */
static const byte *
md_asn_oid( int algo, size_t *asnlen, size_t *mdlen )
{
struct md_digest_list_s *r;
do {
for(r = digest_list; r; r = r->next ) {
if( r->algo == algo ) {
if( asnlen )
*asnlen = r->asnlen;
if( mdlen )
*mdlen = r->mdlen;
return r->asnoid;
}
}
} while( !r && load_digest_module( algo ) );
log_bug("no asn for md algo %d\n", algo);
return NULL;
}
/****************
* Return information about the given cipher algorithm
* WHAT select the kind of information returned:
* GCRYCTL_TEST_ALGO:
* Returns 0 when the specified algorithm is available for use.
* buffer and nbytes must be zero.
* GCRYCTL_GET_ASNOID:
* Return the ASNOID of the algorithm in buffer. if buffer is NULL, only
* the required length is returned.
*
* On error the value -1 is returned and the error reason may be
* retrieved by gcry_errno().
* Note: Because this function is in most caes used to return an
* integer value, we can make it easier for the caller to just look at
* the return value. The caller will in all cases consult the value
* and thereby detecting whether a error occured or not (i.e. while checking
* the block size)
*/
int
gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes)
{
switch( what ) {
case GCRYCTL_TEST_ALGO:
if( buffer || nbytes ) {
set_lasterr( GCRYERR_INV_ARG );
return -1;
}
if( check_digest_algo( algo ) ) {
set_lasterr( GCRYERR_INV_MD_ALGO );
return -1;
}
break;
case GCRYCTL_GET_ASNOID: {
size_t asnlen;
const char *asn = md_asn_oid( algo, &asnlen, NULL );
if( buffer && *nbytes >= asnlen ) {
memcpy( buffer, asn, asnlen );
*nbytes = asnlen;
return 0;
}
if( !buffer && nbytes ) {
*nbytes = asnlen;
return 0;
}
set_lasterr( buffer ? GCRYERR_TOO_SHORT : GCRYERR_INV_ARG );
return -1;
}
break;
default:
set_lasterr( GCRYERR_INV_OP );
return -1;
}
return 0;
}
-void
+static void
md_start_debug( GCRY_MD_HD md, const char *suffix )
{
static int idx=0;
char buf[25];
if( md->ctx->debug ) {
log_debug("Oops: md debug already started\n");
return;
}
idx++;
sprintf(buf, "dbgmd-%05d.%.10s", idx, suffix );
md->ctx->debug = fopen(buf, "w");
if( !md->ctx->debug )
log_debug("md debug: can't open %s\n", buf );
}
-void
+static void
md_stop_debug( GCRY_MD_HD md )
{
if( md->ctx->debug ) {
if( md->bufpos )
md_write( md, NULL, 0 );
fclose(md->ctx->debug);
md->ctx->debug = NULL;
}
#ifdef HAVE_U64_TYPEDEF
{ /* a kludge to pull in the __muldi3 for Solaris */
volatile u32 a = (u32)(ulong)md;
volatile u64 b = 42;
volatile u64 c;
c = a * b;
}
#endif
}
/****************
* Return information about the digest handle.
* GCRYCTL_IS_SECURE:
* Returns 1 when the handle works on secured memory
* otherwise 0 is returned. There is no error return.
*/
int
gcry_md_info( GCRY_MD_HD h, int cmd, void *buffer, size_t *nbytes)
{
switch( cmd ) {
case GCRYCTL_IS_SECURE:
return h->ctx->secure;
default:
set_lasterr( GCRYERR_INV_OP );
return -1;
}
return 0;
}
diff --git a/cipher/md5.c b/cipher/md5.c
index 161d4430..c4351f1f 100644
--- a/cipher/md5.c
+++ b/cipher/md5.c
@@ -1,410 +1,410 @@
/* md5.c - MD5 Message-Digest Algorithm
* Copyright (C) 1995, 1996, 1998, 1999 Free Software Foundation, Inc.
*
* according to the definition of MD5 in RFC 1321 from April 1992.
* NOTE: This is *not* the same file as the one from glibc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
/* heavily modified for GnuPG by <werner.koch@guug.de> */
/* Test values:
* "" D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E
* "a" 0C C1 75 B9 C0 F1 B6 A8 31 C3 99 E2 69 77 26 61
* "abc 90 01 50 98 3C D2 4F B0 D6 96 3F 7D 28 E1 7F 72
* "message digest" F9 6B 69 7D 7C B7 93 8D 52 5A 2F 31 AA F1 61 D0
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "memory.h"
#include "dynload.h"
#include "bithelp.h"
typedef struct {
u32 A,B,C,D; /* chaining variables */
u32 nblocks;
byte buf[64];
int count;
} MD5_CONTEXT;
static void
md5_init( MD5_CONTEXT *ctx )
{
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
ctx->D = 0x10325476;
ctx->nblocks = 0;
ctx->count = 0;
}
/* These are the four functions used in the four steps of the MD5 algorithm
and defined in the RFC 1321. The first function is a little bit optimized
(as found in Colin Plumbs public domain implementation). */
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
#define FF(b, c, d) (d ^ (b & (c ^ d)))
#define FG(b, c, d) FF (d, b, c)
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
/****************
* transform n*64 bytes
*/
static void
/*transform( MD5_CONTEXT *ctx, const void *buffer, size_t len )*/
transform( MD5_CONTEXT *ctx, byte *data )
{
u32 correct_words[16];
u32 A = ctx->A;
u32 B = ctx->B;
u32 C = ctx->C;
u32 D = ctx->D;
u32 *cwp = correct_words;
#ifdef BIG_ENDIAN_HOST
{ int i;
byte *p2, *p1;
for(i=0, p1=data, p2=(byte*)correct_words; i < 16; i++, p2 += 4 ) {
p2[3] = *p1++;
p2[2] = *p1++;
p2[1] = *p1++;
p2[0] = *p1++;
}
}
#else
memcpy( correct_words, data, 64 );
#endif
#define OP(a, b, c, d, s, T) \
do \
{ \
a += FF (b, c, d) + (*cwp++) + T; \
a = rol(a, s); \
a += b; \
} \
while (0)
/* Before we start, one word about the strange constants.
They are defined in RFC 1321 as
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
*/
/* Round 1. */
OP (A, B, C, D, 7, 0xd76aa478);
OP (D, A, B, C, 12, 0xe8c7b756);
OP (C, D, A, B, 17, 0x242070db);
OP (B, C, D, A, 22, 0xc1bdceee);
OP (A, B, C, D, 7, 0xf57c0faf);
OP (D, A, B, C, 12, 0x4787c62a);
OP (C, D, A, B, 17, 0xa8304613);
OP (B, C, D, A, 22, 0xfd469501);
OP (A, B, C, D, 7, 0x698098d8);
OP (D, A, B, C, 12, 0x8b44f7af);
OP (C, D, A, B, 17, 0xffff5bb1);
OP (B, C, D, A, 22, 0x895cd7be);
OP (A, B, C, D, 7, 0x6b901122);
OP (D, A, B, C, 12, 0xfd987193);
OP (C, D, A, B, 17, 0xa679438e);
OP (B, C, D, A, 22, 0x49b40821);
#undef OP
#define OP(f, a, b, c, d, k, s, T) \
do \
{ \
a += f (b, c, d) + correct_words[k] + T; \
a = rol(a, s); \
a += b; \
} \
while (0)
/* Round 2. */
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
OP (FG, D, A, B, C, 10, 9, 0x02441453);
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
/* Round 3. */
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
/* Round 4. */
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
/* Put checksum in context given as argument. */
ctx->A += A;
ctx->B += B;
ctx->C += C;
ctx->D += D;
}
/* The routine updates the message-digest context to
* account for the presence of each of the characters inBuf[0..inLen-1]
* in the message whose digest is being computed.
*/
static void
md5_write( MD5_CONTEXT *hd, byte *inbuf, size_t inlen)
{
if( hd->count == 64 ) { /* flush the buffer */
transform( hd, hd->buf );
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count ) {
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
md5_write( hd, NULL, 0 );
if( !inlen )
return;
}
while( inlen >= 64 ) {
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/* The routine final terminates the message-digest computation and
* ends with the desired message digest in mdContext->digest[0...15].
* The handle is prepared for a new MD5 cycle.
* Returns 16 bytes representing the digest.
*/
static void
md5_final( MD5_CONTEXT *hd )
{
u32 t, msb, lsb;
byte *p;
md5_write(hd, NULL, 0); /* flush */;
msb = 0;
t = hd->nblocks;
if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
msb++;
msb += t >> 26;
t = lsb;
if( (lsb = t + hd->count) < t ) /* add the count */
msb++;
t = lsb;
if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
msb++;
msb += t >> 29;
if( hd->count < 56 ) { /* enough room */
hd->buf[hd->count++] = 0x80; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else { /* need one extra block */
hd->buf[hd->count++] = 0x80; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
md5_write(hd, NULL, 0); /* flush */;
memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = lsb ;
hd->buf[57] = lsb >> 8;
hd->buf[58] = lsb >> 16;
hd->buf[59] = lsb >> 24;
hd->buf[60] = msb ;
hd->buf[61] = msb >> 8;
hd->buf[62] = msb >> 16;
hd->buf[63] = msb >> 24;
transform( hd, hd->buf );
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *p++ = hd->##a ; *p++ = hd->##a >> 8; \
*p++ = hd->##a >> 16; *p++ = hd->##a >> 24; } while(0)
#else /* little endian */
/*#define X(a) do { *(u32*)p = hd->##a ; p += 4; } while(0)*/
/* Unixware's cpp doesn't like the above construct so we do it his way:
* (reported by Allan Clark) */
#define X(a) do { *(u32*)p = (*hd).a ; p += 4; } while(0)
#endif
X(A);
X(B);
X(C);
X(D);
#undef X
}
static byte *
md5_read( MD5_CONTEXT *hd )
{
return hd->buf;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
static const char *
md5_get_info( int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
)
{
static byte asn[18] = /* Object ID is 1.2.840.113549.2.5 */
{ 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,0x48,
0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10 };
if( algo != 1 )
return NULL;
*contextsize = sizeof(MD5_CONTEXT);
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 16;
- *r_init = (void (*)(void *))md5_init;
- *r_write = (void (*)(void *, byte*, size_t))md5_write;
- *r_final = (void (*)(void *))md5_final;
- *r_read = (byte *(*)(void *))md5_read;
+ *(void (**)(MD5_CONTEXT *))r_init = md5_init;
+ *(void (**)(MD5_CONTEXT *, byte*, size_t))r_write = md5_write;
+ *(void (**)(MD5_CONTEXT *))r_final = md5_final;
+ *(byte *(**)(MD5_CONTEXT *))r_read = md5_read;
return "MD5";
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "MD5 ($Revision$)";
static struct {
int class;
int version;
int value;
void (*func)(void);
} func_table[] = {
{ 10, 1, 0, (void(*)(void))md5_get_info },
{ 11, 1, 1 },
};
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if( i >= DIM(func_table) || i < 0 )
return NULL;
*class = func_table[i].class;
*vers = func_table[i].version;
switch( *class ) {
case 11: case 21: case 31: ret = &func_table[i].value; break;
default: ret = func_table[i].func; break;
}
i++;
} while( what && what != *class );
*sequence = i;
return ret;
}
#ifndef IS_MODULE
void
md5_constructor(void)
{
register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
}
#endif
/* end of file */
diff --git a/cipher/primegen.c b/cipher/primegen.c
index 2f16b083..f5dca859 100644
--- a/cipher/primegen.c
+++ b/cipher/primegen.c
@@ -1,557 +1,570 @@
/* primegen.c - prime number generator
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* ***********************************************************************
* The algorithm used to generate practically save primes is due to
* Lim and Lee as described in the CRYPTO '97 proceedings (ISBN3540633847)
* page 260.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
static int no_of_small_prime_numbers;
static MPI gen_prime( unsigned nbits, int mode, int randomlevel );
static int check_prime( MPI prime, MPI val_2 );
static int is_prime( MPI n, int steps, int *count );
static void m_out_of_n( char *array, int m, int n );
+static void (*progress_cb) ( void *, int );
+static void *progress_cb_data;
+
+void
+register_primegen_progress ( void (*cb)( void *, int), void *cb_data )
+{
+ progress_cb = cb;
+ progress_cb_data = cb_data;
+}
+
static void
progress( int c )
{
- fputc( c, stderr );
+ if ( progress_cb )
+ progress_cb ( progress_cb_data, c );
+ else
+ fputc( c, stderr );
}
/****************
* Generate a prime number (stored in secure memory)
*/
MPI
generate_secret_prime( unsigned nbits )
{
MPI prime;
prime = gen_prime( nbits, 1, 2 );
progress('\n');
return prime;
}
MPI
generate_public_prime( unsigned nbits )
{
MPI prime;
prime = gen_prime( nbits, 0, 2 );
progress('\n');
return prime;
}
/****************
* We do not need to use the strongest RNG because we gain no extra
* security from it - The prime number is public and we could also
* offer the factors for those who are willing to check that it is
* indeed a strong prime.
*
* mode 0: Standard
* 1: Make sure that at least one factor is of size qbits.
*/
MPI
generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
MPI g, MPI **ret_factors )
{
int n; /* number of factors */
int m; /* number of primes in pool */
unsigned fbits; /* length of prime factors */
MPI *factors; /* current factors */
MPI *pool; /* pool of primes */
MPI q; /* first prime factor (variable)*/
MPI prime; /* prime test value */
MPI q_factor; /* used for mode 1 */
byte *perms = NULL;
int i, j;
int count1, count2;
unsigned nprime;
unsigned req_qbits = qbits; /* the requested q bits size */
MPI val_2 = mpi_alloc_set_ui( 2 );
/* find number of needed prime factors */
for(n=1; (pbits - qbits - 1) / n >= qbits; n++ )
;
n--;
if( !n || (mode==1 && n < 2) )
log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits );
if( mode == 1 ) {
n--;
fbits = (pbits - 2*req_qbits -1) / n;
qbits = pbits - req_qbits - n*fbits;
}
else {
fbits = (pbits - req_qbits -1) / n;
qbits = pbits - n*fbits;
}
if( DBG_CIPHER )
log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n",
pbits, req_qbits, qbits, fbits, n );
prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB );
- q = gen_prime( qbits, 0, 1 );
- q_factor = mode==1? gen_prime( req_qbits, 0, 1 ) : NULL;
+ q = gen_prime( qbits, 0, 0 );
+ q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL;
/* allocate an array to hold the factors + 2 for later usage */
factors = g10_xcalloc( n+2, sizeof *factors );
/* make a pool of 3n+5 primes (this is an arbitrary value) */
m = n*3+5;
if( mode == 1 )
m += 5; /* need some more for DSA */
if( m < 25 )
m = 25;
pool = g10_xcalloc( m , sizeof *pool );
/* permutate over the pool of primes */
count1=count2=0;
do {
next_try:
if( !perms ) {
/* allocate new primes */
for(i=0; i < m; i++ ) {
mpi_free(pool[i]);
pool[i] = NULL;
}
/* init m_out_of_n() */
perms = g10_xcalloc( 1, m );
for(i=0; i < n; i++ ) {
perms[i] = 1;
pool[i] = gen_prime( fbits, 0, 1 );
factors[i] = pool[i];
}
}
else {
m_out_of_n( perms, n, m );
for(i=j=0; i < m && j < n ; i++ )
if( perms[i] ) {
if( !pool[i] )
pool[i] = gen_prime( fbits, 0, 1 );
factors[j++] = pool[i];
}
if( i == n ) {
g10_free(perms); perms = NULL;
progress('!');
goto next_try; /* allocate new primes */
}
}
mpi_set( prime, q );
mpi_mul_ui( prime, prime, 2 );
if( mode == 1 )
mpi_mul( prime, prime, q_factor );
for(i=0; i < n; i++ )
mpi_mul( prime, prime, factors[i] );
mpi_add_ui( prime, prime, 1 );
nprime = mpi_get_nbits(prime);
if( nprime < pbits ) {
if( ++count1 > 20 ) {
count1 = 0;
qbits++;
progress('>');
- q = gen_prime( qbits, 0, 1 );
+ q = gen_prime( qbits, 0, 0 );
goto next_try;
}
}
else
count1 = 0;
if( nprime > pbits ) {
if( ++count2 > 20 ) {
count2 = 0;
qbits--;
progress('<');
- q = gen_prime( qbits, 0, 1 );
+ q = gen_prime( qbits, 0, 0 );
goto next_try;
}
}
else
count2 = 0;
} while( !(nprime == pbits && check_prime( prime, val_2 )) );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump( "prime : ", prime );
log_mpidump( "factor q: ", q );
if( mode == 1 )
log_mpidump( "factor q0: ", q_factor );
for(i=0; i < n; i++ )
log_mpidump( "factor pi: ", factors[i] );
log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) );
if( mode == 1 )
fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) );
for(i=0; i < n; i++ )
fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) );
progress('\n');
}
if( ret_factors ) { /* caller wants the factors */
*ret_factors = g10_xcalloc( n+2 , sizeof **ret_factors);
if( mode == 1 ) {
i = 0;
(*ret_factors)[i++] = mpi_copy( q_factor );
for(; i <= n; i++ )
(*ret_factors)[i] = mpi_copy( factors[i] );
}
else {
for(i=0; i < n; i++ )
(*ret_factors)[i] = mpi_copy( factors[i] );
}
}
if( g ) { /* create a generator (start with 3)*/
MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) );
MPI b = mpi_alloc( mpi_get_nlimbs(prime) );
MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) );
if( mode == 1 )
BUG(); /* not yet implemented */
factors[n] = q;
factors[n+1] = mpi_alloc_set_ui(2);
mpi_sub_ui( pmin1, prime, 1 );
mpi_set_ui(g,2);
do {
mpi_add_ui(g, g, 1);
if( DBG_CIPHER ) {
log_debug("checking g: ");
/*mpi_print( stderr, g, 1 );*/
#warning we need an internal mpi_print for debugging
}
else
progress('^');
for(i=0; i < n+2; i++ ) {
/*fputc('~', stderr);*/
mpi_fdiv_q(tmp, pmin1, factors[i] );
/* (no mpi_pow(), but it is okay to use this with mod prime) */
gcry_mpi_powm(b, g, tmp, prime );
if( !mpi_cmp_ui(b, 1) )
break;
}
if( DBG_CIPHER )
progress('\n');
} while( i < n+2 );
mpi_free(factors[n+1]);
mpi_free(tmp);
mpi_free(b);
mpi_free(pmin1);
}
if( !DBG_CIPHER )
progress('\n');
g10_free( factors ); /* (factors are shallow copies) */
for(i=0; i < m; i++ )
mpi_free( pool[i] );
g10_free( pool );
g10_free(perms);
mpi_free(val_2);
return prime;
}
static MPI
gen_prime( unsigned nbits, int secret, int randomlevel )
{
unsigned nlimbs;
MPI prime, ptest, pminus1, val_2, val_3, result;
int i;
unsigned x, step;
unsigned count1, count2;
int *mods;
if( 0 && DBG_CIPHER )
log_debug("generate a prime of %u bits ", nbits );
if( !no_of_small_prime_numbers ) {
for(i=0; small_prime_numbers[i]; i++ )
no_of_small_prime_numbers++;
}
mods = g10_xmalloc( no_of_small_prime_numbers * sizeof *mods );
/* make nbits fit into MPI implementation */
nlimbs = (nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB;
val_2 = mpi_alloc_set_ui( 2 );
val_3 = mpi_alloc_set_ui( 3);
prime = secret? mpi_alloc_secure( nlimbs ): mpi_alloc( nlimbs );
result = mpi_alloc_like( prime );
pminus1= mpi_alloc_like( prime );
ptest = mpi_alloc_like( prime );
count1 = count2 = 0;
for(;;) { /* try forvever */
int dotcount=0;
/* generate a random number */
gcry_mpi_randomize( prime, nbits, randomlevel );
/* set high order bit to 1, set low order bit to 1 */
mpi_set_highbit( prime, nbits-1 );
mpi_set_bit( prime, 0 );
/* calculate all remainders */
for(i=0; (x = small_prime_numbers[i]); i++ )
mods[i] = mpi_fdiv_r_ui(NULL, prime, x);
/* now try some primes starting with prime */
for(step=0; step < 20000; step += 2 ) {
/* check against all the small primes we have in mods */
count1++;
for(i=0; (x = small_prime_numbers[i]); i++ ) {
while( mods[i] + step >= x )
mods[i] -= x;
if( !(mods[i] + step) )
break;
}
if( x )
continue; /* found a multiple of an already known prime */
mpi_add_ui( ptest, prime, step );
/* do a faster Fermat test */
count2++;
mpi_sub_ui( pminus1, ptest, 1);
gcry_mpi_powm( result, val_2, pminus1, ptest );
if( !mpi_cmp_ui( result, 1 ) ) { /* not composite */
/* perform stronger tests */
if( is_prime(ptest, 5, &count2 ) ) {
if( !mpi_test_bit( ptest, nbits-1 ) ) {
progress('\n');
log_debug("overflow in prime generation\n");
break; /* step loop, continue with a new prime */
}
mpi_free(val_2);
mpi_free(val_3);
mpi_free(result);
mpi_free(pminus1);
mpi_free(prime);
g10_free(mods);
return ptest;
}
}
if( ++dotcount == 10 ) {
progress('.');
dotcount = 0;
}
}
progress(':'); /* restart with a new random value */
}
}
/****************
* Returns: true if this may be a prime
*/
static int
check_prime( MPI prime, MPI val_2 )
{
int i;
unsigned x;
int count=0;
/* check against small primes */
for(i=0; (x = small_prime_numbers[i]); i++ ) {
if( mpi_divisible_ui( prime, x ) )
return 0;
}
/* a quick fermat test */
{
MPI result = mpi_alloc_like( prime );
MPI pminus1 = mpi_alloc_like( prime );
mpi_sub_ui( pminus1, prime, 1);
gcry_mpi_powm( result, val_2, pminus1, prime );
mpi_free( pminus1 );
if( mpi_cmp_ui( result, 1 ) ) { /* if composite */
mpi_free( result );
progress('.');
return 0;
}
mpi_free( result );
}
/* perform stronger tests */
if( is_prime(prime, 5, &count ) )
return 1; /* is probably a prime */
progress('.');
return 0;
}
/****************
* Return true if n is probably a prime
*/
static int
is_prime( MPI n, int steps, int *count )
{
MPI x = mpi_alloc( mpi_get_nlimbs( n ) );
MPI y = mpi_alloc( mpi_get_nlimbs( n ) );
MPI z = mpi_alloc( mpi_get_nlimbs( n ) );
MPI nminus1 = mpi_alloc( mpi_get_nlimbs( n ) );
MPI a2 = mpi_alloc_set_ui( 2 );
MPI q;
unsigned i, j, k;
int rc = 0;
unsigned nbits = mpi_get_nbits( n );
mpi_sub_ui( nminus1, n, 1 );
/* find q and k, so that n = 1 + 2^k * q */
q = mpi_copy( nminus1 );
k = mpi_trailing_zeros( q );
mpi_tdiv_q_2exp(q, q, k);
for(i=0 ; i < steps; i++ ) {
++*count;
if( !i ) {
mpi_set_ui( x, 2 );
}
else {
gcry_mpi_randomize( x, nbits, GCRY_WEAK_RANDOM );
/* make sure that the number is smaller than the prime
* and keep the randomness of the high bit */
if( mpi_test_bit( x, nbits-2 ) ) {
mpi_set_highbit( x, nbits-2 ); /* clear all higher bits */
}
else {
mpi_set_highbit( x, nbits-2 );
mpi_clear_bit( x, nbits-2 );
}
assert( mpi_cmp( x, nminus1 ) < 0 && mpi_cmp_ui( x, 1 ) > 0 );
}
gcry_mpi_powm( y, x, q, n);
if( mpi_cmp_ui(y, 1) && mpi_cmp( y, nminus1 ) ) {
for( j=1; j < k && mpi_cmp( y, nminus1 ); j++ ) {
gcry_mpi_powm(y, y, a2, n);
if( !mpi_cmp_ui( y, 1 ) )
goto leave; /* not a prime */
}
if( mpi_cmp( y, nminus1 ) )
goto leave; /* not a prime */
}
progress('+');
}
rc = 1; /* may be a prime */
leave:
mpi_free( x );
mpi_free( y );
mpi_free( z );
mpi_free( nminus1 );
mpi_free( q );
return rc;
}
static void
m_out_of_n( char *array, int m, int n )
{
int i=0, i1=0, j=0, jp=0, j1=0, k1=0, k2=0;
if( !m || m >= n )
return;
if( m == 1 ) { /* special case */
for(i=0; i < n; i++ )
if( array[i] ) {
array[i++] = 0;
if( i >= n )
i = 0;
array[i] = 1;
return;
}
BUG();
}
for(j=1; j < n; j++ ) {
if( array[n-1] == array[n-j-1] )
continue;
j1 = j;
break;
}
if( m & 1 ) { /* m is odd */
if( array[n-1] ) {
if( j1 & 1 ) {
k1 = n - j1;
k2 = k1+2;
if( k2 > n )
k2 = n;
goto leave;
}
goto scan;
}
k2 = n - j1 - 1;
if( k2 == 0 ) {
k1 = i;
k2 = n - j1;
}
else if( array[k2] && array[k2-1] )
k1 = n;
else
k1 = k2 + 1;
}
else { /* m is even */
if( !array[n-1] ) {
k1 = n - j1;
k2 = k1 + 1;
goto leave;
}
if( !(j1 & 1) ) {
k1 = n - j1;
k2 = k1+2;
if( k2 > n )
k2 = n;
goto leave;
}
scan:
jp = n - j1 - 1;
for(i=1; i <= jp; i++ ) {
i1 = jp + 2 - i;
if( array[i1-1] ) {
if( array[i1-2] ) {
k1 = i1 - 1;
k2 = n - j1;
}
else {
k1 = i1 - 1;
k2 = n + 1 - j1;
}
goto leave;
}
}
k1 = 1;
k2 = n + 1 - m;
}
leave:
array[k1-1] = !array[k1-1];
array[k2-1] = !array[k2-1];
}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 3ace1d83..b139720d 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1,1346 +1,1403 @@
/* pubkey.c - pubkey dispatcher
- * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "elgamal.h"
#include "dsa.h"
+#if 0
+#include "rsa.h"
+#endif
#include "dynload.h"
/* FIXME: use set_lasterr() */
#define TABLE_SIZE 10
struct pubkey_table_s {
const char *name;
int algo;
int npkey;
int nskey;
int nenc;
int nsig;
int use;
int (*generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
int (*check_secret_key)( int algo, MPI *skey );
int (*encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey );
int (*decrypt)( int algo, MPI *result, MPI *data, MPI *skey );
int (*sign)( int algo, MPI *resarr, MPI data, MPI *skey );
int (*verify)( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev );
unsigned (*get_nbits)( int algo, MPI *pkey );
};
static struct pubkey_table_s pubkey_table[TABLE_SIZE];
static int disabled_algos[TABLE_SIZE];
static struct { const char* name; int algo;
const char* common_elements;
const char* public_elements;
const char* secret_elements;
} algo_info_table[] = {
{ "dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "rsa" , PUBKEY_ALGO_RSA , "ne", "", "dpqu" },
{ "elg" , PUBKEY_ALGO_ELGAMAL , "pgy", "", "x" },
{ "openpgp-dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "openpgp-rsa" , PUBKEY_ALGO_RSA , "pqgy", "", "x" },
{ "openpgp-elg" , PUBKEY_ALGO_ELGAMAL_E , "pgy", "", "x" },
{ "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL , "pgy", "", "x" },
{ NULL }};
static struct {
const char* name; int algo;
const char* elements;
} sig_info_table[] = {
{ "dsa" , PUBKEY_ALGO_DSA , "rs" },
{ "rsa" , PUBKEY_ALGO_RSA , "s" },
{ "elg" , PUBKEY_ALGO_ELGAMAL , "rs" },
{ "openpgp-dsa" , PUBKEY_ALGO_DSA , "rs" },
{ "openpgp-rsa" , PUBKEY_ALGO_RSA , "s" },
{ "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL , "rs" },
{ NULL }};
static struct {
const char* name; int algo;
const char* elements;
} enc_info_table[] = {
{ "elg" , PUBKEY_ALGO_ELGAMAL , "ab" },
{ "rsa" , PUBKEY_ALGO_RSA , "a" },
{ "openpgp-rsa" , PUBKEY_ALGO_RSA , "a" },
{ "openpgp-elg" , PUBKEY_ALGO_ELGAMAL_E , "ab" },
{ "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL , "ab" },
{ NULL }};
static int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
static int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey );
static int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaque );
static int
dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{ log_bug("no generate() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static int
dummy_check_secret_key( int algo, MPI *skey )
{ log_bug("no check_secret_key() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static int
dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{ log_bug("no encrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static int
dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
{ log_bug("no decrypt() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static int
dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{ log_bug("no sign() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static int
dummy_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev )
{ log_bug("no verify() for %d\n", algo ); return GCRYERR_INV_PK_ALGO; }
static unsigned
dummy_get_nbits( int algo, MPI *pkey )
{ log_bug("no get_nbits() for %d\n", algo ); return 0; }
/****************
* Put the static entries into the table.
* This is out constructor function which fill the table
* of algorithms with the one we have statically linked.
*/
static void
setup_pubkey_table(void)
{
int i;
i = 0;
pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL;
pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
&pubkey_table[i].npkey,
&pubkey_table[i].nskey,
&pubkey_table[i].nenc,
&pubkey_table[i].nsig,
&pubkey_table[i].use );
pubkey_table[i].generate = elg_generate;
pubkey_table[i].check_secret_key = elg_check_secret_key;
pubkey_table[i].encrypt = elg_encrypt;
pubkey_table[i].decrypt = elg_decrypt;
pubkey_table[i].sign = elg_sign;
pubkey_table[i].verify = elg_verify;
pubkey_table[i].get_nbits = elg_get_nbits;
if( !pubkey_table[i].name )
BUG();
i++;
pubkey_table[i].algo = PUBKEY_ALGO_ELGAMAL_E;
pubkey_table[i].name = elg_get_info( pubkey_table[i].algo,
&pubkey_table[i].npkey,
&pubkey_table[i].nskey,
&pubkey_table[i].nenc,
&pubkey_table[i].nsig,
&pubkey_table[i].use );
pubkey_table[i].generate = elg_generate;
pubkey_table[i].check_secret_key = elg_check_secret_key;
pubkey_table[i].encrypt = elg_encrypt;
pubkey_table[i].decrypt = elg_decrypt;
pubkey_table[i].sign = elg_sign;
pubkey_table[i].verify = elg_verify;
pubkey_table[i].get_nbits = elg_get_nbits;
if( !pubkey_table[i].name )
BUG();
i++;
pubkey_table[i].algo = PUBKEY_ALGO_DSA;
pubkey_table[i].name = dsa_get_info( pubkey_table[i].algo,
&pubkey_table[i].npkey,
&pubkey_table[i].nskey,
&pubkey_table[i].nenc,
&pubkey_table[i].nsig,
&pubkey_table[i].use );
pubkey_table[i].generate = dsa_generate;
pubkey_table[i].check_secret_key = dsa_check_secret_key;
pubkey_table[i].encrypt = dummy_encrypt;
pubkey_table[i].decrypt = dummy_decrypt;
pubkey_table[i].sign = dsa_sign;
pubkey_table[i].verify = dsa_verify;
pubkey_table[i].get_nbits = dsa_get_nbits;
if( !pubkey_table[i].name )
BUG();
i++;
+ #if 0
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = rsa_encrypt;
+ pubkey_table[i].decrypt = rsa_decrypt;
+ pubkey_table[i].sign = rsa_sign;
+ pubkey_table[i].verify = rsa_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA_E;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = rsa_encrypt;
+ pubkey_table[i].decrypt = rsa_decrypt;
+ pubkey_table[i].sign = dummy_sign;
+ pubkey_table[i].verify = dummy_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ pubkey_table[i].algo = PUBKEY_ALGO_RSA_S;
+ pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
+ &pubkey_table[i].npkey,
+ &pubkey_table[i].nskey,
+ &pubkey_table[i].nenc,
+ &pubkey_table[i].nsig,
+ &pubkey_table[i].use );
+ pubkey_table[i].generate = rsa_generate;
+ pubkey_table[i].check_secret_key = rsa_check_secret_key;
+ pubkey_table[i].encrypt = dummy_encrypt;
+ pubkey_table[i].decrypt = dummy_decrypt;
+ pubkey_table[i].sign = rsa_sign;
+ pubkey_table[i].verify = rsa_verify;
+ pubkey_table[i].get_nbits = rsa_get_nbits;
+ if( !pubkey_table[i].name )
+ BUG();
+ i++;
+ #endif
+
for( ; i < TABLE_SIZE; i++ )
pubkey_table[i].name = NULL;
}
static void
release_mpi_array( MPI *array )
{
for( ; *array; array++ ) {
mpi_free(*array);
*array = NULL;
}
}
/****************
* Try to load all modules and return true if new modules are available
*/
static int
load_pubkey_modules(void)
{
static int initialized = 0;
static int done = 0;
void *context = NULL;
struct pubkey_table_s *ct;
int ct_idx;
int i;
const char *name;
int any = 0;
if( !initialized ) {
cipher_modules_constructor();
setup_pubkey_table();
initialized = 1;
return 1;
}
if( done )
return 0;
done = 1;
for(ct_idx=0, ct = pubkey_table; ct_idx < TABLE_SIZE; ct_idx++,ct++ ) {
if( !ct->name )
break;
}
if( ct_idx >= TABLE_SIZE-1 )
BUG(); /* table already full */
/* now load all extensions */
while( (name = enum_gnupgext_pubkeys( &context, &ct->algo,
&ct->npkey, &ct->nskey, &ct->nenc,
&ct->nsig, &ct->use,
&ct->generate,
&ct->check_secret_key,
&ct->encrypt,
&ct->decrypt,
&ct->sign,
&ct->verify,
&ct->get_nbits )) ) {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == ct->algo )
break;
if( pubkey_table[i].name ) {
log_info("skipping pubkey %d: already loaded\n", ct->algo );
continue;
}
if( !ct->generate ) ct->generate = dummy_generate;
if( !ct->check_secret_key ) ct->check_secret_key =
dummy_check_secret_key;
if( !ct->encrypt ) ct->encrypt = dummy_encrypt;
if( !ct->decrypt ) ct->decrypt = dummy_decrypt;
if( !ct->sign ) ct->sign = dummy_sign;
if( !ct->verify ) ct->verify = dummy_verify;
if( !ct->get_nbits ) ct->get_nbits= dummy_get_nbits;
/* put it into the table */
if( g10_log_verbosity( 2 ) )
log_info("loaded pubkey %d (%s)\n", ct->algo, name);
ct->name = name;
ct_idx++;
ct++;
any = 1;
/* check whether there are more available table slots */
if( ct_idx >= TABLE_SIZE-1 ) {
log_info("pubkey table full; ignoring other extensions\n");
break;
}
}
enum_gnupgext_pubkeys( &context, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL );
return any;
}
/****************
* Map a string to the pubkey algo
*/
int
gcry_pk_map_name( const char *string )
{
int i;
const char *s;
do {
for(i=0; (s=pubkey_table[i].name); i++ )
if( !stricmp( s, string ) )
return pubkey_table[i].algo;
} while( load_pubkey_modules() );
return 0;
}
/****************
* Map a pubkey algo to a string
*/
const char *
gcry_pk_algo_name( int algo )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].name;
} while( load_pubkey_modules() );
return NULL;
}
static void
disable_pubkey_algo( int algo )
{
int i;
for(i=0; i < DIM(disabled_algos); i++ ) {
if( !disabled_algos[i] || disabled_algos[i] == algo ) {
disabled_algos[i] = algo;
return;
}
}
log_fatal("can't disable pubkey algo %d: table full\n", algo );
}
/****************
* a use of 0 means: don't care
*/
static int
check_pubkey_algo( int algo, unsigned use )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
if( (use & GCRY_PK_USAGE_SIGN)
&& !(pubkey_table[i].use & GCRY_PK_USAGE_SIGN) )
return GCRYERR_WRONG_PK_ALGO;
if( (use & GCRY_PK_USAGE_ENCR)
&& !(pubkey_table[i].use & GCRY_PK_USAGE_ENCR) )
return GCRYERR_WRONG_PK_ALGO;
for(i=0; i < DIM(disabled_algos); i++ ) {
if( disabled_algos[i] == algo )
return GCRYERR_INV_PK_ALGO;
}
return 0; /* okay */
}
} while( load_pubkey_modules() );
return GCRYERR_INV_PK_ALGO;
}
/****************
* Return the number of public key material numbers
*/
static int
pubkey_get_npkey( int algo )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].npkey;
} while( load_pubkey_modules() );
if( is_RSA(algo) ) /* special hack, so that we are able to */
return 2; /* see the RSA keyids */
return 0;
}
/****************
* Return the number of secret key material numbers
*/
static int
pubkey_get_nskey( int algo )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nskey;
} while( load_pubkey_modules() );
if( is_RSA(algo) ) /* special hack, so that we are able to */
return 6; /* see the RSA keyids */
return 0;
}
/****************
* Return the number of signature material numbers
*/
static int
pubkey_get_nsig( int algo )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nsig;
} while( load_pubkey_modules() );
if( is_RSA(algo) ) /* special hack, so that we are able to */
return 1; /* see the RSA keyids */
return 0;
}
/****************
* Return the number of encryption material numbers
*/
static int
pubkey_get_nenc( int algo )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nenc;
} while( load_pubkey_modules() );
if( is_RSA(algo) ) /* special hack, so that we are able to */
return 1; /* see the RSA keyids */
return 0;
}
static int
pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return (*pubkey_table[i].generate)( algo, nbits,
skey, retfactors );
} while( load_pubkey_modules() );
return GCRYERR_INV_PK_ALGO;
}
static int
pubkey_check_secret_key( int algo, MPI *skey )
{
int i;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo )
return (*pubkey_table[i].check_secret_key)( algo, skey );
} while( load_pubkey_modules() );
return GCRYERR_INV_PK_ALGO;
}
/****************
* This is the interface to the public key encryption.
* Encrypt DATA with PKEY and put it into RESARR which
* should be an array of MPIs of size PUBKEY_MAX_NENC (or less if the
* algorithm allows this - check with pubkey_get_nenc() )
*/
static int
pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{
int i, rc;
if( DBG_CIPHER ) {
log_debug("pubkey_encrypt: algo=%d\n", algo );
for(i=0; i < pubkey_get_npkey(algo); i++ )
log_mpidump(" pkey:", pkey[i] );
log_mpidump(" data:", data );
}
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
rc = (*pubkey_table[i].encrypt)( algo, resarr, data, pkey );
goto ready;
}
} while( load_pubkey_modules() );
rc = GCRYERR_INV_PK_ALGO;
ready:
if( !rc && DBG_CIPHER ) {
for(i=0; i < pubkey_get_nenc(algo); i++ )
log_mpidump(" encr:", resarr[i] );
}
return rc;
}
/****************
* This is the interface to the public key decryption.
* ALGO gives the algorithm to use and this implicitly determines
* the size of the arrays.
* result is a pointer to a mpi variable which will receive a
* newly allocated mpi or NULL in case of an error.
*/
static int
pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
{
int i, rc;
*result = NULL; /* so the caller can always do a mpi_free */
if( DBG_CIPHER ) {
log_debug("pubkey_decrypt: algo=%d\n", algo );
for(i=0; i < pubkey_get_nskey(algo); i++ )
log_mpidump(" skey:", skey[i] );
for(i=0; i < pubkey_get_nenc(algo); i++ )
log_mpidump(" data:", data[i] );
}
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
rc = (*pubkey_table[i].decrypt)( algo, result, data, skey );
goto ready;
}
} while( load_pubkey_modules() );
rc = GCRYERR_INV_PK_ALGO;
ready:
if( !rc && DBG_CIPHER ) {
log_mpidump(" plain:", *result );
}
return rc;
}
/****************
* This is the interface to the public key signing.
* Sign data with skey and put the result into resarr which
* should be an array of MPIs of size PUBKEY_MAX_NSIG (or less if the
* algorithm allows this - check with pubkey_get_nsig() )
*/
static int
pubkey_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
int i, rc;
if( DBG_CIPHER ) {
log_debug("pubkey_sign: algo=%d\n", algo );
for(i=0; i < pubkey_get_nskey(algo); i++ )
log_mpidump(" skey:", skey[i] );
log_mpidump(" data:", data );
}
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
rc = (*pubkey_table[i].sign)( algo, resarr, data, skey );
goto ready;
}
} while( load_pubkey_modules() );
rc = GCRYERR_INV_PK_ALGO;
ready:
if( !rc && DBG_CIPHER ) {
for(i=0; i < pubkey_get_nsig(algo); i++ )
log_mpidump(" sig:", resarr[i] );
}
return rc;
}
/****************
* Verify a public key signature.
* Return 0 if the signature is good
*/
static int
pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev )
{
int i, rc;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
rc = (*pubkey_table[i].verify)( algo, hash, data, pkey,
cmp, opaquev );
goto ready;
}
} while( load_pubkey_modules() );
rc = GCRYERR_INV_PK_ALGO;
ready:
return rc;
}
/****************
* Convert a S-Exp with either a private or a public key to our
* internal format. Currently we do only support the following
* algorithms:
* dsa
* rsa
* openpgp-dsa
* openpgp-rsa
* openpgp-elg
* openpgp-elg-sig
* Provide a SE with the first element be either "private-key" or
* or "public-key". the followed by a list with its first element
* be one of the above algorithm identifiers and the following
* elements are pairs with parameter-id and value.
* NOTE: we look through the list to find a list beginning with
* "private-key" or "public-key" - the first one found is used.
*
* FIXME: Allow for encrypted secret keys here.
*
* Returns: A pointer to an allocated array of MPIs if the return value is
* zero; the caller has to release this array.
*
* Example of a DSA public key:
* (private-key
* (dsa
* (p <mpi>)
* (g <mpi>)
* (y <mpi>)
* (x <mpi>)
* )
* )
* The <mpi> are expected to be in GCRYMPI_FMT_USG
*/
static int
sexp_to_key( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
{
GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
int algo;
const char *elems1, *elems2;
GCRY_MPI *array;
/* check that the first element is valid */
list = gcry_sexp_find_token( sexp, want_private? "private-key"
:"public-key", 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a public- or private-key object */
list = gcry_sexp_cdr( list );
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the key object */
name = gcry_sexp_car_data( list, &n );
if( !name )
return GCRYERR_INV_OBJ; /* invalid structure of object */
for(i=0; (s=algo_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
algo = algo_info_table[i].algo;
elems1 = algo_info_table[i].common_elements;
elems2 = want_private? algo_info_table[i].secret_elements
: algo_info_table[i].public_elements;
array = g10_calloc( strlen(elems1)+strlen(elems2)+1, sizeof *array );
if( !array )
return GCRYERR_NO_MEM;
idx = 0;
for(s=elems1; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
for(s=elems2; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
/* FIXME: put the MPI in secure memory when needed */
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
for(i=0; i<idx; i++)
g10_free( array[i] );
g10_free( array );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
*retarray = array;
*retalgo = algo;
return 0;
}
static int
sexp_to_sig( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
{
GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
int algo;
const char *elems;
GCRY_MPI *array;
/* check that the first element is valid */
list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a signature value object */
list = gcry_sexp_cdr( list );
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the sig object */
name = gcry_sexp_car_data( list, &n );
if( !name )
return GCRYERR_INV_OBJ; /* invalid structure of object */
for(i=0; (s=sig_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
algo = sig_info_table[i].algo;
elems = sig_info_table[i].elements;
array = g10_calloc( (strlen(elems)+1) , sizeof *array );
if( !array )
return GCRYERR_NO_MEM;
idx = 0;
for(s=elems; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
*retarray = array;
*retalgo = algo;
return 0;
}
/****************
* Take sexp and return an array of MPI as used for our internal decrypt
* function.
*/
static int
sexp_to_enc( GCRY_SEXP sexp, MPI **retarray, int *retalgo)
{
GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
int algo;
const char *elems;
GCRY_MPI *array;
/* check that the first element is valid */
list = gcry_sexp_find_token( sexp, "enc-val" , 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain a encrypted value object */
list = gcry_sexp_cdr( list );
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the data object */
name = gcry_sexp_car_data( list, &n );
if( !name )
return GCRYERR_INV_OBJ; /* invalid structure of object */
for(i=0; (s=enc_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
algo = enc_info_table[i].algo;
elems = enc_info_table[i].elements;
array = g10_calloc( (strlen(elems)+1) , sizeof *array );
if( !array )
return GCRYERR_NO_MEM;
idx = 0;
for(s=elems; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return GCRYERR_NO_OBJ; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return GCRYERR_INV_OBJ; /* required parameter is invalid */
}
}
*retarray = array;
*retalgo = algo;
return 0;
}
/****************
* Do a PK encrypt operation
*
* Caller has to provide a public key as the SEXP pkey and data as a SEXP
* with just one MPI in it. The function returns a a sexp which may
* be passed tp to pk_decrypt.
* Later versions of this functions may take more complex input data.
*
* Returns: 0 or an errorcode.
*
* s_data = (<mpi>)
* s_pkey = <key-as-defined-in-sexp_to_key>
* r_ciph = (enc-val
* (<algo>
* (<param_name1> <mpi>)
* ...
* (<param_namen> <mpi>)
* ))
*/
int
gcry_pk_encrypt( GCRY_SEXP *r_ciph, GCRY_SEXP s_data, GCRY_SEXP s_pkey )
{
MPI *pkey, data, *ciph;
const char *algo_name, *algo_elems;
GCRY_SEXP *s_elems;
int i, rc, algo;
/* get the key */
rc = sexp_to_key( s_pkey, 0, &pkey, &algo );
if( rc ) {
return rc;
}
/* get the name and the required size of the return value */
for(i=0; (algo_name = enc_info_table[i].name); i++ ) {
if( enc_info_table[i].algo == algo )
break;
}
if( !algo_name ) {
release_mpi_array( pkey );
return GCRYERR_INV_PK_ALGO;
}
algo_elems = enc_info_table[i].elements;
/* get the stuff we want to encrypt */
data = gcry_sexp_car_mpi( s_data, 0 );
if( !data ) {
release_mpi_array( pkey );
return GCRYERR_INV_OBJ;
}
/* Now we can encrypt data to ciph */
ciph = g10_xcalloc( (strlen(algo_elems)+1) , sizeof *ciph );
rc = pubkey_encrypt( algo, ciph, data, pkey );
release_mpi_array( pkey );
mpi_free( data );
if( rc ) {
g10_free( ciph );
return rc;
}
/* We did it. Now build the return list */
s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
s_elems[0] = SEXP_NEW( algo_name, 0 );
for(i=0; algo_elems[i]; i++ ) {
char tmp[2];
tmp[0] = algo_elems[i];
tmp[1] = 0;
s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, ciph[i] );
}
release_mpi_array( ciph );
g10_free( ciph );
*r_ciph = SEXP_CONS( SEXP_NEW( "enc-val", 0 ),
gcry_sexp_alist( s_elems ) );
g10_free( s_elems );
return 0;
}
/****************
* Do a PK decrypt operation
*
* Caller has to provide a secret key as the SEXP skey and data in a format
* as created by gcry_pk_encrypt. Currently the function returns
* simply a MPI. Later versions of this functions may return a more
* complex data structure.
*
* Returns: 0 or an errorcode.
*
* s_data = (enc-val
* (<algo>
* (<param_name1> <mpi>)
* ...
* (<param_namen> <mpi>)
* ))
* s_skey = <key-as-defined-in-sexp_to_key>
* r_plain= (<mpi>) FIXME: Return a more structered value
*/
int
gcry_pk_decrypt( GCRY_SEXP *r_plain, GCRY_SEXP s_data, GCRY_SEXP s_skey )
{
MPI *skey, *data, plain;
int rc, algo, dataalgo;
rc = sexp_to_key( s_skey, 1, &skey, &algo );
if( rc ) {
return rc;
}
rc = sexp_to_enc( s_data, &data, &dataalgo );
if( rc ) {
release_mpi_array( skey );
return rc;
}
if( algo != dataalgo ) {
release_mpi_array( skey );
release_mpi_array( data );
return -1; /* fixme: add real errornumber - algo does not match */
}
rc = pubkey_decrypt( algo, &plain, data, skey );
if( rc ) {
release_mpi_array( skey );
release_mpi_array( data );
return -1; /* fixme: add real errornumber - decryption failed */
}
*r_plain = gcry_sexp_new_mpi( plain );
mpi_free( plain );
release_mpi_array( data );
release_mpi_array( skey );
return 0;
}
/****************
* Create a signature.
*
* Caller has to provide a secret key as the SEXP skey and data expressed
* as a SEXP list hash with only one element which should instantly be
* available as a MPI. Later versions of this functions may provide padding
* and other things depending on data.
*
* Returns: 0 or an errorcode.
* In case of 0 the function returns a new SEXP with the
* signature value; the structure of this signature depends on the
* other arguments but is always suitable to be passed to
* gcry_pk_verify
*
* s_hash = (<mpi>)
* s_skey = <key-as-defined-in-sexp_to_key>
* r_sig = (sig-val
* (<algo>
* (<param_name1> <mpi>)
* ...
* (<param_namen> <mpi>)
* ))
*/
int
gcry_pk_sign( GCRY_SEXP *r_sig, GCRY_SEXP s_hash, GCRY_SEXP s_skey )
{
MPI *skey, hash;
MPI *result;
int i, algo, rc;
const char *algo_name, *algo_elems;
GCRY_SEXP *s_elems;
rc = sexp_to_key( s_skey, 1, &skey, &algo );
if( rc )
return rc;
/* get the name and the required size of the result array */
for(i=0; (algo_name = sig_info_table[i].name); i++ ) {
if( sig_info_table[i].algo == algo )
break;
}
if( !algo_name ) {
release_mpi_array( skey );
return -4; /* oops: unknown algorithm */
}
algo_elems = sig_info_table[i].elements;
/* get the stuff we want to sign */
hash = gcry_sexp_car_mpi( s_hash, 0 );
if( !hash ) {
release_mpi_array( skey );
return -1; /* fixme: get a real errorcode for this */
}
result = g10_xcalloc( (strlen(algo_elems)+1) , sizeof *result );
rc = pubkey_sign( algo, result, hash, skey );
release_mpi_array( skey );
mpi_free( hash );
if( rc ) {
g10_free( result );
return rc;
}
s_elems = g10_xcalloc( (strlen(algo_elems)+2), sizeof *s_elems );
s_elems[0] = SEXP_NEW( algo_name, 0 );
for(i=0; algo_elems[i]; i++ ) {
char tmp[2];
tmp[0] = algo_elems[i];
tmp[1] = 0;
s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, result[i] );
}
release_mpi_array( result );
g10_free( result );
*r_sig = SEXP_CONS( SEXP_NEW( "sig-val", 0 ),
gcry_sexp_alist( s_elems ) );
g10_free( s_elems );
return 0;
}
/****************
* Verify a sgnature. Caller has to supply the public key pkey,
* the signature sig and his hashvalue data. Public key has to be
* a standard public key given as an S-Exp, sig is a S-Exp as returned
* from gcry_pk_sign and data must be an S-Exp like the one in sign too.
*/
int
gcry_pk_verify( GCRY_SEXP s_sig, GCRY_SEXP s_hash, GCRY_SEXP s_pkey )
{
MPI *pkey, hash, *sig;
int algo, sigalgo;
int rc;
rc = sexp_to_key( s_pkey, 0, &pkey, &algo );
if( rc )
return rc;
rc = sexp_to_sig( s_sig, &sig, &sigalgo );
if( rc ) {
release_mpi_array( pkey );
return rc;
}
if( algo != sigalgo ) {
release_mpi_array( pkey );
release_mpi_array( sig );
return -1; /* fixme: add real errornumber - algo does not match */
}
hash = gcry_sexp_car_mpi( s_hash, 0 );
if( !hash ) {
release_mpi_array( pkey );
release_mpi_array( sig );
return -1; /* fixme: get a real errorcode for this */
}
rc = pubkey_verify( algo, hash, sig, pkey, NULL, NULL );
release_mpi_array( pkey );
release_mpi_array( sig );
mpi_free(hash);
return rc;
}
/****************
* Test a key. This may be used either for a public or a secret key
* to see whether internal structre is valid.
*
* Returns: 0 or an errorcode.
*
* s_key = <key-as-defined-in-sexp_to_key>
*/
int
gcry_pk_testkey( GCRY_SEXP s_key )
{
MPI *key;
int rc, algo;
/* Note we currently support only secret key checking */
rc = sexp_to_key( s_key, 1, &key, &algo );
if( rc ) {
return rc;
}
rc = pubkey_check_secret_key( algo, key );
release_mpi_array( key );
return rc;
}
/****************
* Create a public key pair and return it in r_key.
* How the key is created depends on s_parms:
* (genkey
* (algo
* (parameter_name_1 ....)
* ....
* (parameter_name_n ....)
* ))
* The key is returned in a format depending on the
* algorithm. Both, private and secret keys are returned
* and optionally some additional informatin.
* For elgamal we return this structure:
* (key-data
* (public-key
* (elg
* (p <mpi>)
* (g <mpi>)
* (y <mpi>)
* )
* )
* (private-key
* (elg
* (p <mpi>)
* (g <mpi>)
* (y <mpi>)
* (x <mpi>)
* )
* )
* (misc-key-info
* (pm1-factors n1 n2 ... nn)
* )
* )
*/
int
gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms )
{
GCRY_SEXP list, l2, *s_elems, pub_list, sec_list, misc_list;
const char *name;
const char *s;
size_t n;
int rc, i;
const char *algo_name;
int algo;
char sec_elems[20], pub_elems[20]; /* fixme: check bounds */
GCRY_MPI skey[10], *factors;
unsigned int nbits;
list = gcry_sexp_find_token( s_parms, "genkey", 0 );
if( !list )
return GCRYERR_INV_OBJ; /* Does not contain genkey data */
list = gcry_sexp_cdr( list );
if( !list )
return GCRYERR_NO_OBJ; /* no cdr for the genkey */
name = gcry_sexp_car_data( list, &n );
if( !name )
return GCRYERR_INV_OBJ; /* algo string missing */
for(i=0; (s=algo_info_table[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return GCRYERR_INV_PK_ALGO; /* unknown algorithm */
algo = algo_info_table[i].algo;
algo_name = algo_info_table[i].name;
strcpy( pub_elems, algo_info_table[i].common_elements );
strcat( pub_elems, algo_info_table[i].public_elements );
strcpy( sec_elems, algo_info_table[i].common_elements );
strcat( sec_elems, algo_info_table[i].secret_elements );
l2 = gcry_sexp_find_token( list, "nbits", 0 );
if( !l2 )
return GCRYERR_NO_OBJ; /* no nbits aparemter */
name = gcry_sexp_cdr_data( l2, &n );
if( !name )
return GCRYERR_INV_OBJ; /* nbits without a cdr */
{
char *p = g10_xmalloc(n+1);
memcpy(p, name, n );
p[n] = 0;
nbits = (unsigned int)strtol( p, NULL, 0 );
g10_free( p );
}
rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
return rc;
}
/* build the public key list */
s_elems = g10_xcalloc( (strlen(pub_elems)+2), sizeof *s_elems );
s_elems[0] = SEXP_NEW( algo_name, 0 );
for(i=0; pub_elems[i]; i++ ) {
char tmp[2];
tmp[0] = pub_elems[i];
tmp[1] = 0;
s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, skey[i] );
}
pub_list = SEXP_CONS( SEXP_NEW( "public-key", 0 ),
gcry_sexp_alist( s_elems ) );
g10_free( s_elems );
/* build the secret key list */
s_elems = g10_xcalloc( (strlen(sec_elems)+2), sizeof *s_elems );
s_elems[0] = SEXP_NEW( algo_name, 0 );
for(i=0; sec_elems[i]; i++ ) {
char tmp[2];
tmp[0] = sec_elems[i];
tmp[1] = 0;
s_elems[i+1] = gcry_sexp_new_name_mpi( tmp, skey[i] );
}
sec_list = SEXP_CONS( SEXP_NEW( "private-key", 0 ),
gcry_sexp_alist( s_elems ) );
g10_free( s_elems );
/* build the list of factors */
for(n=0; factors[n]; n++ )
;
s_elems = g10_xcalloc( n+2, sizeof *s_elems );
s_elems[0] = SEXP_NEW( "pm1-factors", 0 );
for(i=0; factors[i]; i++ ) {
s_elems[i+1] = gcry_sexp_new_mpi( factors[i] );
}
misc_list = SEXP_CONS( SEXP_NEW( "misc-key-info", 0 ),
gcry_sexp_alist( s_elems ) );
g10_free( s_elems );
/* and put all together */
*r_key = gcry_sexp_vlist( SEXP_NEW( "key-data", 0 ),
pub_list, sec_list, misc_list, NULL );
gcry_sexp_release( pub_list );
gcry_sexp_release( sec_list );
gcry_sexp_release( misc_list );
return 0;
}
/****************
* Get the number of nbits from the public key
* Hmmm: Should we have really this function or is it
* better to have a more general function to retrieve
* different propoerties of the key?
*/
unsigned int
gcry_pk_get_nbits( GCRY_SEXP key )
{
int rc, i, algo;
MPI *keyarr;
unsigned int nbits = 0;
rc = sexp_to_key( key, 0, &keyarr, &algo );
if( rc == GCRYERR_INV_OBJ )
rc = sexp_to_key( key, 0, &keyarr, &algo );
if( rc )
return 0;
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
nbits = (*pubkey_table[i].get_nbits)( algo, keyarr );
goto leave;
}
} while( load_pubkey_modules() );
if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */
nbits = mpi_get_nbits( keyarr[0] );
leave:
release_mpi_array( keyarr );
return nbits;
}
int
gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
{
switch( cmd ) {
case GCRYCTL_DISABLE_ALGO:
/* this one expects a buffer pointing to an
* integer with the algo number.
*/
if( !buffer || buflen != sizeof(int) )
return set_lasterr( GCRYERR_INV_CIPHER_ALGO );
disable_pubkey_algo( *(int*)buffer );
break;
default:
return set_lasterr( GCRYERR_INV_OP );
}
return 0;
}
/****************
* Return information about the given algorithm
* WHAT select the kind of information returned:
* GCRYCTL_TEST_ALGO:
* Returns 0 when the specified algorithm is available for use.
* Buffer must be NULL, nbytes may have the address of a variable
* with the required usage of the algorithm. It may be 0 for don't
* care or a combination of the GCRY_PK_USAGE_xxx flags;
*
* On error the value -1 is returned and the error reason may be
* retrieved by gcry_errno().
* Note: Because this function is in most caes used to return an
* integer value, we can make it easier for the caller to just look at
* the return value. The caller will in all cases consult the value
* and thereby detecting whether a error occured or not (i.e. while checking
* the block size)
*/
int
gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
{
switch( what ) {
case GCRYCTL_TEST_ALGO: {
int use = nbytes? *nbytes: 0;
if( buffer ) {
set_lasterr( GCRYERR_INV_ARG );
return -1;
}
if( check_pubkey_algo( algo, use ) ) {
set_lasterr( GCRYERR_INV_PK_ALGO );
return -1;
}
}
break;
case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
case GCRYCTL_GET_ALGO_NENCR: return pubkey_get_nenc( algo );
default:
set_lasterr( GCRYERR_INV_OP );
return -1;
}
return 0;
}
diff --git a/cipher/random.c b/cipher/random.c
index 38991a18..f8faeebf 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -1,494 +1,688 @@
/* random.c - random number generator
- * Copyright (C) 1998 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/****************
* This random number generator is modelled after the one described
* in Peter Gutmann's Paper: "Software Generation of Practically
* Strong Random Numbers".
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.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>
#ifdef HAVE_GETHRTIME
#include <sys/times.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
#include <sys/times.h>
#endif
+#ifdef HAVE_CLOCK_GETTIME
+ #include <time.h>
+#endif
#ifdef HAVE_GETRUSAGE
#include <sys/resource.h>
#endif
+#ifdef __MINGW32__
+ #include <process.h>
+#endif
#include "g10lib.h"
#include "rmd.h"
#include "random.h"
#include "rand-internal.h"
#include "dynload.h"
#ifndef RAND_MAX /* for SunOS */
#define RAND_MAX 32767
#endif
#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
#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
* and poolsize must be a multiple of the digest length
* to make the AND operations faster, the size should also be
* a multiple of ulong
*/
#define POOLBLOCKS 30
#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
#error Please make sure that poolsize is a multiple of ulong
#endif
#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
static int is_initialized;
#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
static char *rndpool; /* allocated size is POOLSIZE+BLOCKLEN */
static char *keypool; /* allocated size is POOLSIZE+BLOCKLEN */
static size_t pool_readpos;
static size_t pool_writepos;
static int pool_filled;
static int pool_balance;
static int just_mixed;
+static int did_initial_extra_seeding;
+static char *seed_file_name;
+static int allow_seed_file_update;
static int secure_alloc;
static int quick_test;
static int faked_rng;
static byte *get_random_bytes( size_t nbytes, int level, int secure );
static void read_pool( byte *buffer, size_t length, int level );
static void add_randomness( const void *buffer, size_t length, int source );
static void random_poll(void);
static void read_random_source( int requester, size_t length, int level);
static int gather_faked( void (*add)(const void*, size_t, int), int requester,
size_t length, int level );
static struct {
ulong mixrnd;
ulong mixkey;
ulong slowpolls;
ulong fastpolls;
ulong getbytes1;
ulong ngetbytes1;
ulong getbytes2;
ulong ngetbytes2;
ulong addbytes;
ulong naddbytes;
} rndstats;
static void
initialize(void)
{
/* 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 ? g10_xcalloc_secure(1,POOLSIZE+BLOCKLEN)
: g10_xcalloc(1,POOLSIZE+BLOCKLEN);
keypool = secure_alloc ? g10_xcalloc_secure(1,POOLSIZE+BLOCKLEN)
: g10_xcalloc(1,POOLSIZE+BLOCKLEN);
is_initialized = 1;
cipher_modules_constructor();
}
void
random_dump_stats()
{
fprintf(stderr,
"random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
" outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
rndstats.naddbytes, rndstats.addbytes,
rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
rndstats.ngetbytes2, rndstats.getbytes2 );
}
void
secure_random_alloc()
{
secure_alloc = 1;
}
int
quick_random_gen( int onoff )
{
int last;
read_random_source(0,0,0); /* init */
last = quick_test;
if( onoff != -1 )
quick_test = onoff;
return faked_rng? 1 : last;
}
/****************
* Fill the buffer with LENGTH bytes of cryptographically strong
* random bytes. level 0 is not very strong, 1 is strong enough
* for most usage, 2 is good for key generation stuff but may be very slow.
*/
void
gcry_randomize( byte *buffer, size_t length, enum gcry_random_level level )
{
char *p = get_random_bytes( length, level, 1 );
memcpy( buffer, p, length );
g10_free(p);
}
int
random_is_faked()
{
if( !is_initialized )
initialize();
return faked_rng || quick_test;
}
/****************
* Return a pointer to a randomized buffer of level 0 and LENGTH bits
* caller must free the buffer.
* Note: The returned value is rounded up to bytes.
*/
static byte *
get_random_bytes( size_t nbytes, int level, int secure )
{
byte *buf, *p;
if( quick_test && level > 1 )
level = 1;
MASK_LEVEL(level);
if( level == 1 ) {
rndstats.getbytes1 += nbytes;
rndstats.ngetbytes1++;
}
else if( level >= 2 ) {
rndstats.getbytes2 += nbytes;
rndstats.ngetbytes2++;
}
buf = secure && secure_alloc ? g10_xmalloc_secure( nbytes )
: g10_xmalloc( nbytes );
for( p = buf; nbytes > 0; ) {
size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
read_pool( p, n, level );
nbytes -= n;
p += n;
}
return buf;
}
void *
gcry_random_bytes( size_t nbytes, enum gcry_random_level level )
{
return get_random_bytes( nbytes, level, 0 );
}
void *
gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level )
{
return get_random_bytes( nbytes, level, 1 );
}
/****************
* Mix the pool
*/
static void
mix_pool(byte *pool)
{
char *hashbuf = pool + POOLSIZE;
char *p, *pend;
int i, n;
RMD160_CONTEXT md;
rmd160_init( &md );
#if DIGESTLEN != 20
#error must have a digest length of 20 for ripe-md-160
#endif
/* loop over the pool */
pend = pool + POOLSIZE;
memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
rmd160_mixblock( &md, hashbuf);
memcpy(pool, hashbuf, 20 );
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 {
char *pp = p+DIGESTLEN;
for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
if( pp >= pend )
pp = pool;
hashbuf[i] = *pp++;
}
}
rmd160_mixblock( &md, hashbuf);
memcpy(p, hashbuf, 20 );
}
}
+void
+set_random_seed_file( const char *name )
+{
+ if( seed_file_name )
+ BUG();
+ seed_file_name = g10_xstrdup( name );
+}
+
+/****************
+ * Read in a seed form the random_seed file
+ * and return true if this was successful
+ */
+static int
+read_seed_file()
+{
+ int fd;
+ struct stat sb;
+ unsigned char buffer[POOLSIZE];
+ int n;
+
+ if( !seed_file_name )
+ return 0;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_RDONLY | O_BINARY );
+ #else
+ fd = open( seed_file_name, O_RDONLY );
+ #endif
+ if( fd == -1 && errno == ENOENT) {
+ allow_seed_file_update = 1;
+ return 0;
+ }
+
+ if( fd == -1 ) {
+ log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+ return 0;
+ }
+ if( fstat( fd, &sb ) ) {
+ log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+ close(fd);
+ return 0;
+ }
+ if( !S_ISREG(sb.st_mode) ) {
+ log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+ close(fd);
+ return 0;
+ }
+ if( !sb.st_size ) {
+ log_info(_("note: random_seed file is empty\n") );
+ close(fd);
+ allow_seed_file_update = 1;
+ return 0;
+ }
+ if( sb.st_size != POOLSIZE ) {
+ log_info(_("warning: invalid size of random_seed file - not used\n") );
+ close(fd);
+ return 0;
+ }
+ do {
+ n = read( fd, buffer, POOLSIZE );
+ } while( n == -1 && errno == EINTR );
+ if( n != POOLSIZE ) {
+ log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ add_randomness( buffer, POOLSIZE, 0 );
+ /* add some minor entropy to the pool now (this will also force a mixing) */
+ { pid_t x = getpid();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 0 );
+ }
+ /* And read a few bytes from our entropy source. By using
+ * a level of 0 this will not block and might not return anything
+ * with some entropy drivers, however the rndlinux driver will use
+ * /dev/urandom and return some stuff - Do not read to much as we
+ * want to be friendly to the scare system entropy resource. */
+ read_random_source( 0, 16, 0 );
+
+ allow_seed_file_update = 1;
+ return 1;
+}
+
+void
+update_random_seed_file()
+{
+ ulong *sp, *dp;
+ int fd, i;
+
+ if( !seed_file_name || !is_initialized || !pool_filled )
+ return;
+ if( !allow_seed_file_update ) {
+ log_info(_("note: random_seed file not updated\n"));
+ return;
+ }
+
+
+ /* copy the entropy pool to a scratch pool and mix both of them */
+ for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+ i < POOLWORDS; i++, dp++, sp++ ) {
+ *dp = *sp + ADD_VALUE;
+ }
+ mix_pool(rndpool); rndstats.mixrnd++;
+ mix_pool(keypool); rndstats.mixkey++;
+
+ #ifdef HAVE_DOSISH_SYSTEM
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+ S_IRUSR|S_IWUSR );
+ #else
+ fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+ #endif
+ if( fd == -1 ) {
+ log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+ return;
+ }
+ do {
+ i = write( fd, keypool, POOLSIZE );
+ } while( i == -1 && errno == EINTR );
+ if( i != POOLSIZE ) {
+ log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+ }
+ if( close(fd) )
+ log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+}
+
static void
read_pool( byte *buffer, size_t length, int level )
{
int i;
ulong *sp, *dp;
- if( length >= POOLSIZE )
- BUG(); /* not allowed */
+ if( length >= POOLSIZE ) {
+ log_fatal(_("too many random bits requested; the limit is %d\n"),
+ POOLSIZE*8-1 );
+ }
+
+ if( !pool_filled ) {
+ if( read_seed_file() )
+ pool_filled = 1;
+ }
+
+ /* For level 2 quality (key generation) we alwas make
+ * sure that the pool has been seeded enough initially */
+ if( level == 2 && !did_initial_extra_seeding ) {
+ size_t needed;
+
+ pool_balance = 0;
+ needed = length - pool_balance;
+ if( needed < POOLSIZE/2 )
+ needed = POOLSIZE/2;
+ else if( needed > POOLSIZE )
+ BUG();
+ read_random_source( 3, needed, 2 );
+ pool_balance += needed;
+ did_initial_extra_seeding=1;
+ }
/* for level 2 make sure that there is enough random in the pool */
if( level == 2 && pool_balance < length ) {
size_t needed;
if( pool_balance < 0 )
pool_balance = 0;
needed = length - pool_balance;
if( needed > POOLSIZE )
BUG();
read_random_source( 3, needed, 2 );
pool_balance += needed;
}
/* make sure the pool is filled */
while( !pool_filled )
random_poll();
/* do always a fast random poll */
fast_random_poll();
if( !level ) { /* no need for cryptographic strong random */
/* create a new pool */
for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
i < POOLWORDS; i++, dp++, sp++ )
*dp = *sp + ADD_VALUE;
/* must mix both pools */
mix_pool(rndpool); rndstats.mixrnd++;
mix_pool(keypool); rndstats.mixkey++;
memcpy( buffer, keypool, length );
}
else {
/* 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=(ulong*)keypool, sp=(ulong*)rndpool;
i < POOLWORDS; i++, dp++, sp++ )
*dp = *sp + ADD_VALUE;
/* and mix both pools */
mix_pool(rndpool); rndstats.mixrnd++;
mix_pool(keypool); rndstats.mixkey++;
/* read the required data
* we use a readpoiter to read from a different postion each
* time */
while( length-- ) {
*buffer++ = keypool[pool_readpos++];
if( pool_readpos >= POOLSIZE )
pool_readpos = 0;
pool_balance--;
}
if( pool_balance < 0 )
pool_balance = 0;
/* and clear the keypool */
memset( keypool, 0, POOLSIZE );
}
}
/****************
* Add LENGTH bytes of randomness from buffer to the pool.
* source may be used to specify the randomness source.
+ * Source is:
+ * 0 - used ony for initialization
+ * 1 - fast random poll function
+ * 2 - normal poll function
+ * 3 - used when level 2 random quality has been requested
+ * to do an extra pool seed.
*/
static void
add_randomness( const void *buffer, size_t length, int source )
{
const byte *p = buffer;
if( !is_initialized )
initialize();
rndstats.addbytes += length;
rndstats.naddbytes++;
while( length-- ) {
rndpool[pool_writepos++] = *p++;
if( pool_writepos >= POOLSIZE ) {
if( source > 1 )
pool_filled = 1;
pool_writepos = 0;
mix_pool(rndpool); rndstats.mixrnd++;
just_mixed = !length;
}
}
}
static void
random_poll()
{
rndstats.slowpolls++;
read_random_source( 2, POOLSIZE/5, 1 );
}
void
fast_random_poll()
{
static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
static int initialized = 0;
rndstats.fastpolls++;
if( !initialized ) {
if( !is_initialized )
initialize();
initialized = 1;
fnc = dynload_getfnc_fast_random_poll();
}
if( fnc ) {
(*fnc)( add_randomness, 1 );
return;
}
/* fall back to the generic function */
#if HAVE_GETHRTIME
{ hrtime_t tv;
tv = gethrtime();
add_randomness( &tv, sizeof(tv), 1 );
}
#elif HAVE_GETTIMEOFDAY
{ struct timeval tv;
if( gettimeofday( &tv, NULL ) )
BUG();
add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
}
+ #elif HAVE_CLOCK_GETTIME
+ { struct timespec tv;
+ if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+ BUG();
+ add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+ add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+ }
#else /* use times */
#ifndef HAVE_DOSISH_SYSTEM
{ struct tms buf;
times( &buf );
add_randomness( &buf, sizeof buf, 1 );
}
#endif
#endif
#ifdef HAVE_GETRUSAGE
+ #ifndef RUSAGE_SELF
+ #ifdef __GCC__
+ #warning There is no RUSAGE_SELF on this system
+ #endif
+ #else
{ struct rusage buf;
if( getrusage( RUSAGE_SELF, &buf ) )
BUG();
add_randomness( &buf, sizeof buf, 1 );
memset( &buf, 0, sizeof buf );
}
+ #endif
#endif
+ /* time and clock are availabe on all systems - so
+ * we better do it just in case one of the above functions
+ * didn't work */
+ { time_t x = time(NULL);
+ add_randomness( &x, sizeof(x), 1 );
+ }
+ { clock_t x = clock();
+ add_randomness( &x, sizeof(x), 1 );
+ }
}
static void
read_random_source( int requester, size_t length, int level )
{
static int (*fnc)(void (*)(const void*, size_t, int), int,
size_t, int) = NULL;
if( !fnc ) {
if( !is_initialized )
initialize();
fnc = dynload_getfnc_gather_random();
if( !fnc ) {
faked_rng = 1;
fnc = gather_faked;
}
if( !requester && !length && !level )
return; /* init only */
}
if( (*fnc)( add_randomness, requester, length, level ) < 0 )
log_fatal("No way to gather entropy for the RNG\n");
}
static int
gather_faked( void (*add)(const void*, size_t, int), int requester,
size_t length, int level )
{
static int initialized=0;
size_t n;
char *buffer, *p;
if( !initialized ) {
log_info(_("WARNING: using insecure random number generator!!\n"));
/* we can't use tty_printf here - do we need this function at
all - does it really make sense or canit be viewed as a potential
security problem ? wk 17.11.99 */
#warning Extended warning disabled
#if 0
tty_printf(_("The random number generator is only a kludge to let\n"
"it run - it is in no way a strong RNG!\n\n"
"DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
#endif
initialized=1;
#ifdef HAVE_RAND
- srand( time(NULL) * getpid());
+ srand(make_timestamp()*getpid());
#else
- srandom( time(NULL) * getpid());
+ srandom(make_timestamp()*getpid());
#endif
}
p = buffer = g10_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, requester );
g10_free(buffer);
return 0; /* okay */
}
diff --git a/cipher/rmd160.c b/cipher/rmd160.c
index 7b230087..fb9d6fa5 100644
--- a/cipher/rmd160.c
+++ b/cipher/rmd160.c
@@ -1,632 +1,632 @@
/* rmd160.c - RIPE-MD160
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "memory.h"
#include "rmd.h"
#include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
#include "dynload.h"
#include "bithelp.h"
/*********************************
* RIPEMD-160 is not patented, see (as of 25.10.97)
* http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
* Note that the code uses Little Endian byteorder, which is good for
* 386 etc, but we must add some conversion when used on a big endian box.
*
*
* Pseudo-code for RIPEMD-160
*
* RIPEMD-160 is an iterative hash function that operates on 32-bit words.
* The round function takes as input a 5-word chaining variable and a 16-word
* message block and maps this to a new chaining variable. All operations are
* defined on 32-bit words. Padding is identical to that of MD4.
*
*
* RIPEMD-160: definitions
*
*
* nonlinear functions at bit level: exor, mux, -, mux, -
*
* f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15)
* f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31)
* f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47)
* f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63)
* f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79)
*
*
* added constants (hexadecimal)
*
* K(j) = 0x00000000 (0 <= j <= 15)
* K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2))
* K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3))
* K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5))
* K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7))
* K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2))
* K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3))
* K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5))
* K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7))
* K'(j) = 0x00000000 (64 <= j <= 79)
*
*
* selection of message word
*
* r(j) = j (0 <= j <= 15)
* r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
* r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
* r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
* r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
* r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
* r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
* r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
* r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
* r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
*
*
* amount for rotate left (rol)
*
* s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
* s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
* s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
* s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
* s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
* s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
* s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
* s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
* s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
* s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
*
*
* initial value (hexadecimal)
*
* h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
* h4 = 0xC3D2E1F0;
*
*
* RIPEMD-160: pseudo-code
*
* It is assumed that the message after padding consists of t 16-word blocks
* that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
* The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
* shift (rotate) over s positions.
*
*
* for i := 0 to t-1 {
* A := h0; B := h1; C := h2; D = h3; E = h4;
* A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
* for j := 0 to 79 {
* T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
* A := E; E := D; D := rol_10(C); C := B; B := T;
* T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
[+] K'(j)) [+] E';
* A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
* }
* T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
* h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
* }
*/
/* Some examples:
* "" 9c1185a5c5e9fc54612808977ee8f548b2258d31
* "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
* "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
* "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36
* "a...z" f71c27109c692c1b56bbdceb5b9d2865b3708dbc
* "abcdbcde...nopq" 12a053384a9c0c88e405a06c27dcf49ada62eb2b
* "A...Za...z0...9" b0e20b6e3116640286ed3a87a5713079b21f5189
* 8 times "1234567890" 9b752e45573d4b39f4dbd3323cab82bf63326bfb
* 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528
*/
void
rmd160_init( RMD160_CONTEXT *hd )
{
hd->h0 = 0x67452301;
hd->h1 = 0xEFCDAB89;
hd->h2 = 0x98BADCFE;
hd->h3 = 0x10325476;
hd->h4 = 0xC3D2E1F0;
hd->nblocks = 0;
hd->count = 0;
}
/****************
* Transform the message X which consists of 16 32-bit-words
*/
static void
transform( RMD160_CONTEXT *hd, byte *data )
{
u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
#ifdef BIG_ENDIAN_HOST
u32 x[16];
{ int i;
byte *p2, *p1;
for(i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
p2[3] = *p1++;
p2[2] = *p1++;
p2[1] = *p1++;
p2[0] = *p1++;
}
}
#else
#if 0
u32 *x =(u32*)data;
#else
/* this version is better because it is always aligned;
* The performance penalty on a 586-100 is about 6% which
* is acceptable - because the data is more local it might
* also be possible that this is faster on some machines.
* This function (when compiled with -02 on gcc 2.7.2)
* executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
* [measured with a 4MB data and "gpgm --print-md rmd160"] */
u32 x[16];
memcpy( x, data, 64 );
#endif
#endif
#define K0 0x00000000
#define K1 0x5A827999
#define K2 0x6ED9EBA1
#define K3 0x8F1BBCDC
#define K4 0xA953FD4E
#define KK0 0x50A28BE6
#define KK1 0x5C4DD124
#define KK2 0x6D703EF3
#define KK3 0x7A6D76E9
#define KK4 0x00000000
#define F0(x,y,z) ( (x) ^ (y) ^ (z) )
#define F1(x,y,z) ( ((x) & (y)) | (~(x) & (z)) )
#define F2(x,y,z) ( ((x) | ~(y)) ^ (z) )
#define F3(x,y,z) ( ((x) & (z)) | ((y) & ~(z)) )
#define F4(x,y,z) ( (x) ^ ((y) | ~(z)) )
#define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
a = rol(t,s) + e; \
c = rol(c,10); \
} while(0)
/* left lane */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
R( a, b, c, d, e, F0, K0, 0, 11 );
R( e, a, b, c, d, F0, K0, 1, 14 );
R( d, e, a, b, c, F0, K0, 2, 15 );
R( c, d, e, a, b, F0, K0, 3, 12 );
R( b, c, d, e, a, F0, K0, 4, 5 );
R( a, b, c, d, e, F0, K0, 5, 8 );
R( e, a, b, c, d, F0, K0, 6, 7 );
R( d, e, a, b, c, F0, K0, 7, 9 );
R( c, d, e, a, b, F0, K0, 8, 11 );
R( b, c, d, e, a, F0, K0, 9, 13 );
R( a, b, c, d, e, F0, K0, 10, 14 );
R( e, a, b, c, d, F0, K0, 11, 15 );
R( d, e, a, b, c, F0, K0, 12, 6 );
R( c, d, e, a, b, F0, K0, 13, 7 );
R( b, c, d, e, a, F0, K0, 14, 9 );
R( a, b, c, d, e, F0, K0, 15, 8 );
R( e, a, b, c, d, F1, K1, 7, 7 );
R( d, e, a, b, c, F1, K1, 4, 6 );
R( c, d, e, a, b, F1, K1, 13, 8 );
R( b, c, d, e, a, F1, K1, 1, 13 );
R( a, b, c, d, e, F1, K1, 10, 11 );
R( e, a, b, c, d, F1, K1, 6, 9 );
R( d, e, a, b, c, F1, K1, 15, 7 );
R( c, d, e, a, b, F1, K1, 3, 15 );
R( b, c, d, e, a, F1, K1, 12, 7 );
R( a, b, c, d, e, F1, K1, 0, 12 );
R( e, a, b, c, d, F1, K1, 9, 15 );
R( d, e, a, b, c, F1, K1, 5, 9 );
R( c, d, e, a, b, F1, K1, 2, 11 );
R( b, c, d, e, a, F1, K1, 14, 7 );
R( a, b, c, d, e, F1, K1, 11, 13 );
R( e, a, b, c, d, F1, K1, 8, 12 );
R( d, e, a, b, c, F2, K2, 3, 11 );
R( c, d, e, a, b, F2, K2, 10, 13 );
R( b, c, d, e, a, F2, K2, 14, 6 );
R( a, b, c, d, e, F2, K2, 4, 7 );
R( e, a, b, c, d, F2, K2, 9, 14 );
R( d, e, a, b, c, F2, K2, 15, 9 );
R( c, d, e, a, b, F2, K2, 8, 13 );
R( b, c, d, e, a, F2, K2, 1, 15 );
R( a, b, c, d, e, F2, K2, 2, 14 );
R( e, a, b, c, d, F2, K2, 7, 8 );
R( d, e, a, b, c, F2, K2, 0, 13 );
R( c, d, e, a, b, F2, K2, 6, 6 );
R( b, c, d, e, a, F2, K2, 13, 5 );
R( a, b, c, d, e, F2, K2, 11, 12 );
R( e, a, b, c, d, F2, K2, 5, 7 );
R( d, e, a, b, c, F2, K2, 12, 5 );
R( c, d, e, a, b, F3, K3, 1, 11 );
R( b, c, d, e, a, F3, K3, 9, 12 );
R( a, b, c, d, e, F3, K3, 11, 14 );
R( e, a, b, c, d, F3, K3, 10, 15 );
R( d, e, a, b, c, F3, K3, 0, 14 );
R( c, d, e, a, b, F3, K3, 8, 15 );
R( b, c, d, e, a, F3, K3, 12, 9 );
R( a, b, c, d, e, F3, K3, 4, 8 );
R( e, a, b, c, d, F3, K3, 13, 9 );
R( d, e, a, b, c, F3, K3, 3, 14 );
R( c, d, e, a, b, F3, K3, 7, 5 );
R( b, c, d, e, a, F3, K3, 15, 6 );
R( a, b, c, d, e, F3, K3, 14, 8 );
R( e, a, b, c, d, F3, K3, 5, 6 );
R( d, e, a, b, c, F3, K3, 6, 5 );
R( c, d, e, a, b, F3, K3, 2, 12 );
R( b, c, d, e, a, F4, K4, 4, 9 );
R( a, b, c, d, e, F4, K4, 0, 15 );
R( e, a, b, c, d, F4, K4, 5, 5 );
R( d, e, a, b, c, F4, K4, 9, 11 );
R( c, d, e, a, b, F4, K4, 7, 6 );
R( b, c, d, e, a, F4, K4, 12, 8 );
R( a, b, c, d, e, F4, K4, 2, 13 );
R( e, a, b, c, d, F4, K4, 10, 12 );
R( d, e, a, b, c, F4, K4, 14, 5 );
R( c, d, e, a, b, F4, K4, 1, 12 );
R( b, c, d, e, a, F4, K4, 3, 13 );
R( a, b, c, d, e, F4, K4, 8, 14 );
R( e, a, b, c, d, F4, K4, 11, 11 );
R( d, e, a, b, c, F4, K4, 6, 8 );
R( c, d, e, a, b, F4, K4, 15, 5 );
R( b, c, d, e, a, F4, K4, 13, 6 );
aa = a; bb = b; cc = c; dd = d; ee = e;
/* right lane */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
R( a, b, c, d, e, F4, KK0, 5, 8);
R( e, a, b, c, d, F4, KK0, 14, 9);
R( d, e, a, b, c, F4, KK0, 7, 9);
R( c, d, e, a, b, F4, KK0, 0, 11);
R( b, c, d, e, a, F4, KK0, 9, 13);
R( a, b, c, d, e, F4, KK0, 2, 15);
R( e, a, b, c, d, F4, KK0, 11, 15);
R( d, e, a, b, c, F4, KK0, 4, 5);
R( c, d, e, a, b, F4, KK0, 13, 7);
R( b, c, d, e, a, F4, KK0, 6, 7);
R( a, b, c, d, e, F4, KK0, 15, 8);
R( e, a, b, c, d, F4, KK0, 8, 11);
R( d, e, a, b, c, F4, KK0, 1, 14);
R( c, d, e, a, b, F4, KK0, 10, 14);
R( b, c, d, e, a, F4, KK0, 3, 12);
R( a, b, c, d, e, F4, KK0, 12, 6);
R( e, a, b, c, d, F3, KK1, 6, 9);
R( d, e, a, b, c, F3, KK1, 11, 13);
R( c, d, e, a, b, F3, KK1, 3, 15);
R( b, c, d, e, a, F3, KK1, 7, 7);
R( a, b, c, d, e, F3, KK1, 0, 12);
R( e, a, b, c, d, F3, KK1, 13, 8);
R( d, e, a, b, c, F3, KK1, 5, 9);
R( c, d, e, a, b, F3, KK1, 10, 11);
R( b, c, d, e, a, F3, KK1, 14, 7);
R( a, b, c, d, e, F3, KK1, 15, 7);
R( e, a, b, c, d, F3, KK1, 8, 12);
R( d, e, a, b, c, F3, KK1, 12, 7);
R( c, d, e, a, b, F3, KK1, 4, 6);
R( b, c, d, e, a, F3, KK1, 9, 15);
R( a, b, c, d, e, F3, KK1, 1, 13);
R( e, a, b, c, d, F3, KK1, 2, 11);
R( d, e, a, b, c, F2, KK2, 15, 9);
R( c, d, e, a, b, F2, KK2, 5, 7);
R( b, c, d, e, a, F2, KK2, 1, 15);
R( a, b, c, d, e, F2, KK2, 3, 11);
R( e, a, b, c, d, F2, KK2, 7, 8);
R( d, e, a, b, c, F2, KK2, 14, 6);
R( c, d, e, a, b, F2, KK2, 6, 6);
R( b, c, d, e, a, F2, KK2, 9, 14);
R( a, b, c, d, e, F2, KK2, 11, 12);
R( e, a, b, c, d, F2, KK2, 8, 13);
R( d, e, a, b, c, F2, KK2, 12, 5);
R( c, d, e, a, b, F2, KK2, 2, 14);
R( b, c, d, e, a, F2, KK2, 10, 13);
R( a, b, c, d, e, F2, KK2, 0, 13);
R( e, a, b, c, d, F2, KK2, 4, 7);
R( d, e, a, b, c, F2, KK2, 13, 5);
R( c, d, e, a, b, F1, KK3, 8, 15);
R( b, c, d, e, a, F1, KK3, 6, 5);
R( a, b, c, d, e, F1, KK3, 4, 8);
R( e, a, b, c, d, F1, KK3, 1, 11);
R( d, e, a, b, c, F1, KK3, 3, 14);
R( c, d, e, a, b, F1, KK3, 11, 14);
R( b, c, d, e, a, F1, KK3, 15, 6);
R( a, b, c, d, e, F1, KK3, 0, 14);
R( e, a, b, c, d, F1, KK3, 5, 6);
R( d, e, a, b, c, F1, KK3, 12, 9);
R( c, d, e, a, b, F1, KK3, 2, 12);
R( b, c, d, e, a, F1, KK3, 13, 9);
R( a, b, c, d, e, F1, KK3, 9, 12);
R( e, a, b, c, d, F1, KK3, 7, 5);
R( d, e, a, b, c, F1, KK3, 10, 15);
R( c, d, e, a, b, F1, KK3, 14, 8);
R( b, c, d, e, a, F0, KK4, 12, 8);
R( a, b, c, d, e, F0, KK4, 15, 5);
R( e, a, b, c, d, F0, KK4, 10, 12);
R( d, e, a, b, c, F0, KK4, 4, 9);
R( c, d, e, a, b, F0, KK4, 1, 12);
R( b, c, d, e, a, F0, KK4, 5, 5);
R( a, b, c, d, e, F0, KK4, 8, 14);
R( e, a, b, c, d, F0, KK4, 7, 6);
R( d, e, a, b, c, F0, KK4, 6, 8);
R( c, d, e, a, b, F0, KK4, 2, 13);
R( b, c, d, e, a, F0, KK4, 13, 6);
R( a, b, c, d, e, F0, KK4, 14, 5);
R( e, a, b, c, d, F0, KK4, 0, 15);
R( d, e, a, b, c, F0, KK4, 3, 13);
R( c, d, e, a, b, F0, KK4, 9, 11);
R( b, c, d, e, a, F0, KK4, 11, 11);
t = hd->h1 + d + cc;
hd->h1 = hd->h2 + e + dd;
hd->h2 = hd->h3 + a + ee;
hd->h3 = hd->h4 + b + aa;
hd->h4 = hd->h0 + c + bb;
hd->h0 = t;
}
/* Update the message digest with the contents
* of INBUF with length INLEN.
*/
static void
rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
{
if( hd->count == 64 ) { /* flush the buffer */
transform( hd, hd->buf );
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count ) {
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
rmd160_write( hd, NULL, 0 );
if( !inlen )
return;
}
while( inlen >= 64 ) {
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/****************
* Apply the rmd160 transform function on the buffer which must have
* a length 64 bytes. Do not use this function together with the
* other functions, use rmd160_init to initialize internal variables.
* Returns: 16 bytes in buffer with the mixed contentes of buffer.
*/
void
rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer )
{
char *p = buffer;
transform( hd, buffer );
#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
X(0);
X(1);
X(2);
X(3);
X(4);
#undef X
}
/* The routine terminates the computation
*/
static void
rmd160_final( RMD160_CONTEXT *hd )
{
u32 t, msb, lsb;
byte *p;
rmd160_write(hd, NULL, 0); /* flush */;
msb = 0;
t = hd->nblocks;
if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
msb++;
msb += t >> 26;
t = lsb;
if( (lsb = t + hd->count) < t ) /* add the count */
msb++;
t = lsb;
if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
msb++;
msb += t >> 29;
if( hd->count < 56 ) { /* enough room */
hd->buf[hd->count++] = 0x80; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else { /* need one extra block */
hd->buf[hd->count++] = 0x80; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
rmd160_write(hd, NULL, 0); /* flush */;
memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = lsb ;
hd->buf[57] = lsb >> 8;
hd->buf[58] = lsb >> 16;
hd->buf[59] = lsb >> 24;
hd->buf[60] = msb ;
hd->buf[61] = msb >> 8;
hd->buf[62] = msb >> 16;
hd->buf[63] = msb >> 24;
transform( hd, hd->buf );
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *p++ = hd->h##a ; *p++ = hd->h##a >> 8; \
*p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
#else /* little endian */
#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
#endif
X(0);
X(1);
X(2);
X(3);
X(4);
#undef X
}
static byte *
rmd160_read( RMD160_CONTEXT *hd )
{
return hd->buf;
}
/****************
* Shortcut functions which puts the hash value of the supplied buffer
* into outbuf which must have a size of 20 bytes.
*/
void
rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
{
RMD160_CONTEXT hd;
rmd160_init( &hd );
rmd160_write( &hd, (byte*)buffer, length );
rmd160_final( &hd );
memcpy( outbuf, hd.buf, 20 );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
static const char *
rmd160_get_info( int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
)
{
static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
if( algo != 3 )
return NULL;
*contextsize = sizeof(RMD160_CONTEXT);
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 20;
- *r_init = (void (*)(void *))rmd160_init;
- *r_write = (void (*)(void *, byte*, size_t))rmd160_write;
- *r_final = (void (*)(void *))rmd160_final;
- *r_read = (byte *(*)(void *))rmd160_read;
+ *(void (**)(RMD160_CONTEXT *))r_init = rmd160_init;
+ *(void (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+ *(void (**)(RMD160_CONTEXT *))r_final = rmd160_final;
+ *(byte *(**)(RMD160_CONTEXT *))r_read = rmd160_read;
return "RIPEMD160";
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "RMD160 ($Revision$)";
static struct {
int class;
int version;
int value;
void (*func)(void);
} func_table[] = {
{ 10, 1, 0, (void(*)(void))rmd160_get_info },
{ 11, 1, 3 },
};
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
switch( *class ) {
case 11:
case 21:
case 31:
ret = &func_table[i].value;
break;
default:
ret = func_table[i].func;
break;
}
i++;
} while( what && what != *class );
*sequence = i;
return ret;
}
#ifndef IS_MODULE
void
rmd160_constructor(void)
{
register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
}
#endif
diff --git a/cipher/rndegd.c b/cipher/rndegd.c
index 4d5f0ef3..f6870cdd 100644
--- a/cipher/rndegd.c
+++ b/cipher/rndegd.c
@@ -1,270 +1,275 @@
/* rndegd.c - interface to the EGD
- * Copyright (C) 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.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"
#ifndef IS_MODULE
#include "ttyio.h"
#endif
#include "dynload.h"
#include "cipher.h"
#ifndef offsetof
#define offsetof(type, member) ((size_t) &((type *)0)->member)
#endif
/* FIXME: this is duplicated code from util/fileutil
* I don't think that this code should go into libgcrypt anyway.
*/
char *
my_make_filename( const char *first_part, ... )
{
va_list arg_ptr ;
size_t n;
const char *s;
char *name, *home, *p;
va_start( arg_ptr, first_part ) ;
n = strlen(first_part)+1;
while( (s=va_arg(arg_ptr, const char *)) )
n += strlen(s) + 1;
va_end(arg_ptr);
home = NULL;
if( *first_part == '~' && first_part[1] == '/'
&& (home = getenv("HOME")) && *home )
n += strlen(home);
name = m_alloc(n);
p = home ? stpcpy(stpcpy(name,home), first_part+1)
: stpcpy(name, first_part);
va_start( arg_ptr, first_part ) ;
while( (s=va_arg(arg_ptr, const char *)) )
p = stpcpy(stpcpy(p,"/"), s);
va_end(arg_ptr);
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 -1;
nread += n;
} while( nread < nbytes );
return nbytes;
}
-/* Note: we always use the highest level.
+/****************
+ * Note: we always use the highest level.
* TO boost the performance we may want to add some
* additional code for level 1
+ *
+ * Using a level of 0 should never block and better add nothing
+ * to the pool. So this is just a dummy for EGD.
*/
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
size_t length, int level )
{
static int fd = -1;
int n;
byte buffer[256+2];
int nbytes;
int do_restart = 0;
if( !length )
return 0;
-
+ if( !level )
+ return 0;
restart:
if( do_restart ) {
if( fd != -1 ) {
close( fd );
fd = -1;
}
}
if( fd == -1 ) {
#warning Fixme: make the filename configurable
char *name = my_make_filename( "~/.gnupg-test", "entropy", NULL );
struct sockaddr_un addr;
int addr_len;
memset( &addr, 0, sizeof addr );
addr.sun_family = AF_UNIX;
strcpy( addr.sun_path, name ); /* fixme: check that it is long enough */
addr_len = offsetof( struct sockaddr_un, sun_path )
+ strlen( addr.sun_path );
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if( fd == -1 )
g10_log_fatal("can't create unix domain socket: %s\n",
strerror(errno) );
if( connect( fd, (struct sockaddr*)&addr, addr_len) == -1 )
g10_log_fatal("can't connect to `%s': %s\n",
name, strerror(errno) );
g10_free(name);
}
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 )
g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
n = do_read( fd, buffer, 1 );
if( n == -1 ) {
g10_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 ) {
g10_log_error("read error on EGD: %s\n", strerror(errno));
do_restart = 1;
goto restart;
}
(*add)( buffer, n, requester );
length -= n;
}
if( length ) {
#ifdef IS_MODULE
fprintf( stderr,
#else
tty_printf(
#endif
_("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 )
g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
n = do_read( fd, buffer, nbytes );
if( n == -1 ) {
g10_log_error("read error on EGD: %s\n", strerror(errno));
do_restart = 1;
goto restart;
}
(*add)( buffer, n, requester );
length -= n;
}
memset(buffer, 0, sizeof(buffer) );
return 0; /* success */
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "RNDEGD ($Revision$)";
static struct {
int class;
int version;
void *func;
} func_table[] = {
{ 40, 1, gather_random },
};
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if ( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
ret = func_table[i].func;
i++;
} while ( what && what != *class );
*sequence = i;
return ret;
}
#ifndef IS_MODULE
void
rndegd_constructor(void)
{
register_internal_cipher_extension( gnupgext_version,
gnupgext_enum_func );
}
#endif
diff --git a/cipher/rndunix.c b/cipher/rndunix.c
index 4ab9f65f..99a416ea 100644
--- a/cipher/rndunix.c
+++ b/cipher/rndunix.c
@@ -1,862 +1,911 @@
/****************************************************************************
* *
* *
* 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
General Public License, version 2 or any later version published by the
Free Software Foundation, in which case the provisions of the GNU GPL are
required INSTEAD OF the above restrictions.
Although not required under the terms of the GPL, it would still be nice if
you could make any changes available to the author to allow a consistent
code base to be maintained */
/* Fixme: We use plain mallocs here beucase it may be used as a module
* should be changed. */
/* General includes */
#include <config.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.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__ */
-#ifdef _AIX
+#if defined( _AIX ) || defined( __QNX__ )
#include <sys/select.h>
#endif /* _AIX */
#ifndef __QNX__
#include <sys/shm.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 */
#ifndef IS_MODULE
#include "dynload.h"
#endif
#include "g10lib.h"
#ifndef EAGAIN
- #define EAGAIN EWOULDBLOCK
+#define EAGAIN EWOULDBLOCK
+#endif
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
#endif
#define GATHER_BUFSIZE 49152 /* Usually about 25K are filled */
/* 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 },
{ "/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 */
#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
+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
#warning 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 )
g10_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
+ nmax = 20; /* assume a reasonable value */
+ #endif
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 */
gather_buffer_size = GATHER_BUFSIZE;
gather_buffer = malloc( gather_buffer_size );
if( !gather_buffer ) {
g10_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.
+ */
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
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 ) ) {
g10_log_error("pipe() failed: %s\n", strerror(errno));
return -1;
}
gatherer_pid = fork();
if( gatherer_pid == -1 ) {
g10_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 ) ) {
g10_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, requester );
/* this is the trick how e cope with the goodness */
subtract = (ulong)n * goodness / 100;
/* subtract at least 1 byte to avoid infinite loops */
length -= subtract ? subtract : 1;
}
return 0;
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "RNDUNIX ($Revision$)";
static struct {
int class;
int version;
void *func;
} func_table[] = {
{ 40, 1, gather_random },
};
/****************
* Enumerate the names of the functions together with informations about
* this function. Set sequence to an integer with a initial value of 0 and
* do not change it.
* If what is 0 all kind of functions are returned.
* Return values: class := class of function:
* 10 = message digest algorithm info function
* 11 = integer with available md algorithms
* 20 = cipher algorithm info function
* 21 = integer with available cipher algorithms
* 30 = public key algorithm info function
* 31 = integer with available pubkey algorithms
* 40 = get read_random_source() function
* 41 = get fast_random_poll function
* version = interface version of the function/pointer
* (currently this is 1 for all functions)
*/
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if ( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
ret = func_table[i].func;
i++;
} while ( what && what != *class );
*sequence = i;
return ret;
}
#ifndef IS_MODULE
void
rndunix_constructor(void)
{
register_internal_cipher_extension( gnupgext_version,
gnupgext_enum_func );
}
#endif
diff --git a/cipher/rndw32.c b/cipher/rndw32.c
index c1045851..25830693 100644
--- a/cipher/rndw32.c
+++ b/cipher/rndw32.c
@@ -1,265 +1,958 @@
-/* rndw32.c - interface to the Winseed DLL
- * Copyright (C) 1999 Free Software Foundation, Inc.
+/* rndw32.c - W32 entropy gatherer
+ * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ * Copyright Peter Gutmann, Matt Thomlinson and Blake Coverett 1996-1999
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *************************************************************************
+ * The code here is based on code from Cryptlib 3.0 beta by Peter Gutmann.
+ * Source file misc/rndwin32.c "Win32 Randomness-Gathering Code" with this
+ * copyright notice:
+ *
+ * This module is part of the cryptlib continuously seeded pseudorandom
+ * number generator. For usage conditions, see lib_rand.c
+ *
+ * [Here is the notice from lib_rand.c, which is now called dev_sys.c]
+ *
+ * This module and the misc/rnd*.c modules represent the cryptlib
+ * continuously seeded pseudorandom number generator (CSPRNG) as described in
+ * my 1998 Usenix Security Symposium paper "The generation of random numbers
+ * for cryptographic purposes".
+ *
+ * The CSPRNG code is copyright Peter Gutmann (and various others) 1996,
+ * 1997, 1998, 1999, all rights reserved. Redistribution of the CSPRNG
+ * modules and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice
+ * and this permission notice in its entirety.
+ *
+ * 2. Redistributions in binary form must reproduce the copyright notice in
+ * the documentation and/or other materials provided with the distribution.
+ *
+ * 3. A copy of any bugfixes or enhancements made must be provided to the
+ * author, <pgut001@cs.auckland.ac.nz> to allow them to be added to the
+ * baseline version of the code.
+ *
+ * ALTERNATIVELY, the code may be distributed under the terms of the GNU
+ * General Public License, version 2 or any later version published by the
+ * Free Software Foundation, in which case the provisions of the GNU GPL are
+ * required INSTEAD OF the above restrictions.
+ *
+ * Although not required under the terms of the GPL, it would still be nice if
+ * you could make any changes available to the author to allow a consistent
+ * code base to be maintained
+ *************************************************************************
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <windows.h>
+
#include "types.h"
#include "g10lib.h"
#include "dynload.h"
+/* We do not use the netropy DLL anymore because a standalone program is
+ * easier to maintain and */
+/*#define USE_ENTROPY_DLL*/
+
+
#ifdef IS_MODULE
#define _(a) (a)
#else
#include "i18n.h"
#endif
+static int debug_me;
+
+#ifdef USE_ENTROPY_DLL
+
#define WIN32_SLOW_SEEDER 0
#define WIN32_FAST_SEEDER 1
#define PCP_SUCCESS 0
#define PCP_NULL_POINTER 1
#define PCP_SEEDER_FAILED 2
#define PCP_SEEDER_NO_MEM 3
#define PCP_SEEDER_TOO_SMALL 4
#define PCP_DLL_LOAD_FAILED 5
#define PCP_UNKNOWN_PLATFORM 6
#define PCP_ERROR_VERSION 7
#define PCP_DLL_FUNC 8
#define PCP_UNKNOWN_SEEDER_TYPE 9
+
+/****************
+ * We sometimes get a SEEDER_TOO_SMALL error, in which case we increment
+ * the internal buffer by SEEDER_INC_CHUNK until we reach MAX_SEEDER_SIZE
+ * MAX_SEEDER_SIZE is used as an arbitrary limit to protect against
+ * bugs in Winseed.
+ */
+#define MAX_SEEDER_SIZE 500000
+#define SEEDER_INC_CHUNK 50000
+
+
typedef void *WIN32_SEEDER;
static WIN32_SEEDER (WINAPI *create_instance)( byte type, unsigned int *reason);
static void (WINAPI *delete_instance)( WIN32_SEEDER that );
static unsigned int (WINAPI *get_internal_seed_size)( WIN32_SEEDER that );
static void (WINAPI *set_internal_seed_size)( WIN32_SEEDER that,
unsigned int new_size);
static unsigned int (WINAPI *get_expected_seed_size)( WIN32_SEEDER that);
static unsigned int (WINAPI *get_seed)( WIN32_SEEDER that, byte *buffer,
unsigned int *desired_length);
static WIN32_SEEDER slow_seeder, fast_seeder;
static byte *entropy_buffer;
static size_t entropy_buffer_size;
-static char *entropy_dll;
-
/****************
* Load and initialize the winseed DLL
* NOTE: winseed is not part of the GnuPG distribution. It should be available
* at the GNU crypto FTP server site.
* We do not load the DLL on demand to have a better control over the
* location of the library.
*/
static void
load_and_init_winseed( void )
{
- int hInstance;
+ HANDLE hInstance;
void *addr;
unsigned int reason = 0;
unsigned int n1, n2;
- const char *dllname = entropy_dll? entropy_dll : "c:/gnupg/entropy.dll";
+ const char *dllname;
+
+ dllname = read_w32_registry_string( "HKEY_LOCAL_MACHINE",
+ "Software\\GNU\\GnuPG",
+ "EntropyDLL" );
+ if( !dllname )
+ dllname = "c:/gnupg/entropy.dll";
hInstance = LoadLibrary( dllname );
if( !hInstance )
goto failure;
if( !(addr = GetProcAddress( hInstance, "WS_create_instance" )) )
goto failure;
create_instance = addr;
if( !(addr = GetProcAddress( hInstance, "WS_delete_instance" )) )
goto failure;
delete_instance = addr;
if( !(addr = GetProcAddress( hInstance, "WS_get_internal_seed_size" )) )
goto failure;
get_internal_seed_size = addr;
if( !(addr = GetProcAddress( hInstance, "WS_set_internal_seed_size" )) )
goto failure;
set_internal_seed_size = addr;
if( !(addr = GetProcAddress( hInstance, "WS_get_expected_seed_size" )) )
goto failure;
get_expected_seed_size = addr;
if( !(addr = GetProcAddress( hInstance, "WS_get_seed" )) )
goto failure;
get_seed = addr;
/* we have all the functions - init the system */
slow_seeder = create_instance( WIN32_SLOW_SEEDER, &reason);
if( !slow_seeder ) {
g10_log_fatal("error creating winseed slow seeder: rc=%u\n", reason );
goto failure;
}
fast_seeder = create_instance( WIN32_FAST_SEEDER, &reason);
if( !fast_seeder ) {
g10_log_fatal("error creating winseed fast seeder: rc=%u\n", reason );
goto failure;
}
- g10_log_info("slow and fast seeders created.\n");
n1 = get_internal_seed_size( slow_seeder );
- g10_log_info("slow buffer size=%u\n", n1);
+ /*g10_log_info("slow buffer size=%u\n", n1);*/
n2 = get_internal_seed_size( fast_seeder );
- g10_log_info("fast buffer size=%u\n", n2);
+ /*g10_log_info("fast buffer size=%u\n", n2);*/
entropy_buffer_size = n1 > n2? n1: n2;
- entropy_buffer = g10_xmalloc( entropy_buffer_size );
- g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );
+ entropy_buffer = m_alloc( entropy_buffer_size );
+ /*g10_log_info("using a buffer of size=%u\n", entropy_buffer_size );*/
return;
failure:
g10_log_fatal("error loading winseed DLL `%s'\n", dllname );
}
/* Note: we always use the highest level.
* TO boost the performance we may want to add some
* additional code for level 1
*/
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
size_t length, int level )
{
unsigned int result;
unsigned int nbytes;
+ if( !level )
+ return 0;
+
if( !slow_seeder )
load_and_init_winseed();
/* Our estimation on how much entropy we should use is very vague.
* Winseed delivers some amount of entropy on each slow poll and
* we add it to our random pool. Depending on the required quality
- * level we adjust the requested length so that for higer quality
+ * level we adjust the requested length so that for higher quality
* we make sure to add more entropy to our pool. However, as we don't
* like to waste any entropy collected by winseed, we always add
* at least everything we got from winseed.
*/
if( level > 1 )
length *= 100;
else if( level > 0 )
length *= 10;
for(;;) {
nbytes = entropy_buffer_size;
result = get_seed( slow_seeder, entropy_buffer, &nbytes);
+ if( result == PCP_SEEDER_TOO_SMALL ) {
+ unsigned int n1 = get_internal_seed_size( slow_seeder );
+
+ if( n1 > MAX_SEEDER_SIZE ) {
+ g10_log_fatal("rndw32: internal seeder problem (size=%u)\n",
+ n1);
+ return -1; /* actually never reached */
+ }
+ n1 += SEEDER_INC_CHUNK;
+ set_internal_seed_size( slow_seeder, n1 );
+ if( n1 > entropy_buffer_size ) {
+ entropy_buffer_size = n1;
+ entropy_buffer = m_realloc( entropy_buffer,
+ entropy_buffer_size );
+ }
+ continue;
+ }
+
+
if( result ) {
g10_log_fatal("rndw32: get_seed(slow) failed: rc=%u\n", result);
return -1; /* actually never reached */
}
- g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
- level, (unsigned int)length, (unsigned int)nbytes );
+ /*g10_log_info("rndw32: slow poll level %d, need %u, got %u\n",
+ level, (unsigned int)length, (unsigned int)nbytes );*/
(*add)( entropy_buffer, nbytes, requester );
if( length <= nbytes )
return 0; /* okay */
length -= nbytes;
- g10_log_info("rndw32: need more\n");
}
}
static int
gather_random_fast( void (*add)(const void*, size_t, int), int requester )
{
unsigned int result;
unsigned int nbytes;
if( !fast_seeder )
load_and_init_winseed();
/* winseed delivers a constant ammount of entropy for a fast
* poll. We can simply use this and add it to the pool; no need
* a loop like it is used in the slow poll */
nbytes = entropy_buffer_size;
result = get_seed( fast_seeder, entropy_buffer, &nbytes);
if( result ) {
g10_log_fatal("rndw32: get_seed(fast) failed: rc=%u\n", result);
return -1; /* actually never reached */
}
/*g10_log_info("rndw32: fast poll got %u\n", (unsigned int)nbytes );*/
(*add)( entropy_buffer, nbytes, requester );
return 0;
}
+#else /* !USE_ENTROPY_DLL */
+/* This is the new code which does not require the entropy.dll */
+
+/*
+ * Definitions which are missing from the current GNU Windows32Api
+ */
+
+#define TH32CS_SNAPHEAPLIST 1
+#define TH32CS_SNAPPROCESS 2
+#define TH32CS_SNAPTHREAD 4
+#define TH32CS_SNAPMODULE 8
+#define TH32CS_SNAPALL (1|2|4|8)
+#define TH32CS_INHERIT 0x80000000
+
+#define IOCTL_DISK_PERFORMANCE 0x00070020
+#define VER_PLATFORM_WIN32_WINDOWS 1
+
+
+typedef struct {
+ DWORD dwSize;
+ DWORD th32ProcessID;
+ DWORD th32HeapID;
+ DWORD dwFlags;
+} HEAPLIST32;
+
+typedef struct {
+ DWORD dwSize;
+ HANDLE hHandle;
+ DWORD dwAddress;
+ DWORD dwBlockSize;
+ DWORD dwFlags;
+ DWORD dwLockCount;
+ DWORD dwResvd;
+ DWORD th32ProcessID;
+ DWORD th32HeapID;
+} HEAPENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ProcessID;
+ DWORD th32DefaultHeapID;
+ DWORD th32ModuleID;
+ DWORD cntThreads;
+ DWORD th32ParentProcessID;
+ LONG pcPriClassBase;
+ DWORD dwFlags;
+ char szExeFile[260];
+} PROCESSENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD cntUsage;
+ DWORD th32ThreadID;
+ DWORD th32OwnerProcessID;
+ LONG tpBasePri;
+ LONG tpDeltaPri;
+ DWORD dwFlags;
+} THREADENTRY32;
+
+typedef struct {
+ DWORD dwSize;
+ DWORD th32ModuleID;
+ DWORD th32ProcessID;
+ DWORD GlblcntUsage;
+ DWORD ProccntUsage;
+ BYTE *modBaseAddr;
+ DWORD modBaseSize;
+ HMODULE hModule;
+ char szModule[256];
+ char szExePath[260];
+} MODULEENTRY32;
+
+
+
+/* Type definitions for function pointers to call Toolhelp32 functions
+ * used with the windows95 gatherer */
+typedef BOOL (WINAPI * MODULEWALK) (HANDLE hSnapshot, MODULEENTRY32 *lpme);
+typedef BOOL (WINAPI * THREADWALK) (HANDLE hSnapshot, THREADENTRY32 *lpte);
+typedef BOOL (WINAPI * PROCESSWALK) (HANDLE hSnapshot, PROCESSENTRY32 *lppe);
+typedef BOOL (WINAPI * HEAPLISTWALK) (HANDLE hSnapshot, HEAPLIST32 *lphl);
+typedef BOOL (WINAPI * HEAPFIRST) (HEAPENTRY32 *lphe, DWORD th32ProcessID,
+ DWORD th32HeapID);
+typedef BOOL (WINAPI * HEAPNEXT) (HEAPENTRY32 *lphe);
+typedef HANDLE (WINAPI * CREATESNAPSHOT) (DWORD dwFlags, DWORD th32ProcessID);
+
+/* Type definitions for function pointers to call NetAPI32 functions */
+typedef DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService,
+ DWORD dwLevel, DWORD dwOptions,
+ LPBYTE * lpBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer);
+typedef DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer);
+
+
+/* When we query the performance counters, we allocate an initial buffer and
+ * then reallocate it as required until RegQueryValueEx() stops returning
+ * ERROR_MORE_DATA. The following values define the initial buffer size and
+ * step size by which the buffer is increased
+ */
+#define PERFORMANCE_BUFFER_SIZE 65536 /* Start at 64K */
+#define PERFORMANCE_BUFFER_STEP 16384 /* Step by 16K */
+
+
+static void
+slow_gatherer_windows95( void (*add)(const void*, size_t, int), int requester )
+{
+ static CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
+ static MODULEWALK pModule32First = NULL;
+ static MODULEWALK pModule32Next = NULL;
+ static PROCESSWALK pProcess32First = NULL;
+ static PROCESSWALK pProcess32Next = NULL;
+ static THREADWALK pThread32First = NULL;
+ static THREADWALK pThread32Next = NULL;
+ static HEAPLISTWALK pHeap32ListFirst = NULL;
+ static HEAPLISTWALK pHeap32ListNext = NULL;
+ static HEAPFIRST pHeap32First = NULL;
+ static HEAPNEXT pHeap32Next = NULL;
+ HANDLE hSnapshot;
+
+
+ /* initialize the Toolhelp32 function pointers */
+ if ( !pCreateToolhelp32Snapshot ) {
+ HANDLE hKernel;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: init toolkit\n" );
+
+ /* Obtain the module handle of the kernel to retrieve the addresses
+ * of the Toolhelp32 functions */
+ if ( ( !(hKernel = GetModuleHandle ("KERNEL32.DLL"))) ) {
+ g10_log_fatal ( "rndw32: can't get module handle\n" );
+ }
+
+ /* Now get pointers to the functions */
+ pCreateToolhelp32Snapshot = (CREATESNAPSHOT) GetProcAddress (hKernel,
+ "CreateToolhelp32Snapshot");
+ pModule32First = (MODULEWALK) GetProcAddress (hKernel, "Module32First");
+ pModule32Next = (MODULEWALK) GetProcAddress (hKernel, "Module32Next");
+ pProcess32First = (PROCESSWALK) GetProcAddress (hKernel,
+ "Process32First");
+ pProcess32Next = (PROCESSWALK) GetProcAddress (hKernel,
+ "Process32Next");
+ pThread32First = (THREADWALK) GetProcAddress (hKernel, "Thread32First");
+ pThread32Next = (THREADWALK) GetProcAddress (hKernel, "Thread32Next");
+ pHeap32ListFirst = (HEAPLISTWALK) GetProcAddress (hKernel,
+ "Heap32ListFirst");
+ pHeap32ListNext = (HEAPLISTWALK) GetProcAddress (hKernel,
+ "Heap32ListNext");
+ pHeap32First = (HEAPFIRST) GetProcAddress (hKernel, "Heap32First");
+ pHeap32Next = (HEAPNEXT) GetProcAddress (hKernel, "Heap32Next");
+
+ if ( !pCreateToolhelp32Snapshot
+ || !pModule32First || !pModule32Next
+ || !pProcess32First || !pProcess32Next
+ || !pThread32First || !pThread32Next
+ || !pHeap32ListFirst || !pHeap32ListNext
+ || !pHeap32First || !pHeap32Next ) {
+ g10_log_fatal ( "rndw32: failed to get a toolhep function\n" );
+ }
+ }
+
+ /* Take a snapshot of everything we can get to which is currently
+ * in the system */
+ if ( !(hSnapshot = pCreateToolhelp32Snapshot (TH32CS_SNAPALL, 0)) ) {
+ g10_log_fatal ( "rndw32: failed to take a toolhelp snapshot\n" );
+ }
+
+ /* Walk through the local heap */
+ { HEAPLIST32 hl32;
+ hl32.dwSize = sizeof (HEAPLIST32);
+ if (pHeap32ListFirst (hSnapshot, &hl32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk heap\n" );
+ do {
+ HEAPENTRY32 he32;
+
+ /* First add the information from the basic Heaplist32 struct */
+ (*add) ( &hl32, sizeof (hl32), requester );
+
+ /* Now walk through the heap blocks getting information
+ * on each of them */
+ he32.dwSize = sizeof (HEAPENTRY32);
+ if (pHeap32First (&he32, hl32.th32ProcessID, hl32.th32HeapID)){
+ do {
+ (*add) ( &he32, sizeof (he32), requester );
+ } while (pHeap32Next (&he32));
+ }
+ } while (pHeap32ListNext (hSnapshot, &hl32));
+ }
+ }
+
+
+ /* Walk through all processes */
+ { PROCESSENTRY32 pe32;
+ pe32.dwSize = sizeof (PROCESSENTRY32);
+ if (pProcess32First (hSnapshot, &pe32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk processes\n" );
+ do {
+ (*add) ( &pe32, sizeof (pe32), requester );
+ } while (pProcess32Next (hSnapshot, &pe32));
+ }
+ }
+
+ /* Walk through all threads */
+ { THREADENTRY32 te32;
+ te32.dwSize = sizeof (THREADENTRY32);
+ if (pThread32First (hSnapshot, &te32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk threads\n" );
+ do {
+ (*add) ( &te32, sizeof (te32), requester );
+ } while (pThread32Next (hSnapshot, &te32));
+ }
+ }
+
+ /* Walk through all modules associated with the process */
+ { MODULEENTRY32 me32;
+ me32.dwSize = sizeof (MODULEENTRY32);
+ if (pModule32First (hSnapshot, &me32)) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_95: walk modules\n" );
+ do {
+ (*add) ( &me32, sizeof (me32), requester );
+ } while (pModule32Next (hSnapshot, &me32));
+ }
+ }
+
+ CloseHandle (hSnapshot);
+}
+
+
+
+static void
+slow_gatherer_windowsNT( void (*add)(const void*, size_t, int), int requester )
+{
+ static int is_initialized = 0;
+ static NETSTATISTICSGET pNetStatisticsGet = NULL;
+ static NETAPIBUFFERSIZE pNetApiBufferSize = NULL;
+ static NETAPIBUFFERFREE pNetApiBufferFree = NULL;
+ static int is_workstation = 1;
+
+ static int cbPerfData = PERFORMANCE_BUFFER_SIZE;
+ PERF_DATA_BLOCK *pPerfData;
+ HANDLE hDevice, hNetAPI32 = NULL;
+ DWORD dwSize, status;
+ int nDrive;
+
+ if ( !is_initialized ) {
+ HKEY hKey;
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: init toolkit\n" );
+ /* Find out whether this is an NT server or workstation if necessary */
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+ BYTE szValue[32];
+ dwSize = sizeof (szValue);
+
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: check product options\n" );
+ status = RegQueryValueEx (hKey, "ProductType", 0, NULL,
+ szValue, &dwSize);
+ if (status == ERROR_SUCCESS && stricmp (szValue, "WinNT")) {
+ /* Note: There are (at least) three cases for ProductType:
+ * WinNT = NT Workstation, ServerNT = NT Server, LanmanNT =
+ * NT Server acting as a Domain Controller */
+ is_workstation = 0;
+ if ( debug_me )
+ log_debug ("rndw32: this is a NT server\n");
+ }
+ RegCloseKey (hKey);
+ }
+
+ /* Initialize the NetAPI32 function pointers if necessary */
+ if ( (hNetAPI32 = LoadLibrary ("NETAPI32.DLL")) ) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: netapi32 loaded\n" );
+ pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32,
+ "NetStatisticsGet");
+ pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32,
+ "NetApiBufferSize");
+ pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32,
+ "NetApiBufferFree");
+
+ if ( !pNetStatisticsGet
+ || !pNetApiBufferSize || !pNetApiBufferFree ) {
+ FreeLibrary (hNetAPI32);
+ hNetAPI32 = NULL;
+ g10_log_debug ("rndw32: No NETAPI found\n" );
+ }
+ }
+
+ is_initialized = 1;
+ }
+
+ /* Get network statistics. Note: Both NT Workstation and NT Server by
+ * default will be running both the workstation and server services. The
+ * heuristic below is probably useful though on the assumption that the
+ * majority of the network traffic will be via the appropriate service.
+ * In any case the network statistics return almost no randomness */
+ { LPBYTE lpBuffer;
+ if (hNetAPI32 && !pNetStatisticsGet (NULL,
+ is_workstation ? L"LanmanWorkstation" :
+ L"LanmanServer", 0, 0, &lpBuffer) ) {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: get netstats\n" );
+ pNetApiBufferSize (lpBuffer, &dwSize);
+ (*add) ( lpBuffer, dwSize,requester );
+ pNetApiBufferFree (lpBuffer);
+ }
+ }
+
+ /* Get disk I/O statistics for all the hard drives */
+ for (nDrive = 0;; nDrive++) {
+ DISK_PERFORMANCE diskPerformance;
+ char szDevice[50];
+
+ /* Check whether we can access this device */
+ sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive);
+ hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ if (hDevice == INVALID_HANDLE_VALUE)
+ break;
+
+ /* Note: This only works if you have turned on the disk performance
+ * counters with 'diskperf -y'. These counters are off by default */
+ if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0,
+ &diskPerformance, sizeof (DISK_PERFORMANCE),
+ &dwSize, NULL))
+ {
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: iostats drive %d\n",
+ nDrive );
+ (*add) ( &diskPerformance, dwSize, requester );
+ }
+ else {
+ log_info ("NOTE: you should run 'diskperf -y' "
+ "to enable the disk statistics\n");
+ }
+ CloseHandle (hDevice);
+ }
+
+ #if 0 /* we don't need this in GnuPG */
+ /* Wait for any async keyset driver binding to complete. You may be
+ * wondering what this call is doing here... the reason it's necessary is
+ * because RegQueryValueEx() will hang indefinitely if the async driver
+ * bind is in progress. The problem occurs in the dynamic loading and
+ * linking of driver DLL's, which work as follows:
+ *
+ * hDriver = LoadLibrary( DRIVERNAME );
+ * pFunction1 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC1 );
+ * pFunction2 = ( TYPE_FUNC1 ) GetProcAddress( hDriver, NAME_FUNC2 );
+ *
+ * If RegQueryValueEx() is called while the GetProcAddress()'s are in
+ * progress, it will hang indefinitely. This is probably due to some
+ * synchronisation problem in the NT kernel where the GetProcAddress()
+ * calls affect something like a module reference count or function
+ * reference count while RegQueryValueEx() is trying to take a snapshot
+ * of the statistics, which include the reference counts. Because of
+ * this, we have to wait until any async driver bind has completed
+ * before we can call RegQueryValueEx() */
+ waitSemaphore (SEMAPHORE_DRIVERBIND);
+ #endif
+
+ /* Get information from the system performance counters. This can take
+ * a few seconds to do. In some environments the call to
+ * RegQueryValueEx() can produce an access violation at some random time
+ * in the future, adding a short delay after the following code block
+ * makes the problem go away. This problem is extremely difficult to
+ * reproduce, I haven't been able to get it to occur despite running it
+ * on a number of machines. The best explanation for the problem is that
+ * on the machine where it did occur, it was caused by an external driver
+ * or other program which adds its own values under the
+ * HKEY_PERFORMANCE_DATA key. The NT kernel calls the required external
+ * modules to map in the data, if there's a synchronisation problem the
+ * external module would write its data at an inappropriate moment,
+ * causing the access violation. A low-level memory checker indicated
+ * that ExpandEnvironmentStrings() in KERNEL32.DLL, called an
+ * interminable number of calls down inside RegQueryValueEx(), was
+ * overwriting memory (it wrote twice the allocated size of a buffer to a
+ * buffer allocated by the NT kernel). This may be what's causing the
+ * problem, but since it's in the kernel there isn't much which can be
+ * done.
+ *
+ * In addition to these problems the code in RegQueryValueEx() which
+ * estimates the amount of memory required to return the performance
+ * counter information isn't very accurate, since it always returns a
+ * worst-case estimate which is usually nowhere near the actual amount
+ * required. For example it may report that 128K of memory is required,
+ * but only return 64K of data */
+ { pPerfData = m_alloc (cbPerfData);
+ for (;;) {
+ dwSize = cbPerfData;
+ if ( debug_me )
+ log_debug ("rndw32#slow_gatherer_nt: get perf data\n" );
+ status = RegQueryValueEx (HKEY_PERFORMANCE_DATA, "Global", NULL,
+ NULL, (LPBYTE) pPerfData, &dwSize);
+ if (status == ERROR_SUCCESS) {
+ if (!memcmp (pPerfData->Signature, L"PERF", 8)) {
+ (*add) ( pPerfData, dwSize, requester );
+ }
+ else
+ g10_log_debug ( "rndw32: no PERF signature\n");
+ break;
+ }
+ else if (status == ERROR_MORE_DATA) {
+ cbPerfData += PERFORMANCE_BUFFER_STEP;
+ pPerfData = m_realloc (pPerfData, cbPerfData);
+ }
+ else {
+ g10_log_debug ( "rndw32: get performance data problem\n");
+ break;
+ }
+ }
+ m_free (pPerfData);
+ }
+ /* Although this isn't documented in the Win32 API docs, it's necessary
+ to explicitly close the HKEY_PERFORMANCE_DATA key after use (it's
+ implicitly opened on the first call to RegQueryValueEx()). If this
+ isn't done then any system components which provide performance data
+ can't be removed or changed while the handle remains active */
+ RegCloseKey (HKEY_PERFORMANCE_DATA);
+}
+
+
+static int
+gather_random( void (*add)(const void*, size_t, int), int requester,
+ size_t length, int level )
+{
+ static int is_initialized;
+ static int is_windows95;
+
+
+ if( !level )
+ return 0;
+ /* We don't differentiate between level 1 and 2 here because
+ * there is no nternal entropy pool as a scary resource. It may
+ * all work slower, but because our entropy source will never
+ * block but deliver some not easy to measure entropy, we assume level 2
+ */
+
+
+ if ( !is_initialized ) {
+ OSVERSIONINFO osvi = { sizeof( osvi ) };
+ DWORD platform;
+
+ GetVersionEx( &osvi );
+ platform = osvi.dwPlatformId;
+ is_windows95 = platform == VER_PLATFORM_WIN32_WINDOWS;
+
+ if ( platform == VER_PLATFORM_WIN32s ) {
+ g10_log_fatal("can't run on a W32s platform\n" );
+ }
+ is_initialized = 1;
+ if ( debug_me )
+ log_debug ("rndw32#gather_random: platform=%d\n", (int)platform );
+ }
+
+
+ if ( debug_me )
+ log_debug ("rndw32#gather_random: req=%d len=%u lvl=%d\n",
+ requester, (unsigned int)length, level );
+
+ if (is_windows95 ) {
+ slow_gatherer_windows95( add, requester );
+ }
+ else {
+ slow_gatherer_windowsNT( add, requester );
+ }
+
+ return 0;
+}
+
+
+
+static int
+gather_random_fast( void (*add)(const void*, size_t, int), int requester )
+{
+ static int addedFixedItems = 0;
+
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: req=%d\n", requester );
+
+ /* Get various basic pieces of system information: Handle of active
+ * window, handle of window with mouse capture, handle of clipboard owner
+ * handle of start of clpboard viewer list, pseudohandle of current
+ * process, current process ID, pseudohandle of current thread, current
+ * thread ID, handle of desktop window, handle of window with keyboard
+ * focus, whether system queue has any events, cursor position for last
+ * message, 1 ms time for last message, handle of window with clipboard
+ * open, handle of process heap, handle of procs window station, types of
+ * events in input queue, and milliseconds since Windows was started */
+ { byte buffer[20*sizeof(ulong)], *bufptr;
+ bufptr = buffer;
+ #define ADD(f) do { ulong along = (ulong)(f); \
+ memcpy (bufptr, &along, sizeof (along) ); \
+ bufptr += sizeof (along); } while (0)
+ ADD ( GetActiveWindow ());
+ ADD ( GetCapture ());
+ ADD ( GetClipboardOwner ());
+ ADD ( GetClipboardViewer ());
+ ADD ( GetCurrentProcess ());
+ ADD ( GetCurrentProcessId ());
+ ADD ( GetCurrentThread ());
+ ADD ( GetCurrentThreadId ());
+ ADD ( GetDesktopWindow ());
+ ADD ( GetFocus ());
+ ADD ( GetInputState ());
+ ADD ( GetMessagePos ());
+ ADD ( GetMessageTime ());
+ ADD ( GetOpenClipboardWindow ());
+ ADD ( GetProcessHeap ());
+ ADD ( GetProcessWindowStation ());
+ ADD ( GetQueueStatus (QS_ALLEVENTS));
+ ADD ( GetTickCount ());
+
+ assert ( bufptr-buffer < sizeof (buffer) );
+ (*add) ( buffer, bufptr-buffer, requester );
+ #undef ADD
+ }
+
+ /* Get multiword system information: Current caret position, current
+ * mouse cursor position */
+ { POINT point;
+ GetCaretPos (&point);
+ (*add) ( &point, sizeof (point), requester );
+ GetCursorPos (&point);
+ (*add) ( &point, sizeof (point), requester );
+ }
+
+ /* Get percent of memory in use, bytes of physical memory, bytes of free
+ * physical memory, bytes in paging file, free bytes in paging file, user
+ * bytes of address space, and free user bytes */
+ { MEMORYSTATUS memoryStatus;
+ memoryStatus.dwLength = sizeof (MEMORYSTATUS);
+ GlobalMemoryStatus (&memoryStatus);
+ (*add) ( &memoryStatus, sizeof (memoryStatus), requester );
+ }
+
+ /* Get thread and process creation time, exit time, time in kernel mode,
+ and time in user mode in 100ns intervals */
+ { HANDLE handle;
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ DWORD minimumWorkingSetSize, maximumWorkingSetSize;
+
+ handle = GetCurrentThread ();
+ GetThreadTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), requester );
+ (*add) ( &exitTime, sizeof (exitTime), requester );
+ (*add) ( &kernelTime, sizeof (kernelTime), requester );
+ (*add) ( &userTime, sizeof (userTime), requester );
+
+ handle = GetCurrentProcess ();
+ GetProcessTimes (handle, &creationTime, &exitTime,
+ &kernelTime, &userTime);
+ (*add) ( &creationTime, sizeof (creationTime), requester );
+ (*add) ( &exitTime, sizeof (exitTime), requester );
+ (*add) ( &kernelTime, sizeof (kernelTime), requester );
+ (*add) ( &userTime, sizeof (userTime), requester );
+
+ /* Get the minimum and maximum working set size for the current process */
+ GetProcessWorkingSetSize (handle, &minimumWorkingSetSize,
+ &maximumWorkingSetSize);
+ (*add) ( &minimumWorkingSetSize,
+ sizeof (&minimumWorkingSetSize), requester );
+ (*add) ( &maximumWorkingSetSize,
+ sizeof (&maximumWorkingSetSize), requester );
+ }
+
+
+ /* The following are fixed for the lifetime of the process so we only
+ * add them once */
+ if (!addedFixedItems) {
+ STARTUPINFO startupInfo;
+
+ /* Get name of desktop, console window title, new window position and
+ * size, window flags, and handles for stdin, stdout, and stderr */
+ startupInfo.cb = sizeof (STARTUPINFO);
+ GetStartupInfo (&startupInfo);
+ (*add) ( &startupInfo, sizeof (STARTUPINFO), requester );
+ addedFixedItems = 1;
+ }
+
+ /* The performance of QPC varies depending on the architecture it's
+ * running on and on the OS. Under NT it reads the CPU's 64-bit timestamp
+ * counter (at least on a Pentium and newer '486's, it hasn't been tested
+ * on anything without a TSC), under Win95 it reads the 1.193180 MHz PIC
+ * timer. There are vague mumblings in the docs that it may fail if the
+ * appropriate hardware isn't available (possibly '386's or MIPS machines
+ * running NT), but who's going to run NT on a '386? */
+ { LARGE_INTEGER performanceCount;
+ if (QueryPerformanceCounter (&performanceCount)) {
+ if ( debug_me )
+ log_debug ("rndw32#gather_random_fast: perf data\n");
+ (*add) (&performanceCount, sizeof (&performanceCount), requester);
+ }
+ else { /* Millisecond accuracy at best... */
+ DWORD aword = GetTickCount ();
+ (*add) (&aword, sizeof (aword), requester );
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+#endif /* !USE_ENTROPY_DLL */
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "RNDW32 ($Revision$)";
static struct {
int class;
int version;
void *func;
} func_table[] = {
{ 40, 1, gather_random },
{ 41, 1, gather_random_fast },
};
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
+ debug_me = !!getenv("DEBUG_RNDW32");
+
do {
if ( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
ret = func_table[i].func;
i++;
} while ( what && what != *class );
*sequence = i;
return ret;
}
-#ifdef USE_STATIC_RNDW32
-void
-rndw32_set_dll_name( const char *name )
-{
- entropy_dll = m_strdup( name );
-}
-#endif
-
#ifndef IS_MODULE
void
rndw32_constructor(void)
{
register_internal_cipher_extension( gnupgext_version,
gnupgext_enum_func );
}
#endif
diff --git a/cipher/rsa.c b/cipher/rsa.c
new file mode 100644
index 00000000..5d852cd8
--- /dev/null
+++ b/cipher/rsa.c
@@ -0,0 +1,375 @@
+/* rsa.c - RSA function
+ * Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
+ * Copyright (C) 2000 Free Software Foundation, Inc.
+ ***********************************************************************
+ * ATTENTION: This code should not be used in the United States
+ * before the U.S. Patent #4,405,829 expires on September 20, 2000!
+ ***********************************************************************
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "util.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "rsa.h"
+
+
+typedef struct {
+ MPI n; /* modulus */
+ MPI e; /* exponent */
+} RSA_public_key;
+
+
+typedef struct {
+ MPI n; /* public modulus */
+ MPI e; /* public exponent */
+ MPI d; /* exponent */
+ MPI p; /* prime p. */
+ MPI q; /* prime q. */
+ MPI u; /* inverse of p mod q. */
+} RSA_secret_key;
+
+
+static void test_keys( RSA_secret_key *sk, unsigned nbits );
+static void generate( RSA_secret_key *sk, unsigned nbits );
+static int check_secret_key( RSA_secret_key *sk );
+static void public(MPI output, MPI input, RSA_public_key *skey );
+static void secret(MPI output, MPI input, RSA_secret_key *skey );
+
+
+static void
+test_keys( RSA_secret_key *sk, unsigned nbits )
+{
+ RSA_public_key pk;
+ MPI test = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ MPI out1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ MPI out2 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+
+ pk.n = sk->n;
+ pk.e = sk->e;
+ { char *p = get_random_bits( nbits, 0, 0 );
+ mpi_set_buffer( test, p, (nbits+7)/8, 0 );
+ m_free(p);
+ }
+
+ public( out1, test, &pk );
+ secret( out2, out1, sk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: public, secret failed\n");
+ secret( out1, test, sk );
+ public( out2, out1, &pk );
+ if( mpi_cmp( test, out2 ) )
+ log_fatal("RSA operation: secret, public failed\n");
+ mpi_free( test );
+ mpi_free( out1 );
+ mpi_free( out2 );
+}
+
+/****************
+ * Generate a key pair with a key of size NBITS
+ * Returns: 2 structures filles with all needed values
+ */
+static void
+generate( RSA_secret_key *sk, unsigned nbits )
+{
+ MPI p, q; /* the two primes */
+ MPI d; /* the private key */
+ MPI u;
+ MPI t1, t2;
+ MPI n; /* the public key */
+ MPI e; /* the exponent */
+ MPI phi; /* helper: (p-a)(q-1) */
+ MPI g;
+ MPI f;
+
+ /* select two (very secret) primes */
+ p = generate_secret_prime( nbits / 2 );
+ q = generate_secret_prime( nbits / 2 );
+ if( mpi_cmp( p, q ) > 0 ) /* p shall be smaller than q (for calc of u)*/
+ mpi_swap(p,q);
+ /* calculate Euler totient: phi = (p-1)(q-1) */
+ t1 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ t2 = mpi_alloc_secure( mpi_get_nlimbs(p) );
+ phi = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ g = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ f = mpi_alloc_secure( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_sub_ui( t1, p, 1 );
+ mpi_sub_ui( t2, q, 1 );
+ mpi_mul( phi, t1, t2 );
+ mpi_gcd(g, t1, t2);
+ mpi_fdiv_q(f, phi, g);
+ /* multiply them to make the private key */
+ n = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_mul( n, p, q );
+ /* find a public exponent */
+ e = mpi_alloc( (6+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_set_ui( e, 17); /* start with 17 */
+ while( !mpi_gcd(t1, e, phi) ) /* (while gcd is not 1) */
+ mpi_add_ui( e, e, 2);
+ /* calculate the secret key d = e^1 mod phi */
+ d = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_invm(d, e, f );
+ /* calculate the inverse of p and q (used for chinese remainder theorem)*/
+ u = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
+ mpi_invm(u, p, q );
+
+ if( DBG_CIPHER ) {
+ log_mpidump(" p= ", p );
+ log_mpidump(" q= ", q );
+ log_mpidump("phi= ", phi );
+ log_mpidump(" g= ", g );
+ log_mpidump(" f= ", f );
+ log_mpidump(" n= ", n );
+ log_mpidump(" e= ", e );
+ log_mpidump(" d= ", d );
+ log_mpidump(" u= ", u );
+ }
+
+ mpi_free(t1);
+ mpi_free(t2);
+ mpi_free(phi);
+ mpi_free(f);
+ mpi_free(g);
+
+ sk->n = n;
+ sk->e = e;
+ sk->p = p;
+ sk->q = q;
+ sk->d = d;
+ sk->u = u;
+
+ /* now we can test our keys (this should never fail!) */
+ test_keys( sk, nbits - 64 );
+}
+
+
+/****************
+ * Test wether the secret key is valid.
+ * Returns: true if this is a valid key.
+ */
+static int
+check_secret_key( RSA_secret_key *sk )
+{
+ int rc;
+ MPI temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 );
+
+ mpi_mul(temp, sk->p, sk->q );
+ rc = mpi_cmp( temp, sk->n );
+ mpi_free(temp);
+ return !rc;
+}
+
+
+
+/****************
+ * Public key operation. Encrypt INPUT with PKEY and put result into OUTPUT.
+ *
+ * c = m^e mod n
+ *
+ * Where c is OUTPUT, m is INPUT and e,n are elements of PKEY.
+ */
+static void
+public(MPI output, MPI input, RSA_public_key *pkey )
+{
+ if( output == input ) { /* powm doesn't like output and input the same */
+ MPI x = mpi_alloc( mpi_get_nlimbs(input)*2 );
+ mpi_powm( x, input, pkey->e, pkey->n );
+ mpi_set(output, x);
+ mpi_free(x);
+ }
+ else
+ mpi_powm( output, input, pkey->e, pkey->n );
+}
+
+/****************
+ * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
+ *
+ * m = c^d mod n
+ *
+ * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ *
+ * FIXME: We should better use the Chinese Remainder Theorem
+ */
+static void
+secret(MPI output, MPI input, RSA_secret_key *skey )
+{
+ mpi_powm( output, input, skey->d, skey->n );
+}
+
+
+/*********************************************
+ ************** interface ******************
+ *********************************************/
+
+int
+rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
+{
+ RSA_secret_key sk;
+
+ if( !is_RSA(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ generate( &sk, nbits );
+ skey[0] = sk.n;
+ skey[1] = sk.e;
+ skey[2] = sk.d;
+ skey[3] = sk.p;
+ skey[4] = sk.q;
+ skey[5] = sk.u;
+ /* make an empty list of factors */
+ *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+ return 0;
+}
+
+
+int
+rsa_check_secret_key( int algo, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( !is_RSA(algo) )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ if( !check_secret_key( &sk ) )
+ return G10ERR_BAD_SECKEY;
+
+ return 0;
+}
+
+
+
+int
+rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
+{
+ RSA_public_key pk;
+
+ if( algo != 1 && algo != 2 )
+ return G10ERR_PUBKEY_ALGO;
+
+ pk.n = pkey[0];
+ pk.e = pkey[1];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.n ) );
+ public( resarr[0], data, &pk );
+ return 0;
+}
+
+int
+rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( algo != 1 && algo != 2 )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ *result = mpi_alloc_secure( mpi_get_nlimbs( sk.n ) );
+ secret( *result, data[0], &sk );
+ return 0;
+}
+
+int
+rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
+{
+ RSA_secret_key sk;
+
+ if( algo != 1 && algo != 3 )
+ return G10ERR_PUBKEY_ALGO;
+
+ sk.n = skey[0];
+ sk.e = skey[1];
+ sk.d = skey[2];
+ sk.p = skey[3];
+ sk.q = skey[4];
+ sk.u = skey[5];
+ resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.n ) );
+ secret( resarr[0], data, &sk );
+
+ return 0;
+}
+
+int
+rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *opaque, MPI tmp), void *opaquev )
+{
+ RSA_public_key pk;
+ MPI result;
+ int rc;
+
+ if( algo != 1 && algo != 3 )
+ return G10ERR_PUBKEY_ALGO;
+ pk.n = pkey[0];
+ pk.e = pkey[1];
+ result = mpi_alloc( (160+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
+ public( result, data[0], &pk );
+ /*rc = (*cmp)( opaquev, result );*/
+ rc = mpi_cmp( result, hash )? G10ERR_BAD_SIGN:0;
+ mpi_free(result);
+
+ return rc;
+}
+
+
+unsigned int
+rsa_get_nbits( int algo, MPI *pkey )
+{
+ if( !is_RSA(algo) )
+ return 0;
+ return mpi_get_nbits( pkey[0] );
+}
+
+
+/****************
+ * Return some information about the algorithm. We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ * the ALGO is invalid.
+ * Usage: Bit 0 set : allows signing
+ * 1 set : allows encryption
+ */
+const char *
+rsa_get_info( int algo,
+ int *npkey, int *nskey, int *nenc, int *nsig, int *usage )
+{
+ *npkey = 2;
+ *nskey = 6;
+ *nenc = 1;
+ *nsig = 1;
+
+ switch( algo ) {
+ case 1: *usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA";
+ case 2: *usage = PUBKEY_USAGE_ENC; return "RSA-E";
+ case 3: *usage = PUBKEY_USAGE_SIG; return "RSA-S";
+ default:*usage = 0; return NULL;
+ }
+}
+
diff --git a/jnlib/dotlock.h b/cipher/rsa.h
similarity index 53%
copy from jnlib/dotlock.h
copy to cipher/rsa.h
index d54219e2..8b60ecbb 100644
--- a/jnlib/dotlock.h
+++ b/cipher/rsa.h
@@ -1,32 +1,36 @@
-/* dotlock.h
+/* rsa.h
+ * Copyright (C) 1997,1998 by Werner Koch (dd9jn)
* Copyright (C) 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#ifndef G10_RSA_H
+#define G10_RSA_H
-#ifndef LIBJNLIB_DOTLOCK_H
-#define LIBJNLIB_DOTLOCK_H
+int rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
+int rsa_check_secret_key( int algo, MPI *skey );
+int rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
+int rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
+int rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
+int rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
+ int (*cmp)(void *, MPI), void *opaquev );
+unsigned rsa_get_nbits( int algo, MPI *pkey );
+const char *rsa_get_info( int algo, int *npkey, int *nskey,
+ int *nenc, int *nsig, int *use );
-struct dotlock_handle;
-typedef struct dotlock_handle *DOTLOCK;
-DOTLOCK create_dotlock( const char *file_to_lock );
-int make_dotlock( DOTLOCK h, long timeout );
-int release_dotlock( DOTLOCK h );
-
-
-#endif /*LIBJNLIB_DOTLOCK_H*/
+#endif /*G10_RSA_H*/
diff --git a/cipher/sha1.c b/cipher/sha1.c
index f231e37b..aa3ac092 100644
--- a/cipher/sha1.c
+++ b/cipher/sha1.c
@@ -1,408 +1,408 @@
/* sha1.c - SHA1 hash function
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* Please see below for more legal information!
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Test vectors:
*
* "abc"
* A999 3E36 4706 816A BA3E 2571 7850 C26C 9CD0 D89D
*
* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
* 8498 3E44 1C3B D26E BAAE 4AA1 F951 29E5 E546 70F1
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "memory.h"
#include "dynload.h"
#include "bithelp.h"
typedef struct {
u32 h0,h1,h2,h3,h4;
u32 nblocks;
byte buf[64];
int count;
} SHA1_CONTEXT;
void
sha1_init( SHA1_CONTEXT *hd )
{
hd->h0 = 0x67452301;
hd->h1 = 0xefcdab89;
hd->h2 = 0x98badcfe;
hd->h3 = 0x10325476;
hd->h4 = 0xc3d2e1f0;
hd->nblocks = 0;
hd->count = 0;
}
/****************
* Transform the message X which consists of 16 32-bit-words
*/
static void
transform( SHA1_CONTEXT *hd, byte *data )
{
u32 a,b,c,d,e,tm;
u32 x[16];
/* get values from the chaining vars */
a = hd->h0;
b = hd->h1;
c = hd->h2;
d = hd->h3;
e = hd->h4;
#ifdef BIG_ENDIAN_HOST
memcpy( x, data, 64 );
#else
{ int i;
byte *p2;
for(i=0, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
p2[3] = *data++;
p2[2] = *data++;
p2[1] = *data++;
p2[0] = *data++;
}
}
#endif
#define K1 0x5A827999L
#define K2 0x6ED9EBA1L
#define K3 0x8F1BBCDCL
#define K4 0xCA62C1D6L
#define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) )
#define F2(x,y,z) ( x ^ y ^ z )
#define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) )
#define F4(x,y,z) ( x ^ y ^ z )
#define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] \
^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
, (x[i&0x0f] = (tm << 1) | (tm >> 31)) )
#define R(a,b,c,d,e,f,k,m) do { e += rol( a, 5 ) \
+ f( b, c, d ) \
+ k \
+ m; \
b = rol( b, 30 ); \
} while(0)
R( a, b, c, d, e, F1, K1, x[ 0] );
R( e, a, b, c, d, F1, K1, x[ 1] );
R( d, e, a, b, c, F1, K1, x[ 2] );
R( c, d, e, a, b, F1, K1, x[ 3] );
R( b, c, d, e, a, F1, K1, x[ 4] );
R( a, b, c, d, e, F1, K1, x[ 5] );
R( e, a, b, c, d, F1, K1, x[ 6] );
R( d, e, a, b, c, F1, K1, x[ 7] );
R( c, d, e, a, b, F1, K1, x[ 8] );
R( b, c, d, e, a, F1, K1, x[ 9] );
R( a, b, c, d, e, F1, K1, x[10] );
R( e, a, b, c, d, F1, K1, x[11] );
R( d, e, a, b, c, F1, K1, x[12] );
R( c, d, e, a, b, F1, K1, x[13] );
R( b, c, d, e, a, F1, K1, x[14] );
R( a, b, c, d, e, F1, K1, x[15] );
R( e, a, b, c, d, F1, K1, M(16) );
R( d, e, a, b, c, F1, K1, M(17) );
R( c, d, e, a, b, F1, K1, M(18) );
R( b, c, d, e, a, F1, K1, M(19) );
R( a, b, c, d, e, F2, K2, M(20) );
R( e, a, b, c, d, F2, K2, M(21) );
R( d, e, a, b, c, F2, K2, M(22) );
R( c, d, e, a, b, F2, K2, M(23) );
R( b, c, d, e, a, F2, K2, M(24) );
R( a, b, c, d, e, F2, K2, M(25) );
R( e, a, b, c, d, F2, K2, M(26) );
R( d, e, a, b, c, F2, K2, M(27) );
R( c, d, e, a, b, F2, K2, M(28) );
R( b, c, d, e, a, F2, K2, M(29) );
R( a, b, c, d, e, F2, K2, M(30) );
R( e, a, b, c, d, F2, K2, M(31) );
R( d, e, a, b, c, F2, K2, M(32) );
R( c, d, e, a, b, F2, K2, M(33) );
R( b, c, d, e, a, F2, K2, M(34) );
R( a, b, c, d, e, F2, K2, M(35) );
R( e, a, b, c, d, F2, K2, M(36) );
R( d, e, a, b, c, F2, K2, M(37) );
R( c, d, e, a, b, F2, K2, M(38) );
R( b, c, d, e, a, F2, K2, M(39) );
R( a, b, c, d, e, F3, K3, M(40) );
R( e, a, b, c, d, F3, K3, M(41) );
R( d, e, a, b, c, F3, K3, M(42) );
R( c, d, e, a, b, F3, K3, M(43) );
R( b, c, d, e, a, F3, K3, M(44) );
R( a, b, c, d, e, F3, K3, M(45) );
R( e, a, b, c, d, F3, K3, M(46) );
R( d, e, a, b, c, F3, K3, M(47) );
R( c, d, e, a, b, F3, K3, M(48) );
R( b, c, d, e, a, F3, K3, M(49) );
R( a, b, c, d, e, F3, K3, M(50) );
R( e, a, b, c, d, F3, K3, M(51) );
R( d, e, a, b, c, F3, K3, M(52) );
R( c, d, e, a, b, F3, K3, M(53) );
R( b, c, d, e, a, F3, K3, M(54) );
R( a, b, c, d, e, F3, K3, M(55) );
R( e, a, b, c, d, F3, K3, M(56) );
R( d, e, a, b, c, F3, K3, M(57) );
R( c, d, e, a, b, F3, K3, M(58) );
R( b, c, d, e, a, F3, K3, M(59) );
R( a, b, c, d, e, F4, K4, M(60) );
R( e, a, b, c, d, F4, K4, M(61) );
R( d, e, a, b, c, F4, K4, M(62) );
R( c, d, e, a, b, F4, K4, M(63) );
R( b, c, d, e, a, F4, K4, M(64) );
R( a, b, c, d, e, F4, K4, M(65) );
R( e, a, b, c, d, F4, K4, M(66) );
R( d, e, a, b, c, F4, K4, M(67) );
R( c, d, e, a, b, F4, K4, M(68) );
R( b, c, d, e, a, F4, K4, M(69) );
R( a, b, c, d, e, F4, K4, M(70) );
R( e, a, b, c, d, F4, K4, M(71) );
R( d, e, a, b, c, F4, K4, M(72) );
R( c, d, e, a, b, F4, K4, M(73) );
R( b, c, d, e, a, F4, K4, M(74) );
R( a, b, c, d, e, F4, K4, M(75) );
R( e, a, b, c, d, F4, K4, M(76) );
R( d, e, a, b, c, F4, K4, M(77) );
R( c, d, e, a, b, F4, K4, M(78) );
R( b, c, d, e, a, F4, K4, M(79) );
/* update chainig vars */
hd->h0 += a;
hd->h1 += b;
hd->h2 += c;
hd->h3 += d;
hd->h4 += e;
}
/* Update the message digest with the contents
* of INBUF with length INLEN.
*/
static void
sha1_write( SHA1_CONTEXT *hd, byte *inbuf, size_t inlen)
{
if( hd->count == 64 ) { /* flush the buffer */
transform( hd, hd->buf );
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count ) {
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
sha1_write( hd, NULL, 0 );
if( !inlen )
return;
}
while( inlen >= 64 ) {
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/* The routine final terminates the computation and
* returns the digest.
* The handle is prepared for a new cycle, but adding bytes to the
* handle will the destroy the returned buffer.
* Returns: 20 bytes representing the digest.
*/
static void
sha1_final(SHA1_CONTEXT *hd)
{
u32 t, msb, lsb;
byte *p;
sha1_write(hd, NULL, 0); /* flush */;
msb = 0;
t = hd->nblocks;
if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
msb++;
msb += t >> 26;
t = lsb;
if( (lsb = t + hd->count) < t ) /* add the count */
msb++;
t = lsb;
if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
msb++;
msb += t >> 29;
if( hd->count < 56 ) { /* enough room */
hd->buf[hd->count++] = 0x80; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else { /* need one extra block */
hd->buf[hd->count++] = 0x80; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
sha1_write(hd, NULL, 0); /* flush */;
memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = msb >> 24;
hd->buf[57] = msb >> 16;
hd->buf[58] = msb >> 8;
hd->buf[59] = msb ;
hd->buf[60] = lsb >> 24;
hd->buf[61] = lsb >> 16;
hd->buf[62] = lsb >> 8;
hd->buf[63] = lsb ;
transform( hd, hd->buf );
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
#else /* little endian */
#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \
*p++ = hd->h##a >> 8; *p++ = hd->h##a; } while(0)
#endif
X(0);
X(1);
X(2);
X(3);
X(4);
#undef X
}
static byte *
sha1_read( SHA1_CONTEXT *hd )
{
return hd->buf;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
static const char *
sha1_get_info( int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
)
{
static byte asn[15] = /* Object ID is 1.3.14.3.2.26 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
if( algo != 2 )
return NULL;
*contextsize = sizeof(SHA1_CONTEXT);
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 20;
- *r_init = (void (*)(void *))sha1_init;
- *r_write = (void (*)(void *, byte*, size_t))sha1_write;
- *r_final = (void (*)(void *))sha1_final;
- *r_read = (byte *(*)(void *))sha1_read;
+ *(void (**)(SHA1_CONTEXT *))r_init = sha1_init;
+ *(void (**)(SHA1_CONTEXT *, byte*, size_t))r_write = sha1_write;
+ *(void (**)(SHA1_CONTEXT *))r_final = sha1_final;
+ *(byte *(**)(SHA1_CONTEXT *))r_read = sha1_read;
return "SHA1";
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "SHA1 ($Revision$)";
static struct {
int class;
int version;
int value;
void (*func)(void);
} func_table[] = {
{ 10, 1, 0, (void(*)(void))sha1_get_info },
{ 11, 1, 2 },
};
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
switch( *class ) {
case 11:
case 21:
case 31:
ret = &func_table[i].value;
break;
default:
ret = func_table[i].func;
break;
}
i++;
} while( what && what != *class );
*sequence = i;
return ret;
}
#ifndef IS_MODULE
void
sha1_constructor(void)
{
register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
}
#endif
diff --git a/cipher/tiger.c b/cipher/tiger.c
index 0e42160a..abe449ab 100644
--- a/cipher/tiger.c
+++ b/cipher/tiger.c
@@ -1,991 +1,991 @@
/* tiger.c - The TIGER hash function
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "g10lib.h"
#include "memory.h"
#ifdef HAVE_U64_TYPEDEF
/* we really need it here, but as this is only experiment we
* can live without Tiger */
typedef struct {
u64 a, b, c;
byte buf[64];
int count;
u32 nblocks;
} TIGER_CONTEXT;
/*********************************
* Okay, okay, this is not the fastest code - improvements are welcome.
*
*/
/* Some test vectors:
* "" 24F0130C63AC9332 16166E76B1BB925F F373DE2D49584E7A
* "abc" F258C1E88414AB2A 527AB541FFC5B8BF 935F7B951C132951
* "Tiger" 9F00F599072300DD 276ABB38C8EB6DEC 37790C116F9D2BDF
* "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
* 87FB2A9083851CF7 470D2CF810E6DF9E B586445034A5A386
* "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789"
* 467DB80863EBCE48 8DF1CD1261655DE9 57896565975F9197
* "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham"
* 0C410A042968868A 1671DA5A3FD29A72 5EC1E457D3CDB303
* "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proc"
* "eedings of Fast Software Encryption 3, Cambridge."
* EBF591D5AFA655CE 7F22894FF87F54AC 89C811B6B0DA3193
* "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proc"
* "eedings of Fast Software Encryption 3, Cambridge, 1996."
* 3D9AEB03D1BD1A63 57B2774DFD6D5B24 DD68151D503974FC
* "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEF"
* "GHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"
* 00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4
*/
static u64 sbox1[256] = {
0x02aab17cf7e90c5eLL /* 0 */, 0xac424b03e243a8ecLL /* 1 */,
0x72cd5be30dd5fcd3LL /* 2 */, 0x6d019b93f6f97f3aLL /* 3 */,
0xcd9978ffd21f9193LL /* 4 */, 0x7573a1c9708029e2LL /* 5 */,
0xb164326b922a83c3LL /* 6 */, 0x46883eee04915870LL /* 7 */,
0xeaace3057103ece6LL /* 8 */, 0xc54169b808a3535cLL /* 9 */,
0x4ce754918ddec47cLL /* 10 */, 0x0aa2f4dfdc0df40cLL /* 11 */,
0x10b76f18a74dbefaLL /* 12 */, 0xc6ccb6235ad1ab6aLL /* 13 */,
0x13726121572fe2ffLL /* 14 */, 0x1a488c6f199d921eLL /* 15 */,
0x4bc9f9f4da0007caLL /* 16 */, 0x26f5e6f6e85241c7LL /* 17 */,
0x859079dbea5947b6LL /* 18 */, 0x4f1885c5c99e8c92LL /* 19 */,
0xd78e761ea96f864bLL /* 20 */, 0x8e36428c52b5c17dLL /* 21 */,
0x69cf6827373063c1LL /* 22 */, 0xb607c93d9bb4c56eLL /* 23 */,
0x7d820e760e76b5eaLL /* 24 */, 0x645c9cc6f07fdc42LL /* 25 */,
0xbf38a078243342e0LL /* 26 */, 0x5f6b343c9d2e7d04LL /* 27 */,
0xf2c28aeb600b0ec6LL /* 28 */, 0x6c0ed85f7254bcacLL /* 29 */,
0x71592281a4db4fe5LL /* 30 */, 0x1967fa69ce0fed9fLL /* 31 */,
0xfd5293f8b96545dbLL /* 32 */, 0xc879e9d7f2a7600bLL /* 33 */,
0x860248920193194eLL /* 34 */, 0xa4f9533b2d9cc0b3LL /* 35 */,
0x9053836c15957613LL /* 36 */, 0xdb6dcf8afc357bf1LL /* 37 */,
0x18beea7a7a370f57LL /* 38 */, 0x037117ca50b99066LL /* 39 */,
0x6ab30a9774424a35LL /* 40 */, 0xf4e92f02e325249bLL /* 41 */,
0x7739db07061ccae1LL /* 42 */, 0xd8f3b49ceca42a05LL /* 43 */,
0xbd56be3f51382f73LL /* 44 */, 0x45faed5843b0bb28LL /* 45 */,
0x1c813d5c11bf1f83LL /* 46 */, 0x8af0e4b6d75fa169LL /* 47 */,
0x33ee18a487ad9999LL /* 48 */, 0x3c26e8eab1c94410LL /* 49 */,
0xb510102bc0a822f9LL /* 50 */, 0x141eef310ce6123bLL /* 51 */,
0xfc65b90059ddb154LL /* 52 */, 0xe0158640c5e0e607LL /* 53 */,
0x884e079826c3a3cfLL /* 54 */, 0x930d0d9523c535fdLL /* 55 */,
0x35638d754e9a2b00LL /* 56 */, 0x4085fccf40469dd5LL /* 57 */,
0xc4b17ad28be23a4cLL /* 58 */, 0xcab2f0fc6a3e6a2eLL /* 59 */,
0x2860971a6b943fcdLL /* 60 */, 0x3dde6ee212e30446LL /* 61 */,
0x6222f32ae01765aeLL /* 62 */, 0x5d550bb5478308feLL /* 63 */,
0xa9efa98da0eda22aLL /* 64 */, 0xc351a71686c40da7LL /* 65 */,
0x1105586d9c867c84LL /* 66 */, 0xdcffee85fda22853LL /* 67 */,
0xccfbd0262c5eef76LL /* 68 */, 0xbaf294cb8990d201LL /* 69 */,
0xe69464f52afad975LL /* 70 */, 0x94b013afdf133e14LL /* 71 */,
0x06a7d1a32823c958LL /* 72 */, 0x6f95fe5130f61119LL /* 73 */,
0xd92ab34e462c06c0LL /* 74 */, 0xed7bde33887c71d2LL /* 75 */,
0x79746d6e6518393eLL /* 76 */, 0x5ba419385d713329LL /* 77 */,
0x7c1ba6b948a97564LL /* 78 */, 0x31987c197bfdac67LL /* 79 */,
0xde6c23c44b053d02LL /* 80 */, 0x581c49fed002d64dLL /* 81 */,
0xdd474d6338261571LL /* 82 */, 0xaa4546c3e473d062LL /* 83 */,
0x928fce349455f860LL /* 84 */, 0x48161bbacaab94d9LL /* 85 */,
0x63912430770e6f68LL /* 86 */, 0x6ec8a5e602c6641cLL /* 87 */,
0x87282515337ddd2bLL /* 88 */, 0x2cda6b42034b701bLL /* 89 */,
0xb03d37c181cb096dLL /* 90 */, 0xe108438266c71c6fLL /* 91 */,
0x2b3180c7eb51b255LL /* 92 */, 0xdf92b82f96c08bbcLL /* 93 */,
0x5c68c8c0a632f3baLL /* 94 */, 0x5504cc861c3d0556LL /* 95 */,
0xabbfa4e55fb26b8fLL /* 96 */, 0x41848b0ab3baceb4LL /* 97 */,
0xb334a273aa445d32LL /* 98 */, 0xbca696f0a85ad881LL /* 99 */,
0x24f6ec65b528d56cLL /* 100 */, 0x0ce1512e90f4524aLL /* 101 */,
0x4e9dd79d5506d35aLL /* 102 */, 0x258905fac6ce9779LL /* 103 */,
0x2019295b3e109b33LL /* 104 */, 0xf8a9478b73a054ccLL /* 105 */,
0x2924f2f934417eb0LL /* 106 */, 0x3993357d536d1bc4LL /* 107 */,
0x38a81ac21db6ff8bLL /* 108 */, 0x47c4fbf17d6016bfLL /* 109 */,
0x1e0faadd7667e3f5LL /* 110 */, 0x7abcff62938beb96LL /* 111 */,
0xa78dad948fc179c9LL /* 112 */, 0x8f1f98b72911e50dLL /* 113 */,
0x61e48eae27121a91LL /* 114 */, 0x4d62f7ad31859808LL /* 115 */,
0xeceba345ef5ceaebLL /* 116 */, 0xf5ceb25ebc9684ceLL /* 117 */,
0xf633e20cb7f76221LL /* 118 */, 0xa32cdf06ab8293e4LL /* 119 */,
0x985a202ca5ee2ca4LL /* 120 */, 0xcf0b8447cc8a8fb1LL /* 121 */,
0x9f765244979859a3LL /* 122 */, 0xa8d516b1a1240017LL /* 123 */,
0x0bd7ba3ebb5dc726LL /* 124 */, 0xe54bca55b86adb39LL /* 125 */,
0x1d7a3afd6c478063LL /* 126 */, 0x519ec608e7669eddLL /* 127 */,
0x0e5715a2d149aa23LL /* 128 */, 0x177d4571848ff194LL /* 129 */,
0xeeb55f3241014c22LL /* 130 */, 0x0f5e5ca13a6e2ec2LL /* 131 */,
0x8029927b75f5c361LL /* 132 */, 0xad139fabc3d6e436LL /* 133 */,
0x0d5df1a94ccf402fLL /* 134 */, 0x3e8bd948bea5dfc8LL /* 135 */,
0xa5a0d357bd3ff77eLL /* 136 */, 0xa2d12e251f74f645LL /* 137 */,
0x66fd9e525e81a082LL /* 138 */, 0x2e0c90ce7f687a49LL /* 139 */,
0xc2e8bcbeba973bc5LL /* 140 */, 0x000001bce509745fLL /* 141 */,
0x423777bbe6dab3d6LL /* 142 */, 0xd1661c7eaef06eb5LL /* 143 */,
0xa1781f354daacfd8LL /* 144 */, 0x2d11284a2b16affcLL /* 145 */,
0xf1fc4f67fa891d1fLL /* 146 */, 0x73ecc25dcb920adaLL /* 147 */,
0xae610c22c2a12651LL /* 148 */, 0x96e0a810d356b78aLL /* 149 */,
0x5a9a381f2fe7870fLL /* 150 */, 0xd5ad62ede94e5530LL /* 151 */,
0xd225e5e8368d1427LL /* 152 */, 0x65977b70c7af4631LL /* 153 */,
0x99f889b2de39d74fLL /* 154 */, 0x233f30bf54e1d143LL /* 155 */,
0x9a9675d3d9a63c97LL /* 156 */, 0x5470554ff334f9a8LL /* 157 */,
0x166acb744a4f5688LL /* 158 */, 0x70c74caab2e4aeadLL /* 159 */,
0xf0d091646f294d12LL /* 160 */, 0x57b82a89684031d1LL /* 161 */,
0xefd95a5a61be0b6bLL /* 162 */, 0x2fbd12e969f2f29aLL /* 163 */,
0x9bd37013feff9fe8LL /* 164 */, 0x3f9b0404d6085a06LL /* 165 */,
0x4940c1f3166cfe15LL /* 166 */, 0x09542c4dcdf3defbLL /* 167 */,
0xb4c5218385cd5ce3LL /* 168 */, 0xc935b7dc4462a641LL /* 169 */,
0x3417f8a68ed3b63fLL /* 170 */, 0xb80959295b215b40LL /* 171 */,
0xf99cdaef3b8c8572LL /* 172 */, 0x018c0614f8fcb95dLL /* 173 */,
0x1b14accd1a3acdf3LL /* 174 */, 0x84d471f200bb732dLL /* 175 */,
0xc1a3110e95e8da16LL /* 176 */, 0x430a7220bf1a82b8LL /* 177 */,
0xb77e090d39df210eLL /* 178 */, 0x5ef4bd9f3cd05e9dLL /* 179 */,
0x9d4ff6da7e57a444LL /* 180 */, 0xda1d60e183d4a5f8LL /* 181 */,
0xb287c38417998e47LL /* 182 */, 0xfe3edc121bb31886LL /* 183 */,
0xc7fe3ccc980ccbefLL /* 184 */, 0xe46fb590189bfd03LL /* 185 */,
0x3732fd469a4c57dcLL /* 186 */, 0x7ef700a07cf1ad65LL /* 187 */,
0x59c64468a31d8859LL /* 188 */, 0x762fb0b4d45b61f6LL /* 189 */,
0x155baed099047718LL /* 190 */, 0x68755e4c3d50baa6LL /* 191 */,
0xe9214e7f22d8b4dfLL /* 192 */, 0x2addbf532eac95f4LL /* 193 */,
0x32ae3909b4bd0109LL /* 194 */, 0x834df537b08e3450LL /* 195 */,
0xfa209da84220728dLL /* 196 */, 0x9e691d9b9efe23f7LL /* 197 */,
0x0446d288c4ae8d7fLL /* 198 */, 0x7b4cc524e169785bLL /* 199 */,
0x21d87f0135ca1385LL /* 200 */, 0xcebb400f137b8aa5LL /* 201 */,
0x272e2b66580796beLL /* 202 */, 0x3612264125c2b0deLL /* 203 */,
0x057702bdad1efbb2LL /* 204 */, 0xd4babb8eacf84be9LL /* 205 */,
0x91583139641bc67bLL /* 206 */, 0x8bdc2de08036e024LL /* 207 */,
0x603c8156f49f68edLL /* 208 */, 0xf7d236f7dbef5111LL /* 209 */,
0x9727c4598ad21e80LL /* 210 */, 0xa08a0896670a5fd7LL /* 211 */,
0xcb4a8f4309eba9cbLL /* 212 */, 0x81af564b0f7036a1LL /* 213 */,
0xc0b99aa778199abdLL /* 214 */, 0x959f1ec83fc8e952LL /* 215 */,
0x8c505077794a81b9LL /* 216 */, 0x3acaaf8f056338f0LL /* 217 */,
0x07b43f50627a6778LL /* 218 */, 0x4a44ab49f5eccc77LL /* 219 */,
0x3bc3d6e4b679ee98LL /* 220 */, 0x9cc0d4d1cf14108cLL /* 221 */,
0x4406c00b206bc8a0LL /* 222 */, 0x82a18854c8d72d89LL /* 223 */,
0x67e366b35c3c432cLL /* 224 */, 0xb923dd61102b37f2LL /* 225 */,
0x56ab2779d884271dLL /* 226 */, 0xbe83e1b0ff1525afLL /* 227 */,
0xfb7c65d4217e49a9LL /* 228 */, 0x6bdbe0e76d48e7d4LL /* 229 */,
0x08df828745d9179eLL /* 230 */, 0x22ea6a9add53bd34LL /* 231 */,
0xe36e141c5622200aLL /* 232 */, 0x7f805d1b8cb750eeLL /* 233 */,
0xafe5c7a59f58e837LL /* 234 */, 0xe27f996a4fb1c23cLL /* 235 */,
0xd3867dfb0775f0d0LL /* 236 */, 0xd0e673de6e88891aLL /* 237 */,
0x123aeb9eafb86c25LL /* 238 */, 0x30f1d5d5c145b895LL /* 239 */,
0xbb434a2dee7269e7LL /* 240 */, 0x78cb67ecf931fa38LL /* 241 */,
0xf33b0372323bbf9cLL /* 242 */, 0x52d66336fb279c74LL /* 243 */,
0x505f33ac0afb4eaaLL /* 244 */, 0xe8a5cd99a2cce187LL /* 245 */,
0x534974801e2d30bbLL /* 246 */, 0x8d2d5711d5876d90LL /* 247 */,
0x1f1a412891bc038eLL /* 248 */, 0xd6e2e71d82e56648LL /* 249 */,
0x74036c3a497732b7LL /* 250 */, 0x89b67ed96361f5abLL /* 251 */,
0xffed95d8f1ea02a2LL /* 252 */, 0xe72b3bd61464d43dLL /* 253 */,
0xa6300f170bdc4820LL /* 254 */, 0xebc18760ed78a77aLL /* 255 */
};
static u64 sbox2[256] = {
0xe6a6be5a05a12138LL /* 256 */, 0xb5a122a5b4f87c98LL /* 257 */,
0x563c6089140b6990LL /* 258 */, 0x4c46cb2e391f5dd5LL /* 259 */,
0xd932addbc9b79434LL /* 260 */, 0x08ea70e42015aff5LL /* 261 */,
0xd765a6673e478cf1LL /* 262 */, 0xc4fb757eab278d99LL /* 263 */,
0xdf11c6862d6e0692LL /* 264 */, 0xddeb84f10d7f3b16LL /* 265 */,
0x6f2ef604a665ea04LL /* 266 */, 0x4a8e0f0ff0e0dfb3LL /* 267 */,
0xa5edeef83dbcba51LL /* 268 */, 0xfc4f0a2a0ea4371eLL /* 269 */,
0xe83e1da85cb38429LL /* 270 */, 0xdc8ff882ba1b1ce2LL /* 271 */,
0xcd45505e8353e80dLL /* 272 */, 0x18d19a00d4db0717LL /* 273 */,
0x34a0cfeda5f38101LL /* 274 */, 0x0be77e518887caf2LL /* 275 */,
0x1e341438b3c45136LL /* 276 */, 0xe05797f49089ccf9LL /* 277 */,
0xffd23f9df2591d14LL /* 278 */, 0x543dda228595c5cdLL /* 279 */,
0x661f81fd99052a33LL /* 280 */, 0x8736e641db0f7b76LL /* 281 */,
0x15227725418e5307LL /* 282 */, 0xe25f7f46162eb2faLL /* 283 */,
0x48a8b2126c13d9feLL /* 284 */, 0xafdc541792e76eeaLL /* 285 */,
0x03d912bfc6d1898fLL /* 286 */, 0x31b1aafa1b83f51bLL /* 287 */,
0xf1ac2796e42ab7d9LL /* 288 */, 0x40a3a7d7fcd2ebacLL /* 289 */,
0x1056136d0afbbcc5LL /* 290 */, 0x7889e1dd9a6d0c85LL /* 291 */,
0xd33525782a7974aaLL /* 292 */, 0xa7e25d09078ac09bLL /* 293 */,
0xbd4138b3eac6edd0LL /* 294 */, 0x920abfbe71eb9e70LL /* 295 */,
0xa2a5d0f54fc2625cLL /* 296 */, 0xc054e36b0b1290a3LL /* 297 */,
0xf6dd59ff62fe932bLL /* 298 */, 0x3537354511a8ac7dLL /* 299 */,
0xca845e9172fadcd4LL /* 300 */, 0x84f82b60329d20dcLL /* 301 */,
0x79c62ce1cd672f18LL /* 302 */, 0x8b09a2add124642cLL /* 303 */,
0xd0c1e96a19d9e726LL /* 304 */, 0x5a786a9b4ba9500cLL /* 305 */,
0x0e020336634c43f3LL /* 306 */, 0xc17b474aeb66d822LL /* 307 */,
0x6a731ae3ec9baac2LL /* 308 */, 0x8226667ae0840258LL /* 309 */,
0x67d4567691caeca5LL /* 310 */, 0x1d94155c4875adb5LL /* 311 */,
0x6d00fd985b813fdfLL /* 312 */, 0x51286efcb774cd06LL /* 313 */,
0x5e8834471fa744afLL /* 314 */, 0xf72ca0aee761ae2eLL /* 315 */,
0xbe40e4cdaee8e09aLL /* 316 */, 0xe9970bbb5118f665LL /* 317 */,
0x726e4beb33df1964LL /* 318 */, 0x703b000729199762LL /* 319 */,
0x4631d816f5ef30a7LL /* 320 */, 0xb880b5b51504a6beLL /* 321 */,
0x641793c37ed84b6cLL /* 322 */, 0x7b21ed77f6e97d96LL /* 323 */,
0x776306312ef96b73LL /* 324 */, 0xae528948e86ff3f4LL /* 325 */,
0x53dbd7f286a3f8f8LL /* 326 */, 0x16cadce74cfc1063LL /* 327 */,
0x005c19bdfa52c6ddLL /* 328 */, 0x68868f5d64d46ad3LL /* 329 */,
0x3a9d512ccf1e186aLL /* 330 */, 0x367e62c2385660aeLL /* 331 */,
0xe359e7ea77dcb1d7LL /* 332 */, 0x526c0773749abe6eLL /* 333 */,
0x735ae5f9d09f734bLL /* 334 */, 0x493fc7cc8a558ba8LL /* 335 */,
0xb0b9c1533041ab45LL /* 336 */, 0x321958ba470a59bdLL /* 337 */,
0x852db00b5f46c393LL /* 338 */, 0x91209b2bd336b0e5LL /* 339 */,
0x6e604f7d659ef19fLL /* 340 */, 0xb99a8ae2782ccb24LL /* 341 */,
0xccf52ab6c814c4c7LL /* 342 */, 0x4727d9afbe11727bLL /* 343 */,
0x7e950d0c0121b34dLL /* 344 */, 0x756f435670ad471fLL /* 345 */,
0xf5add442615a6849LL /* 346 */, 0x4e87e09980b9957aLL /* 347 */,
0x2acfa1df50aee355LL /* 348 */, 0xd898263afd2fd556LL /* 349 */,
0xc8f4924dd80c8fd6LL /* 350 */, 0xcf99ca3d754a173aLL /* 351 */,
0xfe477bacaf91bf3cLL /* 352 */, 0xed5371f6d690c12dLL /* 353 */,
0x831a5c285e687094LL /* 354 */, 0xc5d3c90a3708a0a4LL /* 355 */,
0x0f7f903717d06580LL /* 356 */, 0x19f9bb13b8fdf27fLL /* 357 */,
0xb1bd6f1b4d502843LL /* 358 */, 0x1c761ba38fff4012LL /* 359 */,
0x0d1530c4e2e21f3bLL /* 360 */, 0x8943ce69a7372c8aLL /* 361 */,
0xe5184e11feb5ce66LL /* 362 */, 0x618bdb80bd736621LL /* 363 */,
0x7d29bad68b574d0bLL /* 364 */, 0x81bb613e25e6fe5bLL /* 365 */,
0x071c9c10bc07913fLL /* 366 */, 0xc7beeb7909ac2d97LL /* 367 */,
0xc3e58d353bc5d757LL /* 368 */, 0xeb017892f38f61e8LL /* 369 */,
0xd4effb9c9b1cc21aLL /* 370 */, 0x99727d26f494f7abLL /* 371 */,
0xa3e063a2956b3e03LL /* 372 */, 0x9d4a8b9a4aa09c30LL /* 373 */,
0x3f6ab7d500090fb4LL /* 374 */, 0x9cc0f2a057268ac0LL /* 375 */,
0x3dee9d2dedbf42d1LL /* 376 */, 0x330f49c87960a972LL /* 377 */,
0xc6b2720287421b41LL /* 378 */, 0x0ac59ec07c00369cLL /* 379 */,
0xef4eac49cb353425LL /* 380 */, 0xf450244eef0129d8LL /* 381 */,
0x8acc46e5caf4deb6LL /* 382 */, 0x2ffeab63989263f7LL /* 383 */,
0x8f7cb9fe5d7a4578LL /* 384 */, 0x5bd8f7644e634635LL /* 385 */,
0x427a7315bf2dc900LL /* 386 */, 0x17d0c4aa2125261cLL /* 387 */,
0x3992486c93518e50LL /* 388 */, 0xb4cbfee0a2d7d4c3LL /* 389 */,
0x7c75d6202c5ddd8dLL /* 390 */, 0xdbc295d8e35b6c61LL /* 391 */,
0x60b369d302032b19LL /* 392 */, 0xce42685fdce44132LL /* 393 */,
0x06f3ddb9ddf65610LL /* 394 */, 0x8ea4d21db5e148f0LL /* 395 */,
0x20b0fce62fcd496fLL /* 396 */, 0x2c1b912358b0ee31LL /* 397 */,
0xb28317b818f5a308LL /* 398 */, 0xa89c1e189ca6d2cfLL /* 399 */,
0x0c6b18576aaadbc8LL /* 400 */, 0xb65deaa91299fae3LL /* 401 */,
0xfb2b794b7f1027e7LL /* 402 */, 0x04e4317f443b5bebLL /* 403 */,
0x4b852d325939d0a6LL /* 404 */, 0xd5ae6beefb207ffcLL /* 405 */,
0x309682b281c7d374LL /* 406 */, 0xbae309a194c3b475LL /* 407 */,
0x8cc3f97b13b49f05LL /* 408 */, 0x98a9422ff8293967LL /* 409 */,
0x244b16b01076ff7cLL /* 410 */, 0xf8bf571c663d67eeLL /* 411 */,
0x1f0d6758eee30da1LL /* 412 */, 0xc9b611d97adeb9b7LL /* 413 */,
0xb7afd5887b6c57a2LL /* 414 */, 0x6290ae846b984fe1LL /* 415 */,
0x94df4cdeacc1a5fdLL /* 416 */, 0x058a5bd1c5483affLL /* 417 */,
0x63166cc142ba3c37LL /* 418 */, 0x8db8526eb2f76f40LL /* 419 */,
0xe10880036f0d6d4eLL /* 420 */, 0x9e0523c9971d311dLL /* 421 */,
0x45ec2824cc7cd691LL /* 422 */, 0x575b8359e62382c9LL /* 423 */,
0xfa9e400dc4889995LL /* 424 */, 0xd1823ecb45721568LL /* 425 */,
0xdafd983b8206082fLL /* 426 */, 0xaa7d29082386a8cbLL /* 427 */,
0x269fcd4403b87588LL /* 428 */, 0x1b91f5f728bdd1e0LL /* 429 */,
0xe4669f39040201f6LL /* 430 */, 0x7a1d7c218cf04adeLL /* 431 */,
0x65623c29d79ce5ceLL /* 432 */, 0x2368449096c00bb1LL /* 433 */,
0xab9bf1879da503baLL /* 434 */, 0xbc23ecb1a458058eLL /* 435 */,
0x9a58df01bb401eccLL /* 436 */, 0xa070e868a85f143dLL /* 437 */,
0x4ff188307df2239eLL /* 438 */, 0x14d565b41a641183LL /* 439 */,
0xee13337452701602LL /* 440 */, 0x950e3dcf3f285e09LL /* 441 */,
0x59930254b9c80953LL /* 442 */, 0x3bf299408930da6dLL /* 443 */,
0xa955943f53691387LL /* 444 */, 0xa15edecaa9cb8784LL /* 445 */,
0x29142127352be9a0LL /* 446 */, 0x76f0371fff4e7afbLL /* 447 */,
0x0239f450274f2228LL /* 448 */, 0xbb073af01d5e868bLL /* 449 */,
0xbfc80571c10e96c1LL /* 450 */, 0xd267088568222e23LL /* 451 */,
0x9671a3d48e80b5b0LL /* 452 */, 0x55b5d38ae193bb81LL /* 453 */,
0x693ae2d0a18b04b8LL /* 454 */, 0x5c48b4ecadd5335fLL /* 455 */,
0xfd743b194916a1caLL /* 456 */, 0x2577018134be98c4LL /* 457 */,
0xe77987e83c54a4adLL /* 458 */, 0x28e11014da33e1b9LL /* 459 */,
0x270cc59e226aa213LL /* 460 */, 0x71495f756d1a5f60LL /* 461 */,
0x9be853fb60afef77LL /* 462 */, 0xadc786a7f7443dbfLL /* 463 */,
0x0904456173b29a82LL /* 464 */, 0x58bc7a66c232bd5eLL /* 465 */,
0xf306558c673ac8b2LL /* 466 */, 0x41f639c6b6c9772aLL /* 467 */,
0x216defe99fda35daLL /* 468 */, 0x11640cc71c7be615LL /* 469 */,
0x93c43694565c5527LL /* 470 */, 0xea038e6246777839LL /* 471 */,
0xf9abf3ce5a3e2469LL /* 472 */, 0x741e768d0fd312d2LL /* 473 */,
0x0144b883ced652c6LL /* 474 */, 0xc20b5a5ba33f8552LL /* 475 */,
0x1ae69633c3435a9dLL /* 476 */, 0x97a28ca4088cfdecLL /* 477 */,
0x8824a43c1e96f420LL /* 478 */, 0x37612fa66eeea746LL /* 479 */,
0x6b4cb165f9cf0e5aLL /* 480 */, 0x43aa1c06a0abfb4aLL /* 481 */,
0x7f4dc26ff162796bLL /* 482 */, 0x6cbacc8e54ed9b0fLL /* 483 */,
0xa6b7ffefd2bb253eLL /* 484 */, 0x2e25bc95b0a29d4fLL /* 485 */,
0x86d6a58bdef1388cLL /* 486 */, 0xded74ac576b6f054LL /* 487 */,
0x8030bdbc2b45805dLL /* 488 */, 0x3c81af70e94d9289LL /* 489 */,
0x3eff6dda9e3100dbLL /* 490 */, 0xb38dc39fdfcc8847LL /* 491 */,
0x123885528d17b87eLL /* 492 */, 0xf2da0ed240b1b642LL /* 493 */,
0x44cefadcd54bf9a9LL /* 494 */, 0x1312200e433c7ee6LL /* 495 */,
0x9ffcc84f3a78c748LL /* 496 */, 0xf0cd1f72248576bbLL /* 497 */,
0xec6974053638cfe4LL /* 498 */, 0x2ba7b67c0cec4e4cLL /* 499 */,
0xac2f4df3e5ce32edLL /* 500 */, 0xcb33d14326ea4c11LL /* 501 */,
0xa4e9044cc77e58bcLL /* 502 */, 0x5f513293d934fcefLL /* 503 */,
0x5dc9645506e55444LL /* 504 */, 0x50de418f317de40aLL /* 505 */,
0x388cb31a69dde259LL /* 506 */, 0x2db4a83455820a86LL /* 507 */,
0x9010a91e84711ae9LL /* 508 */, 0x4df7f0b7b1498371LL /* 509 */,
0xd62a2eabc0977179LL /* 510 */, 0x22fac097aa8d5c0eLL /* 511 */
};
static u64 sbox3[256] = {
0xf49fcc2ff1daf39bLL /* 512 */, 0x487fd5c66ff29281LL /* 513 */,
0xe8a30667fcdca83fLL /* 514 */, 0x2c9b4be3d2fcce63LL /* 515 */,
0xda3ff74b93fbbbc2LL /* 516 */, 0x2fa165d2fe70ba66LL /* 517 */,
0xa103e279970e93d4LL /* 518 */, 0xbecdec77b0e45e71LL /* 519 */,
0xcfb41e723985e497LL /* 520 */, 0xb70aaa025ef75017LL /* 521 */,
0xd42309f03840b8e0LL /* 522 */, 0x8efc1ad035898579LL /* 523 */,
0x96c6920be2b2abc5LL /* 524 */, 0x66af4163375a9172LL /* 525 */,
0x2174abdcca7127fbLL /* 526 */, 0xb33ccea64a72ff41LL /* 527 */,
0xf04a4933083066a5LL /* 528 */, 0x8d970acdd7289af5LL /* 529 */,
0x8f96e8e031c8c25eLL /* 530 */, 0xf3fec02276875d47LL /* 531 */,
0xec7bf310056190ddLL /* 532 */, 0xf5adb0aebb0f1491LL /* 533 */,
0x9b50f8850fd58892LL /* 534 */, 0x4975488358b74de8LL /* 535 */,
0xa3354ff691531c61LL /* 536 */, 0x0702bbe481d2c6eeLL /* 537 */,
0x89fb24057deded98LL /* 538 */, 0xac3075138596e902LL /* 539 */,
0x1d2d3580172772edLL /* 540 */, 0xeb738fc28e6bc30dLL /* 541 */,
0x5854ef8f63044326LL /* 542 */, 0x9e5c52325add3bbeLL /* 543 */,
0x90aa53cf325c4623LL /* 544 */, 0xc1d24d51349dd067LL /* 545 */,
0x2051cfeea69ea624LL /* 546 */, 0x13220f0a862e7e4fLL /* 547 */,
0xce39399404e04864LL /* 548 */, 0xd9c42ca47086fcb7LL /* 549 */,
0x685ad2238a03e7ccLL /* 550 */, 0x066484b2ab2ff1dbLL /* 551 */,
0xfe9d5d70efbf79ecLL /* 552 */, 0x5b13b9dd9c481854LL /* 553 */,
0x15f0d475ed1509adLL /* 554 */, 0x0bebcd060ec79851LL /* 555 */,
0xd58c6791183ab7f8LL /* 556 */, 0xd1187c5052f3eee4LL /* 557 */,
0xc95d1192e54e82ffLL /* 558 */, 0x86eea14cb9ac6ca2LL /* 559 */,
0x3485beb153677d5dLL /* 560 */, 0xdd191d781f8c492aLL /* 561 */,
0xf60866baa784ebf9LL /* 562 */, 0x518f643ba2d08c74LL /* 563 */,
0x8852e956e1087c22LL /* 564 */, 0xa768cb8dc410ae8dLL /* 565 */,
0x38047726bfec8e1aLL /* 566 */, 0xa67738b4cd3b45aaLL /* 567 */,
0xad16691cec0dde19LL /* 568 */, 0xc6d4319380462e07LL /* 569 */,
0xc5a5876d0ba61938LL /* 570 */, 0x16b9fa1fa58fd840LL /* 571 */,
0x188ab1173ca74f18LL /* 572 */, 0xabda2f98c99c021fLL /* 573 */,
0x3e0580ab134ae816LL /* 574 */, 0x5f3b05b773645abbLL /* 575 */,
0x2501a2be5575f2f6LL /* 576 */, 0x1b2f74004e7e8ba9LL /* 577 */,
0x1cd7580371e8d953LL /* 578 */, 0x7f6ed89562764e30LL /* 579 */,
0xb15926ff596f003dLL /* 580 */, 0x9f65293da8c5d6b9LL /* 581 */,
0x6ecef04dd690f84cLL /* 582 */, 0x4782275fff33af88LL /* 583 */,
0xe41433083f820801LL /* 584 */, 0xfd0dfe409a1af9b5LL /* 585 */,
0x4325a3342cdb396bLL /* 586 */, 0x8ae77e62b301b252LL /* 587 */,
0xc36f9e9f6655615aLL /* 588 */, 0x85455a2d92d32c09LL /* 589 */,
0xf2c7dea949477485LL /* 590 */, 0x63cfb4c133a39ebaLL /* 591 */,
0x83b040cc6ebc5462LL /* 592 */, 0x3b9454c8fdb326b0LL /* 593 */,
0x56f56a9e87ffd78cLL /* 594 */, 0x2dc2940d99f42bc6LL /* 595 */,
0x98f7df096b096e2dLL /* 596 */, 0x19a6e01e3ad852bfLL /* 597 */,
0x42a99ccbdbd4b40bLL /* 598 */, 0xa59998af45e9c559LL /* 599 */,
0x366295e807d93186LL /* 600 */, 0x6b48181bfaa1f773LL /* 601 */,
0x1fec57e2157a0a1dLL /* 602 */, 0x4667446af6201ad5LL /* 603 */,
0xe615ebcacfb0f075LL /* 604 */, 0xb8f31f4f68290778LL /* 605 */,
0x22713ed6ce22d11eLL /* 606 */, 0x3057c1a72ec3c93bLL /* 607 */,
0xcb46acc37c3f1f2fLL /* 608 */, 0xdbb893fd02aaf50eLL /* 609 */,
0x331fd92e600b9fcfLL /* 610 */, 0xa498f96148ea3ad6LL /* 611 */,
0xa8d8426e8b6a83eaLL /* 612 */, 0xa089b274b7735cdcLL /* 613 */,
0x87f6b3731e524a11LL /* 614 */, 0x118808e5cbc96749LL /* 615 */,
0x9906e4c7b19bd394LL /* 616 */, 0xafed7f7e9b24a20cLL /* 617 */,
0x6509eadeeb3644a7LL /* 618 */, 0x6c1ef1d3e8ef0edeLL /* 619 */,
0xb9c97d43e9798fb4LL /* 620 */, 0xa2f2d784740c28a3LL /* 621 */,
0x7b8496476197566fLL /* 622 */, 0x7a5be3e6b65f069dLL /* 623 */,
0xf96330ed78be6f10LL /* 624 */, 0xeee60de77a076a15LL /* 625 */,
0x2b4bee4aa08b9bd0LL /* 626 */, 0x6a56a63ec7b8894eLL /* 627 */,
0x02121359ba34fef4LL /* 628 */, 0x4cbf99f8283703fcLL /* 629 */,
0x398071350caf30c8LL /* 630 */, 0xd0a77a89f017687aLL /* 631 */,
0xf1c1a9eb9e423569LL /* 632 */, 0x8c7976282dee8199LL /* 633 */,
0x5d1737a5dd1f7abdLL /* 634 */, 0x4f53433c09a9fa80LL /* 635 */,
0xfa8b0c53df7ca1d9LL /* 636 */, 0x3fd9dcbc886ccb77LL /* 637 */,
0xc040917ca91b4720LL /* 638 */, 0x7dd00142f9d1dcdfLL /* 639 */,
0x8476fc1d4f387b58LL /* 640 */, 0x23f8e7c5f3316503LL /* 641 */,
0x032a2244e7e37339LL /* 642 */, 0x5c87a5d750f5a74bLL /* 643 */,
0x082b4cc43698992eLL /* 644 */, 0xdf917becb858f63cLL /* 645 */,
0x3270b8fc5bf86ddaLL /* 646 */, 0x10ae72bb29b5dd76LL /* 647 */,
0x576ac94e7700362bLL /* 648 */, 0x1ad112dac61efb8fLL /* 649 */,
0x691bc30ec5faa427LL /* 650 */, 0xff246311cc327143LL /* 651 */,
0x3142368e30e53206LL /* 652 */, 0x71380e31e02ca396LL /* 653 */,
0x958d5c960aad76f1LL /* 654 */, 0xf8d6f430c16da536LL /* 655 */,
0xc8ffd13f1be7e1d2LL /* 656 */, 0x7578ae66004ddbe1LL /* 657 */,
0x05833f01067be646LL /* 658 */, 0xbb34b5ad3bfe586dLL /* 659 */,
0x095f34c9a12b97f0LL /* 660 */, 0x247ab64525d60ca8LL /* 661 */,
0xdcdbc6f3017477d1LL /* 662 */, 0x4a2e14d4decad24dLL /* 663 */,
0xbdb5e6d9be0a1eebLL /* 664 */, 0x2a7e70f7794301abLL /* 665 */,
0xdef42d8a270540fdLL /* 666 */, 0x01078ec0a34c22c1LL /* 667 */,
0xe5de511af4c16387LL /* 668 */, 0x7ebb3a52bd9a330aLL /* 669 */,
0x77697857aa7d6435LL /* 670 */, 0x004e831603ae4c32LL /* 671 */,
0xe7a21020ad78e312LL /* 672 */, 0x9d41a70c6ab420f2LL /* 673 */,
0x28e06c18ea1141e6LL /* 674 */, 0xd2b28cbd984f6b28LL /* 675 */,
0x26b75f6c446e9d83LL /* 676 */, 0xba47568c4d418d7fLL /* 677 */,
0xd80badbfe6183d8eLL /* 678 */, 0x0e206d7f5f166044LL /* 679 */,
0xe258a43911cbca3eLL /* 680 */, 0x723a1746b21dc0bcLL /* 681 */,
0xc7caa854f5d7cdd3LL /* 682 */, 0x7cac32883d261d9cLL /* 683 */,
0x7690c26423ba942cLL /* 684 */, 0x17e55524478042b8LL /* 685 */,
0xe0be477656a2389fLL /* 686 */, 0x4d289b5e67ab2da0LL /* 687 */,
0x44862b9c8fbbfd31LL /* 688 */, 0xb47cc8049d141365LL /* 689 */,
0x822c1b362b91c793LL /* 690 */, 0x4eb14655fb13dfd8LL /* 691 */,
0x1ecbba0714e2a97bLL /* 692 */, 0x6143459d5cde5f14LL /* 693 */,
0x53a8fbf1d5f0ac89LL /* 694 */, 0x97ea04d81c5e5b00LL /* 695 */,
0x622181a8d4fdb3f3LL /* 696 */, 0xe9bcd341572a1208LL /* 697 */,
0x1411258643cce58aLL /* 698 */, 0x9144c5fea4c6e0a4LL /* 699 */,
0x0d33d06565cf620fLL /* 700 */, 0x54a48d489f219ca1LL /* 701 */,
0xc43e5eac6d63c821LL /* 702 */, 0xa9728b3a72770dafLL /* 703 */,
0xd7934e7b20df87efLL /* 704 */, 0xe35503b61a3e86e5LL /* 705 */,
0xcae321fbc819d504LL /* 706 */, 0x129a50b3ac60bfa6LL /* 707 */,
0xcd5e68ea7e9fb6c3LL /* 708 */, 0xb01c90199483b1c7LL /* 709 */,
0x3de93cd5c295376cLL /* 710 */, 0xaed52edf2ab9ad13LL /* 711 */,
0x2e60f512c0a07884LL /* 712 */, 0xbc3d86a3e36210c9LL /* 713 */,
0x35269d9b163951ceLL /* 714 */, 0x0c7d6e2ad0cdb5faLL /* 715 */,
0x59e86297d87f5733LL /* 716 */, 0x298ef221898db0e7LL /* 717 */,
0x55000029d1a5aa7eLL /* 718 */, 0x8bc08ae1b5061b45LL /* 719 */,
0xc2c31c2b6c92703aLL /* 720 */, 0x94cc596baf25ef42LL /* 721 */,
0x0a1d73db22540456LL /* 722 */, 0x04b6a0f9d9c4179aLL /* 723 */,
0xeffdafa2ae3d3c60LL /* 724 */, 0xf7c8075bb49496c4LL /* 725 */,
0x9cc5c7141d1cd4e3LL /* 726 */, 0x78bd1638218e5534LL /* 727 */,
0xb2f11568f850246aLL /* 728 */, 0xedfabcfa9502bc29LL /* 729 */,
0x796ce5f2da23051bLL /* 730 */, 0xaae128b0dc93537cLL /* 731 */,
0x3a493da0ee4b29aeLL /* 732 */, 0xb5df6b2c416895d7LL /* 733 */,
0xfcabbd25122d7f37LL /* 734 */, 0x70810b58105dc4b1LL /* 735 */,
0xe10fdd37f7882a90LL /* 736 */, 0x524dcab5518a3f5cLL /* 737 */,
0x3c9e85878451255bLL /* 738 */, 0x4029828119bd34e2LL /* 739 */,
0x74a05b6f5d3ceccbLL /* 740 */, 0xb610021542e13ecaLL /* 741 */,
0x0ff979d12f59e2acLL /* 742 */, 0x6037da27e4f9cc50LL /* 743 */,
0x5e92975a0df1847dLL /* 744 */, 0xd66de190d3e623feLL /* 745 */,
0x5032d6b87b568048LL /* 746 */, 0x9a36b7ce8235216eLL /* 747 */,
0x80272a7a24f64b4aLL /* 748 */, 0x93efed8b8c6916f7LL /* 749 */,
0x37ddbff44cce1555LL /* 750 */, 0x4b95db5d4b99bd25LL /* 751 */,
0x92d3fda169812fc0LL /* 752 */, 0xfb1a4a9a90660bb6LL /* 753 */,
0x730c196946a4b9b2LL /* 754 */, 0x81e289aa7f49da68LL /* 755 */,
0x64669a0f83b1a05fLL /* 756 */, 0x27b3ff7d9644f48bLL /* 757 */,
0xcc6b615c8db675b3LL /* 758 */, 0x674f20b9bcebbe95LL /* 759 */,
0x6f31238275655982LL /* 760 */, 0x5ae488713e45cf05LL /* 761 */,
0xbf619f9954c21157LL /* 762 */, 0xeabac46040a8eae9LL /* 763 */,
0x454c6fe9f2c0c1cdLL /* 764 */, 0x419cf6496412691cLL /* 765 */,
0xd3dc3bef265b0f70LL /* 766 */, 0x6d0e60f5c3578a9eLL /* 767 */
};
static u64 sbox4[256] = {
0x5b0e608526323c55LL /* 768 */, 0x1a46c1a9fa1b59f5LL /* 769 */,
0xa9e245a17c4c8ffaLL /* 770 */, 0x65ca5159db2955d7LL /* 771 */,
0x05db0a76ce35afc2LL /* 772 */, 0x81eac77ea9113d45LL /* 773 */,
0x528ef88ab6ac0a0dLL /* 774 */, 0xa09ea253597be3ffLL /* 775 */,
0x430ddfb3ac48cd56LL /* 776 */, 0xc4b3a67af45ce46fLL /* 777 */,
0x4ececfd8fbe2d05eLL /* 778 */, 0x3ef56f10b39935f0LL /* 779 */,
0x0b22d6829cd619c6LL /* 780 */, 0x17fd460a74df2069LL /* 781 */,
0x6cf8cc8e8510ed40LL /* 782 */, 0xd6c824bf3a6ecaa7LL /* 783 */,
0x61243d581a817049LL /* 784 */, 0x048bacb6bbc163a2LL /* 785 */,
0xd9a38ac27d44cc32LL /* 786 */, 0x7fddff5baaf410abLL /* 787 */,
0xad6d495aa804824bLL /* 788 */, 0xe1a6a74f2d8c9f94LL /* 789 */,
0xd4f7851235dee8e3LL /* 790 */, 0xfd4b7f886540d893LL /* 791 */,
0x247c20042aa4bfdaLL /* 792 */, 0x096ea1c517d1327cLL /* 793 */,
0xd56966b4361a6685LL /* 794 */, 0x277da5c31221057dLL /* 795 */,
0x94d59893a43acff7LL /* 796 */, 0x64f0c51ccdc02281LL /* 797 */,
0x3d33bcc4ff6189dbLL /* 798 */, 0xe005cb184ce66af1LL /* 799 */,
0xff5ccd1d1db99beaLL /* 800 */, 0xb0b854a7fe42980fLL /* 801 */,
0x7bd46a6a718d4b9fLL /* 802 */, 0xd10fa8cc22a5fd8cLL /* 803 */,
0xd31484952be4bd31LL /* 804 */, 0xc7fa975fcb243847LL /* 805 */,
0x4886ed1e5846c407LL /* 806 */, 0x28cddb791eb70b04LL /* 807 */,
0xc2b00be2f573417fLL /* 808 */, 0x5c9590452180f877LL /* 809 */,
0x7a6bddfff370eb00LL /* 810 */, 0xce509e38d6d9d6a4LL /* 811 */,
0xebeb0f00647fa702LL /* 812 */, 0x1dcc06cf76606f06LL /* 813 */,
0xe4d9f28ba286ff0aLL /* 814 */, 0xd85a305dc918c262LL /* 815 */,
0x475b1d8732225f54LL /* 816 */, 0x2d4fb51668ccb5feLL /* 817 */,
0xa679b9d9d72bba20LL /* 818 */, 0x53841c0d912d43a5LL /* 819 */,
0x3b7eaa48bf12a4e8LL /* 820 */, 0x781e0e47f22f1ddfLL /* 821 */,
0xeff20ce60ab50973LL /* 822 */, 0x20d261d19dffb742LL /* 823 */,
0x16a12b03062a2e39LL /* 824 */, 0x1960eb2239650495LL /* 825 */,
0x251c16fed50eb8b8LL /* 826 */, 0x9ac0c330f826016eLL /* 827 */,
0xed152665953e7671LL /* 828 */, 0x02d63194a6369570LL /* 829 */,
0x5074f08394b1c987LL /* 830 */, 0x70ba598c90b25ce1LL /* 831 */,
0x794a15810b9742f6LL /* 832 */, 0x0d5925e9fcaf8c6cLL /* 833 */,
0x3067716cd868744eLL /* 834 */, 0x910ab077e8d7731bLL /* 835 */,
0x6a61bbdb5ac42f61LL /* 836 */, 0x93513efbf0851567LL /* 837 */,
0xf494724b9e83e9d5LL /* 838 */, 0xe887e1985c09648dLL /* 839 */,
0x34b1d3c675370cfdLL /* 840 */, 0xdc35e433bc0d255dLL /* 841 */,
0xd0aab84234131be0LL /* 842 */, 0x08042a50b48b7eafLL /* 843 */,
0x9997c4ee44a3ab35LL /* 844 */, 0x829a7b49201799d0LL /* 845 */,
0x263b8307b7c54441LL /* 846 */, 0x752f95f4fd6a6ca6LL /* 847 */,
0x927217402c08c6e5LL /* 848 */, 0x2a8ab754a795d9eeLL /* 849 */,
0xa442f7552f72943dLL /* 850 */, 0x2c31334e19781208LL /* 851 */,
0x4fa98d7ceaee6291LL /* 852 */, 0x55c3862f665db309LL /* 853 */,
0xbd0610175d53b1f3LL /* 854 */, 0x46fe6cb840413f27LL /* 855 */,
0x3fe03792df0cfa59LL /* 856 */, 0xcfe700372eb85e8fLL /* 857 */,
0xa7be29e7adbce118LL /* 858 */, 0xe544ee5cde8431ddLL /* 859 */,
0x8a781b1b41f1873eLL /* 860 */, 0xa5c94c78a0d2f0e7LL /* 861 */,
0x39412e2877b60728LL /* 862 */, 0xa1265ef3afc9a62cLL /* 863 */,
0xbcc2770c6a2506c5LL /* 864 */, 0x3ab66dd5dce1ce12LL /* 865 */,
0xe65499d04a675b37LL /* 866 */, 0x7d8f523481bfd216LL /* 867 */,
0x0f6f64fcec15f389LL /* 868 */, 0x74efbe618b5b13c8LL /* 869 */,
0xacdc82b714273e1dLL /* 870 */, 0xdd40bfe003199d17LL /* 871 */,
0x37e99257e7e061f8LL /* 872 */, 0xfa52626904775aaaLL /* 873 */,
0x8bbbf63a463d56f9LL /* 874 */, 0xf0013f1543a26e64LL /* 875 */,
0xa8307e9f879ec898LL /* 876 */, 0xcc4c27a4150177ccLL /* 877 */,
0x1b432f2cca1d3348LL /* 878 */, 0xde1d1f8f9f6fa013LL /* 879 */,
0x606602a047a7ddd6LL /* 880 */, 0xd237ab64cc1cb2c7LL /* 881 */,
0x9b938e7225fcd1d3LL /* 882 */, 0xec4e03708e0ff476LL /* 883 */,
0xfeb2fbda3d03c12dLL /* 884 */, 0xae0bced2ee43889aLL /* 885 */,
0x22cb8923ebfb4f43LL /* 886 */, 0x69360d013cf7396dLL /* 887 */,
0x855e3602d2d4e022LL /* 888 */, 0x073805bad01f784cLL /* 889 */,
0x33e17a133852f546LL /* 890 */, 0xdf4874058ac7b638LL /* 891 */,
0xba92b29c678aa14aLL /* 892 */, 0x0ce89fc76cfaadcdLL /* 893 */,
0x5f9d4e0908339e34LL /* 894 */, 0xf1afe9291f5923b9LL /* 895 */,
0x6e3480f60f4a265fLL /* 896 */, 0xeebf3a2ab29b841cLL /* 897 */,
0xe21938a88f91b4adLL /* 898 */, 0x57dfeff845c6d3c3LL /* 899 */,
0x2f006b0bf62caaf2LL /* 900 */, 0x62f479ef6f75ee78LL /* 901 */,
0x11a55ad41c8916a9LL /* 902 */, 0xf229d29084fed453LL /* 903 */,
0x42f1c27b16b000e6LL /* 904 */, 0x2b1f76749823c074LL /* 905 */,
0x4b76eca3c2745360LL /* 906 */, 0x8c98f463b91691bdLL /* 907 */,
0x14bcc93cf1ade66aLL /* 908 */, 0x8885213e6d458397LL /* 909 */,
0x8e177df0274d4711LL /* 910 */, 0xb49b73b5503f2951LL /* 911 */,
0x10168168c3f96b6bLL /* 912 */, 0x0e3d963b63cab0aeLL /* 913 */,
0x8dfc4b5655a1db14LL /* 914 */, 0xf789f1356e14de5cLL /* 915 */,
0x683e68af4e51dac1LL /* 916 */, 0xc9a84f9d8d4b0fd9LL /* 917 */,
0x3691e03f52a0f9d1LL /* 918 */, 0x5ed86e46e1878e80LL /* 919 */,
0x3c711a0e99d07150LL /* 920 */, 0x5a0865b20c4e9310LL /* 921 */,
0x56fbfc1fe4f0682eLL /* 922 */, 0xea8d5de3105edf9bLL /* 923 */,
0x71abfdb12379187aLL /* 924 */, 0x2eb99de1bee77b9cLL /* 925 */,
0x21ecc0ea33cf4523LL /* 926 */, 0x59a4d7521805c7a1LL /* 927 */,
0x3896f5eb56ae7c72LL /* 928 */, 0xaa638f3db18f75dcLL /* 929 */,
0x9f39358dabe9808eLL /* 930 */, 0xb7defa91c00b72acLL /* 931 */,
0x6b5541fd62492d92LL /* 932 */, 0x6dc6dee8f92e4d5bLL /* 933 */,
0x353f57abc4beea7eLL /* 934 */, 0x735769d6da5690ceLL /* 935 */,
0x0a234aa642391484LL /* 936 */, 0xf6f9508028f80d9dLL /* 937 */,
0xb8e319a27ab3f215LL /* 938 */, 0x31ad9c1151341a4dLL /* 939 */,
0x773c22a57bef5805LL /* 940 */, 0x45c7561a07968633LL /* 941 */,
0xf913da9e249dbe36LL /* 942 */, 0xda652d9b78a64c68LL /* 943 */,
0x4c27a97f3bc334efLL /* 944 */, 0x76621220e66b17f4LL /* 945 */,
0x967743899acd7d0bLL /* 946 */, 0xf3ee5bcae0ed6782LL /* 947 */,
0x409f753600c879fcLL /* 948 */, 0x06d09a39b5926db6LL /* 949 */,
0x6f83aeb0317ac588LL /* 950 */, 0x01e6ca4a86381f21LL /* 951 */,
0x66ff3462d19f3025LL /* 952 */, 0x72207c24ddfd3bfbLL /* 953 */,
0x4af6b6d3e2ece2ebLL /* 954 */, 0x9c994dbec7ea08deLL /* 955 */,
0x49ace597b09a8bc4LL /* 956 */, 0xb38c4766cf0797baLL /* 957 */,
0x131b9373c57c2a75LL /* 958 */, 0xb1822cce61931e58LL /* 959 */,
0x9d7555b909ba1c0cLL /* 960 */, 0x127fafdd937d11d2LL /* 961 */,
0x29da3badc66d92e4LL /* 962 */, 0xa2c1d57154c2ecbcLL /* 963 */,
0x58c5134d82f6fe24LL /* 964 */, 0x1c3ae3515b62274fLL /* 965 */,
0xe907c82e01cb8126LL /* 966 */, 0xf8ed091913e37fcbLL /* 967 */,
0x3249d8f9c80046c9LL /* 968 */, 0x80cf9bede388fb63LL /* 969 */,
0x1881539a116cf19eLL /* 970 */, 0x5103f3f76bd52457LL /* 971 */,
0x15b7e6f5ae47f7a8LL /* 972 */, 0xdbd7c6ded47e9ccfLL /* 973 */,
0x44e55c410228bb1aLL /* 974 */, 0xb647d4255edb4e99LL /* 975 */,
0x5d11882bb8aafc30LL /* 976 */, 0xf5098bbb29d3212aLL /* 977 */,
0x8fb5ea14e90296b3LL /* 978 */, 0x677b942157dd025aLL /* 979 */,
0xfb58e7c0a390acb5LL /* 980 */, 0x89d3674c83bd4a01LL /* 981 */,
0x9e2da4df4bf3b93bLL /* 982 */, 0xfcc41e328cab4829LL /* 983 */,
0x03f38c96ba582c52LL /* 984 */, 0xcad1bdbd7fd85db2LL /* 985 */,
0xbbb442c16082ae83LL /* 986 */, 0xb95fe86ba5da9ab0LL /* 987 */,
0xb22e04673771a93fLL /* 988 */, 0x845358c9493152d8LL /* 989 */,
0xbe2a488697b4541eLL /* 990 */, 0x95a2dc2dd38e6966LL /* 991 */,
0xc02c11ac923c852bLL /* 992 */, 0x2388b1990df2a87bLL /* 993 */,
0x7c8008fa1b4f37beLL /* 994 */, 0x1f70d0c84d54e503LL /* 995 */,
0x5490adec7ece57d4LL /* 996 */, 0x002b3c27d9063a3aLL /* 997 */,
0x7eaea3848030a2bfLL /* 998 */, 0xc602326ded2003c0LL /* 999 */,
0x83a7287d69a94086LL /* 1000 */, 0xc57a5fcb30f57a8aLL /* 1001 */,
0xb56844e479ebe779LL /* 1002 */, 0xa373b40f05dcbce9LL /* 1003 */,
0xd71a786e88570ee2LL /* 1004 */, 0x879cbacdbde8f6a0LL /* 1005 */,
0x976ad1bcc164a32fLL /* 1006 */, 0xab21e25e9666d78bLL /* 1007 */,
0x901063aae5e5c33cLL /* 1008 */, 0x9818b34448698d90LL /* 1009 */,
0xe36487ae3e1e8abbLL /* 1010 */, 0xafbdf931893bdcb4LL /* 1011 */,
0x6345a0dc5fbbd519LL /* 1012 */, 0x8628fe269b9465caLL /* 1013 */,
0x1e5d01603f9c51ecLL /* 1014 */, 0x4de44006a15049b7LL /* 1015 */,
0xbf6c70e5f776cbb1LL /* 1016 */, 0x411218f2ef552bedLL /* 1017 */,
0xcb0c0708705a36a3LL /* 1018 */, 0xe74d14754f986044LL /* 1019 */,
0xcd56d9430ea8280eLL /* 1020 */, 0xc12591d7535f5065LL /* 1021 */,
0xc83223f1720aef96LL /* 1022 */, 0xc3a0396f7363a51fLL /* 1023 */
};
static void
print_abc( const char *text, u64 a, u64 b, u64 c )
{
/*printf("%s: %08X%08X %08X%08X %08X%08X\n",
text,
(u32)(a>>32),
(u32)(a),
(u32)(b>>32),
(u32)(b),
(u32)(c>>32),
(u32)(c) );*/
}
static void
print_data( const char *text, u64 a, u64 b, u64 c,
u64 d, u64 e, u64 f,
u64 g, u64 h )
{
/*printf("%s: %08X%08X %08X%08X %08X%08X %08X%08X\n"
"%s %08X%08X %08X%08X %08X%08X %08X%08X\n",
text,
(u32)(a>>32),
(u32)(a),
(u32)(b>>32),
(u32)(b),
(u32)(c>>32),
(u32)(c),
(u32)(d>>32),
(u32)(d),
text,
(u32)(e>>32),
(u32)(e),
(u32)(f>>32),
(u32)(f),
(u32)(g>>32),
(u32)(g),
(u32)(h>>32),
(u32)(h) );*/
}
static void
tiger_init( TIGER_CONTEXT *hd )
{
hd->a = 0x0123456789abcdefLL;
hd->b = 0xfedcba9876543210LL;
hd->c = 0xf096a5b4c3b2e187LL;
hd->nblocks = 0;
hd->count = 0;
}
static void
round( u64 *ra, u64 *rb, u64 *rc, u64 x, int mul )
{
u64 a = *ra;
u64 b = *rb;
u64 c = *rc;
c ^= x;
a -= sbox1[ c & 0xff ] ^ sbox2[ (c >> 16) & 0xff ]
^ sbox3[ (c >> 32) & 0xff ] ^ sbox4[ (c >> 48) & 0xff ];
b += sbox4[ (c >> 8) & 0xff ] ^ sbox3[ (c >> 24) & 0xff ]
^ sbox2[ (c >> 40) & 0xff ] ^ sbox1[ (c >> 56) & 0xff ];
b *= mul;
*ra = a;
*rb = b;
*rc = c;
}
static void
pass( u64 *ra, u64 *rb, u64 *rc, u64 *x, int mul )
{
u64 a = *ra;
u64 b = *rb;
u64 c = *rc;
round( &a, &b, &c, x[0], mul );
round( &b, &c, &a, x[1], mul );
round( &c, &a, &b, x[2], mul );
round( &a, &b, &c, x[3], mul );
round( &b, &c, &a, x[4], mul );
round( &c, &a, &b, x[5], mul );
round( &a, &b, &c, x[6], mul );
round( &b, &c, &a, x[7], mul );
*ra = a;
*rb = b;
*rc = c;
}
static void
key_schedule( u64 *x )
{
x[0] -= x[7] ^ 0xa5a5a5a5a5a5a5a5LL;
x[1] ^= x[0];
x[2] += x[1];
x[3] -= x[2] ^ ((~x[1]) << 19 );
x[4] ^= x[3];
x[5] += x[4];
x[6] -= x[5] ^ ((~x[4]) >> 23 );
x[7] ^= x[6];
x[0] += x[7];
x[1] -= x[0] ^ ((~x[7]) << 19 );
x[2] ^= x[1];
x[3] += x[2];
x[4] -= x[3] ^ ((~x[2]) >> 23 );
x[5] ^= x[4];
x[6] += x[5];
x[7] -= x[6] ^ 0x0123456789abcdefLL;
}
/****************
* Transform the message DATA which consists of 512 bytes (8 words)
*/
static void
transform( TIGER_CONTEXT *hd, byte *data )
{
u64 a,b,c,aa,bb,cc;
u64 x[8];
#ifdef BIG_ENDIAN_HOST
#define MKWORD(d,n) \
( ((u64)(d)[8*(n)+7]) << 56 | ((u64)(d)[8*(n)+6]) << 48 \
| ((u64)(d)[8*(n)+5]) << 40 | ((u64)(d)[8*(n)+4]) << 32 \
| ((u64)(d)[8*(n)+3]) << 24 | ((u64)(d)[8*(n)+2]) << 16 \
| ((u64)(d)[8*(n)+1]) << 8 | ((u64)(d)[8*(n) ]) )
x[0] = MKWORD(data, 0);
x[1] = MKWORD(data, 1);
x[2] = MKWORD(data, 2);
x[3] = MKWORD(data, 3);
x[4] = MKWORD(data, 4);
x[5] = MKWORD(data, 5);
x[6] = MKWORD(data, 6);
x[7] = MKWORD(data, 7);
#undef MKWORD
#else
memcpy( &x[0], data, 64 );
#endif
/* save */
a = aa = hd->a;
b = bb = hd->b;
c = cc = hd->c;
print_data(" key0", x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7] );
print_abc(" init", a, b, c );
pass( &a, &b, &c, x, 5);
print_abc("pass1", a, b, c );
key_schedule( x );
pass( &c, &a, &b, x, 7);
print_abc("pass2", a, b, c );
key_schedule( x );
pass( &b, &c, &a, x, 9);
print_abc("pass3", a, b, c );
/* feedforward */
a ^= aa;
b -= bb;
c += cc;
/* store */
hd->a = a;
hd->b = b;
hd->c = c;
}
/* Update the message digest with the contents
* of INBUF with length INLEN.
*/
static void
tiger_write( TIGER_CONTEXT *hd, byte *inbuf, size_t inlen)
{
if( hd->count == 64 ) { /* flush the buffer */
transform( hd, hd->buf );
hd->count = 0;
hd->nblocks++;
}
if( !inbuf )
return;
if( hd->count ) {
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
tiger_write( hd, NULL, 0 );
if( !inlen )
return;
}
while( inlen >= 64 ) {
transform( hd, inbuf );
hd->count = 0;
hd->nblocks++;
inlen -= 64;
inbuf += 64;
}
for( ; inlen && hd->count < 64; inlen-- )
hd->buf[hd->count++] = *inbuf++;
}
/* The routine terminates the computation
*/
static void
tiger_final( TIGER_CONTEXT *hd )
{
u32 t, msb, lsb;
byte *p;
tiger_write(hd, NULL, 0); /* flush */;
msb = 0;
t = hd->nblocks;
if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
msb++;
msb += t >> 26;
t = lsb;
if( (lsb = t + hd->count) < t ) /* add the count */
msb++;
t = lsb;
if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
msb++;
msb += t >> 29;
if( hd->count < 56 ) { /* enough room */
hd->buf[hd->count++] = 0x01; /* pad */
while( hd->count < 56 )
hd->buf[hd->count++] = 0; /* pad */
}
else { /* need one extra block */
hd->buf[hd->count++] = 0x01; /* pad character */
while( hd->count < 64 )
hd->buf[hd->count++] = 0;
tiger_write(hd, NULL, 0); /* flush */;
memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = lsb ;
hd->buf[57] = lsb >> 8;
hd->buf[58] = lsb >> 16;
hd->buf[59] = lsb >> 24;
hd->buf[60] = msb ;
hd->buf[61] = msb >> 8;
hd->buf[62] = msb >> 16;
hd->buf[63] = msb >> 24;
transform( hd, hd->buf );
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(u64*)p = hd->##a ; p += 8; } while(0)
#else /* little endian */
#define X(a) do { *p++ = hd->##a >> 56; *p++ = hd->##a >> 48; \
*p++ = hd->##a >> 40; *p++ = hd->##a >> 32; \
*p++ = hd->##a >> 24; *p++ = hd->##a >> 16; \
*p++ = hd->##a >> 8; *p++ = hd->##a; } while(0)
#endif
X(a);
X(b);
X(c);
#undef X
}
static byte *
tiger_read( TIGER_CONTEXT *hd )
{
return hd->buf;
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
*/
static const char *
tiger_get_info( int algo, size_t *contextsize,
byte **r_asnoid, int *r_asnlen, int *r_mdlen,
void (**r_init)( void *c ),
void (**r_write)( void *c, byte *buf, size_t nbytes ),
void (**r_final)( void *c ),
byte *(**r_read)( void *c )
)
{
/* 40: SEQUENCE {
* 12: SEQUENCE {
* 8: OCTET STRING :54 49 47 45 52 31 39 32
* 0: NULL
* : }
* 24: OCTET STRING
* : }
*
* By replacing the 5th byte (0x04) with 0x16 we would have;
* 8: IA5String 'TIGER192'
*/
static byte asn[18] =
{ 0x30, 0x28, 0x30, 0x0c, 0x04, 0x08, 0x54, 0x49, 0x47,
0x45, 0x52, 0x31, 0x39, 0x32, 0x05, 0x00, 0x04, 0x18 };
if( algo != 6 )
return NULL;
*contextsize = sizeof(TIGER_CONTEXT);
*r_asnoid = asn;
*r_asnlen = DIM(asn);
*r_mdlen = 24;
- *r_init = (void (*)(void *))tiger_init;
- *r_write = (void (*)(void *, byte*, size_t))tiger_write;
- *r_final = (void (*)(void *))tiger_final;
- *r_read = (byte *(*)(void *))tiger_read;
+ *(void (**)(TIGER_CONTEXT *))r_init = tiger_init;
+ *(void (**)(TIGER_CONTEXT *, byte*, size_t))r_write = tiger_write;
+ *(void (**)(TIGER_CONTEXT *))r_final = tiger_final;
+ *(byte *(**)(TIGER_CONTEXT *))r_read = tiger_read;
return "TIGER";
}
#ifndef IS_MODULE
static
#endif
const char * const gnupgext_version = "TIGER ($Revision$)";
static struct {
int class;
int version;
int value;
void (*func)(void);
} func_table[] = {
{ 10, 1, 0, (void(*)(void))tiger_get_info },
{ 11, 1, 6 },
};
/****************
* Enumerate the names of the functions together with informations about
* this function. Set sequence to an integer with a initial value of 0 and
* do not change it.
* If what is 0 all kind of functions are returned.
* Return values: class := class of function:
* 10 = message digest algorithm info function
* 11 = integer with available md algorithms
* 20 = cipher algorithm info function
* 21 = integer with available cipher algorithms
* 30 = public key algorithm info function
* 31 = integer with available pubkey algorithms
* version = interface version of the function/pointer
* (currently this is 1 for all functions)
*/
#ifndef IS_MODULE
static
#endif
void *
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if( i >= DIM(func_table) || i < 0 ) {
/*fprintf(stderr, "failed\n");*/
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
switch( *class ) {
case 11:
case 21:
case 31:
ret = &func_table[i].value;
break;
default:
ret = func_table[i].func;
break;
}
i++;
} while( what && what != *class );
*sequence = i;
/*fprintf(stderr, "success\n");*/
return ret;
}
#ifndef IS_MODULE
void
tiger_constructor(void)
{
register_internal_cipher_extension( gnupgext_version,
gnupgext_enum_func );
}
#endif
#endif /* HAVE_U64_TYPEDEF */
diff --git a/cipher/twofish.c b/cipher/twofish.c
index 1eea4b8e..5766021c 100644
--- a/cipher/twofish.c
+++ b/cipher/twofish.c
@@ -1,1064 +1,1064 @@
/* Twofish for GPG
* By Matthew Skala <mskala@ansuz.sooke.bc.ca>, July 26, 1998
* 256-bit key length added March 20, 1999
* Some modifications to reduce the text size by Werner Koch, April, 1998
*
* The original author has disclaimed all copyright interest in this
* code and thus putting it in the public domain.
*
* This code is a "clean room" implementation, written from the paper
* _Twofish: A 128-Bit Block Cipher_ by Bruce Schneier, John Kelsey,
* Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson, available
* through http://www.counterpane.com/twofish.html
*
* For background information on multiplication in finite fields, used for
* the matrix operations in the key schedule, see the book _Contemporary
* Abstract Algebra_ by Joseph A. Gallian, especially chapter 22 in the
* Third Edition.
*
* Only the 128- and 256-bit key sizes are supported. This code is intended
* for GNU C on a 32-bit system, but it should work almost anywhere. Loops
* are unrolled, precomputation tables are used, etc., for maximum speed at
* some cost in memory consumption. */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for memcmp() */
#include "types.h" /* for byte and u32 typedefs */
#include "g10lib.h"
#include "dynload.h"
/* Prototype for the self-test function. */
static const char *selftest(void);
-/* Macros used by the info function. */
-#define FNCCAST_SETKEY(f) ((int(*)(void*, byte*, unsigned))(f))
-#define FNCCAST_CRYPT(f) ((void(*)(void*, byte*, byte*))(f))
-
/* Structure for an expanded Twofish key. s contains the key-dependent
* S-boxes composed with the MDS matrix; w contains the eight "whitening"
* subkeys, K[0] through K[7]. k holds the remaining, "round" subkeys. Note
* that k[i] corresponds to what the Twofish paper calls K[i+8]. */
typedef struct {
u32 s[4][256], w[8], k[32];
} TWOFISH_context;
/* These two tables are the q0 and q1 permutations, exactly as described in
* the Twofish paper. */
static const byte q0[256] = {
0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
0x4A, 0x5E, 0xC1, 0xE0
};
static const byte q1[256] = {
0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
0x55, 0x09, 0xBE, 0x91
};
/* These MDS tables are actually tables of MDS composed with q0 and q1,
* because it is only ever used that way and we can save some time by
* precomputing. Of course the main saving comes from precomputing the
* GF(2^8) multiplication involved in the MDS matrix multiply; by looking
* things up in these tables we reduce the matrix multiply to four lookups
* and three XORs. Semi-formally, the definition of these tables is:
* mds[0][i] = MDS (q1[i] 0 0 0)^T mds[1][i] = MDS (0 q0[i] 0 0)^T
* mds[2][i] = MDS (0 0 q1[i] 0)^T mds[3][i] = MDS (0 0 0 q0[i])^T
* where ^T means "transpose", the matrix multiply is performed in GF(2^8)
* represented as GF(2)[x]/v(x) where v(x)=x^8+x^6+x^5+x^3+1 as described
* by Schneier et al, and I'm casually glossing over the byte/word
* conversion issues. */
static const u32 mds[4][256] = {
{0xBCBC3275, 0xECEC21F3, 0x202043C6, 0xB3B3C9F4, 0xDADA03DB, 0x02028B7B,
0xE2E22BFB, 0x9E9EFAC8, 0xC9C9EC4A, 0xD4D409D3, 0x18186BE6, 0x1E1E9F6B,
0x98980E45, 0xB2B2387D, 0xA6A6D2E8, 0x2626B74B, 0x3C3C57D6, 0x93938A32,
0x8282EED8, 0x525298FD, 0x7B7BD437, 0xBBBB3771, 0x5B5B97F1, 0x474783E1,
0x24243C30, 0x5151E20F, 0xBABAC6F8, 0x4A4AF31B, 0xBFBF4887, 0x0D0D70FA,
0xB0B0B306, 0x7575DE3F, 0xD2D2FD5E, 0x7D7D20BA, 0x666631AE, 0x3A3AA35B,
0x59591C8A, 0x00000000, 0xCDCD93BC, 0x1A1AE09D, 0xAEAE2C6D, 0x7F7FABC1,
0x2B2BC7B1, 0xBEBEB90E, 0xE0E0A080, 0x8A8A105D, 0x3B3B52D2, 0x6464BAD5,
0xD8D888A0, 0xE7E7A584, 0x5F5FE807, 0x1B1B1114, 0x2C2CC2B5, 0xFCFCB490,
0x3131272C, 0x808065A3, 0x73732AB2, 0x0C0C8173, 0x79795F4C, 0x6B6B4154,
0x4B4B0292, 0x53536974, 0x94948F36, 0x83831F51, 0x2A2A3638, 0xC4C49CB0,
0x2222C8BD, 0xD5D5F85A, 0xBDBDC3FC, 0x48487860, 0xFFFFCE62, 0x4C4C0796,
0x4141776C, 0xC7C7E642, 0xEBEB24F7, 0x1C1C1410, 0x5D5D637C, 0x36362228,
0x6767C027, 0xE9E9AF8C, 0x4444F913, 0x1414EA95, 0xF5F5BB9C, 0xCFCF18C7,
0x3F3F2D24, 0xC0C0E346, 0x7272DB3B, 0x54546C70, 0x29294CCA, 0xF0F035E3,
0x0808FE85, 0xC6C617CB, 0xF3F34F11, 0x8C8CE4D0, 0xA4A45993, 0xCACA96B8,
0x68683BA6, 0xB8B84D83, 0x38382820, 0xE5E52EFF, 0xADAD569F, 0x0B0B8477,
0xC8C81DC3, 0x9999FFCC, 0x5858ED03, 0x19199A6F, 0x0E0E0A08, 0x95957EBF,
0x70705040, 0xF7F730E7, 0x6E6ECF2B, 0x1F1F6EE2, 0xB5B53D79, 0x09090F0C,
0x616134AA, 0x57571682, 0x9F9F0B41, 0x9D9D803A, 0x111164EA, 0x2525CDB9,
0xAFAFDDE4, 0x4545089A, 0xDFDF8DA4, 0xA3A35C97, 0xEAEAD57E, 0x353558DA,
0xEDEDD07A, 0x4343FC17, 0xF8F8CB66, 0xFBFBB194, 0x3737D3A1, 0xFAFA401D,
0xC2C2683D, 0xB4B4CCF0, 0x32325DDE, 0x9C9C71B3, 0x5656E70B, 0xE3E3DA72,
0x878760A7, 0x15151B1C, 0xF9F93AEF, 0x6363BFD1, 0x3434A953, 0x9A9A853E,
0xB1B1428F, 0x7C7CD133, 0x88889B26, 0x3D3DA65F, 0xA1A1D7EC, 0xE4E4DF76,
0x8181942A, 0x91910149, 0x0F0FFB81, 0xEEEEAA88, 0x161661EE, 0xD7D77321,
0x9797F5C4, 0xA5A5A81A, 0xFEFE3FEB, 0x6D6DB5D9, 0x7878AEC5, 0xC5C56D39,
0x1D1DE599, 0x7676A4CD, 0x3E3EDCAD, 0xCBCB6731, 0xB6B6478B, 0xEFEF5B01,
0x12121E18, 0x6060C523, 0x6A6AB0DD, 0x4D4DF61F, 0xCECEE94E, 0xDEDE7C2D,
0x55559DF9, 0x7E7E5A48, 0x2121B24F, 0x03037AF2, 0xA0A02665, 0x5E5E198E,
0x5A5A6678, 0x65654B5C, 0x62624E58, 0xFDFD4519, 0x0606F48D, 0x404086E5,
0xF2F2BE98, 0x3333AC57, 0x17179067, 0x05058E7F, 0xE8E85E05, 0x4F4F7D64,
0x89896AAF, 0x10109563, 0x74742FB6, 0x0A0A75FE, 0x5C5C92F5, 0x9B9B74B7,
0x2D2D333C, 0x3030D6A5, 0x2E2E49CE, 0x494989E9, 0x46467268, 0x77775544,
0xA8A8D8E0, 0x9696044D, 0x2828BD43, 0xA9A92969, 0xD9D97929, 0x8686912E,
0xD1D187AC, 0xF4F44A15, 0x8D8D1559, 0xD6D682A8, 0xB9B9BC0A, 0x42420D9E,
0xF6F6C16E, 0x2F2FB847, 0xDDDD06DF, 0x23233934, 0xCCCC6235, 0xF1F1C46A,
0xC1C112CF, 0x8585EBDC, 0x8F8F9E22, 0x7171A1C9, 0x9090F0C0, 0xAAAA539B,
0x0101F189, 0x8B8BE1D4, 0x4E4E8CED, 0x8E8E6FAB, 0xABABA212, 0x6F6F3EA2,
0xE6E6540D, 0xDBDBF252, 0x92927BBB, 0xB7B7B602, 0x6969CA2F, 0x3939D9A9,
0xD3D30CD7, 0xA7A72361, 0xA2A2AD1E, 0xC3C399B4, 0x6C6C4450, 0x07070504,
0x04047FF6, 0x272746C2, 0xACACA716, 0xD0D07625, 0x50501386, 0xDCDCF756,
0x84841A55, 0xE1E15109, 0x7A7A25BE, 0x1313EF91},
{0xA9D93939, 0x67901717, 0xB3719C9C, 0xE8D2A6A6, 0x04050707, 0xFD985252,
0xA3658080, 0x76DFE4E4, 0x9A084545, 0x92024B4B, 0x80A0E0E0, 0x78665A5A,
0xE4DDAFAF, 0xDDB06A6A, 0xD1BF6363, 0x38362A2A, 0x0D54E6E6, 0xC6432020,
0x3562CCCC, 0x98BEF2F2, 0x181E1212, 0xF724EBEB, 0xECD7A1A1, 0x6C774141,
0x43BD2828, 0x7532BCBC, 0x37D47B7B, 0x269B8888, 0xFA700D0D, 0x13F94444,
0x94B1FBFB, 0x485A7E7E, 0xF27A0303, 0xD0E48C8C, 0x8B47B6B6, 0x303C2424,
0x84A5E7E7, 0x54416B6B, 0xDF06DDDD, 0x23C56060, 0x1945FDFD, 0x5BA33A3A,
0x3D68C2C2, 0x59158D8D, 0xF321ECEC, 0xAE316666, 0xA23E6F6F, 0x82165757,
0x63951010, 0x015BEFEF, 0x834DB8B8, 0x2E918686, 0xD9B56D6D, 0x511F8383,
0x9B53AAAA, 0x7C635D5D, 0xA63B6868, 0xEB3FFEFE, 0xA5D63030, 0xBE257A7A,
0x16A7ACAC, 0x0C0F0909, 0xE335F0F0, 0x6123A7A7, 0xC0F09090, 0x8CAFE9E9,
0x3A809D9D, 0xF5925C5C, 0x73810C0C, 0x2C273131, 0x2576D0D0, 0x0BE75656,
0xBB7B9292, 0x4EE9CECE, 0x89F10101, 0x6B9F1E1E, 0x53A93434, 0x6AC4F1F1,
0xB499C3C3, 0xF1975B5B, 0xE1834747, 0xE66B1818, 0xBDC82222, 0x450E9898,
0xE26E1F1F, 0xF4C9B3B3, 0xB62F7474, 0x66CBF8F8, 0xCCFF9999, 0x95EA1414,
0x03ED5858, 0x56F7DCDC, 0xD4E18B8B, 0x1C1B1515, 0x1EADA2A2, 0xD70CD3D3,
0xFB2BE2E2, 0xC31DC8C8, 0x8E195E5E, 0xB5C22C2C, 0xE9894949, 0xCF12C1C1,
0xBF7E9595, 0xBA207D7D, 0xEA641111, 0x77840B0B, 0x396DC5C5, 0xAF6A8989,
0x33D17C7C, 0xC9A17171, 0x62CEFFFF, 0x7137BBBB, 0x81FB0F0F, 0x793DB5B5,
0x0951E1E1, 0xADDC3E3E, 0x242D3F3F, 0xCDA47676, 0xF99D5555, 0xD8EE8282,
0xE5864040, 0xC5AE7878, 0xB9CD2525, 0x4D049696, 0x44557777, 0x080A0E0E,
0x86135050, 0xE730F7F7, 0xA1D33737, 0x1D40FAFA, 0xAA346161, 0xED8C4E4E,
0x06B3B0B0, 0x706C5454, 0xB22A7373, 0xD2523B3B, 0x410B9F9F, 0x7B8B0202,
0xA088D8D8, 0x114FF3F3, 0x3167CBCB, 0xC2462727, 0x27C06767, 0x90B4FCFC,
0x20283838, 0xF67F0404, 0x60784848, 0xFF2EE5E5, 0x96074C4C, 0x5C4B6565,
0xB1C72B2B, 0xAB6F8E8E, 0x9E0D4242, 0x9CBBF5F5, 0x52F2DBDB, 0x1BF34A4A,
0x5FA63D3D, 0x9359A4A4, 0x0ABCB9B9, 0xEF3AF9F9, 0x91EF1313, 0x85FE0808,
0x49019191, 0xEE611616, 0x2D7CDEDE, 0x4FB22121, 0x8F42B1B1, 0x3BDB7272,
0x47B82F2F, 0x8748BFBF, 0x6D2CAEAE, 0x46E3C0C0, 0xD6573C3C, 0x3E859A9A,
0x6929A9A9, 0x647D4F4F, 0x2A948181, 0xCE492E2E, 0xCB17C6C6, 0x2FCA6969,
0xFCC3BDBD, 0x975CA3A3, 0x055EE8E8, 0x7AD0EDED, 0xAC87D1D1, 0x7F8E0505,
0xD5BA6464, 0x1AA8A5A5, 0x4BB72626, 0x0EB9BEBE, 0xA7608787, 0x5AF8D5D5,
0x28223636, 0x14111B1B, 0x3FDE7575, 0x2979D9D9, 0x88AAEEEE, 0x3C332D2D,
0x4C5F7979, 0x02B6B7B7, 0xB896CACA, 0xDA583535, 0xB09CC4C4, 0x17FC4343,
0x551A8484, 0x1FF64D4D, 0x8A1C5959, 0x7D38B2B2, 0x57AC3333, 0xC718CFCF,
0x8DF40606, 0x74695353, 0xB7749B9B, 0xC4F59797, 0x9F56ADAD, 0x72DAE3E3,
0x7ED5EAEA, 0x154AF4F4, 0x229E8F8F, 0x12A2ABAB, 0x584E6262, 0x07E85F5F,
0x99E51D1D, 0x34392323, 0x6EC1F6F6, 0x50446C6C, 0xDE5D3232, 0x68724646,
0x6526A0A0, 0xBC93CDCD, 0xDB03DADA, 0xF8C6BABA, 0xC8FA9E9E, 0xA882D6D6,
0x2BCF6E6E, 0x40507070, 0xDCEB8585, 0xFE750A0A, 0x328A9393, 0xA48DDFDF,
0xCA4C2929, 0x10141C1C, 0x2173D7D7, 0xF0CCB4B4, 0xD309D4D4, 0x5D108A8A,
0x0FE25151, 0x00000000, 0x6F9A1919, 0x9DE01A1A, 0x368F9494, 0x42E6C7C7,
0x4AECC9C9, 0x5EFDD2D2, 0xC1AB7F7F, 0xE0D8A8A8},
{0xBC75BC32, 0xECF3EC21, 0x20C62043, 0xB3F4B3C9, 0xDADBDA03, 0x027B028B,
0xE2FBE22B, 0x9EC89EFA, 0xC94AC9EC, 0xD4D3D409, 0x18E6186B, 0x1E6B1E9F,
0x9845980E, 0xB27DB238, 0xA6E8A6D2, 0x264B26B7, 0x3CD63C57, 0x9332938A,
0x82D882EE, 0x52FD5298, 0x7B377BD4, 0xBB71BB37, 0x5BF15B97, 0x47E14783,
0x2430243C, 0x510F51E2, 0xBAF8BAC6, 0x4A1B4AF3, 0xBF87BF48, 0x0DFA0D70,
0xB006B0B3, 0x753F75DE, 0xD25ED2FD, 0x7DBA7D20, 0x66AE6631, 0x3A5B3AA3,
0x598A591C, 0x00000000, 0xCDBCCD93, 0x1A9D1AE0, 0xAE6DAE2C, 0x7FC17FAB,
0x2BB12BC7, 0xBE0EBEB9, 0xE080E0A0, 0x8A5D8A10, 0x3BD23B52, 0x64D564BA,
0xD8A0D888, 0xE784E7A5, 0x5F075FE8, 0x1B141B11, 0x2CB52CC2, 0xFC90FCB4,
0x312C3127, 0x80A38065, 0x73B2732A, 0x0C730C81, 0x794C795F, 0x6B546B41,
0x4B924B02, 0x53745369, 0x9436948F, 0x8351831F, 0x2A382A36, 0xC4B0C49C,
0x22BD22C8, 0xD55AD5F8, 0xBDFCBDC3, 0x48604878, 0xFF62FFCE, 0x4C964C07,
0x416C4177, 0xC742C7E6, 0xEBF7EB24, 0x1C101C14, 0x5D7C5D63, 0x36283622,
0x672767C0, 0xE98CE9AF, 0x441344F9, 0x149514EA, 0xF59CF5BB, 0xCFC7CF18,
0x3F243F2D, 0xC046C0E3, 0x723B72DB, 0x5470546C, 0x29CA294C, 0xF0E3F035,
0x088508FE, 0xC6CBC617, 0xF311F34F, 0x8CD08CE4, 0xA493A459, 0xCAB8CA96,
0x68A6683B, 0xB883B84D, 0x38203828, 0xE5FFE52E, 0xAD9FAD56, 0x0B770B84,
0xC8C3C81D, 0x99CC99FF, 0x580358ED, 0x196F199A, 0x0E080E0A, 0x95BF957E,
0x70407050, 0xF7E7F730, 0x6E2B6ECF, 0x1FE21F6E, 0xB579B53D, 0x090C090F,
0x61AA6134, 0x57825716, 0x9F419F0B, 0x9D3A9D80, 0x11EA1164, 0x25B925CD,
0xAFE4AFDD, 0x459A4508, 0xDFA4DF8D, 0xA397A35C, 0xEA7EEAD5, 0x35DA3558,
0xED7AEDD0, 0x431743FC, 0xF866F8CB, 0xFB94FBB1, 0x37A137D3, 0xFA1DFA40,
0xC23DC268, 0xB4F0B4CC, 0x32DE325D, 0x9CB39C71, 0x560B56E7, 0xE372E3DA,
0x87A78760, 0x151C151B, 0xF9EFF93A, 0x63D163BF, 0x345334A9, 0x9A3E9A85,
0xB18FB142, 0x7C337CD1, 0x8826889B, 0x3D5F3DA6, 0xA1ECA1D7, 0xE476E4DF,
0x812A8194, 0x91499101, 0x0F810FFB, 0xEE88EEAA, 0x16EE1661, 0xD721D773,
0x97C497F5, 0xA51AA5A8, 0xFEEBFE3F, 0x6DD96DB5, 0x78C578AE, 0xC539C56D,
0x1D991DE5, 0x76CD76A4, 0x3EAD3EDC, 0xCB31CB67, 0xB68BB647, 0xEF01EF5B,
0x1218121E, 0x602360C5, 0x6ADD6AB0, 0x4D1F4DF6, 0xCE4ECEE9, 0xDE2DDE7C,
0x55F9559D, 0x7E487E5A, 0x214F21B2, 0x03F2037A, 0xA065A026, 0x5E8E5E19,
0x5A785A66, 0x655C654B, 0x6258624E, 0xFD19FD45, 0x068D06F4, 0x40E54086,
0xF298F2BE, 0x335733AC, 0x17671790, 0x057F058E, 0xE805E85E, 0x4F644F7D,
0x89AF896A, 0x10631095, 0x74B6742F, 0x0AFE0A75, 0x5CF55C92, 0x9BB79B74,
0x2D3C2D33, 0x30A530D6, 0x2ECE2E49, 0x49E94989, 0x46684672, 0x77447755,
0xA8E0A8D8, 0x964D9604, 0x284328BD, 0xA969A929, 0xD929D979, 0x862E8691,
0xD1ACD187, 0xF415F44A, 0x8D598D15, 0xD6A8D682, 0xB90AB9BC, 0x429E420D,
0xF66EF6C1, 0x2F472FB8, 0xDDDFDD06, 0x23342339, 0xCC35CC62, 0xF16AF1C4,
0xC1CFC112, 0x85DC85EB, 0x8F228F9E, 0x71C971A1, 0x90C090F0, 0xAA9BAA53,
0x018901F1, 0x8BD48BE1, 0x4EED4E8C, 0x8EAB8E6F, 0xAB12ABA2, 0x6FA26F3E,
0xE60DE654, 0xDB52DBF2, 0x92BB927B, 0xB702B7B6, 0x692F69CA, 0x39A939D9,
0xD3D7D30C, 0xA761A723, 0xA21EA2AD, 0xC3B4C399, 0x6C506C44, 0x07040705,
0x04F6047F, 0x27C22746, 0xAC16ACA7, 0xD025D076, 0x50865013, 0xDC56DCF7,
0x8455841A, 0xE109E151, 0x7ABE7A25, 0x139113EF},
{0xD939A9D9, 0x90176790, 0x719CB371, 0xD2A6E8D2, 0x05070405, 0x9852FD98,
0x6580A365, 0xDFE476DF, 0x08459A08, 0x024B9202, 0xA0E080A0, 0x665A7866,
0xDDAFE4DD, 0xB06ADDB0, 0xBF63D1BF, 0x362A3836, 0x54E60D54, 0x4320C643,
0x62CC3562, 0xBEF298BE, 0x1E12181E, 0x24EBF724, 0xD7A1ECD7, 0x77416C77,
0xBD2843BD, 0x32BC7532, 0xD47B37D4, 0x9B88269B, 0x700DFA70, 0xF94413F9,
0xB1FB94B1, 0x5A7E485A, 0x7A03F27A, 0xE48CD0E4, 0x47B68B47, 0x3C24303C,
0xA5E784A5, 0x416B5441, 0x06DDDF06, 0xC56023C5, 0x45FD1945, 0xA33A5BA3,
0x68C23D68, 0x158D5915, 0x21ECF321, 0x3166AE31, 0x3E6FA23E, 0x16578216,
0x95106395, 0x5BEF015B, 0x4DB8834D, 0x91862E91, 0xB56DD9B5, 0x1F83511F,
0x53AA9B53, 0x635D7C63, 0x3B68A63B, 0x3FFEEB3F, 0xD630A5D6, 0x257ABE25,
0xA7AC16A7, 0x0F090C0F, 0x35F0E335, 0x23A76123, 0xF090C0F0, 0xAFE98CAF,
0x809D3A80, 0x925CF592, 0x810C7381, 0x27312C27, 0x76D02576, 0xE7560BE7,
0x7B92BB7B, 0xE9CE4EE9, 0xF10189F1, 0x9F1E6B9F, 0xA93453A9, 0xC4F16AC4,
0x99C3B499, 0x975BF197, 0x8347E183, 0x6B18E66B, 0xC822BDC8, 0x0E98450E,
0x6E1FE26E, 0xC9B3F4C9, 0x2F74B62F, 0xCBF866CB, 0xFF99CCFF, 0xEA1495EA,
0xED5803ED, 0xF7DC56F7, 0xE18BD4E1, 0x1B151C1B, 0xADA21EAD, 0x0CD3D70C,
0x2BE2FB2B, 0x1DC8C31D, 0x195E8E19, 0xC22CB5C2, 0x8949E989, 0x12C1CF12,
0x7E95BF7E, 0x207DBA20, 0x6411EA64, 0x840B7784, 0x6DC5396D, 0x6A89AF6A,
0xD17C33D1, 0xA171C9A1, 0xCEFF62CE, 0x37BB7137, 0xFB0F81FB, 0x3DB5793D,
0x51E10951, 0xDC3EADDC, 0x2D3F242D, 0xA476CDA4, 0x9D55F99D, 0xEE82D8EE,
0x8640E586, 0xAE78C5AE, 0xCD25B9CD, 0x04964D04, 0x55774455, 0x0A0E080A,
0x13508613, 0x30F7E730, 0xD337A1D3, 0x40FA1D40, 0x3461AA34, 0x8C4EED8C,
0xB3B006B3, 0x6C54706C, 0x2A73B22A, 0x523BD252, 0x0B9F410B, 0x8B027B8B,
0x88D8A088, 0x4FF3114F, 0x67CB3167, 0x4627C246, 0xC06727C0, 0xB4FC90B4,
0x28382028, 0x7F04F67F, 0x78486078, 0x2EE5FF2E, 0x074C9607, 0x4B655C4B,
0xC72BB1C7, 0x6F8EAB6F, 0x0D429E0D, 0xBBF59CBB, 0xF2DB52F2, 0xF34A1BF3,
0xA63D5FA6, 0x59A49359, 0xBCB90ABC, 0x3AF9EF3A, 0xEF1391EF, 0xFE0885FE,
0x01914901, 0x6116EE61, 0x7CDE2D7C, 0xB2214FB2, 0x42B18F42, 0xDB723BDB,
0xB82F47B8, 0x48BF8748, 0x2CAE6D2C, 0xE3C046E3, 0x573CD657, 0x859A3E85,
0x29A96929, 0x7D4F647D, 0x94812A94, 0x492ECE49, 0x17C6CB17, 0xCA692FCA,
0xC3BDFCC3, 0x5CA3975C, 0x5EE8055E, 0xD0ED7AD0, 0x87D1AC87, 0x8E057F8E,
0xBA64D5BA, 0xA8A51AA8, 0xB7264BB7, 0xB9BE0EB9, 0x6087A760, 0xF8D55AF8,
0x22362822, 0x111B1411, 0xDE753FDE, 0x79D92979, 0xAAEE88AA, 0x332D3C33,
0x5F794C5F, 0xB6B702B6, 0x96CAB896, 0x5835DA58, 0x9CC4B09C, 0xFC4317FC,
0x1A84551A, 0xF64D1FF6, 0x1C598A1C, 0x38B27D38, 0xAC3357AC, 0x18CFC718,
0xF4068DF4, 0x69537469, 0x749BB774, 0xF597C4F5, 0x56AD9F56, 0xDAE372DA,
0xD5EA7ED5, 0x4AF4154A, 0x9E8F229E, 0xA2AB12A2, 0x4E62584E, 0xE85F07E8,
0xE51D99E5, 0x39233439, 0xC1F66EC1, 0x446C5044, 0x5D32DE5D, 0x72466872,
0x26A06526, 0x93CDBC93, 0x03DADB03, 0xC6BAF8C6, 0xFA9EC8FA, 0x82D6A882,
0xCF6E2BCF, 0x50704050, 0xEB85DCEB, 0x750AFE75, 0x8A93328A, 0x8DDFA48D,
0x4C29CA4C, 0x141C1014, 0x73D72173, 0xCCB4F0CC, 0x09D4D309, 0x108A5D10,
0xE2510FE2, 0x00000000, 0x9A196F9A, 0xE01A9DE0, 0x8F94368F, 0xE6C742E6,
0xECC94AEC, 0xFDD25EFD, 0xAB7FC1AB, 0xD8A8E0D8}
};
/* The exp_to_poly and poly_to_exp tables are used to perform efficient
* operations in GF(2^8) represented as GF(2)[x]/w(x) where
* w(x)=x^8+x^6+x^3+x^2+1. We care about doing that because it's part of the
* definition of the RS matrix in the key schedule. Elements of that field
* are polynomials of degree not greater than 7 and all coefficients 0 or 1,
* which can be represented naturally by bytes (just substitute x=2). In that
* form, GF(2^8) addition is the same as bitwise XOR, but GF(2^8)
* multiplication is inefficient without hardware support. To multiply
* faster, I make use of the fact x is a generator for the nonzero elements,
* so that every element p of GF(2)[x]/w(x) is either 0 or equal to (x)^n for
* some n in 0..254. Note that that caret is exponentiation in GF(2^8),
* *not* polynomial notation. So if I want to compute pq where p and q are
* in GF(2^8), I can just say:
* 1. if p=0 or q=0 then pq=0
* 2. otherwise, find m and n such that p=x^m and q=x^n
* 3. pq=(x^m)(x^n)=x^(m+n), so add m and n and find pq
* The translations in steps 2 and 3 are looked up in the tables
* poly_to_exp (for step 2) and exp_to_poly (for step 3). To see this
* in action, look at the CALC_S macro. As additional wrinkles, note that
* one of my operands is always a constant, so the poly_to_exp lookup on it
* is done in advance; I included the original values in the comments so
* readers can have some chance of recognizing that this *is* the RS matrix
* from the Twofish paper. I've only included the table entries I actually
* need; I never do a lookup on a variable input of zero and the biggest
* exponents I'll ever see are 254 (variable) and 237 (constant), so they'll
* never sum to more than 491. I'm repeating part of the exp_to_poly table
* so that I don't have to do mod-255 reduction in the exponent arithmetic.
* Since I know my constant operands are never zero, I only have to worry
* about zero values in the variable operand, and I do it with a simple
* conditional branch. I know conditionals are expensive, but I couldn't
* see a non-horrible way of avoiding them, and I did manage to group the
* statements so that each if covers four group multiplications. */
static const byte poly_to_exp[255] = {
0x00, 0x01, 0x17, 0x02, 0x2E, 0x18, 0x53, 0x03, 0x6A, 0x2F, 0x93, 0x19,
0x34, 0x54, 0x45, 0x04, 0x5C, 0x6B, 0xB6, 0x30, 0xA6, 0x94, 0x4B, 0x1A,
0x8C, 0x35, 0x81, 0x55, 0xAA, 0x46, 0x0D, 0x05, 0x24, 0x5D, 0x87, 0x6C,
0x9B, 0xB7, 0xC1, 0x31, 0x2B, 0xA7, 0xA3, 0x95, 0x98, 0x4C, 0xCA, 0x1B,
0xE6, 0x8D, 0x73, 0x36, 0xCD, 0x82, 0x12, 0x56, 0x62, 0xAB, 0xF0, 0x47,
0x4F, 0x0E, 0xBD, 0x06, 0xD4, 0x25, 0xD2, 0x5E, 0x27, 0x88, 0x66, 0x6D,
0xD6, 0x9C, 0x79, 0xB8, 0x08, 0xC2, 0xDF, 0x32, 0x68, 0x2C, 0xFD, 0xA8,
0x8A, 0xA4, 0x5A, 0x96, 0x29, 0x99, 0x22, 0x4D, 0x60, 0xCB, 0xE4, 0x1C,
0x7B, 0xE7, 0x3B, 0x8E, 0x9E, 0x74, 0xF4, 0x37, 0xD8, 0xCE, 0xF9, 0x83,
0x6F, 0x13, 0xB2, 0x57, 0xE1, 0x63, 0xDC, 0xAC, 0xC4, 0xF1, 0xAF, 0x48,
0x0A, 0x50, 0x42, 0x0F, 0xBA, 0xBE, 0xC7, 0x07, 0xDE, 0xD5, 0x78, 0x26,
0x65, 0xD3, 0xD1, 0x5F, 0xE3, 0x28, 0x21, 0x89, 0x59, 0x67, 0xFC, 0x6E,
0xB1, 0xD7, 0xF8, 0x9D, 0xF3, 0x7A, 0x3A, 0xB9, 0xC6, 0x09, 0x41, 0xC3,
0xAE, 0xE0, 0xDB, 0x33, 0x44, 0x69, 0x92, 0x2D, 0x52, 0xFE, 0x16, 0xA9,
0x0C, 0x8B, 0x80, 0xA5, 0x4A, 0x5B, 0xB5, 0x97, 0xC9, 0x2A, 0xA2, 0x9A,
0xC0, 0x23, 0x86, 0x4E, 0xBC, 0x61, 0xEF, 0xCC, 0x11, 0xE5, 0x72, 0x1D,
0x3D, 0x7C, 0xEB, 0xE8, 0xE9, 0x3C, 0xEA, 0x8F, 0x7D, 0x9F, 0xEC, 0x75,
0x1E, 0xF5, 0x3E, 0x38, 0xF6, 0xD9, 0x3F, 0xCF, 0x76, 0xFA, 0x1F, 0x84,
0xA0, 0x70, 0xED, 0x14, 0x90, 0xB3, 0x7E, 0x58, 0xFB, 0xE2, 0x20, 0x64,
0xD0, 0xDD, 0x77, 0xAD, 0xDA, 0xC5, 0x40, 0xF2, 0x39, 0xB0, 0xF7, 0x49,
0xB4, 0x0B, 0x7F, 0x51, 0x15, 0x43, 0x91, 0x10, 0x71, 0xBB, 0xEE, 0xBF,
0x85, 0xC8, 0xA1
};
static const byte exp_to_poly[492] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D, 0x9A, 0x79, 0xF2,
0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC, 0xF5, 0xA7, 0x03,
0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3, 0x8B, 0x5B, 0xB6,
0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52, 0xA4, 0x05, 0x0A,
0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0, 0xED, 0x97, 0x63,
0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1, 0x0F, 0x1E, 0x3C,
0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A, 0xF4, 0xA5, 0x07,
0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11, 0x22, 0x44, 0x88,
0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51, 0xA2, 0x09, 0x12,
0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66, 0xCC, 0xD5, 0xE7,
0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB, 0x1B, 0x36, 0x6C,
0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19, 0x32, 0x64, 0xC8,
0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D, 0x5A, 0xB4, 0x25,
0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56, 0xAC, 0x15, 0x2A,
0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE, 0x91, 0x6F, 0xDE,
0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9, 0x3F, 0x7E, 0xFC,
0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE, 0xB1, 0x2F, 0x5E,
0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41, 0x82, 0x49, 0x92,
0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E, 0x71, 0xE2, 0x89,
0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB, 0xDB, 0xFB, 0xBB,
0x3B, 0x76, 0xEC, 0x95, 0x67, 0xCE, 0xD1, 0xEF, 0x93, 0x6B, 0xD6, 0xE1,
0x8F, 0x53, 0xA6, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x4D,
0x9A, 0x79, 0xF2, 0xA9, 0x1F, 0x3E, 0x7C, 0xF8, 0xBD, 0x37, 0x6E, 0xDC,
0xF5, 0xA7, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0xCD, 0xD7, 0xE3,
0x8B, 0x5B, 0xB6, 0x21, 0x42, 0x84, 0x45, 0x8A, 0x59, 0xB2, 0x29, 0x52,
0xA4, 0x05, 0x0A, 0x14, 0x28, 0x50, 0xA0, 0x0D, 0x1A, 0x34, 0x68, 0xD0,
0xED, 0x97, 0x63, 0xC6, 0xC1, 0xCF, 0xD3, 0xEB, 0x9B, 0x7B, 0xF6, 0xA1,
0x0F, 0x1E, 0x3C, 0x78, 0xF0, 0xAD, 0x17, 0x2E, 0x5C, 0xB8, 0x3D, 0x7A,
0xF4, 0xA5, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0xE0, 0x8D, 0x57, 0xAE, 0x11,
0x22, 0x44, 0x88, 0x5D, 0xBA, 0x39, 0x72, 0xE4, 0x85, 0x47, 0x8E, 0x51,
0xA2, 0x09, 0x12, 0x24, 0x48, 0x90, 0x6D, 0xDA, 0xF9, 0xBF, 0x33, 0x66,
0xCC, 0xD5, 0xE7, 0x83, 0x4B, 0x96, 0x61, 0xC2, 0xC9, 0xDF, 0xF3, 0xAB,
0x1B, 0x36, 0x6C, 0xD8, 0xFD, 0xB7, 0x23, 0x46, 0x8C, 0x55, 0xAA, 0x19,
0x32, 0x64, 0xC8, 0xDD, 0xF7, 0xA3, 0x0B, 0x16, 0x2C, 0x58, 0xB0, 0x2D,
0x5A, 0xB4, 0x25, 0x4A, 0x94, 0x65, 0xCA, 0xD9, 0xFF, 0xB3, 0x2B, 0x56,
0xAC, 0x15, 0x2A, 0x54, 0xA8, 0x1D, 0x3A, 0x74, 0xE8, 0x9D, 0x77, 0xEE,
0x91, 0x6F, 0xDE, 0xF1, 0xAF, 0x13, 0x26, 0x4C, 0x98, 0x7D, 0xFA, 0xB9,
0x3F, 0x7E, 0xFC, 0xB5, 0x27, 0x4E, 0x9C, 0x75, 0xEA, 0x99, 0x7F, 0xFE,
0xB1, 0x2F, 0x5E, 0xBC, 0x35, 0x6A, 0xD4, 0xE5, 0x87, 0x43, 0x86, 0x41,
0x82, 0x49, 0x92, 0x69, 0xD2, 0xE9, 0x9F, 0x73, 0xE6, 0x81, 0x4F, 0x9E,
0x71, 0xE2, 0x89, 0x5F, 0xBE, 0x31, 0x62, 0xC4, 0xC5, 0xC7, 0xC3, 0xCB
};
/* The table constants are indices of
* S-box entries, preprocessed through q0 and q1. */
static byte calc_sb_tbl[512] = {
0xA9, 0x75, 0x67, 0xF3, 0xB3, 0xC6, 0xE8, 0xF4,
0x04, 0xDB, 0xFD, 0x7B, 0xA3, 0xFB, 0x76, 0xC8,
0x9A, 0x4A, 0x92, 0xD3, 0x80, 0xE6, 0x78, 0x6B,
0xE4, 0x45, 0xDD, 0x7D, 0xD1, 0xE8, 0x38, 0x4B,
0x0D, 0xD6, 0xC6, 0x32, 0x35, 0xD8, 0x98, 0xFD,
0x18, 0x37, 0xF7, 0x71, 0xEC, 0xF1, 0x6C, 0xE1,
0x43, 0x30, 0x75, 0x0F, 0x37, 0xF8, 0x26, 0x1B,
0xFA, 0x87, 0x13, 0xFA, 0x94, 0x06, 0x48, 0x3F,
0xF2, 0x5E, 0xD0, 0xBA, 0x8B, 0xAE, 0x30, 0x5B,
0x84, 0x8A, 0x54, 0x00, 0xDF, 0xBC, 0x23, 0x9D,
0x19, 0x6D, 0x5B, 0xC1, 0x3D, 0xB1, 0x59, 0x0E,
0xF3, 0x80, 0xAE, 0x5D, 0xA2, 0xD2, 0x82, 0xD5,
0x63, 0xA0, 0x01, 0x84, 0x83, 0x07, 0x2E, 0x14,
0xD9, 0xB5, 0x51, 0x90, 0x9B, 0x2C, 0x7C, 0xA3,
0xA6, 0xB2, 0xEB, 0x73, 0xA5, 0x4C, 0xBE, 0x54,
0x16, 0x92, 0x0C, 0x74, 0xE3, 0x36, 0x61, 0x51,
0xC0, 0x38, 0x8C, 0xB0, 0x3A, 0xBD, 0xF5, 0x5A,
0x73, 0xFC, 0x2C, 0x60, 0x25, 0x62, 0x0B, 0x96,
0xBB, 0x6C, 0x4E, 0x42, 0x89, 0xF7, 0x6B, 0x10,
0x53, 0x7C, 0x6A, 0x28, 0xB4, 0x27, 0xF1, 0x8C,
0xE1, 0x13, 0xE6, 0x95, 0xBD, 0x9C, 0x45, 0xC7,
0xE2, 0x24, 0xF4, 0x46, 0xB6, 0x3B, 0x66, 0x70,
0xCC, 0xCA, 0x95, 0xE3, 0x03, 0x85, 0x56, 0xCB,
0xD4, 0x11, 0x1C, 0xD0, 0x1E, 0x93, 0xD7, 0xB8,
0xFB, 0xA6, 0xC3, 0x83, 0x8E, 0x20, 0xB5, 0xFF,
0xE9, 0x9F, 0xCF, 0x77, 0xBF, 0xC3, 0xBA, 0xCC,
0xEA, 0x03, 0x77, 0x6F, 0x39, 0x08, 0xAF, 0xBF,
0x33, 0x40, 0xC9, 0xE7, 0x62, 0x2B, 0x71, 0xE2,
0x81, 0x79, 0x79, 0x0C, 0x09, 0xAA, 0xAD, 0x82,
0x24, 0x41, 0xCD, 0x3A, 0xF9, 0xEA, 0xD8, 0xB9,
0xE5, 0xE4, 0xC5, 0x9A, 0xB9, 0xA4, 0x4D, 0x97,
0x44, 0x7E, 0x08, 0xDA, 0x86, 0x7A, 0xE7, 0x17,
0xA1, 0x66, 0x1D, 0x94, 0xAA, 0xA1, 0xED, 0x1D,
0x06, 0x3D, 0x70, 0xF0, 0xB2, 0xDE, 0xD2, 0xB3,
0x41, 0x0B, 0x7B, 0x72, 0xA0, 0xA7, 0x11, 0x1C,
0x31, 0xEF, 0xC2, 0xD1, 0x27, 0x53, 0x90, 0x3E,
0x20, 0x8F, 0xF6, 0x33, 0x60, 0x26, 0xFF, 0x5F,
0x96, 0xEC, 0x5C, 0x76, 0xB1, 0x2A, 0xAB, 0x49,
0x9E, 0x81, 0x9C, 0x88, 0x52, 0xEE, 0x1B, 0x21,
0x5F, 0xC4, 0x93, 0x1A, 0x0A, 0xEB, 0xEF, 0xD9,
0x91, 0xC5, 0x85, 0x39, 0x49, 0x99, 0xEE, 0xCD,
0x2D, 0xAD, 0x4F, 0x31, 0x8F, 0x8B, 0x3B, 0x01,
0x47, 0x18, 0x87, 0x23, 0x6D, 0xDD, 0x46, 0x1F,
0xD6, 0x4E, 0x3E, 0x2D, 0x69, 0xF9, 0x64, 0x48,
0x2A, 0x4F, 0xCE, 0xF2, 0xCB, 0x65, 0x2F, 0x8E,
0xFC, 0x78, 0x97, 0x5C, 0x05, 0x58, 0x7A, 0x19,
0xAC, 0x8D, 0x7F, 0xE5, 0xD5, 0x98, 0x1A, 0x57,
0x4B, 0x67, 0x0E, 0x7F, 0xA7, 0x05, 0x5A, 0x64,
0x28, 0xAF, 0x14, 0x63, 0x3F, 0xB6, 0x29, 0xFE,
0x88, 0xF5, 0x3C, 0xB7, 0x4C, 0x3C, 0x02, 0xA5,
0xB8, 0xCE, 0xDA, 0xE9, 0xB0, 0x68, 0x17, 0x44,
0x55, 0xE0, 0x1F, 0x4D, 0x8A, 0x43, 0x7D, 0x69,
0x57, 0x29, 0xC7, 0x2E, 0x8D, 0xAC, 0x74, 0x15,
0xB7, 0x59, 0xC4, 0xA8, 0x9F, 0x0A, 0x72, 0x9E,
0x7E, 0x6E, 0x15, 0x47, 0x22, 0xDF, 0x12, 0x34,
0x58, 0x35, 0x07, 0x6A, 0x99, 0xCF, 0x34, 0xDC,
0x6E, 0x22, 0x50, 0xC9, 0xDE, 0xC0, 0x68, 0x9B,
0x65, 0x89, 0xBC, 0xD4, 0xDB, 0xED, 0xF8, 0xAB,
0xC8, 0x12, 0xA8, 0xA2, 0x2B, 0x0D, 0x40, 0x52,
0xDC, 0xBB, 0xFE, 0x02, 0x32, 0x2F, 0xA4, 0xA9,
0xCA, 0xD7, 0x10, 0x61, 0x21, 0x1E, 0xF0, 0xB4,
0xD3, 0x50, 0x5D, 0x04, 0x0F, 0xF6, 0x00, 0xC2,
0x6F, 0x16, 0x9D, 0x25, 0x36, 0x86, 0x42, 0x56,
0x4A, 0x55, 0x5E, 0x09, 0xC1, 0xBE, 0xE0, 0x91
};
/* Macro to perform one column of the RS matrix multiplication. The
* parameters a, b, c, and d are the four bytes of output; i is the index
* of the key bytes, and w, x, y, and z, are the column of constants from
* the RS matrix, preprocessed through the poly_to_exp table. */
#define CALC_S(a, b, c, d, i, w, x, y, z) \
if (key[i]) { \
tmp = poly_to_exp[key[i] - 1]; \
(a) ^= exp_to_poly[tmp + (w)]; \
(b) ^= exp_to_poly[tmp + (x)]; \
(c) ^= exp_to_poly[tmp + (y)]; \
(d) ^= exp_to_poly[tmp + (z)]; \
}
/* Macros to calculate the key-dependent S-boxes for a 128-bit key using
* the S vector from CALC_S. CALC_SB_2 computes a single entry in all
* four S-boxes, where i is the index of the entry to compute, and a and b
* are the index numbers preprocessed through the q0 and q1 tables
* respectively. CALC_SB is simply a convenience to make the code shorter;
* it calls CALC_SB_2 four times with consecutive indices from i to i+3,
* using the remaining parameters two by two. */
#define CALC_SB_2(i, a, b) \
ctx->s[0][i] = mds[0][q0[(a) ^ sa] ^ se]; \
ctx->s[1][i] = mds[1][q0[(b) ^ sb] ^ sf]; \
ctx->s[2][i] = mds[2][q1[(a) ^ sc] ^ sg]; \
ctx->s[3][i] = mds[3][q1[(b) ^ sd] ^ sh]
#define CALC_SB(i, a, b, c, d, e, f, g, h) \
CALC_SB_2 (i, a, b); CALC_SB_2 ((i)+1, c, d); \
CALC_SB_2 ((i)+2, e, f); CALC_SB_2 ((i)+3, g, h)
/* Macros exactly like CALC_SB and CALC_SB_2, but for 256-bit keys. */
#define CALC_SB256_2(i, a, b) \
ctx->s[0][i] = mds[0][q0[q0[q1[(b) ^ sa] ^ se] ^ si] ^ sm]; \
ctx->s[1][i] = mds[1][q0[q1[q1[(a) ^ sb] ^ sf] ^ sj] ^ sn]; \
ctx->s[2][i] = mds[2][q1[q0[q0[(a) ^ sc] ^ sg] ^ sk] ^ so]; \
ctx->s[3][i] = mds[3][q1[q1[q0[(b) ^ sd] ^ sh] ^ sl] ^ sp];
#define CALC_SB256(i, a, b, c, d, e, f, g, h) \
CALC_SB256_2 (i, a, b); CALC_SB256_2 ((i)+1, c, d); \
CALC_SB256_2 ((i)+2, e, f); CALC_SB256_2 ((i)+3, g, h)
/* Macros to calculate the whitening and round subkeys. CALC_K_2 computes the
* last two stages of the h() function for a given index (either 2i or 2i+1).
* a, b, c, and d are the four bytes going into the last two stages. For
* 128-bit keys, this is the entire h() function and a and c are the index
* preprocessed through q0 and q1 respectively; for longer keys they are the
* output of previous stages. j is the index of the first key byte to use.
* CALC_K computes a pair of subkeys for 128-bit Twofish, by calling CALC_K_2
* twice, doing the Psuedo-Hadamard Transform, and doing the necessary
* rotations. Its parameters are: a, the array to write the results into,
* j, the index of the first output entry, k and l, the preprocessed indices
* for index 2i, and m and n, the preprocessed indices for index 2i+1.
* CALC_K256_2 expands CALC_K_2 to handle 256-bit keys, by doing two
* additional lookup-and-XOR stages. The parameters a and b are the index
* preprocessed through q0 and q1 respectively; j is the index of the first
* key byte to use. CALC_K256 is identical to CALC_K but for using the
* CALC_K256_2 macro instead of CALC_K_2. */
#define CALC_K_2(a, b, c, d, j) \
mds[0][q0[a ^ key[(j) + 8]] ^ key[j]] \
^ mds[1][q0[b ^ key[(j) + 9]] ^ key[(j) + 1]] \
^ mds[2][q1[c ^ key[(j) + 10]] ^ key[(j) + 2]] \
^ mds[3][q1[d ^ key[(j) + 11]] ^ key[(j) + 3]]
#define CALC_K(a, j, k, l, m, n) \
x = CALC_K_2 (k, l, k, l, 0); \
y = CALC_K_2 (m, n, m, n, 4); \
y = (y << 8) + (y >> 24); \
x += y; y += x; ctx->a[j] = x; \
ctx->a[(j) + 1] = (y << 9) + (y >> 23)
#define CALC_K256_2(a, b, j) \
CALC_K_2 (q0[q1[b ^ key[(j) + 24]] ^ key[(j) + 16]], \
q1[q1[a ^ key[(j) + 25]] ^ key[(j) + 17]], \
q0[q0[a ^ key[(j) + 26]] ^ key[(j) + 18]], \
q1[q0[b ^ key[(j) + 27]] ^ key[(j) + 19]], j)
#define CALC_K256(a, j, k, l, m, n) \
x = CALC_K256_2 (k, l, 0); \
y = CALC_K256_2 (m, n, 4); \
y = (y << 8) + (y >> 24); \
x += y; y += x; ctx->a[j] = x; \
ctx->a[(j) + 1] = (y << 9) + (y >> 23)
/* Perform the key setup. Note that this works only with 128- and 256-bit
* keys, despite the API that looks like it might support other sizes. */
static int
twofish_setkey (TWOFISH_context *ctx, const byte *key, const unsigned keylen)
{
int i, j, k;
/* Temporaries for CALC_K. */
u32 x, y;
/* The S vector used to key the S-boxes, split up into individual bytes.
* 128-bit keys use only sa through sh; 256-bit use all of them. */
byte sa = 0, sb = 0, sc = 0, sd = 0, se = 0, sf = 0, sg = 0, sh = 0;
byte si = 0, sj = 0, sk = 0, sl = 0, sm = 0, sn = 0, so = 0, sp = 0;
/* Temporary for CALC_S. */
byte tmp;
/* Flags for self-test. */
static int initialized = 0;
static const char *selftest_failed=0;
/* Check key length. */
if( ( ( keylen - 16 ) | 16 ) != 16 )
return GCRYERR_INV_KEYLEN;
/* Do self-test if necessary. */
if (!initialized) {
initialized = 1;
selftest_failed = selftest ();
if( selftest_failed )
fprintf(stderr, "%s\n", selftest_failed );
}
if( selftest_failed )
return GCRYERR_SELFTEST;
/* Compute the first two words of the S vector. The magic numbers are
* the entries of the RS matrix, preprocessed through poly_to_exp. The
* numbers in the comments are the original (polynomial form) matrix
* entries. */
CALC_S (sa, sb, sc, sd, 0, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (sa, sb, sc, sd, 1, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (sa, sb, sc, sd, 2, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (sa, sb, sc, sd, 3, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (sa, sb, sc, sd, 4, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (sa, sb, sc, sd, 5, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (sa, sb, sc, sd, 6, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (sa, sb, sc, sd, 7, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
CALC_S (se, sf, sg, sh, 8, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (se, sf, sg, sh, 9, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (se, sf, sg, sh, 10, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (se, sf, sg, sh, 11, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (se, sf, sg, sh, 12, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (se, sf, sg, sh, 13, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (se, sf, sg, sh, 14, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (se, sf, sg, sh, 15, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
if (keylen == 32) { /* 256-bit key */
/* Calculate the remaining two words of the S vector */
CALC_S (si, sj, sk, sl, 16, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (si, sj, sk, sl, 17, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (si, sj, sk, sl, 18, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (si, sj, sk, sl, 19, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (si, sj, sk, sl, 20, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (si, sj, sk, sl, 21, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (si, sj, sk, sl, 22, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (si, sj, sk, sl, 23, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
CALC_S (sm, sn, so, sp, 24, 0x00, 0x2D, 0x01, 0x2D); /* 01 A4 02 A4 */
CALC_S (sm, sn, so, sp, 25, 0x2D, 0xA4, 0x44, 0x8A); /* A4 56 A1 55 */
CALC_S (sm, sn, so, sp, 26, 0x8A, 0xD5, 0xBF, 0xD1); /* 55 82 FC 87 */
CALC_S (sm, sn, so, sp, 27, 0xD1, 0x7F, 0x3D, 0x99); /* 87 F3 C1 5A */
CALC_S (sm, sn, so, sp, 28, 0x99, 0x46, 0x66, 0x96); /* 5A 1E 47 58 */
CALC_S (sm, sn, so, sp, 29, 0x96, 0x3C, 0x5B, 0xED); /* 58 C6 AE DB */
CALC_S (sm, sn, so, sp, 30, 0xED, 0x37, 0x4F, 0xE0); /* DB 68 3D 9E */
CALC_S (sm, sn, so, sp, 31, 0xE0, 0xD0, 0x8C, 0x17); /* 9E E5 19 03 */
/* Compute the S-boxes. */
for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 ) {
CALC_SB256_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
}
/* Calculate whitening and round subkeys. The constants are
* indices of subkeys, preprocessed through q0 and q1. */
CALC_K256 (w, 0, 0xA9, 0x75, 0x67, 0xF3);
CALC_K256 (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
CALC_K256 (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
CALC_K256 (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
CALC_K256 (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
CALC_K256 (k, 2, 0x80, 0xE6, 0x78, 0x6B);
CALC_K256 (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
CALC_K256 (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
CALC_K256 (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
CALC_K256 (k, 10, 0x35, 0xD8, 0x98, 0xFD);
CALC_K256 (k, 12, 0x18, 0x37, 0xF7, 0x71);
CALC_K256 (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
CALC_K256 (k, 16, 0x43, 0x30, 0x75, 0x0F);
CALC_K256 (k, 18, 0x37, 0xF8, 0x26, 0x1B);
CALC_K256 (k, 20, 0xFA, 0x87, 0x13, 0xFA);
CALC_K256 (k, 22, 0x94, 0x06, 0x48, 0x3F);
CALC_K256 (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
CALC_K256 (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
CALC_K256 (k, 28, 0x84, 0x8A, 0x54, 0x00);
CALC_K256 (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
}
else {
/* Compute the S-boxes. */
for(i=j=0,k=1; i < 256; i++, j += 2, k += 2 ) {
CALC_SB_2( i, calc_sb_tbl[j], calc_sb_tbl[k] );
}
/* Calculate whitening and round subkeys. The constants are
* indices of subkeys, preprocessed through q0 and q1. */
CALC_K (w, 0, 0xA9, 0x75, 0x67, 0xF3);
CALC_K (w, 2, 0xB3, 0xC6, 0xE8, 0xF4);
CALC_K (w, 4, 0x04, 0xDB, 0xFD, 0x7B);
CALC_K (w, 6, 0xA3, 0xFB, 0x76, 0xC8);
CALC_K (k, 0, 0x9A, 0x4A, 0x92, 0xD3);
CALC_K (k, 2, 0x80, 0xE6, 0x78, 0x6B);
CALC_K (k, 4, 0xE4, 0x45, 0xDD, 0x7D);
CALC_K (k, 6, 0xD1, 0xE8, 0x38, 0x4B);
CALC_K (k, 8, 0x0D, 0xD6, 0xC6, 0x32);
CALC_K (k, 10, 0x35, 0xD8, 0x98, 0xFD);
CALC_K (k, 12, 0x18, 0x37, 0xF7, 0x71);
CALC_K (k, 14, 0xEC, 0xF1, 0x6C, 0xE1);
CALC_K (k, 16, 0x43, 0x30, 0x75, 0x0F);
CALC_K (k, 18, 0x37, 0xF8, 0x26, 0x1B);
CALC_K (k, 20, 0xFA, 0x87, 0x13, 0xFA);
CALC_K (k, 22, 0x94, 0x06, 0x48, 0x3F);
CALC_K (k, 24, 0xF2, 0x5E, 0xD0, 0xBA);
CALC_K (k, 26, 0x8B, 0xAE, 0x30, 0x5B);
CALC_K (k, 28, 0x84, 0x8A, 0x54, 0x00);
CALC_K (k, 30, 0xDF, 0xBC, 0x23, 0x9D);
}
return 0;
}
/* Macros to compute the g() function in the encryption and decryption
* rounds. G1 is the straight g() function; G2 includes the 8-bit
* rotation for the high 32-bit word. */
#define G1(a) \
(ctx->s[0][(a) & 0xFF]) ^ (ctx->s[1][((a) >> 8) & 0xFF]) \
^ (ctx->s[2][((a) >> 16) & 0xFF]) ^ (ctx->s[3][(a) >> 24])
#define G2(b) \
(ctx->s[1][(b) & 0xFF]) ^ (ctx->s[2][((b) >> 8) & 0xFF]) \
^ (ctx->s[3][((b) >> 16) & 0xFF]) ^ (ctx->s[0][(b) >> 24])
/* Encryption and decryption Feistel rounds. Each one calls the two g()
* macros, does the PHT, and performs the XOR and the appropriate bit
* rotations. The parameters are the round number (used to select subkeys),
* and the four 32-bit chunks of the text. */
#define ENCROUND(n, a, b, c, d) \
x = G1 (a); y = G2 (b); \
x += y; y += x + ctx->k[2 * (n) + 1]; \
(c) ^= x + ctx->k[2 * (n)]; \
(c) = ((c) >> 1) + ((c) << 31); \
(d) = (((d) << 1)+((d) >> 31)) ^ y
#define DECROUND(n, a, b, c, d) \
x = G1 (a); y = G2 (b); \
x += y; y += x; \
(d) ^= y + ctx->k[2 * (n) + 1]; \
(d) = ((d) >> 1) + ((d) << 31); \
(c) = (((c) << 1)+((c) >> 31)); \
(c) ^= (x + ctx->k[2 * (n)])
/* Encryption and decryption cycles; each one is simply two Feistel rounds
* with the 32-bit chunks re-ordered to simulate the "swap" */
#define ENCCYCLE(n) \
ENCROUND (2 * (n), a, b, c, d); \
ENCROUND (2 * (n) + 1, c, d, a, b)
#define DECCYCLE(n) \
DECROUND (2 * (n) + 1, c, d, a, b); \
DECROUND (2 * (n), a, b, c, d)
/* Macros to convert the input and output bytes into 32-bit words,
* and simultaneously perform the whitening step. INPACK packs word
* number n into the variable named by x, using whitening subkey number m.
* OUTUNPACK unpacks word number n from the variable named by x, using
* whitening subkey number m. */
#define INPACK(n, x, m) \
x = in[4 * (n)] ^ (in[4 * (n) + 1] << 8) \
^ (in[4 * (n) + 2] << 16) ^ (in[4 * (n) + 3] << 24) ^ ctx->w[m]
#define OUTUNPACK(n, x, m) \
x ^= ctx->w[m]; \
out[4 * (n)] = x; out[4 * (n) + 1] = x >> 8; \
out[4 * (n) + 2] = x >> 16; out[4 * (n) + 3] = x >> 24
/* Encrypt one block. in and out may be the same. */
static void
twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
/* The four 32-bit chunks of the text. */
u32 a, b, c, d;
/* Temporaries used by the round function. */
u32 x, y;
/* Input whitening and packing. */
INPACK (0, a, 0);
INPACK (1, b, 1);
INPACK (2, c, 2);
INPACK (3, d, 3);
/* Encryption Feistel cycles. */
ENCCYCLE (0);
ENCCYCLE (1);
ENCCYCLE (2);
ENCCYCLE (3);
ENCCYCLE (4);
ENCCYCLE (5);
ENCCYCLE (6);
ENCCYCLE (7);
/* Output whitening and unpacking. */
OUTUNPACK (0, c, 4);
OUTUNPACK (1, d, 5);
OUTUNPACK (2, a, 6);
OUTUNPACK (3, b, 7);
}
/* Decrypt one block. in and out may be the same. */
static void
twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in)
{
/* The four 32-bit chunks of the text. */
u32 a, b, c, d;
/* Temporaries used by the round function. */
u32 x, y;
/* Input whitening and packing. */
INPACK (0, c, 4);
INPACK (1, d, 5);
INPACK (2, a, 6);
INPACK (3, b, 7);
/* Encryption Feistel cycles. */
DECCYCLE (7);
DECCYCLE (6);
DECCYCLE (5);
DECCYCLE (4);
DECCYCLE (3);
DECCYCLE (2);
DECCYCLE (1);
DECCYCLE (0);
/* Output whitening and unpacking. */
OUTUNPACK (0, a, 0);
OUTUNPACK (1, b, 1);
OUTUNPACK (2, c, 2);
OUTUNPACK (3, d, 3);
}
/* Test a single encryption and decryption with each key size. */
static const char*
selftest (void)
{
TWOFISH_context ctx; /* Expanded key. */
byte scratch[16]; /* Encryption/decryption result buffer. */
/* Test vectors for single encryption/decryption. Note that I am using
* the vectors from the Twofish paper's "known answer test", I=3 for
* 128-bit and I=4 for 256-bit, instead of the all-0 vectors from the
* "intermediate value test", because an all-0 key would trigger all the
* special cases in the RS matrix multiply, leaving the math untested. */
static const byte plaintext[16] = {
0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E,
0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19
};
static const byte key[16] = {
0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32,
0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A
};
static const byte ciphertext[16] = {
0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85,
0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3
};
static const byte plaintext_256[16] = {
0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F,
0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6
};
static const byte key_256[32] = {
0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B,
0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F
};
static const byte ciphertext_256[16] = {
0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97,
0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA
};
twofish_setkey (&ctx, key, sizeof(key));
twofish_encrypt (&ctx, scratch, plaintext);
if (memcmp (scratch, ciphertext, sizeof (ciphertext)))
return "Twofish-128 test encryption failed.";
twofish_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext, sizeof (plaintext)))
return "Twofish-128 test decryption failed.";
twofish_setkey (&ctx, key_256, sizeof(key_256));
twofish_encrypt (&ctx, scratch, plaintext_256);
if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256)))
return "Twofish-256 test encryption failed.";
twofish_decrypt (&ctx, scratch, scratch);
if (memcmp (scratch, plaintext_256, sizeof (plaintext_256)))
return "Twofish-256 test decryption failed.";
return NULL;
}
/* More complete test program. This does 1000 encryptions and decryptions
* with each of 250 128-bit keys and 2000 encryptions and decryptions with
* each of 125 256-bit keys, using a feedback scheme similar to a Feistel
* cipher, so as to be sure of testing all the table entries pretty
* thoroughly. We keep changing the keys so as to get a more meaningful
* performance number, since the key setup is non-trivial for Twofish. */
#ifdef TEST
#include <stdio.h>
#include <string.h>
#include <time.h>
int
main()
{
TWOFISH_context ctx; /* Expanded key. */
int i, j; /* Loop counters. */
const char *encrypt_msg; /* Message to print regarding encryption test;
* the printf is done outside the loop to avoid
* stuffing up the timing. */
clock_t timer; /* For computing elapsed time. */
/* Test buffer. */
byte buffer[4][16] = {
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,
0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2 ,0xE1, 0xF0},
{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54 ,0x32, 0x10},
{0x01, 0x23, 0x45, 0x67, 0x76, 0x54 ,0x32, 0x10,
0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98}
};
/* Expected outputs for the million-operation test */
static const byte test_encrypt[4][16] = {
{0xC8, 0x23, 0xB8, 0xB7, 0x6B, 0xFE, 0x91, 0x13,
0x2F, 0xA7, 0x5E, 0xE6, 0x94, 0x77, 0x6F, 0x6B},
{0x90, 0x36, 0xD8, 0x29, 0xD5, 0x96, 0xC2, 0x8E,
0xE4, 0xFF, 0x76, 0xBC, 0xE5, 0x77, 0x88, 0x27},
{0xB8, 0x78, 0x69, 0xAF, 0x42, 0x8B, 0x48, 0x64,
0xF7, 0xE9, 0xF3, 0x9C, 0x42, 0x18, 0x7B, 0x73},
{0x7A, 0x88, 0xFB, 0xEB, 0x90, 0xA4, 0xB4, 0xA8,
0x43, 0xA3, 0x1D, 0xF1, 0x26, 0xC4, 0x53, 0x57}
};
static const byte test_decrypt[4][16] = {
{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF},
{0x0F, 0x1E, 0x2D, 0x3C, 0x4B, 0x5A, 0x69, 0x78,
0x87, 0x96, 0xA5, 0xB4, 0xC3, 0xD2 ,0xE1, 0xF0},
{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54 ,0x32, 0x10},
{0x01, 0x23, 0x45, 0x67, 0x76, 0x54 ,0x32, 0x10,
0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98}
};
/* Start the timer ticking. */
timer = clock ();
/* Encryption test. */
for (i = 0; i < 125; i++) {
twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
for (j = 0; j < 1000; j++)
twofish_encrypt (&ctx, buffer[2], buffer[2]);
twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
for (j = 0; j < 1000; j++)
twofish_encrypt (&ctx, buffer[3], buffer[3]);
twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
for (j = 0; j < 1000; j++) {
twofish_encrypt (&ctx, buffer[0], buffer[0]);
twofish_encrypt (&ctx, buffer[1], buffer[1]);
}
}
encrypt_msg = memcmp (buffer, test_encrypt, sizeof (test_encrypt)) ?
"encryption failure!\n" : "encryption OK!\n";
/* Decryption test. */
for (i = 0; i < 125; i++) {
twofish_setkey (&ctx, buffer[2], sizeof (buffer[2])*2);
for (j = 0; j < 1000; j++) {
twofish_decrypt (&ctx, buffer[0], buffer[0]);
twofish_decrypt (&ctx, buffer[1], buffer[1]);
}
twofish_setkey (&ctx, buffer[1], sizeof (buffer[1]));
for (j = 0; j < 1000; j++)
twofish_decrypt (&ctx, buffer[3], buffer[3]);
twofish_setkey (&ctx, buffer[0], sizeof (buffer[0]));
for (j = 0; j < 1000; j++)
twofish_decrypt (&ctx, buffer[2], buffer[2]);
}
/* Stop the timer, and print results. */
timer = clock () - timer;
printf (encrypt_msg);
printf (memcmp (buffer, test_decrypt, sizeof (test_decrypt)) ?
"decryption failure!\n" : "decryption OK!\n");
printf ("elapsed time: %.1f s.\n", (float) timer / CLOCKS_PER_SEC);
return 0;
}
#endif /* TEST */
#ifdef IS_MODULE
static
#endif
const char *
twofish_get_info (int algo, size_t *keylen,
size_t *blocksize, size_t *contextsize,
int (**r_setkey) (void *c, byte *key, unsigned keylen),
void (**r_encrypt) (void *c, byte *outbuf, byte *inbuf),
void (**r_decrypt) (void *c, byte *outbuf, byte *inbuf)
)
{
*keylen = algo==10? 256 : 128;
*blocksize = 16;
*contextsize = sizeof (TWOFISH_context);
- *r_setkey = FNCCAST_SETKEY (twofish_setkey);
- *r_encrypt= FNCCAST_CRYPT (twofish_encrypt);
- *r_decrypt= FNCCAST_CRYPT (twofish_decrypt);
-
- if( algo == 10 )
- return "TWOFISH";
- if (algo == 102) /* This algorithm number is assigned for
- * experiments, so we can use it */
- return "TWOFISH128";
- return NULL;
+
+ *(int (**)(TWOFISH_context*, const byte*, const unsigned))r_setkey
+ = twofish_setkey;
+ *(void (**)(const TWOFISH_context*, byte*, const byte*))r_encrypt
+ = twofish_encrypt;
+ *(void (**)(const TWOFISH_context*, byte*, const byte*))r_decrypt
+ = twofish_decrypt;
+
+ if( algo == 10 )
+ return "TWOFISH";
+ if (algo == 102) /* This algorithm number is assigned for
+ * experiments, so we can use it */
+ return "TWOFISH128";
+ return NULL;
}
const char * const gnupgext_version = "TWOFISH ($Revision$)";
static struct {
int class;
int version;
int value;
void (*func)(void);
} func_table[] = {
{ 20, 1, 0, (void(*)(void))twofish_get_info },
{ 21, 1, 10 },
{ 21, 1, 102 },
};
/****************
* Enumerate the names of the functions together with information about
* this function. Set sequence to an integer with a initial value of 0 and
* do not change it.
* If what is 0 all kind of functions are returned.
* Return values: class := class of function:
* 10 = message digest algorithm info function
* 11 = integer with available md algorithms
* 20 = cipher algorithm info function
* 21 = integer with available cipher algorithms
* 30 = public key algorithm info function
* 31 = integer with available pubkey algorithms
* version = interface version of the function/pointer
* (currently this is 1 for all functions)
*/
void *
gnupgext_enum_func ( int what, int *sequence, int *class, int *vers )
{
void *ret;
int i = *sequence;
do {
if ( i >= DIM(func_table) || i < 0 ) {
return NULL;
}
*class = func_table[i].class;
*vers = func_table[i].version;
switch( *class ) {
case 11:
case 21:
case 31:
ret = &func_table[i].value;
break;
default:
ret = func_table[i].func;
break;
}
i++;
} while ( what && what != *class );
*sequence = i;
return ret;
}
diff --git a/configure.in b/configure.in
index fddb93d2..b3e44ec7 100644
--- a/configure.in
+++ b/configure.in
@@ -1,739 +1,773 @@
dnl
dnl Configure template for GNUPG
dnl
dnl (Process this file with autoconf to produce a configure script.)
AC_REVISION($Revision$)dnl
dnl Must reset CDPATH so that bash's cd does not print to stdout
CDPATH=
AC_PREREQ(2.13)
AC_INIT(g10/gpg.c)
AC_CONFIG_AUX_DIR(scripts)
AM_CONFIG_HEADER(config.h)
+AC_CANONICAL_SYSTEM
+AM_INIT_AUTOMAKE(gnupg,`cat $srcdir/VERSION`)
-
-VERSION=`cat $srcdir/VERSION`
-PACKAGE=gnupg
-ALL_LINGUAS="de es_ES fr it pl pt_BR pt_PT ru"
+ALL_LINGUAS="da de eo es_ES fr id it ja nl pl pt_BR pt_PT ru sv"
static_modules="sha1 md5 rmd160"
-AC_SUBST(VERSION)
-AC_SUBST(PACKAGE)
-AC_DEFINE_UNQUOTED(VERSION, "$VERSION")
-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE")
+static_random_module=""
+
+AC_PROG_AWK
-MODULES_IN_CIPHER=`awk '/# MODULES: / { for(i=3;i<=NF;i++) print $i}' \
- $srcdir/cipher/Makefile.am`
+MODULES_IN_CIPHER=`$AWK '/^EXTRA_PROGRAMS/ { for(i=3;i<=NF;i++) print $i}' \
+ $srcdir/cipher/Makefile.am`
dnl
dnl Check for random module options
dnl
dnl Fixme: get the list of available modules from MODULES_IN_CIPHER
dnl and check against this list
AC_MSG_CHECKING([which static random module to use])
AC_ARG_ENABLE(static-rnd,
[ --enable-static-rnd=[egd|unix|linux|none] ],
[use_static_rnd=$enableval], [use_static_rnd=default] )
if test "$use_static_rnd" = no; then
use_static_rnd=default
fi
case "$use_static_rnd" in
egd | linux | unix | none | default )
AC_MSG_RESULT($use_static_rnd)
;;
* )
AC_MSG_RESULT(invalid argument)
AC_MSG_ERROR(there is no random module rnd$use_static_rnd)
;;
esac
dnl
dnl See whether the user wants to disable checking for /dev/random
AC_MSG_CHECKING([whether use of /dev/random is requested])
AC_ARG_ENABLE(dev-random,
[ --disable-dev-random disable the use of dev random],
try_dev_random=$enableval, try_dev_random=yes)
AC_MSG_RESULT($try_dev_random)
dnl
dnl Check other options
dnl
AC_MSG_CHECKING([whether use of extensions is requested])
AC_ARG_ENABLE(dynload,
[ --disable-dynload disable use of extensions],
try_dynload=$enableval, try_dynload=yes)
AC_MSG_RESULT($try_dynload)
AC_MSG_CHECKING([whether assembler modules are requested])
AC_ARG_ENABLE(asm,
[ --disable-asm do not use assembler modules],
try_asm_modules=$enableval, try_asm_modules=yes)
AC_MSG_RESULT($try_asm_modules)
AC_MSG_CHECKING([whether memory debugging is requested])
AC_ARG_ENABLE(m-debug,
[ --enable-m-debug enable debugging of memory allocation],
use_m_debug=$enableval, use_m_debug=no)
AC_MSG_RESULT($use_m_debug)
if test "$use_m_debug" = yes; then
AC_DEFINE(M_DEBUG)
use_m_guard=yes
else
AC_MSG_CHECKING([whether memory guard is requested])
AC_ARG_ENABLE(m-guard,
[ --enable-m-guard enable memory guard facility],
use_m_guard=$enableval, use_m_guard=no)
AC_MSG_RESULT($use_m_guard)
fi
if test "$use_m_guard" = yes ; then
AC_DEFINE(M_GUARD)
fi
AC_MSG_CHECKING([whether included zlib is requested])
AC_ARG_WITH(included-zlib,
[ --with-included-zlib use the zlib code included here],
[g10_force_zlib=yes], [g10_force_zlib=no] )
AC_MSG_RESULT($g10_force_zlib)
dnl
dnl Check wether we want to compile libgcrypt
dnl
AC_MSG_CHECKING([whether compilation of libgcrypt is requested])
AC_ARG_ENABLE(libgcrypt,
[ --enable-libgcrypt compile the libgcrypt [default=yes]],
[compile_libgcrypt="$enableval"],[compile_libgcrypt=no])
AC_MSG_RESULT($compile_libgcrypt)
AM_CONDITIONAL(COMPILE_LIBGCRYPT, test x$compile_libgcrypt = xyes)
dnl
dnl Check whether we want to use Linux capabilities
dnl
AC_MSG_CHECKING([whether use of capabilities is requested])
AC_ARG_WITH(capabilities,
[ --with-capabilities use linux capabilities [default=no]],
[use_capabilities="$withval"],[use_capabilities=no])
AC_MSG_RESULT($use_capabilities)
AM_MAINTAINER_MODE
dnl Checks for programs.
-AC_CANONICAL_SYSTEM
dnl
dnl Setup some stuff depending on host/target.
dnl
case "${target}" in
*-*-mingw32)
# special stuff for Windoze NT
# Do we need to set cross_compiling here or is it sufficient
# to rely on AC_PROG_CC which is called later?
cross_compiling=yes
CC="${target}-gcc"
CPP="${target}-gcc -E"
RANLIB="${target}-ranlib"
+ disallowed_modules="rndunix rndlinux rndegd"
;;
*)
+ disallowed_modules="rndw32"
;;
esac
AC_ARG_PROGRAM
AC_PROG_MAKE_SET
AM_SANITY_CHECK
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
dnl AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_PROG_CC
AC_PROG_CPP
AC_ISC_POSIX
AC_PROG_INSTALL
AC_PROG_AWK
GPH_PROG_DOCBOOK
dnl
dnl Build shared libraries only when compilation of libgcrypt
dnl has been requested
dnl
dnl AM_DISABLE_STATIC
dnl enable_shared="$compile_libgcrypt"
AM_PROG_LIBTOOL
MPI_OPT_FLAGS=""
-if test "$GCC" = yes; then
- CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
-fi
try_gettext=yes
try_gdbm=yes
case "${target}" in
*-*-mingw32)
# special stuff for Windoze NT
ac_cv_have_dev_random=no
AC_DEFINE(USE_ONLY_8DOT3)
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
AC_DEFINE(USE_SIMPLE_GETTEXT)
try_gettext="no"
try_gdbm="no"
;;
i?86-emx-os2 | i?86-*-os2*emx )
# OS/2 with the EMX environment
ac_cv_have_dev_random=no
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
try_gettext="no"
try_gdbm="no"
;;
i?86-*-msdosdjgpp*)
# DOS with the DJGPP environment
ac_cv_have_dev_random=no
AC_DEFINE(HAVE_DRIVE_LETTERS)
AC_DEFINE(HAVE_DOSISH_SYSTEM)
try_gettext="no"
try_gdbm="no"
;;
+ *-*-freebsd*)
+ # FreeBSD
+ CPPFLAGS="$CPPFLAGS -I/usr/local/include"
+ LDFLAGS="$LDFLAGS -L/usr/local/lib"
+ ;;
+
*-*-hpux*)
if test -z "$GCC" ; then
CFLAGS="$CFLAGS -Ae -D_HPUX_SOURCE"
fi
;;
*-dec-osf4*)
if test -z "$GCC" ; then
# Suppress all warnings
# to get rid of the unsigned/signed char mismatch warnings.
CFLAGS="$CFLAGS -w"
fi
;;
m68k-atari-mint)
;;
*)
;;
esac
AC_SUBST(MPI_OPT_FLAGS)
GNUPG_SYS_SYMBOL_UNDERSCORE
GNUPG_CHECK_PIC
-GNUPG_CHECK_RDYNAMIC
+GNUPG_CHECK_EXPORTDYNAMIC
if test "$NO_PIC" = yes; then
try_dynload=no
fi
case "${target}" in
*-*-mingw32)
PRINTABLE_OS_NAME="MingW32"
;;
i?86-emx-os2 | i?86-*-os2*emx )
PRINTABLE_OS_NAME="OS/2"
;;
i?86-*-msdosdjgpp*)
PRINTABLE_OS_NAME="MSDOS/DJGPP"
try_dynload=no
;;
*-linux*)
PRINTABLE_OS_NAME="GNU/Linux"
;;
dnl let that after linux to avoid gnu-linux problems
*-gnu*)
PRINTABLE_OS_NAME="GNU/Hurd"
;;
*)
PRINTABLE_OS_NAME=`uname -s || echo "Unknown"`
;;
esac
AC_DEFINE_UNQUOTED(PRINTABLE_OS_NAME, "$PRINTABLE_OS_NAME")
dnl Fixme: Are these the best flags for OpenBSD????
dnl (I have removed the -lc from * ...CFLAGS for test purposes.)
case "${target}" in
*-openbsd*)
NAME_OF_DEV_RANDOM="/dev/srandom"
NAME_OF_DEV_URANDOM="/dev/urandom"
DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
;;
+
+ *-netbsd*)
+ NAME_OF_DEV_RANDOM="/dev/random"
+ NAME_OF_DEV_URANDOM="/dev/urandom"
+ DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+ ;;
+
*)
NAME_OF_DEV_RANDOM="/dev/random"
NAME_OF_DEV_URANDOM="/dev/urandom"
DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
;;
esac
AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, "$NAME_OF_DEV_RANDOM")
AC_DEFINE_UNQUOTED(NAME_OF_DEV_URANDOM, "$NAME_OF_DEV_URANDOM")
AC_SUBST(MPI_OPT_FLAGS)
dnl Checks for libraries.
if test "$try_gettext" = yes; then
AM_GNU_GETTEXT
else
USE_NLS=no
USE_INCLUDED_LIBINTL=no
AC_SUBST(USE_NLS)
AC_SUBST(USE_INCLUDED_LIBINTL)
fi
dnl
dnl There are lot of misconfigured systems. We include
dnl gdbm support only if the lib and the header is installed.
dnl
if test "$try_gdbm" = yes; then
AC_CHECK_HEADERS(gdbm.h)
if test "$ac_cv_header_gdbm_h" = yes ; then
AC_CHECK_LIB(gdbm,gdbm_firstkey)
fi
fi
dnl Solaris needs -lsocket and -lnsl. Unisys system includes
dnl gethostbyname in libsocket but needs libnsl for socket.
AC_CHECK_LIB(nsl, gethostbyname)
AC_CHECK_LIB(socket, socket, ac_need_libsocket=1, ac_try_nsl=1)
if test x$ac_need_libsocket = x1; then
LIBS="$LIBS -lsocket"
fi
if test x$ac_try_nsl = x1; then
AC_CHECK_LIB(nsl, gethostbyname, ac_need_libnsl=1)
if test x$ac_need_libnsl = x1
then
LIBS="$LIBS -lnsl"
fi
fi
if test "$try_dynload" = yes ; then
AC_CHECK_LIB(dl,dlopen)
if test "$ac_cv_lib_dl_dlopen" = "yes"; then
AC_DEFINE(USE_DYNAMIC_LINKING)
AC_DEFINE(HAVE_DL_DLOPEN)
- DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+ DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
use_gnupg_extensions=yes
else
- AC_CHECK_LIB(c,dlopen)
- if test "$ac_cv_lib_c_dlopen" = "yes"; then
+ AC_CHECK_FUNCS(dlopen)
+ if test "$ac_cv_func_dlopen" = "yes"; then
AC_DEFINE(USE_DYNAMIC_LINKING)
AC_DEFINE(HAVE_DL_DLOPEN)
- DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+ DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
use_gnupg_extensions=yes
else
AC_CHECK_LIB(dld,shl_load)
if test "$ac_cv_lib_dld_shl_load" = "yes"; then
AC_DEFINE(USE_DYNAMIC_LINKING)
AC_DEFINE(HAVE_DL_SHL_LOAD)
- DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+ DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
use_gnupg_extensions=yes
dnl -----------------
dnl DLD is not ready for use. So I better disable this test
dnl
dnl AC_CHECK_LIB(dld,dld_link)
dnl if test "$ac_cv_lib_dld_dld_link" = "yes"; then
dnl AC_DEFINE(USE_DYNAMIC_LINKING)
dnl AC_DEFINE(HAVE_DLD_DLD_LINK)
-dnl DYNLINK_LDFLAGS="$CFLAGS_RDYNAMIC"
+dnl DYNLINK_LDFLAGS="$CFLAGS_EXPORTDYNAMIC"
dnl use_gnupg_extensions=yes
dnl ---------------
fi
fi
fi
else
AC_MSG_CHECKING(for dynamic loading)
DYNLINK_LDFLAGS=
DYNLINK_MOD_CFLAGS=
use_gnupg_extensions=no
AC_MSG_RESULT(has been disabled)
fi
AM_CONDITIONAL(ENABLE_GNUPG_EXTENSIONS, test "$use_gnupg_extensions" = yes )
AC_SUBST(DYNLINK_LDFLAGS)
AC_SUBST(DYNLINK_MOD_CFLAGS)
dnl Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS(unistd.h langinfo.h)
+AC_CHECK_HEADERS(unistd.h langinfo.h termio.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
AC_TYPE_SIGNAL
AC_DECL_SYS_SIGLIST
GNUPG_CHECK_ENDIAN
GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF)
GNUPG_CHECK_TYPEDEF(ushort, HAVE_USHORT_TYPEDEF)
GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF)
GNUPG_CHECK_TYPEDEF(u16, HAVE_U16_TYPEDEF)
GNUPG_CHECK_TYPEDEF(u32, HAVE_U32_TYPEDEF)
AC_CHECK_SIZEOF(unsigned short, 2)
AC_CHECK_SIZEOF(unsigned int, 4)
AC_CHECK_SIZEOF(unsigned long, 4)
+AC_CHECK_SIZEOF(unsigned long long, 0)
if test "$ac_cv_sizeof_unsigned_short" = "0" \
|| test "$ac_cv_sizeof_unsigned_int" = "0" \
|| test "$ac_cv_sizeof_unsigned_long" = "0"; then
AC_MSG_WARN([Hmmm, something is wrong with the sizes - using defaults]);
fi
dnl Checks for library functions.
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap)
-AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit)
+AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit clock_gettime)
AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo)
+AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask)
GNUPG_CHECK_MLOCK
GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
dnl
dnl Check whether we can use Linux capabilities as requested
dnl
if test "$use_capabilities" = "yes" ; then
use_capabilities=no
AC_CHECK_HEADERS(sys/capability.h)
if test "$ac_cv_header_sys_capability_h" = "yes" ; then
AC_CHECK_LIB(cap, cap_init, ac_need_libcap=1)
if test "$ac_cv_lib_cap_cap_init" = "yes"; then
AC_DEFINE(USE_CAPABILITIES)
LIBS="$LIBS -lcap"
use_capabilities=yes
fi
fi
if test "$use_capabilities" = "no" ; then
AC_MSG_WARN([[
***
*** The use of capabilities on this system is not possible.
*** You need a recent Linux kernel and some patches:
*** fcaps-2.2.9-990610.patch (kernel patch for 2.2.9)
*** fcap-module-990613.tar.gz (kernel module)
*** libcap-1.92.tar.gz (user mode library and utilities)
*** And you have to configure the kernel with CONFIG_VFS_CAP_PLUGIN
*** set (filesystems menu). Be warned: This code is *really* ALPHA.
***]])
fi
fi
GNUPG_CHECK_IPC
if test "$ac_cv_header_sys_shm_h" = "yes"; then
AC_DEFINE(USE_SHM_COPROCESSING)
fi
dnl
dnl check whether we have a random device
dnl
if test "$try_dev_random" = yes ; then
AC_CACHE_CHECK(for random device, ac_cv_have_dev_random,
[if test -c "$NAME_OF_DEV_RANDOM" && test -c "$NAME_OF_DEV_URANDOM" ; then
ac_cv_have_dev_random=yes; else ac_cv_have_dev_random=no; fi])
if test "$ac_cv_have_dev_random" = yes; then
AC_DEFINE(HAVE_DEV_RANDOM)
fi
else
AC_MSG_CHECKING(for random device)
ac_cv_have_dev_random=no
AC_MSG_RESULT(has been disabled)
fi
dnl
dnl and whether this device supports ioctl
dnl (Note, that we should do a real test here)
dnl
if test "$ac_cv_have_dev_random" = yes ; then
AC_CHECK_HEADERS(linux/random.h)
AC_CACHE_CHECK(for random device ioctl, ac_cv_have_dev_random_ioctl,
[ if test "$ac_cv_header_linux_random_h" = yes ; then
ac_cv_have_dev_random_ioctl=yes;
else
ac_cv_have_dev_random_ioctl=no;
fi
])
if test "$ac_cv_have_dev_random_ioctl" = yes; then
AC_DEFINE(HAVE_DEV_RANDOM_IOCTL)
fi
fi
dnl
dnl Figure out the default linkage mode for cipher modules
dnl
-dnl (We always need a static rmd160)
print_egd_notice=no
-static_modules="$static_modules rmd160"
if test "$use_static_rnd" = default; then
if test "$ac_cv_have_dev_random" = yes; then
- static_modules="$static_modules rndlinux"
+ static_random_module="rndlinux"
else
case "${target}" in
*-*-mingw32)
- static_modules="$static_modules rndw32"
+ static_random_module="rndw32"
AC_DEFINE(USE_STATIC_RNDW32)
;;
i?86-emx-os2|i?86-*-os2*emx)
- static_modules="$static_modules rndos2"
+ static_random_module="rndos2"
;;
m68k-atari-mint)
- static_modules="$static_modules rndatari"
+ static_random_module="rndatari"
;;
i?86-*-msdosdjgpp*)
- static_modules="$static_modules"
+ :
;;
*)
- static_modules="$static_modules rndunix"
+ static_random_module="rndunix"
print_egd_notice=yes
;;
esac
fi
else
if test "$use_static_rnd" = none; then
:
else
- static_modules="$static_modules rnd$use_static_rnd"
+ static_random_module="rnd$use_static_rnd"
if test "$use_static_rnd" = "unix"; then
print_egd_notice=yes
fi
fi
fi
if test "$print_egd_notice" = "yes"; then
AC_MSG_WARN([[
***
*** The performance of the UNIX random gatherer module is not very good
*** and it does not keep the entropy pool over multiple invocations of
*** GnuPG. The suggested way to overcome this problem is to use the
***
*** Entropy Gathering Daemon (EGD)
***
*** which provides a entropy source for the whole system. It is written
*** in Perl and available at the GnuPG FTP servers. For more information
*** consult the GnuPG webpages:
***
*** http://www.gnupg.org/download.html#egd
***
*** You may want to run ./configure with --enable-static-rnd=none to be
*** able to load the EGD client code dynamically; this way you can choose
*** between RNDUNIX and RNDEGD without recompilation.
***]])
fi
dnl
dnl Parse the modules list and build the list
dnl of static and dymically linked modules
dnl
+dnl (We always need a static rmd160)
+static_modules="$static_modules rmd160 $static_random_module"
STATIC_CIPHER_NAMES=""
STATIC_CIPHER_OBJS=""
DYNAMIC_CIPHER_MODS=""
GNUPG_MSG_PRINT([dynamically linked cipher modules:])
for name in $MODULES_IN_CIPHER; do
- x="no"
- for i in $static_modules; do
- if test "$name" = "$i" ; then
- x="yes"
- fi
+ x="yes"
+ for i in $disallowed_modules; do
+ if test "$name" = "$i" ; then x="no" ; fi
done;
if test $x = yes; then
- STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
- STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.lo"
- else
- DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
- GNUPG_MSG_PRINT([$name])
+ x="no"
+ for i in $static_modules; do
+ if test "$name" = "$i" ; then
+ x="yes"
+ fi
+ done;
+ if test $x = yes; then
+ STATIC_CIPHER_NAMES="$STATIC_CIPHER_NAMES $name"
+ STATIC_CIPHER_OBJS="$STATIC_CIPHER_OBJS $name.o"
+ else
+ DYNAMIC_CIPHER_MODS="$DYNAMIC_CIPHER_MODS $name"
+ GNUPG_MSG_PRINT([$name])
+ fi
fi
done
AC_MSG_RESULT()
AC_SUBST(STATIC_CIPHER_OBJS)
AC_SUBST(STATIC_CIPHER_NAMES)
AC_SUBST(DYNAMIC_CIPHER_MODS)
dnl
dnl And build the constructor file
dnl
test -d cipher || mkdir cipher
cat <<G10EOF >cipher/construct.c
/* automatically generated by configure - do not edit */
G10EOF
GNUPG_MSG_PRINT([statically linked cipher modules:])
for name in $STATIC_CIPHER_NAMES; do
echo "void ${name}_constructor(void);" >>cipher/construct.c
GNUPG_MSG_PRINT([$name])
done
AC_MSG_RESULT()
cat <<G10EOF >>cipher/construct.c
void
cipher_modules_constructor(void)
{
static int done = 0;
if( done )
return;
done = 1;
G10EOF
for name in $STATIC_CIPHER_NAMES; do
echo " ${name}_constructor();" >>cipher/construct.c
done
echo '}' >>cipher/construct.c
dnl
dnl Figure how to link the cipher modules
dnl
AC_SUBST(STATIC_CIPHER_OBJS)
AC_SUBST(DYNAMIC_CIPHER_MODS)
dnl setup assembler stuff
AC_MSG_CHECKING(for mpi assembler functions)
if test -f $srcdir/mpi/config.links ; then
. $srcdir/mpi/config.links
GNUPG_LINK_FILES($mpi_ln_src, $mpi_ln_dst)
ac_cv_mpi_extra_asm_modules="$mpi_extra_modules"
ac_cv_mpi_sflags="$mpi_sflags"
ac_cv_mpi_config_done="yes"
AC_MSG_RESULT(done)
else
AC_MSG_RESULT(failed)
AC_MSG_ERROR([mpi/config.links missing!])
fi
MPI_EXTRA_ASM_OBJS=""
if test "$ac_cv_mpi_extra_asm_modules" != ""; then
GNUPG_MSG_PRINT([mpi extra asm functions:])
for i in $ac_cv_mpi_extra_asm_modules; do
GNUPG_MSG_PRINT([$i])
MPI_EXTRA_ASM_OBJS="$MPI_EXTRA_ASM_OBJS $i.lo"
done
AC_MSG_RESULT()
fi
AC_SUBST(MPI_EXTRA_ASM_OBJS)
MPI_SFLAGS="$ac_cv_mpi_sflags"
AC_SUBST(MPI_SFLAGS)
dnl Do we have zlib? Must do it here because Solaris failed
dnl when compiling a conftest (due to the "-lz" from LIBS).
use_local_zlib=yes
if test "$g10_force_zlib" = "yes"; then
:
else
AC_CHECK_HEADERS(zlib.h)
if test "$ac_cv_header_zlib_h" = yes ; then
AC_CHECK_LIB(z,deflateInit2_,use_local_zlib=no,:)
fi
fi
if test "$use_local_zlib" = yes ; then
AM_CONDITIONAL(ENABLE_LOCAL_ZLIB, true)
GNUPG_LINK_FILES(zlib/zlib.h, zlib.h )
GNUPG_LINK_FILES(zlib/zconf.h, zconf.h )
ZLIBS="../zlib/libzlib.a"
else
AM_CONDITIONAL(ENABLE_LOCAL_ZLIB, false)
ZLIBS=
LIBS="-lz $LIBS"
fi
AC_SUBST(ZLIBS)
+# Allow users to append something to the version string without
+# flagging it as development version. The user version parts is
+# considered everything after a dash.
changequote(,)dnl
tmp_pat='[a-zA-Z]'
changequote([,])dnl
if echo "$VERSION" | sed 's/-.*//' | grep "$tmp_pat" >/dev/null ; then
AC_DEFINE(IS_DEVELOPMENT_VERSION)
fi
dnl Temp workarounds:
GNUPG_LINK_FILES(gcrypt/gcrypt.h, gcrypt.h )
GNUPG_LINK_FILES(include/types.h, gcrypt/types.h )
AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
GNUPG_DO_LINK_FILES
+GNUPG_CHECK_GNUMAKE
+
+if test "$GCC" = yes; then
+ if test "$MAINTAINER_MODE" = "yes"; then
+ CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes"
+ else
+ CFLAGS="$CFLAGS -Wall"
+ fi
+fi
+
dnl
dnl Make the version number in gcrypt/gcrypt.h the same as the one here.
dnl (this is easier than to have a .in file just for one substitution)
dnl
GNUPG_FIX_HDR_VERSION(gcrypt/gcrypt.h, GCRYPT_VERSION)
+GCRYPT_LIBS="-L${libdir} -lgcrypt"
+GCRYPT_CFLAGS=""
+AC_SUBST(GCRYPT_LIBS)
+AC_SUBST(GCRYPT_CFLAGS)
AC_OUTPUT_COMMANDS([
chmod +x scripts/db2html
chmod +x gcrypt/gcrypt-config
cat >gnupg-defs.tmp <<G10EOF
/* Generated automatically by configure */
#ifdef HAVE_DRIVE_LETTERS
#define GNUPG_LOCALEDIR "c:/lib/gnupg/locale"
#define GNUPG_LIBDIR "c:/lib/gnupg"
#define GNUPG_DATADIR "c:/lib/gnupg"
#else
#define GNUPG_LOCALEDIR "${prefix}/${DATADIRNAME}/locale"
#define GNUPG_LIBDIR "${libdir}/gnupg"
#define GNUPG_DATADIR "${datadir}/gnupg"
#endif
G10EOF
if cmp -s gnupg-defs.h gnupg-defs.tmp 2>/dev/null; then
echo "gnupg-defs.h is unchanged"
rm -f gnupg-defs.tmp
else
rm -f gnupg-defs.h
mv gnupg-defs.tmp gnupg-defs.h
echo "gnupg-defs.h created"
fi
],[
prefix=$prefix
exec_prefix=$exec_prefix
libdir=$libdir
datadir=$datadir
DATADIRNAME=$DATADIRNAME
])
AC_OUTPUT([
Makefile
scripts/db2html
intl/Makefile
po/Makefile.in
jnlib/Makefile
util/Makefile
mpi/Makefile
cipher/Makefile
g10/Makefile
doc/Makefile
doc/version.sgml
tools/Makefile
zlib/Makefile
checks/Makefile
gcrypt/Makefile
gcrypt/gcrypt-config
])
dnl *-*wedit:notab*-* Please keep this as the last line.
diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog
index a41901bf..5bb8faf3 100644
--- a/jnlib/ChangeLog
+++ b/jnlib/ChangeLog
@@ -1,14 +1,20 @@
+Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+
+ * argparse.c (default_strusage): Changed year of default copyright.
+
+ * dotlock.c (disable_dotlock): New.
+
Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
* README: New.
* Makefile.am: new.
* argparse.c argparse.h logging.c logging.h
mischelp.h stringhelp.c stringhelp.h xmalloc.c
xmalloc.h dotlock.c: Moved from ../util to here.
* dotlock.h: New.
* libjnlib-config.h: New.
* logging.c (log_set_file): New.
(log_printf): New.
(do_logv): Add kludge to insert LFs.
diff --git a/jnlib/argparse.c b/jnlib/argparse.c
index 3f778053..6293d3eb 100644
--- a/jnlib/argparse.c
+++ b/jnlib/argparse.c
@@ -1,994 +1,994 @@
/* [argparse.c wk 17.06.97] Argument Parser for option handling
- * Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "libjnlib-config.h"
#include "mischelp.h"
#include "stringhelp.h"
#include "logging.h"
#include "argparse.h"
/*********************************
* @Summary arg_parse
* #include <wk/lib.h>
*
* typedef struct {
* char *argc; pointer to argc (value subject to change)
* char ***argv; pointer to argv (value subject to change)
* unsigned flags; Global flags (DO NOT CHANGE)
* int err; print error about last option
* 1 = warning, 2 = abort
* int r_opt; return option
* int r_type; type of return value (0 = no argument found)
* union {
* int ret_int;
* long ret_long
* ulong ret_ulong;
* char *ret_str;
* } r; Return values
* struct {
* int idx;
* const char *last;
* void *aliases;
* } internal; DO NOT CHANGE
* } ARGPARSE_ARGS;
*
* typedef struct {
* int short_opt;
* const char *long_opt;
* unsigned flags;
* } ARGPARSE_OPTS;
*
* int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
*
* @Description
* This is my replacement for getopt(). See the example for a typical usage.
* Global flags are:
* Bit 0 : Do not remove options form argv
* Bit 1 : Do not stop at last option but return other args
* with r_opt set to -1.
* Bit 2 : Assume options and real args are mixed.
* Bit 3 : Do not use -- to stop option processing.
* Bit 4 : Do not skip the first arg.
* Bit 5 : allow usage of long option with only one dash
* Bit 6 : ignore --version
* all other bits must be set to zero, this value is modified by the
* function, so assume this is write only.
* Local flags (for each option):
* Bit 2-0 : 0 = does not take an argument
* 1 = takes int argument
* 2 = takes string argument
* 3 = takes long argument
* 4 = takes ulong argument
* Bit 3 : argument is optional (r_type will the be set to 0)
* Bit 4 : allow 0x etc. prefixed values.
* Bit 7 : this is a command and not an option
* You stop the option processing by setting opts to NULL, the function will
* then return 0.
* @Return Value
* Returns the args.r_opt or 0 if ready
* r_opt may be -2/-7 to indicate an unknown option/command.
* @See Also
* ArgExpand
* @Notes
* You do not need to process the options 'h', '--help' or '--version'
* because this function includes standard help processing; but if you
* specify '-h', '--help' or '--version' you have to do it yourself.
* The option '--' stops argument processing; if bit 1 is set the function
* continues to return normal arguments.
* To process float args or unsigned args you must use a string args and do
* the conversion yourself.
* @Example
*
* ARGPARSE_OPTS opts[] = {
* { 'v', "verbose", 0 },
* { 'd', "debug", 0 },
* { 'o', "output", 2 },
* { 'c', "cross-ref", 2|8 },
* { 'm', "my-option", 1|8 },
* { 500, "have-no-short-option-for-this-long-option", 0 },
* {0} };
* ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
*
* while( ArgParse( &pargs, &opts) ) {
* switch( pargs.r_opt ) {
* case 'v': opt.verbose++; break;
* case 'd': opt.debug++; break;
* case 'o': opt.outfile = pargs.r.ret_str; break;
* case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
* case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
* case 500: opt.a_long_one++; break
* default : pargs.err = 1; break; -- force warning output --
* }
* }
* if( argc > 1 )
* log_fatal( "Too many args");
*
*/
typedef struct alias_def_s *ALIAS_DEF;
struct alias_def_s {
ALIAS_DEF next;
char *name; /* malloced buffer with name, \0, value */
const char *value; /* ptr into name */
};
static const char *(*strusage_handler)( int ) = NULL;
static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
static void show_version(void);
static void
initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
{
if( !(arg->flags & (1<<15)) ) { /* initialize this instance */
arg->internal.idx = 0;
arg->internal.last = NULL;
arg->internal.inarg = 0;
arg->internal.stopped = 0;
arg->internal.aliases = NULL;
arg->internal.cur_alias = NULL;
arg->err = 0;
arg->flags |= 1<<15; /* mark initialized */
if( *arg->argc < 0 )
jnlib_log_bug("Invalid argument for ArgParse\n");
}
if( arg->err ) { /* last option was erroneous */
const char *s;
if( filename ) {
if( arg->r_opt == -6 )
s = "%s:%u: argument not expected\n";
else if( arg->r_opt == -5 )
s = "%s:%u: read error\n";
else if( arg->r_opt == -4 )
s = "%s:%u: keyword too long\n";
else if( arg->r_opt == -3 )
s = "%s:%u: missing argument\n";
else if( arg->r_opt == -7 )
s = "%s:%u: invalid command\n";
else if( arg->r_opt == -10 )
s = "%s:%u: invalid alias definition\n";
else
s = "%s:%u: invalid option\n";
jnlib_log_error(s, filename, *lineno );
}
else {
if( arg->r_opt == -3 )
s = "Missing argument for option \"%.50s\"\n";
else if( arg->r_opt == -6 )
s = "Option \"%.50s\" does not expect an argument\n";
else if( arg->r_opt == -7 )
s = "Invalid command \"%.50s\"\n";
else if( arg->r_opt == -8 )
s = "Option \"%.50s\" is ambiguous\n";
else if( arg->r_opt == -9 )
s = "Command \"%.50s\" is ambiguous\n";
else
s = "Invalid option \"%.50s\"\n";
jnlib_log_error(s, arg->internal.last? arg->internal.last:"[??]" );
}
if( arg->err != 1 )
exit(2);
arg->err = 0;
}
/* clearout the return value union */
arg->r.ret_str = NULL;
arg->r.ret_long= 0;
}
static void
store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
{
/* TODO: replace this dummy function with a rea one
* and fix the probelms IRIX has with (ALIAS_DEV)arg..
* used as lvalue
*/
#if 0
ALIAS_DEF a = jnlib_xmalloc( sizeof *a );
a->name = name;
a->value = value;
a->next = (ALIAS_DEF)arg->internal.aliases;
(ALIAS_DEF)arg->internal.aliases = a;
#endif
}
/****************
* Get options from a file.
* Lines starting with '#' are comment lines.
* Syntax is simply a keyword and the argument.
* Valid keywords are all keywords from the long_opt list without
* the leading dashes. The special keywords "help", "warranty" and "version"
* are not valid here.
* The special keyword "alias" may be used to store alias definitions,
* which are later expanded like long options.
* Caller must free returned strings.
* If called with FP set to NULL command line args are parse instead.
*
* Q: Should we allow the syntax
* keyword = value
* and accept for boolean options a value of 1/0, yes/no or true/false?
* Note: Abbreviation of options is here not allowed.
*/
int
optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
{
int state, i, c;
int idx=0;
char keyword[100];
char *buffer = NULL;
size_t buflen = 0;
int inverse=0;
int in_alias=0;
if( !fp ) /* same as arg_parse() in this case */
return arg_parse( arg, opts );
initialize( arg, filename, lineno );
/* find the next keyword */
state = i = 0;
for(;;) {
c=getc(fp);
if( c == '\n' || c== EOF ) {
if( c != EOF )
++*lineno;
if( state == -1 )
break;
else if( state == 2 ) {
keyword[i] = 0;
for(i=0; opts[i].short_opt; i++ )
if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
break;
idx = i;
arg->r_opt = opts[idx].short_opt;
if( inverse ) /* this does not have an effect, hmmm */
arg->r_opt = -arg->r_opt;
if( !opts[idx].short_opt ) /* unknown command/option */
arg->r_opt = (opts[idx].flags & 256)? -7:-2;
else if( (opts[idx].flags & 8) ) /* no argument */
arg->r_opt = -3; /* error */
else /* no or optional argument */
arg->r_type = 0; /* okay */
break;
}
else if( state == 3 ) { /* no argument found */
if( in_alias )
arg->r_opt = -3; /* error */
else if( !(opts[idx].flags & 7) ) /* does not take an arg */
arg->r_type = 0; /* okay */
else if( (opts[idx].flags & 8) ) /* no optional argument */
arg->r_type = 0; /* okay */
else /* no required argument */
arg->r_opt = -3; /* error */
break;
}
else if( state == 4 ) { /* have an argument */
if( in_alias ) {
if( !buffer )
arg->r_opt = -6;
else {
char *p;
buffer[i] = 0;
p = strpbrk( buffer, " \t" );
if( p ) {
*p++ = 0;
trim_spaces( p );
}
if( !p || !*p ) {
jnlib_free( buffer );
arg->r_opt = -10;
}
else {
store_alias( arg, buffer, p );
}
}
}
else if( !(opts[idx].flags & 7) ) /* does not take an arg */
arg->r_opt = -6; /* error */
else {
char *p;
if( !buffer ) {
keyword[i] = 0;
buffer = jnlib_xstrdup(keyword);
}
else
buffer[i] = 0;
trim_spaces( buffer );
p = buffer;
if( *p == '"' ) { /* remove quotes */
p++;
if( *p && p[strlen(p)-1] == '"' )
p[strlen(p)-1] = 0;
}
if( !set_opt_arg(arg, opts[idx].flags, p) )
jnlib_free(buffer);
}
break;
}
else if( c == EOF ) {
if( ferror(fp) )
arg->r_opt = -5; /* read error */
else
arg->r_opt = 0; /* eof */
break;
}
state = 0;
i = 0;
}
else if( state == -1 )
; /* skip */
else if( !state && isspace(c) )
; /* skip leading white space */
else if( !state && c == '#' )
state = 1; /* start of a comment */
else if( state == 1 )
; /* skip comments */
else if( state == 2 && isspace(c) ) {
keyword[i] = 0;
for(i=0; opts[i].short_opt; i++ )
if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
break;
idx = i;
arg->r_opt = opts[idx].short_opt;
if( !opts[idx].short_opt ) {
if( !strcmp( keyword, "alias" ) ) {
in_alias = 1;
state = 3;
}
else {
arg->r_opt = (opts[idx].flags & 256)? -7:-2;
state = -1; /* skip rest of line and leave */
}
}
else
state = 3;
}
else if( state == 3 ) { /* skip leading spaces of the argument */
if( !isspace(c) ) {
i = 0;
keyword[i++] = c;
state = 4;
}
}
else if( state == 4 ) { /* collect the argument */
if( buffer ) {
if( i < buflen-1 )
buffer[i++] = c;
else {
buflen += 50;
buffer = jnlib_xrealloc(buffer, buflen);
buffer[i++] = c;
}
}
else if( i < DIM(keyword)-1 )
keyword[i++] = c;
else {
buflen = DIM(keyword)+50;
buffer = jnlib_xmalloc(buflen);
memcpy(buffer, keyword, i);
buffer[i++] = c;
}
}
else if( i >= DIM(keyword)-1 ) {
arg->r_opt = -4; /* keyword to long */
state = -1; /* skip rest of line and leave */
}
else {
keyword[i++] = c;
state = 2;
}
}
return arg->r_opt;
}
static int
find_long_option( ARGPARSE_ARGS *arg,
ARGPARSE_OPTS *opts, const char *keyword )
{
int i;
size_t n;
/* Would be better if we can do a binary search, but it is not
possible to reorder our option table because we would mess
up our help strings - What we can do is: Build a nice option
lookup table wehn this function is first invoked */
if( !*keyword )
return -1;
for(i=0; opts[i].short_opt; i++ )
if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
return i;
#if 0
{
ALIAS_DEF a;
/* see whether it is an alias */
for( a = args->internal.aliases; a; a = a->next ) {
if( !strcmp( a->name, keyword) ) {
/* todo: must parse the alias here */
args->internal.cur_alias = a;
return -3; /* alias available */
}
}
}
#endif
/* not found, see whether it is an abbreviation */
/* aliases may not be abbreviated */
n = strlen( keyword );
for(i=0; opts[i].short_opt; i++ ) {
if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
int j;
for(j=i+1; opts[j].short_opt; j++ ) {
if( opts[j].long_opt
&& !strncmp( opts[j].long_opt, keyword, n ) )
return -2; /* abbreviation is ambiguous */
}
return i;
}
}
return -1;
}
int
arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
{
int idx;
int argc;
char **argv;
char *s, *s2;
int i;
initialize( arg, NULL, NULL );
argc = *arg->argc;
argv = *arg->argv;
idx = arg->internal.idx;
if( !idx && argc && !(arg->flags & (1<<4)) ) { /* skip the first entry */
argc--; argv++; idx++;
}
next_one:
if( !argc ) { /* no more args */
arg->r_opt = 0;
goto leave; /* ready */
}
s = *argv;
arg->internal.last = s;
if( arg->internal.stopped && (arg->flags & (1<<1)) ) {
arg->r_opt = -1; /* not an option but a argument */
arg->r_type = 2;
arg->r.ret_str = s;
argc--; argv++; idx++; /* set to next one */
}
else if( arg->internal.stopped ) { /* ready */
arg->r_opt = 0;
goto leave;
}
else if( *s == '-' && s[1] == '-' ) { /* long option */
char *argpos;
arg->internal.inarg = 0;
if( !s[2] && !(arg->flags & (1<<3)) ) { /* stop option processing */
arg->internal.stopped = 1;
argc--; argv++; idx++;
goto next_one;
}
argpos = strchr( s+2, '=' );
if( argpos )
*argpos = 0;
i = find_long_option( arg, opts, s+2 );
if( argpos )
*argpos = '=';
if( i < 0 && !strcmp( "help", s+2) )
show_help(opts, arg->flags);
else if( i < 0 && !strcmp( "version", s+2) ) {
if( !(arg->flags & (1<<6)) ) {
show_version();
exit(0);
}
}
else if( i < 0 && !strcmp( "warranty", s+2) ) {
puts( strusage(16) );
exit(0);
}
else if( i < 0 && !strcmp( "dump-options", s+2) ) {
for(i=0; opts[i].short_opt; i++ ) {
if( opts[i].long_opt )
printf( "--%s\n", opts[i].long_opt );
}
fputs("--dump-options\n--help\n--version\n--warranty\n", stdout );
exit(0);
}
if( i == -2 ) /* ambiguous option */
arg->r_opt = -8;
else if( i == -1 ) {
arg->r_opt = -2;
arg->r.ret_str = s+2;
}
else
arg->r_opt = opts[i].short_opt;
if( i < 0 )
;
else if( (opts[i].flags & 7) ) {
if( argpos ) {
s2 = argpos+1;
if( !*s2 )
s2 = NULL;
}
else
s2 = argv[1];
if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
arg->r_type = 0; /* because it is optional */
}
else if( !s2 ) {
arg->r_opt = -3; /* missing argument */
}
else if( !argpos && *s2 == '-' && (opts[i].flags & 8) ) {
/* the argument is optional and the next seems to be
* an option. We do not check this possible option
* but assume no argument */
arg->r_type = 0;
}
else {
set_opt_arg(arg, opts[i].flags, s2);
if( !argpos ) {
argc--; argv++; idx++; /* skip one */
}
}
}
else { /* does not take an argument */
if( argpos )
arg->r_type = -6; /* argument not expected */
else
arg->r_type = 0;
}
argc--; argv++; idx++; /* set to next one */
}
else if( (*s == '-' && s[1]) || arg->internal.inarg ) { /* short option */
int dash_kludge = 0;
i = 0;
if( !arg->internal.inarg ) {
arg->internal.inarg++;
if( arg->flags & (1<<5) ) {
for(i=0; opts[i].short_opt; i++ )
if( opts[i].long_opt && !strcmp( opts[i].long_opt, s+1)) {
dash_kludge=1;
break;
}
}
}
s += arg->internal.inarg;
if( !dash_kludge ) {
for(i=0; opts[i].short_opt; i++ )
if( opts[i].short_opt == *s )
break;
}
if( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
show_help(opts, arg->flags);
arg->r_opt = opts[i].short_opt;
if( !opts[i].short_opt ) {
arg->r_opt = (opts[i].flags & 256)? -7:-2;
arg->internal.inarg++; /* point to the next arg */
arg->r.ret_str = s;
}
else if( (opts[i].flags & 7) ) {
if( s[1] && !dash_kludge ) {
s2 = s+1;
set_opt_arg(arg, opts[i].flags, s2);
}
else {
s2 = argv[1];
if( !s2 && (opts[i].flags & 8) ) { /* no argument but it is okay*/
arg->r_type = 0; /* because it is optional */
}
else if( !s2 ) {
arg->r_opt = -3; /* missing argument */
}
else if( *s2 == '-' && s2[1] && (opts[i].flags & 8) ) {
/* the argument is optional and the next seems to be
* an option. We do not check this possible option
* but assume no argument */
arg->r_type = 0;
}
else {
set_opt_arg(arg, opts[i].flags, s2);
argc--; argv++; idx++; /* skip one */
}
}
s = "x"; /* so that !s[1] yields false */
}
else { /* does not take an argument */
arg->r_type = 0;
arg->internal.inarg++; /* point to the next arg */
}
if( !s[1] || dash_kludge ) { /* no more concatenated short options */
arg->internal.inarg = 0;
argc--; argv++; idx++;
}
}
else if( arg->flags & (1<<2) ) {
arg->r_opt = -1; /* not an option but a argument */
arg->r_type = 2;
arg->r.ret_str = s;
argc--; argv++; idx++; /* set to next one */
}
else {
arg->internal.stopped = 1; /* stop option processing */
goto next_one;
}
leave:
*arg->argc = argc;
*arg->argv = argv;
arg->internal.idx = idx;
return arg->r_opt;
}
static int
set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
{
int base = (flags & 16)? 0 : 10;
switch( arg->r_type = (flags & 7) ) {
case 1: /* takes int argument */
arg->r.ret_int = (int)strtol(s,NULL,base);
return 0;
case 3: /* takes long argument */
arg->r.ret_long= strtol(s,NULL,base);
return 0;
case 4: /* takes ulong argument */
arg->r.ret_ulong= strtoul(s,NULL,base);
return 0;
case 2: /* takes string argument */
default:
arg->r.ret_str = s;
return 1;
}
}
static size_t
long_opt_strlen( ARGPARSE_OPTS *o )
{
size_t n = strlen(o->long_opt);
if( o->description && *o->description == '|' ) {
const char *s;
s=o->description+1;
if( *s != '=' )
n++;
for(; *s && *s != '|'; s++ )
n++;
}
return n;
}
/****************
* Print formatted help. The description string has some special
* meanings:
* - A description string which is "@" suppresses help output for
* this option
* - a description,ine which starts with a '@' and is followed by
* any other characters is printed as is; this may be used for examples
* ans such.
* - A description which starts with a '|' outputs the string between this
* bar and the next one as arguments of the long option.
*/
static void
show_help( ARGPARSE_OPTS *opts, unsigned flags )
{
const char *s;
show_version();
putchar('\n');
s = strusage(41);
puts(s);
if( opts[0].description ) { /* auto format the option description */
int i,j, indent;
/* get max. length of long options */
for(i=indent=0; opts[i].short_opt; i++ ) {
if( opts[i].long_opt )
if( !opts[i].description || *opts[i].description != '@' )
if( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
indent = j;
}
/* example: " -v, --verbose Viele Sachen ausgeben" */
indent += 10;
if( *opts[0].description != '@' )
puts("Options:");
for(i=0; opts[i].short_opt; i++ ) {
s = _( opts[i].description );
if( s && *s== '@' && !s[1] ) /* hide this line */
continue;
if( s && *s == '@' ) { /* unindented comment only line */
for(s++; *s; s++ ) {
if( *s == '\n' ) {
if( s[1] )
putchar('\n');
}
else
putchar(*s);
}
putchar('\n');
continue;
}
j = 3;
if( opts[i].short_opt < 256 ) {
printf(" -%c", opts[i].short_opt );
if( !opts[i].long_opt ) {
if(s && *s == '|' ) {
putchar(' '); j++;
for(s++ ; *s && *s != '|'; s++, j++ )
putchar(*s);
if( *s )
s++;
}
}
}
else
fputs(" ", stdout);
if( opts[i].long_opt ) {
j += printf("%c --%s", opts[i].short_opt < 256?',':' ',
opts[i].long_opt );
if(s && *s == '|' ) {
if( *++s != '=' ) {
putchar(' ');
j++;
}
for( ; *s && *s != '|'; s++, j++ )
putchar(*s);
if( *s )
s++;
}
fputs(" ", stdout);
j += 3;
}
for(;j < indent; j++ )
putchar(' ');
if( s ) {
if( *s && j > indent ) {
putchar('\n');
for(j=0;j < indent; j++ )
putchar(' ');
}
for(; *s; s++ ) {
if( *s == '\n' ) {
if( s[1] ) {
putchar('\n');
for(j=0;j < indent; j++ )
putchar(' ');
}
}
else
putchar(*s);
}
}
putchar('\n');
}
if( flags & 32 )
puts("\n(A single dash may be used instead of the double ones)");
}
if( (s=strusage(19)) ) { /* bug reports to ... */
putchar('\n');
fputs(s, stdout);
}
fflush(stdout);
exit(0);
}
static void
show_version()
{
const char *s;
int i;
/* version line */
fputs(strusage(11), stdout);
if( (s=strusage(12)) )
printf(" (%s)", s );
printf(" %s\n", strusage(13) );
/* additional version lines */
for(i=20; i < 30; i++ )
if( (s=strusage(i)) )
printf("%s\n", s );
/* copyright string */
if( (s=strusage(14)) )
printf("%s\n", s );
/* copying conditions */
if( (s=strusage(15)) )
fputs(s, stdout);
/* thanks */
if( (s=strusage(18)) )
fputs(s, stdout);
/* additional program info */
for(i=30; i < 40; i++ )
if( (s=strusage(i)) )
fputs( (const byte*)s, stdout);
fflush(stdout);
}
void
usage( int level )
{
if( !level ) {
fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
strusage(14) );
fflush(stderr);
}
else if( level == 1 ) {
fputs(strusage(40),stderr);
exit(2);
}
else if( level == 2 ) {
puts(strusage(41));
exit(0);
}
}
/* Level
* 0: Copyright String auf stderr ausgeben
* 1: Kurzusage auf stderr ausgeben und beenden
* 2: Langusage auf stdout ausgeben und beenden
* 11: name of program
* 12: optional name of package which includes this program.
* 13: version string
* 14: copyright string
* 15: Short copying conditions (with LFs)
* 16: Long copying conditions (with LFs)
* 17: Optional printable OS name
* 18: Optional thanks list (with LFs)
* 19: Bug report info
*20..29: Additional lib version strings.
*30..39: Additional program info (with LFs)
* 40: short usage note (with LF)
* 41: long usage note (with LF)
*/
const char *
strusage( int level )
{
const char *p = strusage_handler? strusage_handler(level) : NULL;
if( p )
return p;
switch( level ) {
case 11: p = "foo"; break;
case 13: p = "0.0"; break;
- case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break;
+ case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break;
case 15: p =
"This program comes with ABSOLUTELY NO WARRANTY.\n"
"This is free software, and you are welcome to redistribute it\n"
"under certain conditions. See the file COPYING for details.\n"; break;
case 16: p =
"This is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"(at your option) any later version.\n\n"
"It is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n";
break;
case 40: /* short and long usage */
case 41: p = ""; break;
}
return p;
}
void
set_strusage( const char *(*f)( int ) )
{
strusage_handler = f;
}
#ifdef TEST
static struct {
int verbose;
int debug;
char *outfile;
char *crf;
int myopt;
int echo;
int a_long_one;
}opt;
int
main(int argc, char **argv)
{
ARGPARSE_OPTS opts[] = {
{ 'v', "verbose", 0 , "Laut sein"},
{ 'e', "echo" , 0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
{ 'd', "debug", 0 , "Debug\nfalls mal etasws\nSchief geht"},
{ 'o', "output", 2 },
{ 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
{ 'm', "my-option", 1|8 },
{ 500, "a-long-option", 0 },
{0} };
ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
int i;
while( ArgParse( &pargs, opts) ) {
switch( pargs.r_opt ) {
case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break;
case 'v': opt.verbose++; break;
case 'e': opt.echo++; break;
case 'd': opt.debug++; break;
case 'o': opt.outfile = pargs.r.ret_str; break;
case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
case 500: opt.a_long_one++; break;
default : pargs.err = 1; break; /* force warning output */
}
}
for(i=0; i < argc; i++ )
printf("%3d -> (%s)\n", i, argv[i] );
puts("Options:");
if( opt.verbose )
printf(" verbose=%d\n", opt.verbose );
if( opt.debug )
printf(" debug=%d\n", opt.debug );
if( opt.outfile )
printf(" outfile=`%s'\n", opt.outfile );
if( opt.crf )
printf(" crffile=`%s'\n", opt.crf );
if( opt.myopt )
printf(" myopt=%d\n", opt.myopt );
if( opt.a_long_one )
printf(" a-long-one=%d\n", opt.a_long_one );
if( opt.echo )
printf(" echo=%d\n", opt.echo );
return 0;
}
#endif
/**** bottom of file ****/
diff --git a/jnlib/dotlock.c b/jnlib/dotlock.c
index 8e61f7a0..29ab65df 100644
--- a/jnlib/dotlock.c
+++ b/jnlib/dotlock.c
@@ -1,346 +1,374 @@
/* dotlock.c - dotfile locking
- * Copyright (C) 1998,2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#ifndef HAVE_DOSISH_SYSTEM
#include <sys/utsname.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include "libjnlib-config.h"
#include "dotlock.h"
struct dotlock_handle {
struct dotlock_handle *next;
char *tname; /* name of lockfile template */
char *lockname; /* name of the real lockfile */
int locked; /* lock status */
+ int disable; /* locking */
};
static DOTLOCK all_lockfiles;
+static int never_lock;
static int read_lockfile( const char *name );
static void remove_lockfiles(void);
+void
+disable_dotlock(void)
+{
+ never_lock = 1;
+}
+
/****************
* Create a lockfile with the given name and return an object of
* type DOTLOCK which may be used later to actually do the lock.
* A cleanup routine gets installed to cleanup left over locks
* or other files used together with the lockmechanism.
* Althoug the function is called dotlock, this does not necessarily
* mean that real lockfiles are used - the function may decide to
* use fcntl locking. Calling the function with NULL only install
* the atexit handler and maybe used to assure that the cleanup
* is called after all other atexit handlers.
*
* Notes: This function creates a lock file in the same directory
* as file_to_lock with the name "file_to_lock.lock"
* A temporary file ".#lk.<hostname>.pid[.threadid] is used.
* This function does nothing for Windoze.
*/
DOTLOCK
create_dotlock( const char *file_to_lock )
{
static int initialized;
DOTLOCK h;
int fd = -1;
char pidstr[16];
#ifndef HAVE_DOSISH_SYSTEM
struct utsname utsbuf;
#endif
const char *nodename;
const char *dirpart;
int dirpartlen;
if( !initialized ) {
atexit( remove_lockfiles );
initialized = 1;
}
if( !file_to_lock )
return NULL;
h = jnlib_xcalloc( 1, sizeof *h );
+ if( never_lock ) {
+ h->disable = 1;
+ #ifdef _REENTRANT
+ /* fixme: aquire mutex on all_lockfiles */
+ #endif
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+ return h;
+ }
+
#ifndef HAVE_DOSISH_SYSTEM
sprintf( pidstr, "%10d\n", (int)getpid() );
/* fixme: add the hostname to the second line (FQDN or IP addr?) */
/* create a temporary file */
if( uname( &utsbuf ) )
nodename = "unknown";
else
nodename = utsbuf.nodename;
if( !(dirpart = strrchr( file_to_lock, '/' )) ) {
dirpart = ".";
dirpartlen = 1;
}
else {
dirpartlen = dirpart - file_to_lock;
dirpart = file_to_lock;
}
#ifdef _REENTRANT
/* fixme: aquire mutex on all_lockfiles */
#endif
h->next = all_lockfiles;
all_lockfiles = h;
h->tname = jnlib_xmalloc( dirpartlen + 6+30+ strlen(nodename) + 11 );
sprintf( h->tname, "%.*s/.#lk%p.%s.%d",
dirpartlen, dirpart, h, nodename, (int)getpid() );
do {
errno = 0;
fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
} while( fd == -1 && errno == EINTR );
if( fd == -1 ) {
all_lockfiles = h->next;
log_error( "failed to create temporary file `%s': %s\n",
h->tname, strerror(errno));
jnlib_free(h->tname);
jnlib_free(h);
return NULL;
}
if( write(fd, pidstr, 11 ) != 11 ) {
all_lockfiles = h->next;
#ifdef _REENTRANT
/* release mutex */
#endif
log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) );
close(fd);
unlink(h->tname);
jnlib_free(h->tname);
jnlib_free(h);
return NULL;
}
if( close(fd) ) {
all_lockfiles = h->next;
#ifdef _REENTRANT
/* release mutex */
#endif
log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
unlink(h->tname);
jnlib_free(h->tname);
jnlib_free(h);
return NULL;
}
#ifdef _REENTRANT
/* release mutex */
#endif
#endif /* !HAVE_DOSISH_SYSTEM */
h->lockname = jnlib_xmalloc( strlen(file_to_lock) + 6 );
strcpy(stpcpy(h->lockname, file_to_lock), ".lock");
return h;
}
static int
maybe_deadlock( DOTLOCK h )
{
DOTLOCK r;
for( r=all_lockfiles; r; r = r->next ) {
if( r != h && r->locked )
return 1;
}
return 0;
}
/****************
* Do a lock on H. A TIMEOUT of 0 returns immediately,
* -1 waits forever (hopefully not), other
* values are timeouts in milliseconds.
* Returns: 0 on success
*/
int
make_dotlock( DOTLOCK h, long timeout )
{
#ifdef HAVE_DOSISH_SYSTEM
return 0;
#else
int pid;
const char *maybe_dead="";
int backoff=0;
+ if( h->disable ) {
+ return 0;
+ }
+
if( h->locked ) {
log_debug("oops, `%s' is already locked\n", h->lockname );
return 0;
}
for(;;) {
if( !link(h->tname, h->lockname) ) {
/* fixme: better use stat to check the link count */
h->locked = 1;
return 0; /* okay */
}
if( errno != EEXIST ) {
log_error( "lock not made: link() failed: %s\n", strerror(errno) );
return -1;
}
if( (pid = read_lockfile(h->lockname)) == -1 ) {
if( errno != ENOENT ) {
log_info("cannot read lockfile\n");
return -1;
}
log_info( "lockfile disappeared\n");
continue;
}
else if( pid == getpid() ) {
log_info( "Oops: lock already hold by us\n");
h->locked = 1;
return 0; /* okay */
}
else if( kill(pid, 0) && errno == ESRCH ) {
maybe_dead = " - probably dead";
#if 0 /* we should not do this without checking the permissions */
/* and the hostname */
log_info( "removing stale lockfile (created by %d)", pid );
#endif
}
if( timeout == -1 ) {
struct timeval tv;
log_info( "waiting for lock (hold by %d%s) %s...\n",
pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
/* can't use sleep, cause signals may be blocked */
tv.tv_sec = 1 + backoff;
tv.tv_usec = 0;
select(0, NULL, NULL, NULL, &tv);
if( backoff < 10 )
backoff++ ;
}
else
return -1;
}
/*not reached */
#endif /* !HAVE_DOSISH_SYSTEM */
}
/****************
* release a lock
* Returns: 0 := success
*/
int
release_dotlock( DOTLOCK h )
{
#ifdef HAVE_DOSISH_SYSTEM
return 0;
#else
int pid;
+ if( h->disable ) {
+ return 0;
+ }
+
if( !h->locked ) {
log_debug("oops, `%s' is not locked\n", h->lockname );
return 0;
}
pid = read_lockfile( h->lockname );
if( pid == -1 ) {
log_error( "release_dotlock: lockfile error\n");
return -1;
}
if( pid != getpid() ) {
log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
return -1;
}
if( unlink( h->lockname ) ) {
log_error( "release_dotlock: error removing lockfile `%s'",
h->lockname);
return -1;
}
/* fixme: check that the link count is now 1 */
h->locked = 0;
return 0;
#endif /* !HAVE_DOSISH_SYSTEM */
}
/****************
* Read the lock file and return the pid, returns -1 on error.
*/
static int
read_lockfile( const char *name )
{
#ifdef HAVE_DOSISH_SYSTEM
return 0;
#else
int fd, pid;
char pidstr[16];
if( (fd = open(name, O_RDONLY)) == -1 ) {
int e = errno;
log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) );
errno = e;
return -1;
}
if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */
log_debug("error reading lockfile `%s'", name );
close(fd);
errno = 0;
return -1;
}
pidstr[10] = 0; /* terminate pid string */
close(fd);
pid = atoi(pidstr);
if( !pid || pid == -1 ) {
log_error("invalid pid %d in lockfile `%s'", pid, name );
errno = 0;
return -1;
}
return pid;
#endif
}
static void
remove_lockfiles()
{
#ifndef HAVE_DOSISH_SYSTEM
DOTLOCK h, h2;
h = all_lockfiles;
all_lockfiles = NULL;
while( h ) {
h2 = h->next;
- if( h->locked )
- unlink( h->lockname );
- unlink(h->tname);
- jnlib_free(h->tname);
- jnlib_free(h->lockname);
+ if( !h->disable ) {
+ if( h->locked )
+ unlink( h->lockname );
+ unlink(h->tname);
+ jnlib_free(h->tname);
+ jnlib_free(h->lockname);
+ }
jnlib_free(h);
h = h2;
}
#endif
}
diff --git a/jnlib/dotlock.h b/jnlib/dotlock.h
index d54219e2..74ac876f 100644
--- a/jnlib/dotlock.h
+++ b/jnlib/dotlock.h
@@ -1,32 +1,33 @@
/* dotlock.h
* Copyright (C) 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef LIBJNLIB_DOTLOCK_H
#define LIBJNLIB_DOTLOCK_H
struct dotlock_handle;
typedef struct dotlock_handle *DOTLOCK;
+void disable_dotlock(void);
DOTLOCK create_dotlock( const char *file_to_lock );
int make_dotlock( DOTLOCK h, long timeout );
int release_dotlock( DOTLOCK h );
#endif /*LIBJNLIB_DOTLOCK_H*/
diff --git a/src/ChangeLog b/src/ChangeLog
index dda6d393..83d1517c 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,77 +1,89 @@
+Fri Jul 14 19:38:23 CEST 2000 Werner Koch <wk@>
+
+ * gcrypt.h (gcry_md_start_debug, gcry_md_stop_debug): New.
+ (gcry_ctl_cmds): New control values
+
+ * sexp.c (gcry_sexp_sscan): Add hex format parsing.
+
+ * secmem.c (lock_pool): Check for ENOSYS return my mlock() on old SCOs.
+ (pool_is_mmapped): Made volatile.
+ (lock_pool): No more warning for QNX. By Sam Roberts.
+ (lock_pool,secmem_init): Additional check for dropped privs.
+
2000-03-21 09:18:48 Werner Koch (wk@habibti.gnupg.de)
* gcrypt.h (gcry_md_setkey): New.
(GCRY_MD_FLAG_HMAC): New.
Mon Jan 31 16:37:34 CET 2000 Werner Koch <wk@gnupg.de>
* Makefile.am: Add g10lib.h
Thu Jan 27 18:00:44 CET 2000 Werner Koch <wk@gnupg.de>
* sexp.c (gcry_sexp_sscan): Allow NULL for erroff.
Mon Jan 24 22:24:38 CET 2000 Werner Koch <wk@gnupg.de>
* sexp.c (gcry_sexp_alist): New.
Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de>
* secmem.c: Moved from ../util to here.
* secmem.h: New.
* stdmem.c: New. Based on the old ../util/memory.c.
* stdmem.h: New.
Wed Dec 8 21:58:32 CET 1999 Werner Koch <wk@gnupg.de>
* gcrypt.m4: New.
* gcrypt-config: New.
* mpi.h (mpi_get_nbit_info): Removed
(mpi_set_nbit_info): Removed.
(struct gcry_mpi): Removed the nbits field.
* misc.c (g10_log_verbosity): New.
* global.c (g10_xstrdup): New.
* mpiapi.c: Removed.
* mpi.h: Moved from ../include to here. Removed some obsolete
prototypes and the iobuf.h header.
* cipher.h: Moved from ../include to here. Removed the mpi.h header.
* g10lib.h: Moved from ../include to here.
Fri Nov 19 17:15:20 CET 1999 Werner Koch <wk@gnupg.de>
* sexp.c (dump_string): New. Taken from gnupg/util/miscutil.c.
(do_dump_list): s/print_string/dump_string/.
* testapi.c: New.
* mpiapi.c (gcry_mpi_randomize): Use new random API.
Sat Nov 13 17:44:23 CET 1999 Werner Koch <wk@gnupg.de>
* gloabl.c (gcry_control): Add cases for dumping random
and secmem stats.
Tue Oct 26 14:10:21 CEST 1999 Werner Koch <wk@gnupg.de>
* pkapi.c: Removed.
* symapi.c: Removed.
* g10lib.h: Moved to ../include.
* mdapi.c: Removed.
Wed Jul 7 13:08:40 CEST 1999 Werner Koch <wk@isil.d.shuttle.de>
* sexp.c: New.
Tue Dec 8 13:15:16 CET 1998 Werner Koch <wk@isil.d.shuttle.de>
* gcrypt.h: New
* mpiapi.c: New
diff --git a/src/Makefile.am b/src/Makefile.am
index 0681e918..359bc1cf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,50 +1,50 @@
## Process this file with automake to produce Makefile.in
# It seems that we need gcrypt.m4 here too
EXTRA_DIST = gcrypt-config.in gcrypt.m4
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
lib_LTLIBRARIES = libgcrypt.la
bin_SCRIPTS = gcrypt-config
m4datadir = $(datadir)/aclocal
m4data_DATA = gcrypt.m4
-noinst_PROGRAMS = testapi
-#sexp_SOURCES = sexp.c mpiapi.c
-#sexp_LDADD = ../cipher/libcipher.la ../mpi/libmpi.la ../util/libutil.la ./libgcrypt.la @INTLLIBS@
+noinst_PROGRAMS = testapi sexp
+sexp_SOURCES = sexp.c
+sexp_LDADD = libgcrypt.la
testapi_SOURCES = testapi.c
testapi_LDADD = libgcrypt.la
include_HEADERS = gcrypt.h
libgcrypt_la_LDFLAGS = -version-info 0:0:0 -export-symbols libgcrypt.sym
libgcrypt_la_SOURCES = g10lib.h \
mpi.h \
cipher.h \
misc.c \
global.c \
sexp.c \
wrapper.c \
stdmem.c \
stdmem.h \
secmem.c \
secmem.h
libgcrypt_la_DEPENDENCIES = libgcrypt.sym
libgcrypt_la_LIBADD = ../cipher/libcipher.la \
../mpi/libmpi.la
BUILT_SOURCES = libgcrypt.sym
# libtool's --export-symbols-regex does not work in 1.3.2
# so we do it ourself
libgcrypt.sym: $(libgcrypt_la_OBJECTS)
$(NM) $(libgcrypt_la_OBJECTS) \
| $(AWK) '$$2=="T" && $$3 ~ /^gcry_/ {print $$3}' >libgcrypt.sym
diff --git a/src/gcrypt-config.in b/src/gcrypt-config.in
index ab577a91..0f7fffdd 100644
--- a/src/gcrypt-config.in
+++ b/src/gcrypt-config.in
@@ -1,93 +1,93 @@
#!/bin/sh
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+exec_prefix_set=no
gcrypt_libs="@GCRYPT_LIBS@"
gcrypt_cflags="@GCRYPT_CFLAGS@"
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-exec_prefix_set=no
usage()
{
cat <<EOF
Usage: gcrypt-config [OPTIONS]
Options:
[--prefix[=DIR]]
[--exec-prefix[=DIR]]
[--version]
[--libs]
[--cflags]
EOF
exit $1
}
if test $# -eq 0; then
usage 1 1>&2
fi
while test $# -gt 0; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case $1 in
--prefix=*)
prefix=$optarg
if test $exec_prefix_set = no ; then
exec_prefix=$optarg
fi
;;
--prefix)
echo_prefix=yes
;;
--exec-prefix=*)
exec_prefix=$optarg
exec_prefix_set=yes
;;
--exec-prefix)
echo_exec_prefix=yes
;;
--version)
echo "@VERSION@"
exit 0
;;
--cflags)
echo_cflags=yes
;;
--libs)
echo_libs=yes
;;
*)
usage 1 1>&2
;;
esac
shift
done
if test "$echo_prefix" = "yes"; then
echo $prefix
fi
if test "$echo_exec_prefix" = "yes"; then
echo $exec_prefix
fi
if test "$echo_cflags" = "yes"; then
if test "@includedir@" != "/usr/include" ; then
includes="-I@includedir@"
for i in $gcrypt_cflags ; do
if test "$i" = "-I@includedir@" ; then
includes=""
fi
done
fi
echo $includes $gcrypt_cflags
fi
if test "$echo_libs" = "yes"; then
echo ${gcrypt_libs}
fi
diff --git a/src/gcrypt.h b/src/gcrypt.h
index 416505df..aaeb95b1 100644
--- a/src/gcrypt.h
+++ b/src/gcrypt.h
@@ -1,482 +1,490 @@
/* gcrypt.h - GNU digital encryption library interface
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _GCRYPT_H
#define _GCRYPT_H
#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* The version of this header should match the one of the library
* It should not be used by a program because gcry_check_version()
* should reurn the same version. The purpose of this macro is to
* let autoconf (using the AM_PATH_GCRYPT macro) check that this
* header matches the installed library.
* Note: Do not edit the next line as configure may fix the string here.
*/
#define GCRYPT_VERSION "1.1.0a"
#ifndef HAVE_BYTE_TYPEDEF
# undef byte /* maybe there is a macro with this name */
typedef unsigned char byte;
# define HAVE_BYTE_TYPEDEF
#endif
#ifdef _GCRYPT_IN_LIBGCRYPT
# ifndef GCRYPT_NO_MPI_MACROS
# define GCRYPT_NO_MPI_MACROS 1
# endif
#endif
struct gcry_mpi;
typedef struct gcry_mpi *GCRY_MPI;
/*******************************************
* *
* error handling etc. *
* *
*******************************************/
/* FIXME: We should use the same values as they were used in GnuPG 1.0.
* gpg --status-fd may print some of these values */
enum {
GCRYERR_SUCCESS = 0, /* "no error" */
GCRYERR_GENERAL = 1, /* catch all the other errors code */
GCRYERR_INV_PK_ALGO = 4, /* invalid public key algorithm */
GCRYERR_INV_MD_ALGO = 5, /* invalid message digest algorithm */
GCRYERR_BAD_PUBLIC_KEY = 6, /* Bad public key */
GCRYERR_BAD_SECRET_KEY = 7, /* Bad secret key */
GCRYERR_BAD_SIGNATURE = 8, /* Bad signature */
GCRYERR_INV_CIPHER_ALGO = 12, /* invalid cipher algorithm */
GCRYERR_BAD_MPI = 30,
GCRYERR_WRONG_PK_ALGO = 41, /* wrong public key algorithm */
GCRYERR_WEAK_KEY = 43, /* weak encryption key */
GCRYERR_INV_KEYLEN = 44, /* invalid length of a key*/
GCRYERR_INV_ARG = 45, /* invalid argument */
GCRYERR_SELFTEST = 50, /* selftest failed */
/* error codes not used in GnuPG 1.0 */
GCRYERR_INV_OP = 61, /* invalid operation code or ctl command */
GCRYERR_NO_MEM = 62, /* out of core */
GCRYERR_INTERNAL = 63, /* internal error */
GCRYERR_EOF = 64, /* (-1) is remapped to this value */
GCRYERR_INV_OBJ = 65, /* an object is not valid */
GCRYERR_TOO_SHORT = 66, /* provided buffer too short */
GCRYERR_TOO_LARGE = 67, /* object is too large */
GCRYERR_NO_OBJ = 68, /* Missing item in an object */
GCRYERR_NOT_IMPL = 69, /* Not implemented */
GCRYERR_CONFLICT = 70,
};
const char *gcry_check_version( const char *req_version );
int gcry_errno(void);
const char *gcry_strerror( int ec );
enum gcry_ctl_cmds {
GCRYCTL_SET_KEY = 1,
GCRYCTL_SET_IV = 2,
GCRYCTL_CFB_SYNC = 3,
GCRYCTL_RESET = 4, /* e.g. for MDs */
GCRYCTL_FINALIZE = 5,
GCRYCTL_GET_KEYLEN = 6,
GCRYCTL_GET_BLKLEN = 7,
GCRYCTL_TEST_ALGO = 8,
GCRYCTL_IS_SECURE = 9,
GCRYCTL_GET_ASNOID = 10,
GCRYCTL_ENABLE_ALGO = 11,
GCRYCTL_DISABLE_ALGO = 12,
GCRYCTL_DUMP_RANDOM_STATS = 13,
GCRYCTL_DUMP_SECMEM_STATS = 14,
GCRYCTL_GET_ALGO_NPKEY = 15,
GCRYCTL_GET_ALGO_NSKEY = 16,
GCRYCTL_GET_ALGO_NSIGN = 17,
GCRYCTL_GET_ALGO_NENCR = 18,
GCRYCTL_SET_VERBOSITY = 19,
GCRYCTL_SET_DEBUG_FLAGS = 20,
GCRYCTL_CLEAR_DEBUG_FLAGS = 21,
GCRYCTL_USE_SECURE_RNDPOOL= 22,
GCRYCTL_DUMP_MEMORY_STATS = 23,
GCRYCTL_INIT_SECMEM = 24,
GCRYCTL_TERM_SECMEM = 25,
GCRYCTL_DISABLE_SECMEM_WARN = 27,
GCRYCTL_SUSPEND_SECMEM_WARN = 28,
GCRYCTL_RESUME_SECMEM_WARN = 29,
GCRYCTL_DROP_PRIVS = 30,
GCRYCTL_ENABLE_M_GUARD = 31,
+ GCRYCTL_START_DUMP = 32,
+ GCRYCTL_STOP_DUMP = 33,
};
int gcry_control( enum gcry_ctl_cmds, ... );
enum gcry_random_level {
GCRY_WEAK_RANDOM = 0,
GCRY_STRONG_RANDOM = 1,
GCRY_VERY_STRONG_RANDOM = 2
};
struct gcry_sexp;
typedef struct gcry_sexp *GCRY_SEXP;
enum gcry_sexp_format {
GCRYSEXP_FMT_DEFAULT = 0,
GCRYSEXP_FMT_CANON = 1,
GCRYSEXP_FMT_BASE64 = 2,
GCRYSEXP_FMT_ADVANCED = 3,
};
GCRY_SEXP gcry_sexp_new_data( const char *buffer, size_t length );
GCRY_SEXP gcry_sexp_new_mpi( GCRY_MPI mpi );
GCRY_SEXP gcry_sexp_new_name_data( const char *name,
const char *buffer, size_t length );
GCRY_SEXP gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi );
void gcry_sexp_release( GCRY_SEXP sexp );
void gcry_sexp_dump( GCRY_SEXP a );
GCRY_SEXP gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b );
GCRY_SEXP gcry_sexp_alist( GCRY_SEXP *array );
GCRY_SEXP gcry_sexp_vlist( GCRY_SEXP a, ... );
GCRY_SEXP gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n );
GCRY_SEXP gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n );
int gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
size_t length, size_t *erroff );
size_t gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer,
size_t maxlength );
GCRY_SEXP gcry_sexp_find_token( GCRY_SEXP list,
const char *tok, size_t toklen );
GCRY_SEXP gcry_sexp_enum( GCRY_SEXP list, void **context, int mode );
GCRY_SEXP gcry_sexp_car( GCRY_SEXP list );
GCRY_SEXP gcry_sexp_cdr( GCRY_SEXP list );
const char *gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen );
const char *gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen );
GCRY_MPI gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt );
GCRY_MPI gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt );
#ifndef GCRYPT_NO_SEXP_MACROS
#define SEXP GCRY_SEXP
#define SEXP_NEW(a,b) gcry_sexp_new_data( (a), (b) )
#define SEXP_RELEASE(a) do { gcry_sexp_release( (a) ); (a)=NULL; } while(0)
#define SEXP_CONS(a,b) gcry_sexp_cons((a),(b))
#endif /*GCRYPT_NO_SEXP_MACROS*/
/*******************************************
* *
* multi precision integer functions *
* *
*******************************************/
enum gcry_mpi_format {
GCRYMPI_FMT_NONE= 0,
GCRYMPI_FMT_STD = 1, /* twos complement stored without length */
GCRYMPI_FMT_PGP = 2, /* As used by OpenPGP */
GCRYMPI_FMT_SSH = 3, /* As used by SSH (same as 0 but with length)*/
GCRYMPI_FMT_HEX = 4, /* hex format */
GCRYMPI_FMT_USG = 5, /* like STD but this is an unsigned one */
};
enum gcry_mpi_flag {
GCRYMPI_FLAG_SECURE = 1,
GCRYMPI_FLAG_OPAQUE = 2,
};
GCRY_MPI gcry_mpi_new( unsigned int nbits );
GCRY_MPI gcry_mpi_snew( unsigned int nbits );
void gcry_mpi_release( GCRY_MPI a );
GCRY_MPI gcry_mpi_copy( const GCRY_MPI a );
GCRY_MPI gcry_mpi_set( GCRY_MPI w, const GCRY_MPI u );
GCRY_MPI gcry_mpi_set_ui( GCRY_MPI w, unsigned long u );
int gcry_mpi_cmp( const GCRY_MPI u, const GCRY_MPI v );
int gcry_mpi_cmp_ui( const GCRY_MPI u, unsigned long v );
void gcry_mpi_randomize( GCRY_MPI w,
unsigned int nbits, enum gcry_random_level level);
int gcry_mpi_scan( GCRY_MPI *ret_mpi, enum gcry_mpi_format format,
const char *buffer, size_t *nbytes );
int gcry_mpi_print( enum gcry_mpi_format format,
char *buffer, size_t *nbytes, const GCRY_MPI a );
int gcry_mpi_aprint( enum gcry_mpi_format format,
void **buffer, size_t *nbytes, const GCRY_MPI a );
void gcry_mpi_powm( GCRY_MPI w,
const GCRY_MPI b, const GCRY_MPI e, const GCRY_MPI m );
GCRY_MPI gcry_mpi_set_opaque( GCRY_MPI a, void *p, unsigned int nbits );
void *gcry_mpi_get_opaque( GCRY_MPI a, unsigned int *nbits );
void gcry_mpi_set_flag( GCRY_MPI a, enum gcry_mpi_flag flag );
void gcry_mpi_clear_flag( GCRY_MPI a, enum gcry_mpi_flag flag );
int gcry_mpi_get_flag( GCRY_MPI a, enum gcry_mpi_flag flag );
unsigned int gcry_mpi_get_nbits( GCRY_MPI a );
#ifndef GCRYPT_NO_MPI_MACROS
#define mpi_new(n) gcry_mpi_new( (n) )
#define mpi_secure_new( n ) gcry_mpi_snew( (n) )
#define mpi_release( a ) do { gcry_mpi_release( (a) ); \
(a) = NULL; } while(0)
#define mpi_copy( a ) gcry_mpi_copy( (a) )
#define mpi_set( w, u) gcry_mpi_set( (w), (u) )
#define mpi_set_ui( w, u) gcry_mpi_set_ui( (w), (u) )
#define mpi_cmp( u, v ) gcry_mpi_cmp( (u), (v) )
#define mpi_cmp_ui( u, v ) gcry_mpi_cmp_ui( (u), (v) )
#define mpi_powm(w,b,e,m) gcry_mpi_powm( (w), (b), (e), (m) )
#define mpi_set_opaque(a,b,c) gcry_mpi_set_opaque( (a), (b), (c) )
#define mpi_get_opaque(a,b) gcry_mpi_get_opaque( (a), (b) )
#endif /* GCRYPT_NO_MPI_MACROS */
/********************************************
******* symmetric cipher functions *******
********************************************/
struct gcry_cipher_handle;
typedef struct gcry_cipher_handle *GCRY_CIPHER_HD;
enum gcry_cipher_algos {
GCRY_CIPHER_NONE = 0,
GCRY_CIPHER_IDEA = 1,
GCRY_CIPHER_3DES = 2,
GCRY_CIPHER_CAST5 = 3,
GCRY_CIPHER_BLOWFISH = 4,
GCRY_CIPHER_SAFER_SK128 = 5,
GCRY_CIPHER_DES_SK = 6,
GCRY_CIPHER_TWOFISH = 10,
};
enum gcry_cipher_modes {
GCRY_CIPHER_MODE_NONE = 0,
GCRY_CIPHER_MODE_ECB = 1,
GCRY_CIPHER_MODE_CFB = 2,
GCRY_CIPHER_MODE_CBC = 3,
};
enum gcry_cipher_flags {
GCRY_CIPHER_SECURE = 1, /* allocate in secure memory */
GCRY_CIPHER_ENABLE_SYNC = 2, /* enable CFB sync mode */
};
GCRY_CIPHER_HD gcry_cipher_open( int algo, int mode, unsigned flags);
void gcry_cipher_close( GCRY_CIPHER_HD h );
int gcry_cipher_ctl( GCRY_CIPHER_HD h, int cmd, void *buffer, size_t buflen);
int gcry_cipher_info( GCRY_CIPHER_HD h, int what, void *buffer, size_t *nbytes);
int gcry_cipher_algo_info( int algo, int what, void *buffer, size_t *nbytes);
const char *gcry_cipher_algo_name( int algo );
int gcry_cipher_map_name( const char* name );
int gcry_cipher_encrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
const byte *in, size_t inlen );
int gcry_cipher_decrypt( GCRY_CIPHER_HD h, byte *out, size_t outsize,
const byte *in, size_t inlen );
/* some handy macros */
#define gcry_cipher_setkey(h,k,l) gcry_cipher_ctl( (h), GCRYCTL_SET_KEY, \
(k), (l) )
#define gcry_cipher_setiv(h,k,l) gcry_cipher_ctl( (h), GCRYCTL_SET_IV, \
(k), (l) )
#define gcry_cipher_sync(h) gcry_cipher_ctl( (h), GCRYCTL_CFB_SYNC, \
NULL, 0 )
#define gcry_cipher_get_algo_keylen(a) \
gcry_cipher_algo_info( (a), GCRYCTL_GET_KEYLEN, NULL, NULL )
#define gcry_cipher_get_algo_blklen(a) \
gcry_cipher_algo_info( (a), GCRYCTL_GET_BLKLEN, NULL, NULL )
#define gcry_cipher_test_algo(a) \
gcry_cipher_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
/*********************************************
******* asymmetric cipher functions *******
*********************************************/
enum gcry_pk_algos {
GCRY_PK_RSA = 1,
GCRY_PK_RSA_E = 2, /* use only for OpenPGP */
GCRY_PK_RSA_S = 3, /* use only for OpenPGP */
GCRY_PK_ELG_E = 16, /* use only for OpenPGP */
GCRY_PK_DSA = 17,
GCRY_PK_ELG = 20,
};
/* Flags describing usage capabilites/request of a PK algorithm */
#define GCRY_PK_USAGE_SIGN 1
#define GCRY_PK_USAGE_ENCR 2
int gcry_pk_encrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP pkey );
int gcry_pk_decrypt( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP skey );
int gcry_pk_sign( GCRY_SEXP *result, GCRY_SEXP data, GCRY_SEXP skey );
int gcry_pk_verify( GCRY_SEXP sigval, GCRY_SEXP data, GCRY_SEXP pkey );
int gcry_pk_testkey( GCRY_SEXP key );
int gcry_pk_genkey( GCRY_SEXP *r_key, GCRY_SEXP s_parms );
int gcry_pk_ctl( int cmd, void *buffer, size_t buflen);
int gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes);
const char *gcry_pk_algo_name( int algo );
int gcry_pk_map_name( const char* name );
unsigned int gcry_pk_get_nbits( GCRY_SEXP key );
#define gcry_pk_test_algo(a) \
gcry_pk_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
/*********************************************
******* cryptograhic hash functions *******
*********************************************/
enum gcry_md_algos {
GCRY_MD_NONE = 0,
GCRY_MD_MD5 = 1,
GCRY_MD_SHA1 = 2,
GCRY_MD_RMD160 = 3,
GCRY_MD_TIGER = 6
};
enum gcry_md_flags {
GCRY_MD_FLAG_SECURE = 1,
GCRY_MD_FLAG_HMAC = 2
};
struct gcry_md_context;
struct gcry_md_handle {
struct gcry_md_context *ctx;
int bufpos;
int bufsize;
byte buf[1];
};
typedef struct gcry_md_handle *GCRY_MD_HD;
GCRY_MD_HD gcry_md_open( int algo, unsigned flags );
void gcry_md_close( GCRY_MD_HD hd );
int gcry_md_enable( GCRY_MD_HD hd, int algo );
GCRY_MD_HD gcry_md_copy( GCRY_MD_HD hd );
void gcry_md_reset( GCRY_MD_HD hd );
int gcry_md_ctl( GCRY_MD_HD hd, int cmd, byte *buffer, size_t buflen);
void gcry_md_write( GCRY_MD_HD hd, const byte *buffer, size_t length);
byte *gcry_md_read( GCRY_MD_HD hd, int algo );
void gcry_md_hash_buffer( int algo, char *digest,
const char *buffer, size_t length);
int gcry_md_get_algo( GCRY_MD_HD hd );
unsigned int gcry_md_get_algo_dlen( int algo );
/*??int gcry_md_get( GCRY_MD_HD hd, int algo, byte *buffer, int buflen );*/
int gcry_md_info( GCRY_MD_HD h, int what, void *buffer, size_t *nbytes);
int gcry_md_algo_info( int algo, int what, void *buffer, size_t *nbytes);
const char *gcry_md_algo_name( int algo );
int gcry_md_map_name( const char* name );
#define gcry_md_setkey(h,k,l) gcry_md_ctl( (h), GCRYCTL_SET_KEY, (k), (l) )
#define gcry_md_putc(h,c) \
do { \
if( (h)->bufpos == (h)->bufsize ) \
gcry_md_write( (h), NULL, 0 ); \
(h)->buf[(h)->bufpos++] = (c) & 0xff; \
} while(0)
#define gcry_md_final(a) \
gcry_md_ctl( (a), GCRYCTL_FINALIZE, NULL, 0 )
#define gcry_md_is_secure(a) \
gcry_md_info( (a), GCRYCTL_IS_SECURE, NULL, NULL )
#define gcry_md_test_algo(a) \
gcry_md_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
+#define gcry_md_start_debug(a,b) \
+ gcry_md_ctl( (a), GCRYCTL_START_DUMP, (b), 0 )
+#define gcry_md_stop_debug(a,b) \
+ gcry_md_ctl( (a), GCRYCTL_STOP_DUMP, (b), 0 )
+
+
/*********************************************
******* random generating functions *******
*********************************************/
void gcry_randomize( byte *buffer, size_t length,
enum gcry_random_level level );
void *gcry_random_bytes( size_t nbytes, enum gcry_random_level level );
void *gcry_random_bytes_secure( size_t nbytes, enum gcry_random_level level );
/*****************************************
******* miscellaneous stuff **********
*****************************************/
enum gcry_log_levels {
GCRY_LOG_CONT = 0, /* continue the last log line */
GCRY_LOG_INFO = 10,
GCRY_LOG_WARN = 20,
GCRY_LOG_ERROR = 30,
GCRY_LOG_FATAL = 40,
GCRY_LOG_BUG = 50,
GCRY_LOG_DEBUG = 100,
};
/* Provide custom functions for special tasks of libgcrypt.
*/
void gcry_set_allocation_handler( void *(*new_alloc_func)(size_t n),
void *(*new_alloc_secure_func)(size_t n),
int (*new_is_secure_func)(const void*),
void *(*new_realloc_func)(void *p, size_t n),
void (*new_free_func)(void*) );
void gcry_set_outofcore_handler( int (*h)( void*, size_t, unsigned int ),
void *opaque );
void gcry_set_fatalerror_handler( void (*fnc)(void*,int, const char*),
void *opaque );
void gcry_set_gettext_handler( const char *(*f)(const char*) );
void gcry_set_log_handler( void (*f)(void*,int, const char*, va_list ),
void *opaque );
/* Access to the memory function of libgcrypt.
* Especially the gcry_free() should be used for memory
* allocated by gcry_ functions.
*/
void *gcry_malloc( size_t n );
void *gcry_calloc( size_t n, size_t m );
void *gcry_malloc_secure( size_t n );
void *gcry_calloc_secure( size_t n, size_t m );
void *gcry_realloc( void *a, size_t n );
void *gcry_xmalloc( size_t n );
void *gcry_xcalloc( size_t n, size_t m );
void *gcry_xmalloc_secure( size_t n );
void *gcry_xcalloc_secure( size_t n, size_t m );
void *gcry_xrealloc( void *a, size_t n );
char *gcry_xstrdup( const char * a);
void gcry_free( void *a );
int gcry_is_secure( const void *a );
#ifndef GCRYPT_NO_MPI_MACROS
# ifndef DID_MPI_TYPEDEF
typedef struct gcry_mpi *MPI;
# define DID_MPI_TYPEDEF
# endif
#endif /* GCRYPT_NO_MPI_MACROS */
#ifdef __cplusplus
}
#endif
#endif /* _GCRYPT_H */
diff --git a/src/secmem.c b/src/secmem.c
index 388fa91d..56df4f8f 100644
--- a/src/secmem.c
+++ b/src/secmem.c
@@ -1,420 +1,428 @@
/* secmem.c - memory allocation from a secure heap
- * Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef USE_CAPABILITIES
#include <sys/capability.h>
#endif
#endif
#include "g10lib.h"
#include "secmem.h"
#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
#define MAP_ANONYMOUS MAP_ANON
#endif
#define DEFAULT_POOLSIZE 16384
typedef struct memblock_struct MEMBLOCK;
struct memblock_struct {
unsigned size;
union {
MEMBLOCK *next;
PROPERLY_ALIGNED_TYPE aligned;
} u;
};
static void *pool;
static volatile int pool_okay; /* may be checked in an atexit function */
-static int pool_is_mmapped;
+static volatile int pool_is_mmapped;
static size_t poolsize; /* allocated length */
static size_t poollen; /* used length */
static MEMBLOCK *unused_blocks;
static unsigned max_alloced;
static unsigned cur_alloced;
static unsigned max_blocks;
static unsigned cur_blocks;
static int disable_secmem;
static int show_warning;
static int no_warning;
static int suspend_warning;
static void
print_warn(void)
{
if( !no_warning )
log_info(_("Warning: using insecure memory!\n"));
}
static void
lock_pool( void *p, size_t n )
{
#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
int err;
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
err = mlock( p, n );
if( err && errno )
err = errno;
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
if( err ) {
if( errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this */
&& errno != EAGAIN
#endif
#ifdef ENOSYS /* Some SCOs return this (function not implemented) */
&& errno != ENOSYS
#endif
)
log_error("can't lock memory: %s\n", strerror(err));
show_warning = 1;
}
#elif defined(HAVE_MLOCK)
uid_t uid;
int err;
uid = getuid();
#ifdef HAVE_BROKEN_MLOCK
if( uid ) {
errno = EPERM;
err = errno;
}
else {
err = mlock( p, n );
if( err && errno )
err = errno;
}
#else
err = mlock( p, n );
if( err && errno )
err = errno;
#endif
if( uid && !geteuid() ) {
- if( setuid( uid ) || getuid() != geteuid() )
+ /* check that we really dropped the privs.
+ * Note: setuid(0) should always fail */
+ if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
log_fatal("failed to reset uid: %s\n", strerror(errno));
}
if( err ) {
if( errno != EPERM
#ifdef EAGAIN /* OpenBSD returns this */
&& errno != EAGAIN
#endif
#ifdef ENOSYS /* Some SCOs return this (function not implemented) */
&& errno != ENOSYS
#endif
)
log_error("can't lock memory: %s\n", strerror(err));
show_warning = 1;
}
+ #elif defined ( __QNX__ )
+ /* QNX does not page at all, so the whole secure memory stuff does
+ * not make much sense. However it is still of use because it
+ * wipes out the memory on a free().
+ * Therefore it is sufficient to suppress the warning
+ */
#else
log_info("Please note that you don't have secure memory on this system\n");
#endif
}
static void
init_pool( size_t n)
{
size_t pgsize;
poolsize = n;
if( disable_secmem )
log_bug("secure memory is disabled");
#ifdef HAVE_GETPAGESIZE
pgsize = getpagesize();
#else
pgsize = 4096;
#endif
#if HAVE_MMAP
poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
#ifdef MAP_ANONYMOUS
pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
#else /* map /dev/zero instead */
{ int fd;
fd = open("/dev/zero", O_RDWR);
if( fd == -1 ) {
log_error("can't open /dev/zero: %s\n", strerror(errno) );
pool = (void*)-1;
}
else {
pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fd, 0);
}
}
#endif
if( pool == (void*)-1 )
log_info("can't mmap pool of %u bytes: %s - using malloc\n",
(unsigned)poolsize, strerror(errno));
else {
pool_is_mmapped = 1;
pool_okay = 1;
}
#endif
if( !pool_okay ) {
pool = malloc( poolsize );
if( !pool )
log_fatal("can't allocate memory pool of %u bytes\n",
(unsigned)poolsize);
else
pool_okay = 1;
}
lock_pool( pool, poolsize );
poollen = 0;
}
/* concatenate unused blocks */
static void
compress_pool(void)
{
/* fixme: we really should do this */
}
void
secmem_set_flags( unsigned flags )
{
int was_susp = suspend_warning;
no_warning = flags & 1;
suspend_warning = flags & 2;
/* and now issue the warning if it is not longer suspended */
if( was_susp && !suspend_warning && show_warning ) {
show_warning = 0;
print_warn();
}
}
unsigned
secmem_get_flags(void)
{
unsigned flags;
flags = no_warning ? 1:0;
flags |= suspend_warning ? 2:0;
return flags;
}
void
secmem_init( size_t n )
{
if( !n ) {
#ifdef USE_CAPABILITIES
/* drop all capabilities */
cap_set_proc( cap_from_text("all-eip") );
#elif !defined(HAVE_DOSISH_SYSTEM)
uid_t uid;
disable_secmem=1;
uid = getuid();
if( uid != geteuid() ) {
- if( setuid( uid ) || getuid() != geteuid() )
+ if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
log_fatal("failed to drop setuid\n" );
}
#endif
}
else {
if( n < DEFAULT_POOLSIZE )
n = DEFAULT_POOLSIZE;
if( !pool_okay )
init_pool(n);
else
log_error("Oops, secure memory pool already initialized\n");
}
}
void *
secmem_malloc( size_t size )
{
MEMBLOCK *mb, *mb2;
int compressed=0;
if( !pool_okay ) {
log_info(
_("operation is not possible without initialized secure memory\n"));
log_info(_("(you may have used the wrong program for this task)\n"));
exit(2);
}
if( show_warning && !suspend_warning ) {
show_warning = 0;
print_warn();
}
/* blocks are always a multiple of 32 */
size += sizeof(MEMBLOCK);
size = ((size + 31) / 32) * 32;
retry:
/* try to get it from the used blocks */
for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
if( mb->size >= size ) {
if( mb2 )
mb2->u.next = mb->u.next;
else
unused_blocks = mb->u.next;
goto leave;
}
/* allocate a new block */
if( (poollen + size <= poolsize) ) {
mb = (void*)((char*)pool + poollen);
poollen += size;
mb->size = size;
}
else if( !compressed ) {
compressed=1;
compress_pool();
goto retry;
}
else
return NULL;
leave:
cur_alloced += mb->size;
cur_blocks++;
if( cur_alloced > max_alloced )
max_alloced = cur_alloced;
if( cur_blocks > max_blocks )
max_blocks = cur_blocks;
return &mb->u.aligned.c;
}
void *
secmem_realloc( void *p, size_t newsize )
{
MEMBLOCK *mb;
size_t size;
void *a;
mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
size = mb->size;
if( newsize < size )
return p; /* it is easier not to shrink the memory */
a = secmem_malloc( newsize );
memcpy(a, p, size);
memset((char*)a+size, 0, newsize-size);
secmem_free(p);
return a;
}
void
secmem_free( void *a )
{
MEMBLOCK *mb;
size_t size;
if( !a )
return;
mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
size = mb->size;
/* This does not make much sense: probably this memory is held in the
* cache. We do it anyway: */
memset(mb, 0xff, size );
memset(mb, 0xaa, size );
memset(mb, 0x55, size );
memset(mb, 0x00, size );
mb->size = size;
mb->u.next = unused_blocks;
unused_blocks = mb;
cur_blocks--;
cur_alloced -= size;
}
int
g10_private_is_secure( const void *p )
{
return p >= pool && p < (void*)((char*)pool+poolsize);
}
/****************
* Warning: This code might be called by an interrupt handler
* and frankly, there should really be such a handler,
* to make sure that the memory is wiped out.
* We hope that the OS wipes out mlocked memory after
* receiving a SIGKILL - it really should do so, otherwise
* there is no chance to get the secure memory cleaned.
*/
void
secmem_term()
{
if( !pool_okay )
return;
memset( pool, 0xff, poolsize);
memset( pool, 0xaa, poolsize);
memset( pool, 0x55, poolsize);
memset( pool, 0x00, poolsize);
#if HAVE_MMAP
if( pool_is_mmapped )
munmap( pool, poolsize );
#endif
pool = NULL;
pool_okay = 0;
poolsize=0;
poollen=0;
unused_blocks=NULL;
}
void
secmem_dump_stats()
{
if( disable_secmem )
return;
fprintf(stderr,
"secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
cur_alloced, max_alloced, cur_blocks, max_blocks,
(ulong)poollen, (ulong)poolsize );
}
diff --git a/src/sexp.c b/src/sexp.c
index d720d4fa..cd7af7a3 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -1,1098 +1,1169 @@
/* sexp.c - S-Expression handling
- * Copyright (C) 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/****************
* TODO:
* - implement reference counting to defere freeing of
* data and make copies of the data on demand.
* --> do we really need this?
*
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <assert.h>
#define GCRYPT_NO_MPI_MACROS 1
#include "g10lib.h"
#include "memory.h"
#if 0
struct sexp_node;
typedef struct sexp_node *NODE;
struct gcry_sexp {
int orig_format; /* format which we used to create this object */
NODE sexp; /* a NULL indicates an empty list */
};
#else
typedef struct gcry_sexp *NODE;
#endif
enum node_types { ntLIST, ntDATA, ntMPI };
struct gcry_sexp {
NODE next;
NODE up; /* helper needed for faster traversal */
enum node_types type;
union {
NODE list;
GCRY_MPI mpi;
struct {
size_t len;
byte d[1];
} data;
} u;
};
static void
dump_mpi( GCRY_MPI a )
{
char buffer[1000];
size_t n = 1000;
if( !a )
fputs("[no MPI]", stderr );
else if( gcry_mpi_print( GCRYMPI_FMT_HEX, buffer, &n, a ) )
fputs("[MPI too large to print]", stderr );
else
fputs( buffer, stderr );
}
static void
dump_string( FILE *fp, const byte *p, size_t n, int delim )
{
for( ; n; n--, p++ )
if( iscntrl( *p ) || *p == delim ) {
putc('\\', fp);
if( *p == '\n' )
putc('n', fp);
else if( *p == '\r' )
putc('r', fp);
else if( *p == '\f' )
putc('f', fp);
else if( *p == '\v' )
putc('v', fp);
else if( *p == '\b' )
putc('b', fp);
else if( !*p )
putc('0', fp);
else
fprintf(fp, "x%02x", *p );
}
else
putc(*p, fp);
}
static void
do_dump_list( NODE node, int indent )
{
for( ; node; node = node->next ) {
switch( node->type ) {
case ntLIST:
if( indent )
putc('\n', stderr);
fprintf(stderr, "%*s(", indent, "");
do_dump_list( node->u.list, indent+1 );
putc(')', stderr);
break;
case ntDATA:
if( !node->u.data.len )
fputs("EMPTY", stderr );
else
dump_string(stderr, node->u.data.d, node->u.data.len, ')');
putc(' ', stderr);
break;
case ntMPI:
dump_mpi( node->u.mpi );
putc(' ', stderr);
break;
}
if( !indent )
putc('\n', stderr);
}
}
static void
dump_sexp( NODE node )
{
do_dump_list( node, 0 );
}
void
gcry_sexp_dump( GCRY_SEXP a )
{
do_dump_list( a, 0 );
}
/****************
* Create a new SEXP element (data)
* If length is 0 it is assumed that buffer is a C string.
*/
GCRY_SEXP
gcry_sexp_new_data( const char *buffer, size_t length )
{
NODE list, node;
if( !length )
length = strlen(buffer);
node = g10_xcalloc( 1, sizeof *node + length );
node->type = ntDATA;
node->u.data.len = length;
memcpy(node->u.data.d, buffer, length );
list = g10_xcalloc( 1, sizeof *list );
list->type = ntLIST;
list->u.list = node;
return list;
}
/****************
* Create a new SEXP element (mpi)
*/
GCRY_SEXP
gcry_sexp_new_mpi( GCRY_MPI mpi )
{
NODE list, node;
node = g10_xcalloc( 1, sizeof *node );
node->type = ntMPI;
node->u.mpi = gcry_mpi_copy( mpi );
list = g10_xcalloc( 1, sizeof *list );
list->type = ntLIST;
list->u.list = node;
return list;
}
/****************
* Create a pair of a name and some arbitrary data.
*/
GCRY_SEXP
gcry_sexp_new_name_data( const char *name, const char *buffer, size_t length )
{
return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
gcry_sexp_new_data( buffer, length ) );
}
/****************
* Create a pair of a name and a MPI
*/
GCRY_SEXP
gcry_sexp_new_name_mpi( const char *name, GCRY_MPI mpi )
{
return gcry_sexp_cons( gcry_sexp_new_data( name, 0 ),
gcry_sexp_new_mpi( mpi ) );
}
/****************
* Release resource of the given SEXP object.
*/
void
gcry_sexp_release( GCRY_SEXP sexp )
{
/* FIXME! */
}
/****************
* Make a pair from lists a and b, don't use a or b later on.
* Special behaviour: If one is a single element list we put the
* element straight into the new pair.
*/
GCRY_SEXP
gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b )
{
NODE head;
if( a->type != ntLIST ) {
fputs("sexp_cons: arg 1 is not a list\n", stderr );
return NULL;
}
if( b->type != ntLIST ) {
fputs("sexp_cons: arg 2 is not a list\n", stderr );
return NULL;
}
head = g10_xcalloc( 1, sizeof *head );
head->type = ntLIST;
if( !a->u.list->next ) { /* a has only one item */
NODE tmp = a;
a = a->u.list;
/* fixme: release tmp here */
}
if( !b->u.list->next ) { /* b has only one item */
NODE tmp = b;
b = b->u.list;
/* fixme: release tmp here */
}
head->u.list = a;
a->up = head;
a->next = b;
b->up = head;
return head;
}
/****************
* Make a list from all items in the array the end of the array is marked
* with a NULL. y a NULL
* Don't use the passed lists later on, they are void.
*/
GCRY_SEXP
gcry_sexp_alist( GCRY_SEXP *array )
{
NODE head, tail = NULL, node;
va_list arg_ptr ;
int i;
if( !*array )
return NULL;
head = g10_xcalloc( 1, sizeof *node );
head->type = ntLIST;
for( i=0; (node = array[i]); i++ ) {
if( node->type != ntLIST ) {
fputs("sexp_alist: an arg is not a list\n", stderr );
return NULL; /* fixme: we should release already allocated nodes */
}
if( !node->u.list->next ) { /* node has only one item */
NODE tmp = node;
node = node->u.list;
/* fixme: release tmp here */
}
if( !tail ) {
head->u.list = node;
}
else
tail->next = node;
node->up = head;
tail = node;
}
return head;
}
/****************
* Make a list from all items, the end of list is indicated by a NULL
* don't use the passed lists later on, they are void.
*/
GCRY_SEXP
gcry_sexp_vlist( GCRY_SEXP a, ... )
{
NODE head, tail, node;
va_list arg_ptr ;
if( a->type != ntLIST ) {
fputs("sexp_vlist: arg 1 is not a list\n", stderr );
return NULL;
}
head = g10_xcalloc( 1, sizeof *node );
head->type = ntLIST;
if( !a->u.list->next ) { /* a has only one item */
NODE tmp = a;
a = a->u.list;
/* fixme: release tmp here */
}
head->u.list = a;
a->up = head;
tail = a;
va_start( arg_ptr, a ) ;
while( (node = va_arg( arg_ptr, NODE )) ) {
if( node->type != ntLIST ) {
fputs("sexp_vlist: an arg is not a list\n", stderr );
return NULL; /* fixme: we should release already allocated nodes */
}
if( !node->u.list->next ) { /* node has only one item */
NODE tmp = node;
node = node->u.list;
/* fixme: release tmp here */
}
tail->next = node;
node->up = head;
tail = node;
}
va_end( arg_ptr );
return head;
}
/****************
* Append n to the list a
* Don't use n later on.
* Returns: a new ist (which maybe a)
*/
GCRY_SEXP
gcry_sexp_append( GCRY_SEXP a, GCRY_SEXP n )
{
GCRY_SEXP node;
if( a->type != ntLIST ) {
fputs("sexp_append: a is not a list\n", stderr );
return a;
}
if( n->type != ntLIST ) {
fputs("sexp_append: n is not a list\n", stderr );
return a;
}
for( node = a; node->next; node = node->next )
;
node->next = n;
return a;
}
GCRY_SEXP
gcry_sexp_prepend( GCRY_SEXP a, GCRY_SEXP n )
{
fputs("sexp_prepend: not impl.\n", stderr );
return a;
}
/****************
* Locate data in a list. Data must be the first item in the list.
* Returns: The sublist with that Data (don't modify it!)
*/
GCRY_SEXP
gcry_sexp_find_token( GCRY_SEXP list, const char *tok, size_t toklen )
{
NODE node;
if( !toklen )
toklen = strlen(tok);
for( node=list ; node; node = node->next )
{
switch( node->type ) {
case ntLIST: {
NODE n = gcry_sexp_find_token( node->u.list, tok, toklen );
if( n )
return n;
}
break;
case ntDATA:
if( node == list
&& node->u.data.len == toklen
&& !memcmp( node->u.data.d, tok, toklen ) )
{
return node;
}
break;
case ntMPI:
break;
}
}
return NULL;
}
/****************
* Enumerate all objects in the list. Ther first time you call this, pass
* the address of a void pointer initialized to NULL. Then don't touch this
* variable anymore but pass it verbatim to the function; you will get
* all lists back in turn. End of lists is indicated by a returned NIL in
* which case you should not continue to use this function
* (it would wrap around). If you decide to cancel the operation before
* the final NIL you have to release the context by calling the function
* with a the context but a LIST set to NULL.
* Note that this function returns only lists and not single objects.
*/
GCRY_SEXP
gcry_sexp_enum( GCRY_SEXP list, void **context, int mode )
{
NODE node;
if( mode )
return NULL; /* mode is reserved and must be 0 */
if( !list ) {
/* we are lucky that we can hold all information in the pointer
* value ;-) - so there is no need to release any memory */
*context = NULL;
return NULL;
}
if( !*context ) /* start enumeration */
node = list;
else {
node = *context;
node = node->next;
}
for( ; node; node = node->next ) {
*context = node; /* store our context */
if( node->type == ntLIST )
return node->u.list;
return node;
}
/* release resources and return nil */
return gcry_sexp_enum( NULL, context, mode );
}
/****************
* Get the CAR
*/
GCRY_SEXP
gcry_sexp_car( GCRY_SEXP list )
{
return list;
}
/****************
* Get data from the car
*/
const char *
gcry_sexp_car_data( GCRY_SEXP list, size_t *datalen )
{
if( list && list->type == ntLIST && !list->next )
list = list->u.list;
if( list && list->type == ntDATA ) {
*datalen = list->u.data.len;
return list->u.data.d;
}
return NULL;
}
/****************
* Get a MPI from the car
*/
GCRY_MPI
gcry_sexp_car_mpi( GCRY_SEXP list, int mpifmt )
{
if( list && list->type == ntLIST && !list->next )
list = list->u.list;
if( mpifmt && list->type == ntDATA ) {
MPI a;
size_t n = list->u.data.len;
if( gcry_mpi_scan( &a, mpifmt, list->u.data.d, &n ) )
return NULL;
return a;
}
else if( list->type == ntMPI )
return gcry_mpi_copy( list->u.mpi );
return NULL;
}
/****************
* Get the CDR
*/
GCRY_SEXP
gcry_sexp_cdr( GCRY_SEXP list )
{
if( list && (list = list->next) )
return list;
return NULL;
}
/****************
* Get data from the cdr assuming this is a pair
*/
const char *
gcry_sexp_cdr_data( GCRY_SEXP list, size_t *datalen )
{
if( list && (list = list->next) && list->type == ntDATA ) {
*datalen = list->u.data.len;
return list->u.data.d;
}
return NULL;
}
/****************
* cdr the mpi from the list or NULL if there is no MPI.
* This function tries to convert plain data to an MPI.
* Actually this funtion returns only the second item of the list
* and ignores any further arguments.
*/
GCRY_MPI
gcry_sexp_cdr_mpi( GCRY_SEXP list, int mpifmt )
{
NODE node = list;
if( !node || !(node = node->next) || node == ntLIST )
return NULL;
if( mpifmt && node->type == ntDATA ) {
MPI a;
size_t n = node->u.data.len;
if( gcry_mpi_scan( &a, mpifmt, node->u.data.d, &n ) )
return NULL;
return a;
}
else if( node->type == ntMPI )
return gcry_mpi_copy( node->u.mpi );
else
return NULL;
}
+
+
+
+static int
+hextobyte( const byte *s )
+{
+ int c=0;
+
+ if( *s >= '0' && *s <= '9' )
+ c = 16 * (*s - '0');
+ else if( *s >= 'A' && *s <= 'F' )
+ c = 16 * (10 + *s - 'A');
+ else if( *s >= 'a' && *s <= 'f' ) {
+ c = 16 * (10 + *s - 'a');
+ }
+ s++;
+ if( *s >= '0' && *s <= '9' )
+ c += *s - '0';
+ else if( *s >= 'A' && *s <= 'F' )
+ c += 10 + *s - 'A';
+ else if( *s >= 'a' && *s <= 'f' ) {
+ c += 10 + *s - 'a';
+ }
+ return c;
+}
+
+
+
/****************
* Scan the provided buffer and return the S expression in our internal
* format. Returns a newly allocated expression. If erroff is not NULL and
* a parsing error has occured, the offset into buffer will be returned.
*/
int
gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer,
size_t length, size_t *erroff )
{
static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789-./_:*+=";
const char *p;
size_t n;
NODE head, tail, node;
const char *digptr=NULL;
const char *quoted=NULL;
const char *tokenp=NULL;
const char *hexfmt=NULL;
const char *base64=NULL;
const char *disphint=NULL;
+ int hexcount=0;
int quoted_esc=0;
int datalen=0;
int first;
size_t dummy_erroff;
if( !erroff )
erroff = &dummy_erroff;
tail = head = NULL;
first = 0;
for(p=buffer,n=length; n; p++, n-- ) {
- if( tokenp ) {
+ if( tokenp && !hexfmt ) {
if( strchr( tokenchars, *p ) )
continue;
}
if( quoted ) {
if( quoted_esc ) {
switch( *p ) {
case 'b': case 't': case 'v': case 'n': case 'f':
case 'r': case '"': case '\'': case '\\':
quoted_esc = 0;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7':
if( !(n > 2 && p[1] >= '0' && p[1] <= '7'
&& p[2] >= '0' && p[2] <= '7') ) {
*erroff = p - buffer;
return -6; /* invalid octal value */
}
p += 2; n -= 2;
quoted_esc = 0;
break;
case 'x':
if( !(n > 2 && isxdigit(p[1]) && isxdigit(p[2]) ) ) {
*erroff = p - buffer;
return -6; /* invalid hex value */
}
p += 2; n -= 2;
quoted_esc = 0;
break;
case '\r': /* ignore CR[,LF] */
if( n && p[1] == '\n' ) {
p++; n--;
}
quoted_esc = 0;
break;
case '\n': /* ignore LF[,CR] */
if( n && p[1] == '\r' ) {
p++; n--;
}
quoted_esc = 0;
break;
default:
*erroff = p - buffer;
return -6; /* invalid quoted string escape */
}
}
else if( *p == '\\' )
quoted_esc = 1;
else if( *p == '\"' ) {
/* fixme: add item */
quoted = NULL;
}
}
else if( hexfmt ) {
- if( *p == '#' )
- hexfmt = NULL;
+ if( isxdigit( *p ) )
+ hexcount++;
+ else if( *p == '#' ) {
+ int i;
+
+ if( (hexcount & 1) ) {
+ *erroff = p - buffer;
+ return -12; /* odd number of hex digits */
+ }
+
+ /* make a new list entry */
+ datalen = hexcount/2;
+ node = g10_xcalloc( 1, sizeof *node + datalen );
+ if( first ) { /* stuff it into the first node */
+ first = 0;
+ node->up = tail;
+ tail->u.list = node;
+ }
+ else {
+ node->up = tail->up;
+ tail->next = node;
+ }
+ tail = node;
+ /* and fill in the value (we store the value in the node)*/
+ node->type = ntDATA;
+ node->u.data.len = datalen;
+ for(i=0, hexfmt++; hexfmt < p; hexfmt++ ) {
+ if( isspace( *hexfmt ) )
+ continue;
+ node->u.data.d[i++] = hextobyte( hexfmt );
+ hexfmt++;
+ }
+ assert( hexfmt == p );
+ assert( i == datalen );
+ hexfmt = NULL;
+ }
+ else if( !isspace( *p ) ) {
+ *erroff = p - buffer;
+ return -11; /* invalid hex character */
+ }
}
else if( base64 ) {
if( *p == '|' )
base64 = NULL;
}
else if( digptr ) {
if( isdigit(*p) )
;
else if( *p == ':' ) {
if( !head ) {
*erroff = 0;
return -4; /* not a list */
}
datalen = atoi( digptr ); /* fixme: check for overflow */
digptr = NULL;
if( datalen > n-1 ) {
*erroff = p - buffer;
return -2; /* buffer too short */
}
/* make a new list entry */
node = g10_xcalloc( 1, sizeof *node + datalen );
if( first ) { /* stuff it into the first node */
first = 0;
node->up = tail;
tail->u.list = node;
}
else {
node->up = tail->up;
tail->next = node;
}
tail = node;
/* and fill in the value (we store the value in the node)*/
node->type = ntDATA;
node->u.data.len = datalen;
memcpy(node->u.data.d, p+1, datalen );
n -= datalen;
p += datalen;
}
else if( *p == '\"' ) {
digptr = NULL; /* we ignore the optional length */
quoted = p;
quoted_esc = 0;
}
else if( *p == '#' ) {
digptr = NULL; /* we ignore the optional length */
hexfmt = p;
+ hexcount = 0;
}
else if( *p == '|' ) {
digptr = NULL; /* we ignore the optional length */
base64 = p;
}
else {
*erroff = p - buffer;
return -1;
}
}
else if( *p == '(' ) {
if( disphint ) {
*erroff = p - buffer;
return -9; /* open display hint */
}
node = g10_xcalloc( 1, sizeof *node );
if( !head )
head = node;
else {
node->up = tail->up;
tail->next = node;
}
node->type = ntLIST;
tail = node;
first = 1;
}
else if( *p == ')' ) { /* walk up */
if( disphint ) {
*erroff = p - buffer;
return -9; /* open display hint */
}
if( !head ) {
*erroff = 0;
return -4; /* not a list */
}
tail = tail->up;
if( !tail ) {
*erroff = p - buffer;
return -3;
}
}
else if( *p == '\"' ) {
quoted = p;
quoted_esc = 0;
}
- else if( *p == '#' )
+ else if( *p == '#' ) {
hexfmt = p;
+ hexcount = 0;
+ }
else if( *p == '|' )
base64 = p;
else if( *p == '[' ) {
if( disphint ) {
*erroff = p - buffer;
return -8; /* nested display hints */
}
disphint = p;
}
else if( *p == ']' ) {
if( !disphint ) {
*erroff = p - buffer;
return -9; /* unmatched display hint close */
}
disphint = NULL;
}
else if( isdigit(*p) ) {
if( *p == '0' ) { /* a length may not begin with zero */
*erroff = p - buffer;
return -7;
}
digptr = p;
}
else if( strchr( tokenchars, *p ) )
tokenp = p;
else if( isspace(*p) )
;
else if( *p == '{' ) {
/* fixme: handle rescanning:
* we can do this by saving our current state
* and start over at p+1 -- Hmmm. At this point here
* we are in a well defined state, so we don't need to save
* it. Great.
*/
*erroff = p - buffer;
return -10; /* unexpected reserved punctuation */
}
else if( strchr( "&\\", *p ) ) { /*reserved punctuation*/
*erroff = p - buffer;
return -10; /* unexpected reserved punctuation */
}
else { /* bad or unavailable*/
*erroff = p - buffer;
return -5;
}
}
*retsexp = head;
return 0;
}
/****************
* Print SEXP to buffer using the MODE. Returns the length of the
* SEXP in buffer or 0 if the buffer is too short (We have at least an
* empty list consisting of 2 bytes). If a buffer of NULL is provided,
* the required length is returned.
*/
size_t
gcry_sexp_sprint( GCRY_SEXP sexp, int mode, char *buffer, size_t maxlength )
{
return 0;
}
-#if 0
+#if 1
/***********************************************************/
const char *
strusage( int level )
{
- return default_strusage(level);
+ return "?";
}
+#if 0
static int
sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo)
{
GCRY_SEXP list, l2;
const char *name;
const char *s;
size_t n;
int i, idx;
int algo;
const char *elems1, *elems2;
GCRY_MPI *array;
static struct { const char* name; int algo;
const char* common_elements;
const char* public_elements;
const char* secret_elements;
} algos[] = {
{ "dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "rsa" , PUBKEY_ALGO_RSA , "ne", "", "dpqu" },
{ "openpgp-dsa" , PUBKEY_ALGO_DSA , "pqgy", "", "x" },
{ "openpgp-rsa" , PUBKEY_ALGO_RSA , "pqgy", "", "x" },
{ "openpgp-elg" , PUBKEY_ALGO_ELGAMAL_E , "pgy", "", "x" },
{ "openpgp-elg-sig", PUBKEY_ALGO_ELGAMAL , "pgy", "", "x" },
{ NULL }};
/* check that the first element is valid */
list = gcry_sexp_find_token( sexp, want_private? "private-key"
:"public-key", 0 );
if( !list )
return -1; /* Does not contain a public- or private-key object */
list = gcry_sexp_cdr( list );
if( !list )
return -2; /* no cdr for the key object */
name = gcry_sexp_car_data( list, &n );
if( !name )
return -3; /* invalid structure of object */
fprintf(stderr, "algorithm name: `%.*s'\n", (int)n, name );
for(i=0; (s=algos[i].name); i++ ) {
if( strlen(s) == n && !memcmp( s, name, n ) )
break;
}
if( !s )
return -4; /* unknown algorithm */
algo = algos[i].algo;
elems1 = algos[i].common_elements;
elems2 = want_private? algos[i].secret_elements : algos[i].public_elements;
array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array );
idx = 0;
for(s=elems1; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return -5; /* required parameter not found */
}
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return -6; /* required parameter is invalid */
}
}
for(s=elems2; *s; s++, idx++ ) {
l2 = gcry_sexp_find_token( list, s, 1 );
if( !l2 ) {
g10_free( array );
return -5; /* required parameter not found */
}
/* FIXME: put the MPI in secure memory when needed */
array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG );
if( !array[idx] ) {
g10_free( array );
return -6; /* required parameter is invalid */
}
}
*retarray = array;
*retalgo = algo;
return 0;
}
-
+#endif
int
main(int argc, char **argv)
{
char buffer[5000];
size_t erroff;
int rc, n;
FILE *fp;
GCRY_SEXP s_pk, s_dsa, s_p, s_q, s_g, s_y, sexp;
- #if 0
+ #if 1
fp = stdin;
n = fread(buffer, 1, 5000, fp );
rc = gcry_sexp_sscan( &sexp, buffer, n, &erroff );
if( rc ) {
fprintf(stderr, "parse error %d at offset %u\n", rc, erroff );
exit(1);
}
fputs("We have this S-Exp:\n",stderr);
dump_sexp( sexp );
#else
s_pk = SEXP_NEW( "public-key", 10 );
fputs("pk:\n",stderr);dump_sexp( s_pk );
s_dsa = SEXP_NEW( "dsa", 3 );
s_p = SEXP_CONS( SEXP_NEW( "p", 1 ), SEXP_NEW( "PPPPPP", 6 ) );
fputs("p:\n",stderr);dump_sexp( s_p );
s_y = SEXP_CONS( SEXP_NEW( "y", 1 ), SEXP_NEW( "YYYYYYYY", 8 ) );
fputs("y:\n",stderr);dump_sexp( s_y );
s_q = gcry_sexp_new_name_data( "q", "QQQ", 3 );
fputs("q:\n",stderr);dump_sexp( s_q );
s_g = gcry_sexp_new_name_mpi( "g" , gcry_mpi_set_ui(NULL, 42) );
fputs("g:\n",stderr);dump_sexp( s_g );
sexp = SEXP_CONS( s_pk, gcry_sexp_vlist( s_dsa,
s_y,
s_p,
s_q,
s_g,
NULL ));
fputs("Here is what we have:\n",stderr);
dump_sexp( sexp );
#endif
/* now find something */
if( argc > 1 )
{
GCRY_SEXP s1;
s1 = gcry_sexp_find_token( sexp, argv[1], strlen(argv[1]) );
if( !s1 )
{
fprintf(stderr, "didn't found `%s'\n", argv[1] );
}
else
{
fprintf(stderr, "found `%s':\n", argv[1] );
dump_sexp( s1 );
}
- #if 1
+ #if 0
{ int i,rc, algo;
GCRY_MPI *array;
rc = sexp_to_pk( s1, 0, &array, &algo);
if( rc )
fprintf(stderr, "sexp_to_pk failed: rc=%d\n", rc );
else {
for(i=0; array[i]; i++ ) {
fprintf(stderr, "MPI[%d]: ", i);
dump_mpi( array[i] );
fprintf(stderr, "\n");
}
}
}
#endif
if( argc > 2 ) /* get the MPI out of the list */
#if 0
{
GCRY_SEXP s2;
const char *p;
size_t n;
p = gcry_sexp_car_data( s1, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
p = gcry_sexp_cdr_data( s1, &n );
if( !p ) {
s2 = gcry_sexp_cdr( s1 );
if( !s2 ) {
fputs("no CDR at all\n", stderr );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
}
if( !p ) {
fputs("no CDR data\n", stderr );
exit(1);
}
fprintf(stderr, "CDR=`%.*s'\n", (int)n, p );
}
#elif 1
{
GCRY_SEXP s2;
MPI a;
const char *p;
size_t n;
fprintf(stderr,"*********************************\n");
p = gcry_sexp_car_data( s1, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
s2 = gcry_sexp_cdr( s1 );
if( !s2 ) {
fputs("no CDR\n", stderr );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
if( !p ) {
fputs("no data at CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
s2 = gcry_sexp_find_token( s1, argv[2], strlen(argv[2]) );
if( !s2 )
{
fprintf(stderr, "didn't found `%s'\n", argv[2] );
exit(1);
}
p = gcry_sexp_car_data( s2, &n );
if( !p ) {
fputs("no CAR\n", stderr );
exit(1);
}
fprintf(stderr, "CAR=`%.*s'\n", (int)n, p );
a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
if( a ) {
fprintf(stderr, "MPI: ");
dump_mpi( a );
fprintf(stderr, "\n");
}
else
fprintf(stderr, "cannot cdr a mpi\n" );
}
#else
{ /* print all MPIs */
void *ctx = NULL;
GCRY_SEXP s2;
MPI a;
while( (s2 = gcry_sexp_enum( s1, &ctx, 0 )) )
{
const char *car_d;
size_t car_n;
car_d = gcry_sexp_car_data( s2, &car_n );
if( car_d ) {
fprintf(stderr, "CAR: %.*s=", (int)car_n, car_d );
a = gcry_sexp_cdr_mpi( s2, GCRYMPI_FMT_USG );
dump_mpi( a );
fprintf(stderr, "\n");
}
else
fprintf(stderr, "no CAR\n");
}
}
#endif
}
return 0;
}
#endif

File Metadata

Mime Type
text/x-diff
Expires
Tue, Apr 14, 9:29 PM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
5e/25/3e2ff65bb53ea055cee507fe540d

Event Timeline