diff --git a/checks/ChangeLog b/checks/ChangeLog index b5c810bfd..3bb786325 100644 --- a/checks/ChangeLog +++ b/checks/ChangeLog @@ -1,23 +1,110 @@ -Wed Oct 4 13:16:18 CEST 2000 Werner Koch +2002-05-10 Werner Koch - * run-gpg: redirect fgrep output to stderr + * Makefile.am: Add gpg_dearmor to all targets where it is used. + Noted by Andreas Haumer. -Sat Nov 13 17:44:23 CET 1999 Werner Koch +2002-04-19 Werner Koch - * genkey1024.test: Does not use --quick-random anymore. + * signencrypt-dsa.test, sigs-dsa.test: Don't check with MD5 as + this is not valid with DSA signatures. -Thu Oct 28 16:17:46 CEST 1999 Werner Koch +2001-12-22 Werner Koch + + * options.in: Add no-permission-warning. + +2001-12-21 Werner Koch + + * Makefile.am (distclean-local): prefix mkdemodirs with srcdir + (DISTCLEANFILES): Add random_seed. + +2001-12-19 Werner Koch + + * options.in: Remove load-extension tiger + * Makefile.am (./options): append it if there is such a module. + +2001-10-23 Werner Koch + + * defs.inc, Makefile.am: Do not use $srcdir when invoking gpg. + Write the logfile to the current directory. + +2001-09-28 Werner Koch + + * defs.inc: Write a log file for each test. + * run-gpg, run-gpgm, run-gpg.patterns: Removed. Replaced in all + tests by a simple macro from defs.inc. + * Makefile.am (CLEANFILES): Remove log files. + (./gpg_dearmor): create it and use it instead of the macro. + This is needed in multisig.test due to IFS tricks. + + * armsignencrypt.test, signencrypt-dsa.test, signencrypt.test, + armencryptp.test, armencrypt.test, encryptp.test, seat.test, + encrypt-dsa.test, encrypt.test: Use --always-trust because the + test are not designed to check the validity. + +2001-09-06 Werner Koch + + * genkey1024.test: Simplified by using a parameter file. + +2001-05-30 Werner Koch + + * multisig.test (IFS): Reset IFS just before the test. + +2001-04-30 Werner Koch + + * multisig.test: Add an set +x to avoid ksh problems + +2001-04-28 Werner Koch + + * run-gpg.patterns: a v3 test key expired yesterday, suppress the + messages. + +2001-03-27 Werner Koch + + * defs.inc: Removed creation of options file. + * options.in: New. + * Makefile.am: Create options file and fixed import of pubdemo.asc. + + * run-gpg.patterns (gpg): Add some more patterns. + +2001-03-20 Werner Koch + + * Makefile.am: Import the pubdemo.asc file + + * sigs.test (hash_algo_list): s/tiger/tiger192/ + +2001-03-19 Werner Koch + + * mkdemodirs (GPGDEMO): Add --allow-secret-key-import to all gpg + invocations. Use echon -n instead of an argument with \c. + +2001-02-12 Werner Koch + + * multisig.test: new + * Makefile.am (TESTS): Added. + +2000-10-18 Werner Koch + + * conventional-mdc.test: Add Rijndael and fix for empty plain texts. + +Thu Feb 10 17:39:44 CET 2000 Werner Koch + + * mkdemodirs: Fixed the --clean loop. + +Thu Jan 13 19:31:58 CET 2000 Werner Koch + + * defs.inc (chdir): Removed becuase it is unsused an plain old sh + does not like this name. Reported by Alec Habig. + +Tue Oct 26 20:02:23 1999 Werner Koch (wk@gnupg.org) * Makefile.am (GPG_DEARMOR): New and use --no-options. Tue Aug 31 17:20:44 CEST 1999 Werner Koch - * defs.inc: set LC_ALL empty Wed Aug 4 10:34:18 CEST 1999 Werner Koch - * defs.inc (echo_n): New and used instead of /bin/echo "\c" Sun Apr 18 10:11:28 CEST 1999 Werner Koch @@ -70,3 +157,15 @@ Mon May 18 15:40:02 1998 Werner Koch (wk@isil.d.shuttle.de) * ChangeLog: New. + + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/checks/Makefile.am b/checks/Makefile.am index 41ded3cd6..ed779a432 100644 --- a/checks/Makefile.am +++ b/checks/Makefile.am @@ -1,6 +1,24 @@ -## Process this file with automake to create Makefile.in +# Copyright (C) 1998, 1999, 2000, 2001 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 -GPG_DEARMOR = ../g10/gpg --no-options --quiet --yes --dearmor +# Process this file with automake to create Makefile.in + +GPG_IMPORT = ../g10/gpg --homedir . --quiet --yes --import TESTS = version.test mds.test \ decrypt.test decrypt-dsa.test \ @@ -11,54 +29,67 @@ TESTS = version.test mds.test \ signencrypt.test signencrypt-dsa.test \ armsignencrypt.test armdetach.test \ armdetachm.test detachm.test genkey1024.test \ - conventional.test + conventional.test conventional-mdc.test \ + multisig.test TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \ plain-1.asc plain-2.asc plain-3.asc plain-1-pgp.asc \ - pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc + pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc options.in DATA_FILES = data-500 data-9000 data-32000 data-80000 plain-large -EXTRA_DIST = defs.inc run-gpg run-gpg.patterns $(TESTS) $(TEST_FILES) \ +EXTRA_DIST = defs.inc $(TESTS) $(TEST_FILES) \ mkdemodirs signdemokey CLEANFILES = prepared.stamp x y yy z out err $(DATA_FILES) \ - plain-1 plain-2 plain-3 options trustdb.gpg *.lock .\#lk* \ + plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \ + *.test.log options gpg_dearmor \ pubring.gpg secring.gpg pubring.pkr secring.skr -DISTCLEANFILES = pubring.gpg~ +DISTCLEANFILES = pubring.gpg~ random_seed all-local: prepared.stamp distclean-local: - ./mkdemodirs --clean + $(srcdir)/mkdemodirs --clean prepared.stamp: ./pubring.gpg ./secring.gpg ./plain-1 ./plain-2 ./plain-3 \ - ./pubring.pkr ./secring.skr $(DATA_FILES) + ./pubring.pkr ./secring.skr ./options ./gpg_dearmor \ + $(DATA_FILES) + $(GPG_IMPORT) $(srcdir)/pubdemo.asc echo timestamp >./prepared.stamp +./options: $(srcdir)/options.in + cat $(srcdir)/options.in >./options + @set -e; if echo "@DYNAMIC_CIPHER_MODS@" |grep tiger >/dev/null ;then \ + echo load-extension ../cipher/tiger >>./options; fi -./pubring.gpg: $(srcdir)/pubring.asc - $(GPG_DEARMOR) -o ./pubring.gpg $(srcdir)/pubring.asc +./gpg_dearmor: + echo '#!/bin/sh' >./gpg_dearmor + echo "../g10/gpg --no-options --no-greeting \ + --no-secmem-warning --batch --dearmor" >>./gpg_dearmor + chmod 755 ./gpg_dearmor -./secring.gpg: $(srcdir)/secring.asc - $(GPG_DEARMOR) -o ./secring.gpg $(srcdir)/secring.asc +./pubring.gpg: $(srcdir)/pubring.asc $(srcdir)/pubdemo.asc ./gpg_dearmor + ./gpg_dearmor > ./pubring.gpg < $(srcdir)/pubring.asc -./pubring.pkr: $(srcdir)/pubring.pkr.asc - $(GPG_DEARMOR) -o ./pubring.pkr $(srcdir)/pubring.pkr.asc +./secring.gpg: $(srcdir)/secring.asc ./gpg_dearmor + ./gpg_dearmor > ./secring.gpg < $(srcdir)/secring.asc -./secring.skr: $(srcdir)/secring.skr.asc - $(GPG_DEARMOR) -o ./secring.skr $(srcdir)/secring.skr.asc +./pubring.pkr: $(srcdir)/pubring.pkr.asc ./gpg_dearmor + ./gpg_dearmor > ./pubring.pkr < $(srcdir)/pubring.pkr.asc -./plain-1: $(srcdir)/plain-1o.asc - $(GPG_DEARMOR) -o ./plain-1 $(srcdir)/plain-1o.asc +./secring.skr: $(srcdir)/secring.skr.asc ./gpg_dearmor + ./gpg_dearmor > ./secring.skr < $(srcdir)/secring.skr.asc -./plain-2: $(srcdir)/plain-2o.asc - $(GPG_DEARMOR) -o ./plain-2 $(srcdir)/plain-2o.asc +./plain-1: $(srcdir)/plain-1o.asc ./gpg_dearmor + ./gpg_dearmor > ./plain-1 < $(srcdir)/plain-1o.asc -./plain-3: $(srcdir)/plain-3o.asc - $(GPG_DEARMOR) -o ./plain-3 $(srcdir)/plain-3o.asc +./plain-2: $(srcdir)/plain-2o.asc ./gpg_dearmor + ./gpg_dearmor > ./plain-2 < $(srcdir)/plain-2o.asc +./plain-3: $(srcdir)/plain-3o.asc ./gpg_dearmor + ./gpg_dearmor > ./plain-3 < $(srcdir)/plain-3o.asc data-500: diff --git a/checks/armdetach.test b/checks/armdetach.test index c68c5da82..c445d6ce6 100755 --- a/checks/armdetach.test +++ b/checks/armdetach.test @@ -5,7 +5,7 @@ #info Checking armored detached signatures for i in $plain_files $data_files ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sab -o x --yes $i - $srcdir/run-gpg -o /dev/null --yes x <$i || error "$i: bad signature" + echo "$usrpass1" | $GPG --passphrase-fd 0 -sab -o x --yes $i + $GPG -o /dev/null --yes x <$i || error "$i: bad signature" done diff --git a/checks/armdetachm.test b/checks/armdetachm.test index f628fcf2b..f1958424c 100755 --- a/checks/armdetachm.test +++ b/checks/armdetachm.test @@ -4,6 +4,6 @@ #info Checking armored detached signatures of multiple files i="$plain_files $data_files" -echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sab -o x --yes $i -cat $i | $srcdir/run-gpg -o /dev/null --yes x || error "$i: bad signature" +echo "$usrpass1" | $GPG --passphrase-fd 0 -sab -o x --yes $i +cat $i | $GPG -o /dev/null --yes x || error "$i: bad signature" diff --git a/checks/armencrypt.test b/checks/armencrypt.test index cade9dde4..356d1bda7 100755 --- a/checks/armencrypt.test +++ b/checks/armencrypt.test @@ -4,8 +4,8 @@ #info Checking armored encryption for i in $plain_files $data_files ; do - $srcdir/run-gpg -ea -o x --yes -r "$usrname2" $i - $srcdir/run-gpg -o y --yes x + $GPG --always-trust -ea -o x --yes -r "$usrname2" $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/armencryptp.test b/checks/armencryptp.test index 95a1efd63..d18c56b7e 100755 --- a/checks/armencryptp.test +++ b/checks/armencryptp.test @@ -4,9 +4,9 @@ #info Checking armored encryption with a pipe for i in $plain_files $data_files ; do - $srcdir/run-gpg -ea --yes -r "$usrname2" < $i | tee x | $srcdir/run-gpg -o y --yes + $GPG --always-trust -ea --yes -r "$usrname2" < $i | tee x | $GPG -o y --yes cmp $i y || error "$i: mismatch" - $srcdir/run-gpg --yes < x > y + $GPG --yes < x > y cmp $i y || error "$i: mismatch" done diff --git a/checks/armsignencrypt.test b/checks/armsignencrypt.test index f8ffdaf4d..24b9575ad 100755 --- a/checks/armsignencrypt.test +++ b/checks/armsignencrypt.test @@ -5,9 +5,9 @@ #info Checking armored signing and encryption for i in $plain_files $data_files ; do - echo "$usrpass1" \ - | $srcdir/run-gpg --passphrase-fd 0 -sae -o x --yes -r "$usrname2" $i - $srcdir/run-gpg -o y --yes x + echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust \ + -sae -o x --yes -r "$usrname2" $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/armsigs.test b/checks/armsigs.test index 34b5a7fa3..aecc06429 100755 --- a/checks/armsigs.test +++ b/checks/armsigs.test @@ -4,8 +4,8 @@ #info Checking armored signatures for i in $plain_files $data_files ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sa -o x --yes $i - $srcdir/run-gpg -o y --yes x + echo "$usrpass1" | $GPG --passphrase-fd 0 -sa -o x --yes $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/clearsig.test b/checks/clearsig.test index f77fd5db0..89d323317 100755 --- a/checks/clearsig.test +++ b/checks/clearsig.test @@ -14,17 +14,17 @@ # it is clear text and not binary text. # ====================================== for i in $plain_files plain-large ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sat -o x --yes $i - $srcdir/run-gpg --verify x + echo "$usrpass1" | $GPG --passphrase-fd 0 -sat -o x --yes $i + $GPG --verify x done # ====================================== # and once more to check rfc1991 # ====================================== for i in $plain_files plain-large ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 \ + echo "$usrpass1" | $GPG --passphrase-fd 0 \ --rfc1991 --digest-algo md5 -sat -o x --yes $i - $srcdir/run-gpg --verify x + $GPG --verify x done # ====================================== @@ -35,8 +35,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx EOF -echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 --clearsign -o x --yes y -$srcdir/run-gpg --verify x +echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y +$GPG --verify x # ====================================== # and one with only one long lines @@ -44,14 +44,15 @@ $srcdir/run-gpg --verify x cat >y <y <y echo_n " " >>y -echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 --clearsign -o x --yes y -$srcdir/run-gpg --verify x - +echo "$usrpass1" | $GPG --passphrase-fd 0 --clearsign -o x --yes y +$GPG --verify x + + +# ====================================== +# check our special diff mode +# ====================================== +cat >y <mfx.md, n1->pkt->pkt.signature->digest_algo); + } + /* ask for file and hash it */ +- if( c->sigs_only ) { ++ if( c->sigs_only ) + rc = hash_datafiles( c->mfx.md, NULL, + c->signed_data, c->sigfilename, + n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); +EOF +echo "$usrpass1" | $GPG --passphrase-fd 0 \ + --not-dash-escaped --clearsign -o x --yes y +$GPG --verify x diff --git a/checks/conventional-mdc.test b/checks/conventional-mdc.test new file mode 100755 index 000000000..463e0c49f --- /dev/null +++ b/checks/conventional-mdc.test @@ -0,0 +1,21 @@ +#!/bin/sh + +. $srcdir/defs.inc || exit 3 + +#info Checking conventional encryption +for i in 0 1 2 3 9 10 11 19 20 21 22 23 39 40 41 8192 32000 ; do + for ciph in 3des cast5 blowfish twofish rijndael; do + # *BSD's dd can't cope with a count of 0 + if test "$i" = "0"; then + : >z + else + dd if=data-80000 of=z bs=1 count=$i 2>/dev/null + fi + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \ + --force-mdc --cipher $ciph -c -o x --yes z + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \ + -o y --yes x + cmp z y || error "$ciph/$i: mismatch" + done +done + diff --git a/checks/conventional.test b/checks/conventional.test index 289a85095..87aeb9c56 100755 --- a/checks/conventional.test +++ b/checks/conventional.test @@ -2,22 +2,22 @@ . $srcdir/defs.inc || exit 3 -# temp. hack cause the format for 128 biut blocksize messages may change +# temp. hack cause the format for 128 bit blocksize messages may change GNUPG_ENABLE_TWOFISH=1 export GNUPG_ENABLE_TWOFISH #info Checking conventional encryption for i in plain-2 data-32000 ; do - echo "Hier spricht HAL" | $srcdir/run-gpg --passphrase-fd 0 -c -o x --yes $i - echo "Hier spricht HAL" | $srcdir/run-gpg --passphrase-fd 0 -o y --yes x + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -c -o x --yes $i + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -o y --yes x cmp $i y || error "$i: mismatch" done for a in cast5 3des twofish; do for i in plain-1 data-80000 ; do - echo "Hier spricht HAL" | $srcdir/run-gpg --passphrase-fd 0 \ + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 \ --cipher-algo $a -c -o x --yes $i - echo "Hier spricht HAL" | $srcdir/run-gpg --passphrase-fd 0 -o y --yes x + echo "Hier spricht HAL" | $GPG --passphrase-fd 0 -o y --yes x cmp $i y || error "$i: ($a) mismatch" done done diff --git a/checks/decrypt-dsa.test b/checks/decrypt-dsa.test index ba73ddf5f..6dc7dc459 100755 --- a/checks/decrypt-dsa.test +++ b/checks/decrypt-dsa.test @@ -4,7 +4,7 @@ #info Checking decryption of supplied DSA encrypted file for i in "plain-1" ; do - $srcdir/run-gpg $dsa_keyrings -o y --yes $srcdir/$i-pgp.asc + $GPG $dsa_keyrings -o y --yes $srcdir/$i-pgp.asc cmp $i y || error "$i: mismatch" done diff --git a/checks/decrypt.test b/checks/decrypt.test index 1d7449401..aab416750 100755 --- a/checks/decrypt.test +++ b/checks/decrypt.test @@ -4,8 +4,7 @@ #info Checking decryption of supplied files for i in $plain_files ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 \ - -o y --yes $srcdir/$i.asc + echo "$usrpass1" | $GPG --passphrase-fd 0 -o y --yes $srcdir/$i.asc cmp $i y || error "$i: mismatch" done diff --git a/checks/defs.inc b/checks/defs.inc index c975025da..2eb25c7f1 100755 --- a/checks/defs.inc +++ b/checks/defs.inc @@ -49,9 +49,6 @@ info () { echo "$pgmname:" $* >&2 } -chdir () { - cd $1 || fatal "cannot cd to $1" -} echo_n_init=no echo_n () { @@ -101,11 +98,9 @@ pgmname=`basename $0` [ -z "$srcdir" ] && fatal "not called from make" -cat <./options -no-greeting -no-secmem-warning -load-extension ../cipher/tiger -batch -emulate-md-encode-bug -EOF +GPG="../g10/gpg --homedir . " +exec 2> ${pgmname}.log + +: +# end \ No newline at end of file diff --git a/checks/detach.test b/checks/detach.test index cdad558c1..6a3ae05c5 100755 --- a/checks/detach.test +++ b/checks/detach.test @@ -4,7 +4,7 @@ #info Checking detached signatures for i in $plain_files $data_files ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sb -o x --yes $i - $srcdir/run-gpg -o /dev/null --yes x <$i || error "$i: bad signature" + echo "$usrpass1" | $GPG --passphrase-fd 0 -sb -o x --yes $i + $GPG -o /dev/null --yes x <$i || error "$i: bad signature" done diff --git a/checks/detachm.test b/checks/detachm.test index b5fb05af5..dc60bb239 100755 --- a/checks/detachm.test +++ b/checks/detachm.test @@ -4,6 +4,6 @@ #info Checking detached signatures of multiple files i="$plain_files $data_files" -echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -sb -o x --yes $i -cat $i | $srcdir/run-gpg -o /dev/null --yes x || error "$i: bad signature" +echo "$usrpass1" | $GPG --passphrase-fd 0 -sb -o x --yes $i +cat $i | $GPG -o /dev/null --yes x || error "$i: bad signature" diff --git a/checks/encrypt-dsa.test b/checks/encrypt-dsa.test index ba0564fd8..27891bf01 100755 --- a/checks/encrypt-dsa.test +++ b/checks/encrypt-dsa.test @@ -4,16 +4,16 @@ #info Checking encryption for i in $plain_files $data_files ; do - $srcdir/run-gpg $dsa_keyrings -e -o x --yes -r "$dsa_usrname2" $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings --always-trust -e -o x --yes -r "$dsa_usrname2" $i + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" done # and with cast for i in $plain_files $data_files ; do - $srcdir/run-gpg $dsa_keyrings --cipher-algo cast5 -e \ + $GPG $dsa_keyrings --always-trust --cipher-algo cast5 -e \ -o x --yes -r "$dsa_usrname2" $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/encrypt.test b/checks/encrypt.test index 468136cca..4e5c5c042 100755 --- a/checks/encrypt.test +++ b/checks/encrypt.test @@ -4,13 +4,13 @@ #info Checking encryption for i in $plain_files $data_files ; do - $srcdir/run-gpg -e -o x --yes -r "$usrname2" $i - $srcdir/run-gpg -o y --yes x + $GPG --always-trust -e -o x --yes -r "$usrname2" $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done for i in $plain_files $data_files ; do - $srcdir/run-gpg -e -o x --yes -r "$usrname2" --cipher-algo cast5 $i - $srcdir/run-gpg -o y --yes x + $GPG --always-trust -e -o x --yes -r "$usrname2" --cipher-algo cast5 $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/encryptp.test b/checks/encryptp.test index c63fb822f..7df24efec 100755 --- a/checks/encryptp.test +++ b/checks/encryptp.test @@ -4,7 +4,7 @@ #info Checking encryption with a pipe for i in $plain_files $data_files ; do - $srcdir/run-gpg -e --yes -r "$usrname2" <$i | tee yy | $srcdir/run-gpg --yes > y + $GPG --always-trust -e --yes -r "$usrname2" <$i | $GPG --yes > y cmp $i y || error "$i: mismatch" done diff --git a/checks/genkey1024.test b/checks/genkey1024.test index 6e01a61c4..e9852d7b6 100755 --- a/checks/genkey1024.test +++ b/checks/genkey1024.test @@ -1,105 +1,26 @@ #!/bin/sh -echo "test is currently disabled" -exit 0 - - . $srcdir/defs.inc || exit 3 -ignore_errors=yes - -if (expect -v) < /dev/null > /dev/null 2>&1 ; then - : -else - echo "\"expect\" needed but not found - test skipped" - exit 0 -fi - -LANG= -LANGUAGE= - -expect - </dev/null -#set timeout -1 -set timeout 8 -match_max 100000 -spawn ../g10/gpg --no-batch --homedir . --gen-key -expect { - -exact "Please select what kind of key you want:\r - (1) DSA and ElGamal (default)\r - (2) DSA (sign only)\r - (4) ElGamal (sign and encrypt)\r -Your selection? " { send -- "1\r" } - timeout { exit 1 } } -expect { - -exact "1\r -\r \rDSA keypair will have 1024 bits.\r -About to generate a new ELG-E keypair.\r - minimum keysize is 768 bits\r - default keysize is 1024 bits\r - highest suggested keysize is 2048 bits\r -What keysize do you want? (1024) " { send -- "\r" } - timeout { exit 1 } } -expect { - -exact "\r -\r \rRequested keysize is 1024 bits\r -Please specify how long the key should be valid.\r - 0 = key does not expire\r - = key expires in n days\r - w = key expires in n weeks\r - m = key expires in n months\r - y = key expires in n years\r -Key is valid for? (0) " { send -- "1\r" } - timeout { exit 1 } } -expect { - -exact "1\r -\r \rKey expires at " { } - timeout { exit 1 } } -expect { - -re "(.*)\r -" {} - timeout { exit 1 } } -expect { - -exact "Is this correct (y/n)? " { send -- "y\r" } - timeout { exit 1 } } -expect { - -exact "y\r -\r \r\r -You need a User-ID to identify your key; the software constructs the user id\r -from Real Name, Comment and Email Address in this form:\r - \"Heinrich Heine (Der Dichter) \"\r -\r -Real name: " { send -- "Harry H.\r" } - timeout { exit 1 } } -expect { - -exact "Harry H.\r -\r \rEmail address: " { send -- "hh@ddorf.de\r" } - timeout { exit 1 } } -expect { - -exact "hh@ddorf.de\r -\r \rComment: " { send -- "a test\r" } - timeout { exit 1 } } -expect { - -exact "a test\r -\r \rYou selected this USER-ID:\r - \"Harry H. (a test) \"\r -\r -Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? " { send -- "o\r" } - timeout { exit 1 } } -expect { - -exact "o\r -\r \rYou need a Passphrase to protect your secret key.\r -\r -Enter passphrase: " { sleep 1; send -- "abc\r" } - timeout { exit 1 } } -expect { - -ex "\r \rRepeat passphrase: " { sleep 1; send -- "abc\r" } - timeout { exit 1 } } -set timeout 600 -expect { - -re "^.*\r\npublic and secret key" { exit 0 } - eof { exit 1 } -} -exit 1 +../g10/gpg --quiet --batch --quick-random --homedir . --gen-key <y +cat /dev/null | $GPG -v --print-mds >y test_one "MD5" "D41D8CD98F00B204E9800998ECF8427E" test_one "SHA1" "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709" test_one "RMD160" "9C1185A5C5E9FC54612808977EE8F548B2258D31" @@ -25,7 +25,7 @@ fi [ "$failed" != "" ] && error "$failed failed for empty string" -echo_n "abcdefghijklmnopqrstuvwxyz" | $srcdir/run-gpg --print-mds >y +echo_n "abcdefghijklmnopqrstuvwxyz" | $GPG --print-mds >y test_one "MD5" "C3FCD3D76192E4007DFB496CCA67E13B" test_one "SHA1" "32D10C7B8CF96570CA04CE37F2A19D84240D3A89" test_one "RMD160" "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC" diff --git a/checks/mkdemodirs b/checks/mkdemodirs index b0755ab48..d6b7d7c4c 100755 --- a/checks/mkdemodirs +++ b/checks/mkdemodirs @@ -2,15 +2,15 @@ set -e -GPG="../g10/gpg --batch --quiet --no-secmem-warning" +GPG="../g10/gpg --batch --quiet --no-secmem-warning --allow-secret-key-import" NAMES='Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo Sierra Tango Uniform Victor Whisky XRay Yankee Zulu' if [ "$1" = "--clean" ]; then - for i in $NAMES; do + (for i in $NAMES; do [ -d $i ] && rm -r $i - done + done) || true exit 0 fi @@ -19,15 +19,15 @@ $GPG --dearmor -o pubdemo.gpg --yes ../checks/pubdemo.asc [ -f ./tdb.tmp ] && rm ./tdb.tmp GPGDEMO="$GPG --homedir . --trustdb-name ./tdb.tmp --no-default-keyring --keyring pubdemo.gpg --secret-keyring secdemo.gpg" -/bin/echo "Creating:\c" +echo -n "Creating:" for name in $NAMES; do - /bin/echo " $name\c" + echo -n " $name" [ -d $name ] && rm -r $name mkdir $name - $GPGDEMO --export-secret-key -o - $name | tee $name/Secret.gpg | \ - $GPG --homedir $name --import - $GPGDEMO --export -o - $name | tee $name/Public.gpg | \ - $GPG --homedir $name --import + $GPGDEMO --export-secret-key -o - $name > $name/Secret.gpg + $GPG --homedir $name --import $name/Secret.gpg + $GPGDEMO --export -o - $name > $name/Public.gpg + $GPG --homedir $name --import $name/Public.gpg [ -f $name/pubring.gpg~ ] && rm $name/pubring.gpg~ done echo "." diff --git a/checks/multisig.test b/checks/multisig.test new file mode 100755 index 000000000..c391f6fdc --- /dev/null +++ b/checks/multisig.test @@ -0,0 +1,145 @@ +#!/bin/sh +# Check that gpg verifies only signatures where there is no ambiguity +# in the order of packets. Needs the Demo Keys Lima and Mike. + +. $srcdir/defs.inc || exit 3 + +# (variable intialization was created using: +# for i in files; do echo "`echo $i | sed 's,[.-],_,g'`='"; \ +# gpg --no-version --enarmor <$i | grep -v ^Comment:; echo "'" ; done +# ) + +sig_1ls1ls_valid=' +-----BEGIN PGP ARMORED FILE----- + +kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg +ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e +8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOZANAwACETfKtR+3kQP4AawnYgV0ZXh0 +MTqIKvRJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCr0N8q1H7eR +A/gRAto6AKCWkmlzmRLUmakO/NByFxu+3vDwewCeMAqa5mhUztHwWk3Fw7hDgXQF +pzk= +=8jSC +-----END PGP ARMORED FILE----- +' +sig_ls_valid=' +-----BEGIN PGP ARMORED FILE----- + +rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI +K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT +QDUFTH2PvZRxjw== +=J+lb +-----END PGP ARMORED FILE----- +' +sig_sl_valid=' +-----BEGIN PGP ARMORED FILE----- + +iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU +tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n +dCBkbyB0aGF0Cg== +=N9MP +-----END PGP ARMORED FILE----- +' +sig_11lss_valid_but_is_not=' +-----BEGIN PGP ARMORED FILE----- + +kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g +c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT +mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy +XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB +Q341WRXKS/at +=Ekrs +-----END PGP ARMORED FILE----- +' +sig_11lss11lss_valid_but_is_not=' +-----BEGIN PGP ARMORED FILE----- + +kA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogyXUkgYW0g +c29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED+BECwQAAnRXT +mXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp5Yg/AwUAOogy +XTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0P01WmbgZJoZB +Q341WRXKS/atkA0DAAIRN8q1H7eRA/gAkA0DAAIRN8q1H7eRA/gBrCdiBXRleHQx +OogyXUkgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqIMl03yrUft5ED ++BECwQAAnRXTmXjVd385oD38W80XuheWKTGcAJ9pZ6/flaKDfw+SLido7xaUHuhp +5Yg/AwUAOogyXTfKtR+3kQP4EQLBAACgnN0IP+NztE0aAc/DZ17yHWR9diwAniN0 +P01WmbgZJoZBQ341WRXKS/at +=P1Mu +-----END PGP ARMORED FILE----- +' +sig_ssl_valid_but_is_not=' +-----BEGIN PGP ARMORED FILE----- + +iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU +tH60PslLE0A1BUx9j72UcY+IPwMFADqIK0s3yrUft5ED+BECLQMAn2jZUNOpB4Ou +urSQkc2TRfg6ek02AJ9+oJS0frQ+yUsTQDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJ +IGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRoYXQK +=Zven +-----END PGP ARMORED FILE----- +' +sig_1lsls_invalid=' +-----BEGIN PGP ARMORED FILE----- + +kA0DAAIRN8q1H7eRA/gBrCdiBXRleHQxOogq9EkgYW0gc29ycnksIEkgY2FuJ3Qg +ZG8gdGhhdAqIPwMFADqIKvQ3yrUft5ED+BEC2joAoJaSaXOZEtSZqQ780HIXG77e +8PB7AJ4wCprmaFTO0fBaTcXDuEOBdAWnOawnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5 +LCBJIGNhbid0IGRvIHRoYXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeD +rrq0kJHNk0X4OnpNNgCffqCUtH60PslLE0A1BUx9j72UcY8= +=nkeu +-----END PGP ARMORED FILE----- +' +sig_lsls_invalid=' +-----BEGIN PGP ARMORED FILE----- + +rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI +K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT +QDUFTH2PvZRxj6wnYgV0ZXh0MTqIK0tJIGFtIHNvcnJ5LCBJIGNhbid0IGRvIHRo +YXQKiD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCf +fqCUtH60PslLE0A1BUx9j72UcY8= +=BlZH +-----END PGP ARMORED FILE----- +' +sig_lss_invalid=' +-----BEGIN PGP ARMORED FILE----- + +rCdiBXRleHQxOogrS0kgYW0gc29ycnksIEkgY2FuJ3QgZG8gdGhhdAqIPwMFADqI +K0s3yrUft5ED+BECLQMAn2jZUNOpB4OuurSQkc2TRfg6ek02AJ9+oJS0frQ+yUsT +QDUFTH2PvZRxj4g/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF ++Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGP +=jmt6 +-----END PGP ARMORED FILE----- +' +sig_slsl_invalid=' +-----BEGIN PGP ARMORED FILE----- + +iD8DBQA6iCtLN8q1H7eRA/gRAi0DAJ9o2VDTqQeDrrq0kJHNk0X4OnpNNgCffqCU +tH60PslLE0A1BUx9j72UcY+sJ2IFdGV4dDE6iCtLSSBhbSBzb3JyeSwgSSBjYW4n +dCBkbyB0aGF0Cog/AwUAOogrSzfKtR+3kQP4EQItAwCfaNlQ06kHg666tJCRzZNF ++Dp6TTYAn36glLR+tD7JSxNANQVMfY+9lHGPrCdiBXRleHQxOogrS0kgYW0gc29y +cnksIEkgY2FuJ3QgZG8gdGhhdAo= +=phBF +-----END PGP ARMORED FILE----- +' + +save_IFS="${IFS}" +IFS="" +for i in "$sig_1ls1ls_valid" "$sig_ls_valid" "$sig_sl_valid"; do + echo "$i" | ./gpg_dearmor >x + IFS="${save_IFS}" + $GPG --verify x 2>/dev/null || error "valid is invalid" + IFS="" +done +#for i in "$sig_11lss_valid_but_is_not" "$sig_11lss11lss_valid_but_is_not" \ +# "$sig_ssl_valid_but_is_not"; do +# echo "$i" | $GPG --dearmor >x +# $GPG --verify /dev/null || error "valid is invalid" +#done + +# without the +e ksh seems to terminate the for loop +set +e +for i in "$sig_1lsls_invalid" "$sig_lsls_invalid" \ + "$sig_lss_invalid" "$sig_slsl_invalid" ; do + echo "$i" | ./gpg_dearmor >x + IFS="${save_IFS}" + $GPG --verify /dev/null && error "invalid is valid" + IFS="" +done +IFS="${save_IFS}" diff --git a/checks/options.in b/checks/options.in new file mode 100644 index 000000000..c789164aa --- /dev/null +++ b/checks/options.in @@ -0,0 +1,6 @@ +no-greeting +no-secmem-warning +no-permission-warning +batch +emulate-md-encode-bug +no-auto-check-trustdb diff --git a/checks/pgp263-test.pub.asc b/checks/pgp263-test.pub.asc new file mode 100644 index 000000000..53310d778 --- /dev/null +++ b/checks/pgp263-test.pub.asc @@ -0,0 +1,14 @@ +Type Bits/KeyID Date User ID +pub 888/A50283F1 2001/11/08 pgp2.6.3-test-key + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQB8AzvqRosAAAEDeNMKLJMJQeGC2RG5Nec6R2mzC12N1wGLiYYJCsmSQd1Y8mht +A2Sc+4k/q5+l6GHtfqUR/RTCIIudAZUzrQVIMhHDKF+5de9lsE5QxQS1u43QGVCb +/9IYrOLOizYQ2pkBtD9LCrf7W2DccMEkpQKD8QAFE7QRcGdwMi42LjMtdGVzdC1r +ZXmJAIQDBRA76kaL3HDBJKUCg/EBAZMoA3Yqqdix6B2RAzywi9bKSLqwAFVL+MMw +W+BnYeBXF9u+bPpQvtyxgi0vx8F9r84B3HAhZNEjBWODF6vctIQhXhAhXIniDTSj +HNzQ/+nbWnebQn18XUV2SdM1PzMOblD+nISte7+WUfWzlD7YUJPkFPw= +=b498 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/checks/pgp263-test.sec.asc b/checks/pgp263-test.sec.asc new file mode 100644 index 000000000..78992e3b7 --- /dev/null +++ b/checks/pgp263-test.sec.asc @@ -0,0 +1,18 @@ +Type Bits/KeyID Date User ID +sec 888/A50283F1 2001/11/08 pgp2.6.3-test-key + +-----BEGIN PGP SECRET KEY BLOCK----- +Version: 2.6.3a + +lQGdAzvqRosAAAEDeNMKLJMJQeGC2RG5Nec6R2mzC12N1wGLiYYJCsmSQd1Y8mht +A2Sc+4k/q5+l6GHtfqUR/RTCIIudAZUzrQVIMhHDKF+5de9lsE5QxQS1u43QGVCb +/9IYrOLOizYQ2pkBtD9LCrf7W2DccMEkpQKD8QAFEwADd0Kk5aeyFM3zbPgfikkE +7iFg9h2LG3nARmA4wAnCZaQ3CS5zRHCdXOf5KLkm6xFza1yMat4iWx6ULvuuNpIc +RmkHccyXYkRi3Hvacd5A9VCNw1UKtCdaCKgacsfplU0s1xYWGZd4J8Jg8boSfW5W +gwG8Dc9R20HHno8uD2vfr5rg8ElWvbFyJI/j4eCVAd+NYAGNvB8I3VP38IIYcavh +YYcGjrpxbGVRybsBvA9IJltpGaVulxwpeCp5NecCGgoAUsN4Ktf42Pg7HXDlQL6r +Xs/YggMztj4NzEgBHXAOLShdKKhDAbEByVSKXZD9A8J+RejXBl6VbuJmD/5qOvph +GAPKS3ahPDj8438HyD7yIDLYYVRKfxjWHLubc46Pgui0EXBncDIuNi4zLXRlc3Qt +a2V5 +=l/aV +-----END PGP SECRET KEY BLOCK----- diff --git a/checks/pubring.asc b/checks/pubring.asc index 2bb25df14..b58aa5c11 100644 --- a/checks/pubring.asc +++ b/checks/pubring.asc @@ -1,78 +1,734 @@ -This is a test public keyring simply stored by GNUPG so that -it is easier to make diff files. - -pub 768G/9D266E0F 1998-04-28 Test one (pp=def) -sig 9D266E0F 1998-04-28 Test one (pp=def) -sig 2E5FA4F4 1998-04-28 test two (no pp) -sig 6D11D6D3 1998-04-28 test three (pp=abc) -pub 800G/2E5FA4F4 1998-04-28 test two (no pp) -sig 2E5FA4F4 1998-04-28 test two (no pp) -sig 9D266E0F 1998-04-28 Test one (pp=def) -sig 6D11D6D3 1998-04-28 test three (pp=abc) -pub 768G/6D11D6D3 1998-04-28 test three (pp=abc) -sig 6D11D6D3 1998-04-28 test three (pp=abc) -sig 9D266E0F 1998-04-28 Test one (pp=def) -sig 2E5FA4F4 1998-04-28 test two (no pp) - - - -----BEGIN PGP ARMORED FILE----- -Version: GNUPG v0.2.15a (Linux) -Comment: This is an alpha version! -Comment: Use "gpgm --dearmor" for unpacking +Version: GnuPG v1.0.7 (GNU/Linux) +Comment: Use "gpg --dearmor" for unpacking -mM8DNUWBuARHEAMA8bSQw1VFSXbgZ+nNXhM9xeDD+OpKQU4hUaCKfuTtRHoY5QxTPz3DFWRl -FewsA50Ou28jlPWxIKZaaGxMqbDtqyUsm6AEz/vRi5VKiVHf28XUkMryQSTHvjwJFVb7+6Wb -AAMFAwDXZiawNtgYsjwVedv/xXdhTsrf0Tn/8HCj3S9N/MAT0zCnXL0flYeqhqL/okuBcrwM -A4amAIWGVW7ws7k7QgrfJoWG2SELxIT9MovMLvq5Kh55J7H6Yn6uoFzIOX0A43HQIiNjcmVh -dGVkIGJ5IEdOVVBHIHYwLjIuMTVhIChMaW51eCm0KFRlc3Qgb25lIChwcD1kZWYpIDxvbmVA -dGVzdC5ub3doZXJlLm5pbD6I1wMFEzVFgbg8a7vmnSZuDxADD/4DAK0FELG1gICh/fxO5dXu -lV+S1CY9YPQwRxQN7zYlixA7vedTCN9jutMC6fOlmMXqfivF2CMux3uz0oTJgjF/myh+jkcO -sE+iUgcO+fdMIn4oY53Pval5zuCcmqqbszP6mQMAqIYYNtE2BI6acRU8sqwIxx/GiVqELwzX -4QGp5N/4oURoZJ4Ybb8+6eEePI1vzIpLq9TO0ttQzDv9hO8WNyYEPVAoe9gOIoMYOh9E0W9R -u0wf4sh67KCrRvc7yrFTMwHtiN8DBRA1RYLMDvng6C5fpPQQAzlHAx4qEZmAhoAtCfgQmlmq -HIwcOa2xI/eOsqexT6eYMty8f/vsNznGhTh5gJ3PDDy8U/Lj1KRJWPeDSZJ/6tZ/3DUd/x+K -jPzVVnm1zlJSflR5AWLS7IQiyJzz7uo2dUiCs2nO4rZcAyDaLbj/2aWwI92UQzKjWvcS49lW -r2wp0QURUomqvNexKkHHDyIRhwspXwT9glETyn+focZKRBJTv0QtxOMVQeGaUnIuAcsDgpZu -ZkXBcdXgPbmj39rN+nNUW1UI0fKsnBl5cnSgiNcDBRA1RYLaZE80um0R1tMQAwq4Av9rzmMg -XgDtJy+mauJJ5FUEE5GY3bIul1MuIbaMv6T99uWgwD9q2HsV0z9/T552cOTJ/DIkSjdusZ6+ -PlY8jYDK4xTYwcglPuMH5/EsKW8zZwcwYiqnGMbmY4F70SxZW2EC/1p760rM7MrNCDAWnEle -gTvEMvutfK+K3DOu+Ba+KxU3zfgWr4z6B74QV2TvHrF0Zgu9UpXOp0FghufA6JevCvYhzNDM -4VJV24QaF3bt16JoHQyiS9jtYcMl4IzexeeO0JjXAzVFggEAABADINyO1leIKxvoee6oi0zk -I9SCJ6dSTEH7/kETqetNArjqClenO1K0AVd+MqMajl97bg5iUYGam55PECkkozOlscDzDF9e -xWY6sey44dBREQhgXLVWE4GZ1G3sy85aD+sVHgxwlz8AAwUDILAV8w6FL7PpgiedAOHslMtq -f7sh1IeNSkCjRdqvMCKgKroSLQto9WprXMUv3KHmTL7TpZNad+8xJUK7R5GHUTR1OIFQMJvT -odG8RU6JOaGoeTqWgs61v00fFgwY6sYO11ckmsfQIiNjcmVhdGVkIGJ5IEdOVVBHIHYwLjIu -MTVhIChMaW51eCm0J3Rlc3QgdHdvIChubyBwcCkgPHR3b0B0ZXN0Lm5vd2hlcmUubmlsPojf -AwUTNUWCAQ754OguX6T0EAOQsQMfXrBhe1g+hBCwQH94+08VqNGS/+Fs8s4FRmEP1Y0TuT6U -qf9QLHtfbPgKbJL1NwGgy6dn4TfWo2PRj0U8ai+YIIPZopl4hnrj+v1f94V/IbMd3N77K0F0 -rJrHzL4egHi95BUVdgMgr00QAYcbbZItd/wIb2TNSu/DRlzEXezA3xRuCIBnTdsrHMPc2B4l -mCQsyx9/fmBlwrVLlaftBTvrOUa/yXf8hHwPv48avRwgClaoChExhFMdEA9Df5ju4192VldJ -yJgPVz0Ze4jXAwUQNUWCsTxru+adJm4PEAOeIwMAhzYyjVb5vlae3V3VO+5+Zsx4SVRB2NeC -Y74FIN5vXMoWJyt/UjmXC9CmI82PvVD3F8RXKUZqZC9gXcGyDYyZ87oooYc9HbQ7lhyOWsv/ -0dWztX9UQQrHdScQ0TbZcC2aAvwJF7WESAGhOGssVKWaUkXZJV1sCpyyEtkUP/UJtcGha/Op -PlmG6vC9XW5ymtRk0XhFkvG4dLopbRIZgAI0CmHSloKIL5Y4JzOfc5bccNCB/tiI+3Y1JIr3 -AYMqaSTjoGOI1gMFEDVFgwJkTzS6bRHW0xAD83sC93MCuEN8MCJGTZX//I7QVsg5DJ9xJRdy -5Te6MNA1Ie1o7+EJZ1MqDVF/6+HkITqGWFOPD/GYPmgdP5QALfHW6z9YddHOHH6Skt2fC2NW -Tip4e+/t8iAOR/ynwocPpyHkAwCHsxTXtRlaCbIt40/3d0LFPoN4JYBVDM+pWfNgNAWUzgME -Mua2P24g4P4NZnW3fsJuYQ6Ro7jqu6oolfFkxVOYd2/KrnH5Mggu3D8q+gg68kzXTj62QW9v -TBax5Ve0Kk+YzwM1RYJlAAAQAwCWZQsoNJJI8u1nV+5VZaXZqZBn+uk3fp/my7l9YLQeV5S9 -U76Ogdw0la/YiWX2m8Aw+hO47pYswsyRi2lu/FE/dr0o0CB53LB4EnFJPiBHrB8rm3wI142B -QeJ9Dj5YU/MAAwYC/1gB0NoFl2QhbYY83tuLg/UlIkM8CZtxtXR9vfQq0UgrVuDoeLx0/mln -Wm8pmJsHR+0r8sL2yjl7P0RQ+FJtiaMTVHihJyhXukCO1bPM3PX8L/QsmXFzWcfmavk11xpP -NdAiI2NyZWF0ZWQgYnkgR05VUEcgdjAuMi4xNWEgKExpbnV4KbQsdGVzdCB0aHJlZSAocHA9 -YWJjKSA8dGhyZWVAdGVzdC5ub3doZXJlLm5pbD6I1wMFEzVFgmVkTzS6bRHW0xADVtEDAIWy -FsZZgyT9wLmEsVbLcv2WNK/z7XweyDOV203Z3Po5lo75+c8bFkRPNcD/0R/nD5wbyNPACFHx -e7VUm+wLHZFq5Hw8TuAegqNq0ZlgeR/vLgs54m1eOi3jbDfyZMJASAL/XKRGnGu3oi6SjknK -sKhFOprdn7DeMW0q7YP5WtRTnnrJjIhDl0c+mi82Yj2OVEOLg3SaILBDZJd9muLPHQLAp95X -sKZ0nHfBzlFFsr0V5BvWF4UV+U9JHxyDuXLWyEDbiNcDBRA1RYK7PGu75p0mbg8QA3mwAvsH -XEo6HotEGw0stskTnV/Dp32bSJ8yRq2kOWfQAgaY1ZZWVRSPtHBDAJZJ/LpfWXPke90M3B72 -v0a9gAxOx5VfevaaXJAdp/ZjrVh1TE90LujbPVNeHt4a1dD0bQa9EbwC/1NTZMfb8LDHxYds -JdDdZxsxfCDy2U7BWC1e3LLQCJOeNfSx76ICJBLq+HOpCgP2AodGgV9Rx01O3Fz8Gx3iVRgZ -bKnyS8perkS3AFayedGat/6reUI6KJtddro0SIeBxIjfAwUQNUWDEw754OguX6T0EAPKMgMe -L8YKAj4KvkJBWNxt1W+WTjF2YBj4pYmrWisXxgmRZWEwwyDHYecH1zE2L12o82QGprbU8BW+ -GUXQVxbRt0rvlDqfGPN5HAgdjES7sK3qVZLsVeMcnhpjDDQkpYkCIsWueCKKRwMfSiqZ1S3o -BHIz3CVzbQkdMp6FbpSYXRR55CyzVdUZDb9ynXKxQCk3Pmn0bTFsRWRFOlRe3oVpS2lM2EQF -u5cWheypAt2y86ZuoevHPkcpsR0UXD129IzwOV3cstGm3jCAhdGMmA== -=eCl1 +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 +oda1yt8vyXK5AQ0ENuOPDxAEAJyN1x9X9LsjfX2Z8O9s7BzMO9OoOxFtvZw+FA0B +uDs0WVYkq1GuZ9/XiO0K30zvtZnlb7NMvBfz7xbLeYx+vKzy5xkq18+LE5dU+HKK +dRQZKrrwgCsDy8tJRO447QsiLTksCDqPMaE32OCRBF5nKrG5vih7/cmEhf2CuAn+ +2yM3AAMHA/0Z5eYysaLnAwPeqQ9vNvUyrCxUEmrvl4svG7zkkg3ZcgAbDpDQUmni +jt3gEBCoAzO3c41TU5wJaUNBEPGPWfKcTlmBEGJWjK50QQuA2diGncxIS5SDs+QV +af434a6/KFVQcCmV7K8/T2S8/nuGJ/rIlFL5XovW6A/S9mYEjh2pD4hOBBgRAgAG +BQI2448PABIJEC1yfMdoaXc0B2VHUEcAAQEgqQCfcDXmD8uNVdKg/C9vqI3JSndq +knsAnRxzVeHi/iJ73OCKtvFrHbV9GogqmQGiBDbjkGcRBAC/DCQungO2iJ7j9+9q +d2crjBU8K+AmQhs27JBkJqtAbC/xFqkHBsA1Pi8Zb6TLa/OCm2PbXFiM5x00wiEn +VKNzuGOzU8uHB6kwWtLj8+V7VOWOkSDEtnlTF6u0y9JOvs7GwDvqOM5C3QH7La+z +nNeAu1527Hj6l0XGSAzyvp+NkwCgnktU11VFpKSIdoplZBayN9OzT8sD/Awc/890 +fiSMWYNGo4+n6IHxhjBBM9lL+DAe1RtCEtwUSWNrGsIxFnDRkMxvMpaT4GusG+DP +haTddrDBSyFiCLxKDBYgMbSO6wQ9g6zWEEh1ZMTMVU/akr81DOEColXn/f3Q4sRj +xI3hu2z8tjVewAPNTuWETQ6iHHoVqdpkK4aABACfbMrnfK6TujxSs91MfKBWfYxy +w9hjM6+VV8cJJdDXiheMKzWcrVecwgYYzukmNinO//BRmQcs1wdfi5UdfHLNFDig +w96SdyZpHx+79ghD3NqDmzYakoRIoDKcZAIrAjgfl5if6vIiA4c1LjhSdcVTBsSy +ic/mkk01EgztWKY0abQtQ2hhcmxpZSBUZXN0IChkZW1vIGtleSkgPGNoYXJsaWVA +ZXhhbXBsZS5uZXQ+iF0EExECABUFAjbjkGcDCwoDAxUDAgMWAgECF4AAEgkQQT9K +8xr9q2wHZUdQRwABAT5EAJ9fcDAXA+7n6av9/VJr9a/Sb1PnuACfVMEihQSsyol6 +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 +=Xw/z -----END PGP ARMORED FILE----- diff --git a/checks/run-gpg b/checks/run-gpg deleted file mode 100755 index 28d575e95..000000000 --- a/checks/run-gpg +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -[ -n "$show_cmds" ] && echo "../g10/gpg --homedir . $*" >&2 - -if ../g10/gpg --homedir . $* 2>err.tmp.$$ ; then - : -else - echo "(../g10/gpg --homedir . $*) failed" >&2 - cat err.tmp.$$ >&2 - rm err.tmp.$$ - exit 1 -fi -fgrep -v -f $srcdir/run-gpg.patterns err.tmp.$$ >&2 -rm err.tmp.$$ - diff --git a/checks/run-gpg.patterns b/checks/run-gpg.patterns deleted file mode 100644 index fde7bbbe7..000000000 --- a/checks/run-gpg.patterns +++ /dev/null @@ -1,14 +0,0 @@ -gpg: Good signature from -gpg: aka " -gpg: Signature made -gpg: ./trustdb.gpg: trustdb created -gpg: NOTE: cipher algorithm 3 not found in preferences -gpg: NOTE: cipher algorithm 4 not found in preferences -gpg: NOTE: secret key 2E5FA4F4 is NOT protected. -gpg: NOTE: secret key 439F02CA is NOT protected. -gpg: WARNING: using insecure random number generator -gpg: NOTE: signature key expired -NOTE: this is a development version! -secret key without public key - skipped -gpg: using secondary key CB879DE9 instead of primary key 439F02CA - diff --git a/checks/run-gpgm b/checks/run-gpgm deleted file mode 100755 index 9afbee393..000000000 --- a/checks/run-gpgm +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if ../g10/gpgm --homedir . $* 2>err.tmp.$$ ; then - : -else - echo "(../g10/gpgm --homedir . $*) failed" >&2 - cat err.tmp.$$ >&2 - rm err.tmp.$$ - exit 1 -fi -rm err.tmp.$$ - diff --git a/checks/seat.test b/checks/seat.test index f89234e60..72ab27f41 100755 --- a/checks/seat.test +++ b/checks/seat.test @@ -3,8 +3,9 @@ . $srcdir/defs.inc || exit 3 for i in $plain_files ; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -seat -r two -o x --yes $i - $srcdir/run-gpg -o y --yes x + echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust -seat \ + -r two -o x --yes $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/signencrypt-dsa.test b/checks/signencrypt-dsa.test index b93e5d359..41bf83164 100755 --- a/checks/signencrypt-dsa.test +++ b/checks/signencrypt-dsa.test @@ -1,24 +1,20 @@ #!/bin/sh -echo "test is currently disabled" -exit 0 - . $srcdir/defs.inc || exit 3 - #info Checking signing and encryption for DSA for i in $plain_files $data_files ; do - $srcdir/run-gpg $dsa_keyrings -se -o x --yes \ + $GPG $dsa_keyrings --always-trust -se -o x --yes \ -u "$dsa_usrname1" -r "$dsa_usrname2" $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" done -for da in ripemd160 sha1 md5; do +for da in ripemd160 sha1; do for i in $plain_files; do - $srcdir/run-gpg $dsa_keyrings -se -o x --yes --digest-algo $da \ + $GPG $dsa_keyrings --always-trust -se -o x --yes --digest-algo $da \ -u "$dsa_usrname1" -r "$dsa_usrname2" $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" # process only the first one break diff --git a/checks/signencrypt.test b/checks/signencrypt.test index fa9363f7f..1d05990fc 100755 --- a/checks/signencrypt.test +++ b/checks/signencrypt.test @@ -5,9 +5,9 @@ #info Checking signing and encryption for i in $plain_files $data_files ; do - echo "$usrpass1" \ - | $srcdir/run-gpg --passphrase-fd 0 -se -o x --yes -r "$usrname2" $i - $srcdir/run-gpg -o y --yes x + echo "$usrpass1" | $GPG --passphrase-fd 0 --always-trust \ + -se -o x --yes -r "$usrname2" $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done diff --git a/checks/sigs-dsa.test b/checks/sigs-dsa.test index 0e14f2060..2294cf55a 100755 --- a/checks/sigs-dsa.test +++ b/checks/sigs-dsa.test @@ -1,24 +1,19 @@ #!/bin/sh -echo "test is currently disabled" -exit 0 - - . $srcdir/defs.inc || exit 3 - #info Checking DSA signatures (default digest algo) for i in $plain_files $data_files; do - $srcdir/run-gpg $dsa_keyrings -s -o x --yes -u $dsa_usrname1 $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings -s -o x --yes -u $dsa_usrname1 $i + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" done -for da in ripemd160 sha1 md5; do +for da in ripemd160 sha1; do for i in $plain_files; do - $srcdir/run-gpg $dsa_keyrings --digest-algo $da \ + $GPG $dsa_keyrings --digest-algo $da \ -s -o x --yes -u $dsa_usrname1 $i - $srcdir/run-gpg $dsa_keyrings -o y --yes x + $GPG $dsa_keyrings -o y --yes x cmp $i y || error "$i: mismatch" # process only the first one break diff --git a/checks/sigs.test b/checks/sigs.test index a32388948..7a8f998c1 100755 --- a/checks/sigs.test +++ b/checks/sigs.test @@ -4,21 +4,21 @@ #info Checking signatures for i in $plain_files $data_files; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 -s -o x --yes $i - $srcdir/run-gpg -o y --yes x + echo "$usrpass1" | $GPG --passphrase-fd 0 -s -o x --yes $i + $GPG -o y --yes x cmp $i y || error "$i: mismatch" done hash_algo_list="ripemd160 sha1 md5" -if have_hash_algo "TIGER"; then - hash_algo_list="$hash_algo_list tiger" +if have_hash_algo "TIGER192"; then + hash_algo_list="$hash_algo_list tiger192" fi for da in $hash_algo_list ; do for i in $plain_files; do - echo "$usrpass1" | $srcdir/run-gpg --passphrase-fd 0 --digest-algo $da \ + echo "$usrpass1" | $GPG --passphrase-fd 0 --digest-algo $da \ -s -o x --yes $i - $srcdir/run-gpg -o y --yes x + $GPG -o y --yes x cmp $i y || error "$i: mismatch" # process only the first one break diff --git a/checks/version.test b/checks/version.test index 13ca07364..f1fd7284f 100755 --- a/checks/version.test +++ b/checks/version.test @@ -3,7 +3,7 @@ . $srcdir/defs.inc || exit 3 # print the GPG version -$srcdir/run-gpg --version +$GPG --version #fixme: check that the output is correct diff --git a/cipher/ChangeLog b/cipher/ChangeLog new file mode 100644 index 000000000..da3ff580e --- /dev/null +++ b/cipher/ChangeLog @@ -0,0 +1,902 @@ +2002-05-07 Stefan Bellon + + * md.c (md_start_debug): Use EXTSEP_S instead of ".". + +2002-04-24 Werner Koch + + * tiger.c (tiger_final): Removed superfluous token pasting operators. + * md5.c (md5_final): Ditto. + +2002-04-22 Stefan Bellon + + * rndriscos.c (func_table): Made func a function pointer. + (init_device): Improved loading of CryptRandom module. + +2002-04-18 Werner Koch + + * rndlinux.c, rndegd.c, rndunix.c (func_table): Made func a + function pointer. Note that we still need to change the module + interface to cope with data vs function pointer problems. Hmmm, + even dlsym has a problem with this. + +2002-04-10 David Shaw + + * cipher.c (setup_cipher_table, cipher_open, cipher_encrypt, + cipher_decrypt, dummy_setkey, dummy_encrypt_block, + dummy_decrypt_block): the dummy cipher should only be built on + development versions. + +2002-04-06 Werner Koch + + * rijndael.c (rijndael_get_info): We do only support a 128 bit + blocksize so it makes sense to change the algorithm strings to + AES. + * cipher.c (string_to_cipher_algo): Map "RIJNDAEL" to "AES". + +2002-02-14 Werner Koch + + * random.c (mix_pool): Removed the failsafe stuff again. It makes + the code more complicate and may give the path to more bugs. + +2002-02-10 Werner Koch + + * random.c (mix_pool): Carry an extra failsafe_digest buffer + around to make the function more robust. + +2002-02-08 Werner Koch + + * random.c (add_randomness): Xor new data into the pool and not + just copy it. This avoids any choosen input attacks which are not + serious in our setting because an outsider won't be able to mix + data in and even then we keep going with a PRNG. Thanks to Stefan + Keller for pointing this out. + +2002-01-02 Stefan Bellon + + * rndriscos.c [__riscos__]: Updated include file name. + +2001-12-21 Werner Koch + + * Makefile.am (DISCLEANFILES): Add construct.c + +2001-12-19 Werner Koch + + * rndw32.c [CYGWIN32]: Include winioctl.h. By Disastry. + +2001-11-08 Werner Koch + + * primegen.c (gen_prime): Set 2 high order bits for secret primes. + * rsa.c (generate): Loop until we find the exact modulus size. + Changed the exponent to 41. + +2001-10-22 Werner Koch + + * Makefile.am: Need to use $(EXEEXT) where approriate. + +2001-09-09 Werner Koch + + * rsa.c (rsa_get_info): s/usage/r_usage/ to avoid shadow warnings. + +2001-08-24 Werner Koch + + * md.c (md_write): Made buf arg const. + +2001-08-22 Werner Koch + + * random.c (fast_random_poll): Don't use gethrtime if it is broken. + +2001-08-20 Werner Koch + + Applied patches from Stefan Bellon to support + RISC OS. Nearly all of these patches are identified by the + __riscos__ macro. + * blowfish.c, twofish.c: Added pragmas for use with a Norcraft + compiler. + * dynload.c, md5.c, rmd160.c, sha1.c: Minor patches for RISC OS. + * rndriscos.c: New. + * rnd-internal.h: Added prototype. + * random.c (fast_random_poll): Use '#if defined' instead of just + 'defined'; needed for RISC OS. + * primegen.c (gen_prime): count? are now ints for consistence + with is_prime(). + +2001-08-08 Werner Koch + + * rndw32.c (gather_random): Use toolhelp in addition to the NT + gatherer for Windows2000. Suggested by Sami Tolvanen. + + * random.c (read_pool): Fixed length check, this used to be one + byte to strict. Made an assert out of it because the caller has + already made sure that only poolsize bytes are requested. + Reported by Marcus Brinkmann. + +2001-07-18 Werner Koch + + * rndlinux.c (gather_random): casted a size_t arg to int so that + the format string is correct. Casting is okay here and avoids + translation changes. + +2001-06-12 Werner Koch + + * cipher.c (string_to_cipher_algo): Use ascii_strcasecmp(). + * md.c (string_to_digest_algo): Ditto. + * pubkey.c (string_to_pubkey_algo): Ditto. + * rndw32.c (slow_gatherer_windowsNT): Ditto. Not really needed + here but anyway. + +2001-04-29 Werner Koch + + * random.c (fast_random_poll): Do not check the return code of + getrusage. + +2001-04-17 Werner Koch + + * rndunix.c: Add a signal.h header to avoid warnings on Solaris 7 + and 8. + +2001-04-16 Werner Koch + + * dynload.c [__MINGW32__]: Applied patch from Timo Schulz to make + it work under W32. This patches is based on the one from + Disastry@saiknes.lv + +2001-04-06 Werner Koch + + * rijndael.c, des.c, blowfish.c, twofish.c, cast5.c (burn_stack): + New. Add wrappers for most functions to be able to call + burn_stack after the function invocation. This methods seems to be + the most portable way to zeroise the stack used. It does only work + on stack frame based machines but it is highly portable and has no + side effects. Just setting the automatic variables at the end of + a function to zero does not work well because the compiler will + optimize them away - marking them as volatile would be bad for + performance. + * md5.c, sha1.c, rmd160.c, tiger.c (burn_stack): Likewise. + * random.c (burn_stack): New. + (mix_pool): Use it here to burn the stack of the mixblock function. + +2001-04-02 Werner Koch + + * primegen.c (generate_elg_prime): I was not initialized for mode + != 1. Freed q at 3 places. Thanks to Tommi Komulainen. + +2001-03-28 Werner Koch + + * md5.c (md5_final): Fixed calculation of hashed length. Thanks + to disastry@saiknes.lv for pointing out that it was horrible wrong + for more than 512MB of input. + * sha1.c (sha1_final): Ditto. + * rmd160.c (rmd160_final): Ditto. + * tiger.c (tiger_final): Ditto. + +2001-03-19 Werner Koch + + * blowfish.c (encrypt,do_encrypt): Changed name to do_encrypt to + avoid name clahses with an encrypt function in stdlib.h of + Dynix/PIX. Thanks to Gene Carter. + * elgamal.c (encrypt,do_encrypt): Ditto. + +2001-03-12 Werner Koch + + * twofish.c (gnupgext_enum_func): Add some static when comnpiled + as a module. + + * tiger.c (tiger_get_info): Return "TIGER192" and not just + "TIGER". By Edwin Woudt. + +2001-03-08 Werner Koch + + * random.c: Always include time.h - standard requirement. Thanks + to James Troup. + +2001-01-18 Werner Koch + + * rndw32.c: Fixed typo and wrong ifdef for VER_PLATFORM* macro + +2001-01-12 Werner Koch + + * cipher.c (cipher_encrypt,cipher_encrypt): Use blocksize and + not 8 for CBC mode (However: we don't use CBS in OpenPGP). + +2000-11-22 Werner Koch + + * rndegd.c (gather_random): Fixed default socket to be '=entropy'. + Thanks to Tomasz Kozlowski. + +2000-10-12 Werner Koch + + * rijndael.c: New. + * cipher.c: Add Rijndael support. + +Wed Oct 4 15:50:18 CEST 2000 Werner Koch + + * sha1.c (transform): Use rol() macro. Actually this is not needed + for a newer gcc but there are still aoter compilers. + +Thu Sep 14 14:20:38 CEST 2000 Werner Koch + + * random.c (fast_random_poll): Check ENOSYS for getrusage. + * rndunix.c: Add 2 sources for QNX. By Sam Roberts. + +Wed Sep 13 18:12:34 CEST 2000 Werner Koch + + * rsa.c (secret): Speed up by using the CRT. For a 2k keys this + is about 3 times faster. + (stronger_key_check): New but unused code to check the secret key. + +Wed Sep 6 17:55:47 CEST 2000 Werner Koch + + * rsa.c: Changed the comment about the patent. + * Makefile.am: Included rsa.[ch]. + * pubkey.c: Enabled RSA support. + (pubkey_get_npkey): Removed RSA workaround. + +Fri Aug 25 16:05:38 CEST 2000 Werner Koch + + * rndlinux.c (open_device): Loose random device checking. + By Nils Ellmenreich. + + * rndegd.c (gather_random): Name of socket is nom configurable. + +Wed Jun 28 11:54:44 CEST 2000 Werner Koch + + * 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. + +Fri Jun 9 10:09:52 CEST 2000 Werner Koch + + * 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 + +Sun May 28 13:55:17 CEST 2000 Werner Koch + + * random.c (read_seed_file): Binary open for DOSish system + (update_random_seed_file): Ditto. + + * rndw32.c: Add some debuging code enabled by an environment variable. + +Tue May 23 09:19:00 CEST 2000 Werner Koch + + * rndw32.c: Started with alternative code to replace entropy.dll + +Thu May 18 11:38:54 CEST 2000 Werner Koch + + * primegen.c (register_primegen_progress): New. + * dsa.c (register_pk_dsa_progress): New. + * elgamal.c (register_pk_elg_progress): New. + +Fri Apr 14 19:37:08 CEST 2000 Werner Koch + + * twofish.c (twofish_get_info): Fixed warning about cast. + +Tue Mar 28 14:26:58 CEST 2000 Werner Koch + + * random.c [MINGW32]: Include process.h for getpid. + +Thu Mar 2 15:37:46 CET 2000 Werner Koch + + * random.c (fast_random_poll): Add clock_gettime() as fallback for + system which support this POSIX.4 fucntion. By Sam Roberts. + + * rndunix.c: Add some more headers for QNX. 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. + + * sha1.c (sha1_get_info): Removed those stupid double lines. Dave + is really a good lint. + +Wed Feb 23 10:07:57 CET 2000 Werner Koch + + * twofish.c (twofish_get_info): Add some const to the casts. By Martin + Kahlert. + +Mon Feb 14 14:30:20 CET 2000 Werner Koch + + (update_random_seed_file): Silently ignore update request when pool + is not filled. + +Fri Feb 11 17:44:40 CET 2000 Werner Koch + + * 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. + + * rndegd.c (gather_random): Shortcut level 0. + * rndunix.c (gather_random): Ditto. + * rndw32.c (gather_random): Ditto. + +Fri Jan 14 18:32:01 CET 2000 Werner Koch + + * 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. + +Thu Jan 13 19:31:58 CET 2000 Werner Koch + + * 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 + + * random.c (read_pool): Print a more friendly error message in + cases when too much random is requested in one call. + + * Makefile.am (tiger): Replaced -O1 by -O. Suggested by Alec Habig. + +Sat Dec 4 12:30:28 CET 1999 Werner Koch + + * primegen.c (generate_elg_prime): All primes are now generated with + the lowest random quality level. Becuase they are public anyway we + don't need stronger random and by this we do not drain the systems + entropy so much. + +Thu Oct 28 16:08:20 CEST 1999 Werner Koch + + * 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(). + + * elgamal.c (sign): Hugh found strange code here. Replaced by BUG(). + +Mon Oct 11 09:24:12 CEST 1999 Werner Koch + + * rndw32.c (gather_random): Handle PCP_SEEDER_TOO_SMALL. + +Sat Oct 9 20:34:41 CEST 1999 Werner Koch + + * Makefile.am: Tweaked module build and removed libtool + +Fri Oct 8 20:32:01 CEST 1999 Werner Koch + + * rndw32.c (load_and_init_winseed): Use the Registry to locate the DLL + +Mon Oct 4 21:23:04 CEST 1999 Werner Koch + + * md.c (md_reset): Clear finalized; thanks to Ulf Moeller for + fixing this bug. + +Sat Sep 18 12:51:51 CEST 1999 Werner Koch + + + * Makefile.am: Never compile mingw32 as module + +Wed Sep 15 14:39:59 CEST 1999 Michael Roth + + * 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 + + * rndw32.c: New. + +Mon Sep 13 10:51:29 CEST 1999 Werner Koch + + * 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 + + * Makefile.am: Fixed seds for latest egcc. By Ollivier Robert. + +Mon Sep 6 19:59:08 CEST 1999 Werner Koch + + * des.c (selftest): Add some testpattern + +Mon Aug 30 20:38:33 CEST 1999 Werner Koch + + * 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 + + * md5.c (md5_final): Fix for a SCO cpp bug. + +Thu Jul 15 10:15:35 CEST 1999 Werner Koch + + * 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 + + * Makefile.am: Support for libtool. + +Fri Jul 2 11:45:54 CEST 1999 Werner Koch + + * 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 + + * 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 + + * 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 + + * 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 + + * dynload.c (register_internal_cipher_extension): Minor init fix. + +Tue May 4 15:47:53 CEST 1999 Werner Koch + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * rndlinux.c (tty_printf) [IS_MODULE]: Removed. + + * rndegd.c (gather_random): Some fixes. + +Wed Mar 17 13:09:03 CET 1999 Werner Koch + + * rndegd.c (do_read): New. + (gather_random): Changed the implementation. + +Mon Mar 8 20:47:17 CET 1999 Werner Koch + + * dynload.c (DLSYM_NEEDS_UNDERSCORE): Renamed. + +Fri Feb 26 17:55:41 CET 1999 Werner Koch + + * md.c: Nearly a total rewrote. + +Wed Feb 24 11:07:27 CET 1999 Werner Koch + + * cipher.c (context): Fixed alignment + * md.c: Ditto. + + * rndegd.c: New + +Mon Feb 22 20:04:00 CET 1999 Werner Koch + + * rndegd.c: New. + +Wed Feb 10 17:15:39 CET 1999 Werner Koch + + * 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 + + * rndunix.c (gather_random): Fix to avoid infinite loop. + +Sun Jan 17 11:04:33 CET 1999 Werner Koch + + * 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 + + * 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 + + * 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 + + * 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 + + * rndunix.c (start_gatherer): Fixed stupid ==/= bug + +1998-12-31 Geoff Keating + + * des.c (is_weak_key): Rewrite loop end condition. + +Tue Dec 29 14:41:47 CET 1998 Werner Koch + + * random.c: add unistd.h for getpid(). + (RAND_MAX): Fallback value for Sun. + +Wed Dec 23 17:12:24 CET 1998 Werner Koch + + * md.c (md_copy): Reset debug. + +Mon Dec 14 21:18:49 CET 1998 Werner Koch + + * 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 + + * 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 + + * 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 + + * 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 + +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. + + + + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/cipher/Makefile.am b/cipher/Makefile.am new file mode 100644 index 000000000..83e81877e --- /dev/null +++ b/cipher/Makefile.am @@ -0,0 +1,114 @@ +# Copyright (C) 1998, 1999, 2000, 2001 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 + +## Process this file with automake to produce Makefile.in + + +INCLUDES = -I.. -I$(top_srcdir)/include -I$(top_srcdir)/intl + +noinst_LIBRARIES = libcipher.a + +# 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_a_LDFLAGS = +libcipher_a_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 \ + rijndael.c \ + elgamal.c \ + elgamal.h \ + rsa.c rsa.h \ + primegen.c \ + random.h \ + random.c \ + rand-internal.h \ + rmd.h \ + dsa.h \ + dsa.c \ + g10c.c \ + smallprime.c \ + construct.c + +# configure creates the constructor file +BUILT_SOURCES = construct.c +DISTCLEANFILES = construct.c + +libcipher_a_DEPENDENCIES = @STATIC_CIPHER_OBJS@ +libcipher_a_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$(EXEEXT): $(srcdir)/tiger.c + `echo $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o tiger $(srcdir)/tiger.c | \ + 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$(EXEEXT): $(srcdir)/rndunix.c + $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndunix $(srcdir)/rndunix.c + +rndlinux$(EXEEXT): $(srcdir)/rndlinux.c + $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndlinux $(srcdir)/rndlinux.c + +rndegd$(EXEEXT): $(srcdir)/rndegd.c + $(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndegd $(srcdir)/rndegd.c + diff --git a/cipher/bithelp.h b/cipher/bithelp.h new file mode 100644 index 000000000..188db168a --- /dev/null +++ b/cipher/bithelp.h @@ -0,0 +1,41 @@ +/* bithelp.h - Some bit manipulation helpers + * Copyright (C) 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 + */ +#ifndef G10_BITHELP_H +#define G10_BITHELP_H + + +/**************** + * Rotate a 32 bit integer by n bytes + */ +#if defined(__GNUC__) && defined(__i386__) +static inline u32 +rol( u32 x, int n) +{ + __asm__("roll %%cl,%0" + :"=r" (x) + :"0" (x),"c" (n)); + return x; +} +#else + #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) +#endif + + +#endif /*G10_BITHELP_H*/ diff --git a/cipher/blowfish.c b/cipher/blowfish.c new file mode 100644 index 000000000..d8ad1d00d --- /dev/null +++ b/cipher/blowfish.c @@ -0,0 +1,633 @@ +/* blowfish.c - Blowfish encryption + * Copyright (C) 1998, 1999, 2000, 2001 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 + * + * For a description of the algorithm, see: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. Pages 336 ff. + */ + +/* Test values: + * key "abcdefghijklmnopqrstuvwxyz"; + * plain "BLOWFISH" + * cipher 32 4E D0 FE F4 13 A2 03 + * + */ + +#include +#include +#include +#include +#include +#include "types.h" +#include "errors.h" +#include "blowfish.h" +#include "dynload.h" + + + +#define CIPHER_ALGO_BLOWFISH 4 /* blowfish 128 bit key */ + +#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 +burn_stack (int bytes) +{ + char buf[64]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + +static void +do_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 +do_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]; + do_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 +encrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +{ + do_encrypt_block (bc, outbuf, inbuf); + burn_stack (64); +} + +static void +do_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 void +decrypt_block( BLOWFISH_context *bc, byte *outbuf, byte *inbuf ) +{ + do_decrypt_block (bc, outbuf, inbuf); + burn_stack (64); +} + + +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; +} + +#ifdef __riscos__ +/* need to switch off CSE optimisation for Norcroft C (Acorn/Pace) */ +#pragma no_optimise_cse +#endif /* __riscos__ */ + +static int +do_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 G10ERR_SELFTEST_FAILED; + + 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 ) { + do_encrypt( c, &datal, &datar ); + c->p[i] = datal; + c->p[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + do_encrypt( c, &datal, &datar ); + c->s0[i] = datal; + c->s0[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + do_encrypt( c, &datal, &datar ); + c->s1[i] = datal; + c->s1[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + do_encrypt( c, &datal, &datar ); + c->s2[i] = datal; + c->s2[i+1] = datar; + } + for(i=0; i < 256; i += 2 ) { + do_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 G10ERR_WEAK_KEY; + } + } + + return 0; +} + +#ifdef __riscos__ +#pragma optimise_cse +#endif /* __riscos__ */ + +static int +bf_setkey( BLOWFISH_context *c, byte *key, unsigned keylen ) +{ + int rc = do_bf_setkey (c, key, keylen); + burn_stack (64); + return rc; +} + +/**************** + * 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); + *(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/blowfish.h b/cipher/blowfish.h new file mode 100644 index 000000000..bed034c73 --- /dev/null +++ b/cipher/blowfish.h @@ -0,0 +1,54 @@ +/* blowfish.h + * 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 G10_BLOWFISH_H +#define G10_BLOWFISH_H + +#include "types.h" + + +const char * +blowfish_get_info( int algo, size_t *keylen, + size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ); + +/* this is just a kludge for the time we have not yet chnaged the cipher + * stuff to the scheme we use for random and digests */ +const char * +twofish_get_info( int algo, size_t *keylen, + size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ); + +/* this is just a kludge for the time we have not yet chnaged the cipher + * stuff to the scheme we use for random and digests */ +const char * +rijndael_get_info( int algo, size_t *keylen, + size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ); + +#endif /*G10_BLOWFISH_H*/ diff --git a/cipher/cast5.c b/cipher/cast5.c new file mode 100644 index 000000000..c99b47e13 --- /dev/null +++ b/cipher/cast5.c @@ -0,0 +1,654 @@ +/* cast5.c - CAST5 cipher (RFC2144) + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include "types.h" +#include "errors.h" +#include "cast5.h" + + +#define CIPHER_ALGO_CAST5 3 + +#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 +burn_stack (int bytes) +{ + char buf[64]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + +static void +do_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 +encrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf ) +{ + do_encrypt_block (c, outbuf, inbuf); + burn_stack (20+4*sizeof(void*)); +} + +static void +do_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 void +decrypt_block( CAST5_context *c, byte *outbuf, byte *inbuf ) +{ + do_decrypt_block (c, outbuf, inbuf); + burn_stack (20+4*sizeof(void*)); +} + + +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 +do_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 G10ERR_SELFTEST_FAILED; + + if( keylen != 16 ) + return G10ERR_WRONG_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; +} + +static int +cast_setkey( CAST5_context *c, byte *key, unsigned keylen ) +{ + int rc = do_cast_setkey (c, key, keylen); + burn_stack (96+7*sizeof(void*)); + return rc; +} + +/**************** + * 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); + *(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/cast5.h b/cipher/cast5.h new file mode 100644 index 000000000..798eaa23f --- /dev/null +++ b/cipher/cast5.h @@ -0,0 +1,33 @@ +/* cast5.h + * 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 G10_CAST5_H +#define G10_CAST5_H + +#include "types.h" + +const char * +cast5_get_info( int algo, size_t *keylen, + size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ); + +#endif /*G10_CAST5_H*/ diff --git a/cipher/cipher.c b/cipher/cipher.c new file mode 100644 index 000000000..2744f041a --- /dev/null +++ b/cipher/cipher.c @@ -0,0 +1,712 @@ +/* cipher.c - cipher dispatcher + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include +#include "util.h" +#include "errors.h" +#include "cipher.h" +#include "des.h" +#include "blowfish.h" +#include "cast5.h" +#include "dynload.h" + + +#define MAX_BLOCKSIZE 16 +#define TABLE_SIZE 14 + +struct cipher_table_s { + const char *name; + int algo; + size_t blocksize; + size_t keylen; + size_t contextsize; /* allocate this amount of context */ + int (*setkey)( void *c, byte *key, unsigned keylen ); + void (*encrypt)( void *c, byte *outbuf, byte *inbuf ); + void (*decrypt)( void *c, byte *outbuf, byte *inbuf ); +}; + +static struct cipher_table_s cipher_table[TABLE_SIZE]; +static int disabled_algos[TABLE_SIZE]; + + +struct cipher_handle_s { + int algo; + int mode; + size_t blocksize; + byte iv[MAX_BLOCKSIZE]; /* (this should be ulong aligned) */ + byte lastiv[MAX_BLOCKSIZE]; + int unused; /* in IV */ + int (*setkey)( void *c, byte *key, unsigned keylen ); + void (*encrypt)( void *c, byte *outbuf, byte *inbuf ); + void (*decrypt)( void *c, byte *outbuf, byte *inbuf ); + PROPERLY_ALIGNED_TYPE context; +}; + + +#ifdef IS_DEVELOPMENT_VERSION +static int +dummy_setkey( void *c, byte *key, unsigned keylen ) { return 0; } +static void +dummy_encrypt_block( void *c, byte *outbuf, byte *inbuf ) { BUG(); } +static void +dummy_decrypt_block( void *c, byte *outbuf, byte *inbuf ) { BUG(); } +#endif + + +/**************** + * Put the static entries into the table. + */ +static void +setup_cipher_table(void) +{ + + int i; + + i = 0; + cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL; + cipher_table[i].name = rijndael_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL192; + cipher_table[i].name = rijndael_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_RIJNDAEL256; + cipher_table[i].name = rijndael_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_TWOFISH; + cipher_table[i].name = twofish_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_BLOWFISH; + cipher_table[i].name = blowfish_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_CAST5; + cipher_table[i].name = cast5_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + cipher_table[i].algo = CIPHER_ALGO_3DES; + cipher_table[i].name = des_get_info( cipher_table[i].algo, + &cipher_table[i].keylen, + &cipher_table[i].blocksize, + &cipher_table[i].contextsize, + &cipher_table[i].setkey, + &cipher_table[i].encrypt, + &cipher_table[i].decrypt ); + if( !cipher_table[i].name ) + BUG(); + i++; + +#ifdef IS_DEVELOPMENT_VERSION + cipher_table[i].algo = CIPHER_ALGO_DUMMY; + cipher_table[i].name = "DUMMY"; + cipher_table[i].blocksize = 8; + cipher_table[i].keylen = 128; + cipher_table[i].contextsize = 0; + cipher_table[i].setkey = dummy_setkey; + cipher_table[i].encrypt = dummy_encrypt_block; + cipher_table[i].decrypt = dummy_decrypt_block; + i++; +#endif + + for( ; i < TABLE_SIZE; i++ ) + cipher_table[i].name = NULL; +} + + +/**************** + * Try to load all modules and return true if new modules are available + */ +static int +load_cipher_modules(void) +{ + static int done = 0; + static int initialized = 0; + void *context = NULL; + struct cipher_table_s *ct; + int ct_idx; + int i; + const char *name; + int any = 0; + + if( !initialized ) { + cipher_modules_constructor(); + setup_cipher_table(); /* load static modules on the first call */ + initialized = 1; + return 1; + } + + if( done ) + return 0; + done = 1; + + for(ct_idx=0, ct = cipher_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_ciphers( &context, &ct->algo, + &ct->keylen, &ct->blocksize, &ct->contextsize, + &ct->setkey, &ct->encrypt, &ct->decrypt)) ) { + if( ct->blocksize != 8 && ct->blocksize != 16 ) { + log_info("skipping cipher %d: unsupported blocksize\n", ct->algo); + continue; + } + for(i=0; cipher_table[i].name; i++ ) + if( cipher_table[i].algo == ct->algo ) + break; + if( cipher_table[i].name ) { + log_info("skipping cipher %d: already loaded\n", ct->algo ); + continue; + } + /* put it into the table */ + if( g10_opt_verbose > 1 ) + log_info("loaded cipher %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("cipher table full; ignoring other extensions\n"); + break; + } + } + enum_gnupgext_ciphers( &context, NULL, NULL, NULL, NULL, + NULL, NULL, NULL ); + return any; +} + + + + + + + +/**************** + * Map a string to the cipher algo + */ +int +string_to_cipher_algo( const char *string ) +{ + int i; + const char *s; + + /* kludge to alias RIJNDAEL to AES */ + if ( *string == 'R' || *string == 'r') + { + if (!ascii_strcasecmp (string, "RIJNDAEL")) + string = "AES"; + else if (!ascii_strcasecmp (string, "RIJNDAEL192")) + string = "AES192"; + else if (!ascii_strcasecmp (string, "RIJNDAEL256")) + string = "AES256"; + } + + do + { + for(i=0; (s=cipher_table[i].name); i++ ) + { + if( !ascii_strcasecmp( s, string ) ) + return cipher_table[i].algo; + } + } while( load_cipher_modules() ); + return 0; +} + +/**************** + * Map a cipher algo to a string + */ +const char * +cipher_algo_to_string( int algo ) +{ + int i; + + do { + for(i=0; cipher_table[i].name; i++ ) + if( cipher_table[i].algo == algo ) + return cipher_table[i].name; + } while( load_cipher_modules() ); + return NULL; +} + + +void +disable_cipher_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; + } + } + /* fixme: we should use a linked list */ + log_fatal("can't disable cipher algo %d: table full\n", algo ); +} + +/**************** + * Return 0 if the cipher algo is available + */ +int +check_cipher_algo( int algo ) +{ + int i; + + do { + for(i=0; cipher_table[i].name; i++ ) + if( cipher_table[i].algo == algo ) { + for(i=0; i < DIM(disabled_algos); i++ ) { + if( disabled_algos[i] == algo ) + return G10ERR_CIPHER_ALGO; + } + return 0; /* okay */ + } + } while( load_cipher_modules() ); + return G10ERR_CIPHER_ALGO; +} + + +unsigned +cipher_get_keylen( int algo ) +{ + int i; + unsigned len = 0; + + do { + for(i=0; cipher_table[i].name; i++ ) { + if( cipher_table[i].algo == algo ) { + len = cipher_table[i].keylen; + if( !len ) + log_bug("cipher %d w/o key length\n", algo ); + return len; + } + } + } while( load_cipher_modules() ); + log_bug("cipher %d not found\n", algo ); + return 0; +} + +unsigned +cipher_get_blocksize( int algo ) +{ + int i; + unsigned len = 0; + + do { + for(i=0; cipher_table[i].name; i++ ) { + if( cipher_table[i].algo == algo ) { + len = cipher_table[i].blocksize; + if( !len ) + log_bug("cipher %d w/o blocksize\n", algo ); + return len; + } + } + } while( load_cipher_modules() ); + log_bug("cipher %d not found\n", algo ); + return 0; +} + + +/**************** + * Open a cipher handle for use with algorithm ALGO, in mode MODE + * and put it into secure memory if SECURE is true. + */ +CIPHER_HANDLE +cipher_open( int algo, int mode, int secure ) +{ + CIPHER_HANDLE hd; + int i; + + fast_random_poll(); + do { + for(i=0; cipher_table[i].name; i++ ) + if( cipher_table[i].algo == algo ) + break; + } while( !cipher_table[i].name && load_cipher_modules() ); + if( !cipher_table[i].name ) { + log_fatal("cipher_open: algorithm %d not available\n", algo ); + return NULL; + } + + /* ? perform selftest here and mark this with a flag in cipher_table ? */ + + hd = secure ? m_alloc_secure_clear( sizeof *hd + + cipher_table[i].contextsize + - sizeof(PROPERLY_ALIGNED_TYPE) ) + : m_alloc_clear( sizeof *hd + cipher_table[i].contextsize + - sizeof(PROPERLY_ALIGNED_TYPE) ); + hd->algo = algo; + hd->blocksize = cipher_table[i].blocksize; + hd->setkey = cipher_table[i].setkey; + hd->encrypt = cipher_table[i].encrypt; + hd->decrypt = cipher_table[i].decrypt; + + if( mode == CIPHER_MODE_AUTO_CFB ) { + if( algo >= 100 ) + hd->mode = CIPHER_MODE_CFB; + else + hd->mode = CIPHER_MODE_PHILS_CFB; + } + else + hd->mode = mode; + +#ifdef IS_DEVELOPMENT_VERSION + if( algo == CIPHER_ALGO_DUMMY ) + hd->mode = CIPHER_MODE_DUMMY; +#endif + + return hd; +} + + +void +cipher_close( CIPHER_HANDLE c ) +{ + m_free(c); +} + + +int +cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) +{ + return (*c->setkey)( &c->context.c, key, keylen ); +} + + + +void +cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ) +{ + memset( c->iv, 0, c->blocksize ); + if( iv ) { + if( ivlen != c->blocksize ) + log_info("WARNING: cipher_setiv: ivlen=%u blklen=%u\n", + ivlen, (unsigned)c->blocksize ); + if( ivlen > c->blocksize ) + ivlen = c->blocksize; + memcpy( c->iv, iv, ivlen ); + } + c->unused = 0; +} + + + +static void +do_ecb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + (*c->encrypt)( &c->context.c, outbuf, inbuf ); + inbuf += c->blocksize; + outbuf += c->blocksize; + } +} + +static void +do_ecb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned n; + + for(n=0; n < nblocks; n++ ) { + (*c->decrypt)( &c->context.c, outbuf, inbuf ); + inbuf += c->blocksize; + outbuf += c->blocksize; + } +} + +static void +do_cbc_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned int n; + byte *ivp; + int i; + size_t blocksize = c->blocksize; + + for(n=0; n < nblocks; n++ ) { + /* fixme: the xor should works on words and not on + * bytes. Maybe it is a good idea to enhance the cipher backend + * API to allow for CBC handling in the backend */ + for(ivp=c->iv,i=0; i < blocksize; i++ ) + outbuf[i] = inbuf[i] ^ *ivp++; + (*c->encrypt)( &c->context.c, outbuf, outbuf ); + memcpy(c->iv, outbuf, blocksize ); + inbuf += c->blocksize; + outbuf += c->blocksize; + } +} + +static void +do_cbc_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ + unsigned int n; + byte *ivp; + int i; + size_t blocksize = c->blocksize; + + for(n=0; n < nblocks; n++ ) { + /* because outbuf and inbuf might be the same, we have + * to save the original ciphertext block. We use lastiv + * for this here because it is not used otherwise */ + memcpy(c->lastiv, inbuf, blocksize ); + (*c->decrypt)( &c->context.c, outbuf, inbuf ); + for(ivp=c->iv,i=0; i < blocksize; i++ ) + outbuf[i] ^= *ivp++; + memcpy(c->iv, c->lastiv, blocksize ); + inbuf += c->blocksize; + outbuf += c->blocksize; + } +} + + +static void +do_cfb_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +{ + byte *ivp; + size_t blocksize = c->blocksize; + + if( nbytes <= c->unused ) { + /* short enough to be encoded by the remaining XOR mask */ + /* XOR the input with the IV and store input into IV */ + for(ivp=c->iv+c->blocksize - c->unused; nbytes; nbytes--, c->unused-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + return; + } + + if( c->unused ) { + /* XOR the input with the IV and store input into IV */ + nbytes -= c->unused; + for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } + + /* now we can process complete blocks */ + while( nbytes >= blocksize ) { + int i; + /* encrypt the IV (and save the current one) */ + memcpy( c->lastiv, c->iv, blocksize ); + (*c->encrypt)( &c->context.c, c->iv, c->iv ); + /* XOR the input with the IV and store input into IV */ + for(ivp=c->iv,i=0; i < blocksize; i++ ) + *outbuf++ = (*ivp++ ^= *inbuf++); + nbytes -= blocksize; + } + if( nbytes ) { /* process the remaining bytes */ + /* encrypt the IV (and save the current one) */ + memcpy( c->lastiv, c->iv, blocksize ); + (*c->encrypt)( &c->context.c, c->iv, c->iv ); + c->unused = blocksize; + /* and apply the xor */ + c->unused -= nbytes; + for(ivp=c->iv; nbytes; nbytes-- ) + *outbuf++ = (*ivp++ ^= *inbuf++); + } +} + +static void +do_cfb_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +{ + byte *ivp; + ulong temp; + size_t blocksize = c->blocksize; + + if( nbytes <= c->unused ) { + /* short enough to be encoded by the remaining XOR mask */ + /* XOR the input with the IV and store input into IV */ + for(ivp=c->iv+blocksize - c->unused; nbytes; nbytes--,c->unused--){ + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + return; + } + + if( c->unused ) { + /* XOR the input with the IV and store input into IV */ + nbytes -= c->unused; + for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- ) { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } + + /* now we can process complete blocks */ + while( nbytes >= blocksize ) { + int i; + /* encrypt the IV (and save the current one) */ + memcpy( c->lastiv, c->iv, blocksize ); + (*c->encrypt)( &c->context.c, c->iv, c->iv ); + /* XOR the input with the IV and store input into IV */ + for(ivp=c->iv,i=0; i < blocksize; i++ ) { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + nbytes -= blocksize; + } + if( nbytes ) { /* process the remaining bytes */ + /* encrypt the IV (and save the current one) */ + memcpy( c->lastiv, c->iv, blocksize ); + (*c->encrypt)( &c->context.c, c->iv, c->iv ); + c->unused = blocksize; + /* and apply the xor */ + c->unused -= nbytes; + for(ivp=c->iv; nbytes; nbytes-- ) { + temp = *inbuf++; + *outbuf++ = *ivp ^ temp; + *ivp++ = temp; + } + } +} + + +/**************** + * Encrypt INBUF to OUTBUF with the mode selected at open. + * inbuf and outbuf may overlap or be the same. + * Depending on the mode some some contraints apply to NBYTES. + */ +void +cipher_encrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +{ + switch( c->mode ) { + case CIPHER_MODE_ECB: + assert(!(nbytes%c->blocksize)); + do_ecb_encrypt(c, outbuf, inbuf, nbytes/c->blocksize ); + break; + case CIPHER_MODE_CBC: + assert(!(nbytes%c->blocksize)); + do_cbc_encrypt(c, outbuf, inbuf, nbytes/c->blocksize ); + break; + case CIPHER_MODE_CFB: + case CIPHER_MODE_PHILS_CFB: + do_cfb_encrypt(c, outbuf, inbuf, nbytes ); + break; +#ifdef IS_DEVELOPMENT_VERSION + case CIPHER_MODE_DUMMY: + if( inbuf != outbuf ) + memmove( outbuf, inbuf, nbytes ); + break; +#endif + default: log_fatal("cipher_encrypt: invalid mode %d\n", c->mode ); + } +} + + +/**************** + * Decrypt INBUF to OUTBUF with the mode selected at open. + * inbuf and outbuf may overlap or be the same. + * Depending on the mode some some contraints apply to NBYTES. + */ +void +cipher_decrypt( CIPHER_HANDLE c, byte *outbuf, byte *inbuf, unsigned nbytes ) +{ + switch( c->mode ) { + case CIPHER_MODE_ECB: + assert(!(nbytes%c->blocksize)); + do_ecb_decrypt(c, outbuf, inbuf, nbytes/c->blocksize ); + break; + case CIPHER_MODE_CBC: + assert(!(nbytes%c->blocksize)); + do_cbc_decrypt(c, outbuf, inbuf, nbytes/c->blocksize ); + break; + case CIPHER_MODE_CFB: + case CIPHER_MODE_PHILS_CFB: + do_cfb_decrypt(c, outbuf, inbuf, nbytes ); + break; +#ifdef IS_DEVELOPMENT_VERSION + case CIPHER_MODE_DUMMY: + if( inbuf != outbuf ) + memmove( outbuf, inbuf, nbytes ); + break; +#endif + default: log_fatal("cipher_decrypt: invalid mode %d\n", c->mode ); + } +} + + + +/**************** + * Used for PGP's somewhat strange CFB mode. Only works if + * the handle is in PHILS_CFB mode + */ +void +cipher_sync( CIPHER_HANDLE c ) +{ + if( c->mode == CIPHER_MODE_PHILS_CFB && c->unused ) { + memmove(c->iv + c->unused, c->iv, c->blocksize - c->unused ); + memcpy(c->iv, c->lastiv + c->blocksize - c->unused, c->unused); + c->unused = 0; + } +} + diff --git a/cipher/des.c b/cipher/des.c new file mode 100644 index 000000000..90fd8199e --- /dev/null +++ b/cipher/des.c @@ -0,0 +1,1024 @@ +/* des.c - DES and Triple-DES encryption/decryption Algorithm + * Copyright (C) 1998, 1999, 2000, 2001 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 + * + * + * 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. + */ + + +/* + * Written by Michael Roth , 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 +#include +#include /* memcpy, memcmp */ +#include "types.h" /* for byte and u32 typedefs */ +#include "errors.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 + + + + +/* + * 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<> 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) + + +static void +burn_stack (int bytes) +{ + char buf[64]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + +/* + * 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 G10ERR_SELFTEST_FAILED; + + des_key_schedule (key, ctx->encrypt_subkeys); + burn_stack (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]; + } + + 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])); + burn_stack (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])); + burn_stack (32); + + 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 +#include +#include +#include +#include +#include "util.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 ) +{ + 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 ) { + m_free(rndbuf); + rndbuf = get_random_bits( nbits, 1, 1 ); + } + else { /* change only some of the higher bits */ + /* we could imporove this by directly requesting more memory + * at the first call to get_random_bits() and use this the here + * maybe it is easier to do this directly in random.c */ + char *pp = get_random_bits( 32, 1, 1 ); + memcpy( rndbuf,pp, 4 ); + m_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 */ + } + m_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; + /*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/ + { char *p = get_random_bits( qbits, 0, 0 ); + mpi_set_buffer( test, p, (qbits+7)/8, 0 ); + m_free(p); + } + + 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 */ + 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 = get_random_bits( qbits, 2, 1 ); + else { /* change only some of the higher bits (= 2 bytes)*/ + char *r = get_random_bits( 16, 2, 1 ); + memcpy(rndbuf, r, 16/8 ); + m_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 ) ); + m_free(rndbuf); + mpi_free( e ); + mpi_free( h ); + + /* y = g^x mod p */ + y = mpi_alloc( mpi_get_nlimbs(p) ); + 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) ); + + 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. + * + * Without generating the k this function runs in + * about 26ms on a 300 Mhz Mobile Pentium + */ + +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 */ + 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. + * + * Without the checks this function runs in + * about 31ms on a 300 Mhz Mobile Pentium + */ +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 G10ERR_PUBKEY_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 G10ERR_PUBKEY_ALGO; + if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] ) + return G10ERR_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 G10ERR_BAD_SECKEY; + + return 0; +} + + + +int +dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ + DSA_secret_key sk; + + if( algo != PUBKEY_ALGO_DSA ) + return G10ERR_PUBKEY_ALGO; + if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] ) + return G10ERR_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 G10ERR_PUBKEY_ALGO; + if( !data[0] || !data[1] || !hash + || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] ) + return G10ERR_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 G10ERR_BAD_SIGN; + 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 = PUBKEY_USAGE_SIG; return "DSA"; + default: *use = 0; return NULL; + } +} + + diff --git a/cipher/dsa.h b/cipher/dsa.h new file mode 100644 index 000000000..89fd1f5a0 --- /dev/null +++ b/cipher/dsa.h @@ -0,0 +1,32 @@ +/* dsa.h - DSA signature algorithm + * 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 G10_DSA_H +#define G10_DSA_H + +int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int dsa_check_secret_key( int algo, MPI *skey ); +int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ); +int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey, + int (*cmp)(void *, MPI), void *opaquev ); +unsigned dsa_get_nbits( int algo, MPI *pkey ); +const char *dsa_get_info( int algo, int *npkey, int *nskey, + int *nenc, int *nsig, int *use ); + +#endif /*G10_DSA_H*/ diff --git a/cipher/dynload.c b/cipher/dynload.c new file mode 100644 index 000000000..09cd1366a --- /dev/null +++ b/cipher/dynload.c @@ -0,0 +1,681 @@ +/* dynload.c - load cipher extensions + * Copyright (C) 1998, 1999, 2001 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 +#include +#include +#include +#include +#ifdef HAVE_DL_DLOPEN + #include +#elif defined(HAVE_DLD_DLD_LINK) + #include +#elif defined(HAVE_DL_SHL_LOAD) + #include + #include +#endif +#ifdef __MINGW32__ + #include +#endif +#include "util.h" +#include "cipher.h" +#include "dynload.h" + +#ifdef WITH_SYMBOL_UNDERSCORE + #define SYMBOL_VERSION "_gnupgext_version" + #define SYMBOL_ENUM "_gnupgext_enum_func" +#else + #define SYMBOL_VERSION "gnupgext_version" + #define SYMBOL_ENUM "gnupgext_enum_func" +#endif + + +#ifndef RTLD_NOW + #define RTLD_NOW 1 +#endif + +#ifdef HAVE_DL_SHL_LOAD /* HPUX has shl_load instead of dlopen */ +#define HAVE_DL_DLOPEN +#define dlopen(PATHNAME,MODE) \ + ((void *) shl_load(PATHNAME, DYNAMIC_PATH | \ + (((MODE) & RTLD_NOW) ? BIND_IMMEDIATE : BIND_DEFERRED), 0L)) +#define dlclose(HANDLE) shl_unload((shl_t) (HANDLE)) +#define dlerror() (errno == 0 ? NULL : strerror(errno)) + +static void * +dlsym(void *handle, char *name) +{ + void *addr; + if (shl_findsym((shl_t *)&handle,name,(short)TYPE_UNDEFINED,&addr) != 0) { + return NULL; + } + return addr; +} +#endif /*HAVE_DL_SHL_LOAD*/ + +#ifdef __MINGW32__ +#define HAVE_DL_DLOPEN +#define USE_DYNAMIC_LINKING + +static int last_error = 0; + +void* +dlopen(const char *pathname, int mode) +{ + void *h = LoadLibrary( pathname ); + if (!h) { + log_error( "LoadLibrary failed ec=%d\n", (int)GetLastError() ); + last_error = 1; + return NULL; + } + return h; +} + +int +dlclose( void *handle ) +{ + last_error = 0; + return FreeLibrary( handle ); +} + +char* +dlerror(void) +{ + static char dlerrstr[10]; + if (last_error) { + sprintf(dlerrstr, "%d", (int)GetLastError() ); + return dlerrstr; + } + return NULL; +} + +void* +dlsym( void *handle, const char *name ) +{ + void *h = GetProcAddress( handle, name ); + if (!h) { + log_error( "GetProcAddress failed ec=%d\n", (int)GetLastError() ); + last_error = 1; + return NULL; + } + return h; +} +#endif /*__MINGW32__*/ + + + + + +typedef struct ext_list { + struct ext_list *next; + int internal; + #ifdef HAVE_DL_DLOPEN + void *handle; /* handle from dlopen() */ + #else + int handle; /* if the function has been loaded, this is true */ + #endif + int failed; /* already tried but failed */ + void * (*enumfunc)(int, int*, int*, int*); + char *hintstr; /* pointer into name */ + char name[1]; +} *EXTLIST; + +static EXTLIST extensions; + +typedef struct { + EXTLIST r; + int seq1; + int seq2; + void *sym; + int reqalgo; +} ENUMCONTEXT; + + +#ifdef HAVE_DLD_DLD_LINK +static char *mainpgm_path; +static int did_dld_init; +static int dld_available; +#endif + + +/**************** + * Register an extension module. The last registered module will + * be loaded first. A name may have a list of classes + * appended; e.g: + * mymodule.so(1:17,3:20,3:109) + * means that this module provides digest algorithm 17 and public key + * algorithms 20 and 109. This is only a hint but if it is there the + * loader may decide to only load a module which claims to have a + * requested algorithm. + * + * mainpgm is the path to the program which wants to load a module + * it is only used in some environments. + */ +void +register_cipher_extension( const char *mainpgm, const char *fname ) +{ + EXTLIST r, el, intex; + char *p, *pe; + + #ifdef HAVE_DLD_DLD_LINK + if( !mainpgm_path && mainpgm && *mainpgm ) + mainpgm_path = m_strdup(mainpgm); + #endif + if( *fname != DIRSEP_C ) { /* do tilde expansion etc */ + char *tmp; + + if( strchr(fname, DIRSEP_C) ) + tmp = make_filename(fname, NULL); + else + tmp = make_filename(GNUPG_LIBDIR, fname, NULL); + el = m_alloc_clear( sizeof *el + strlen(tmp) ); + strcpy(el->name, tmp ); + m_free(tmp); + } + else { + el = m_alloc_clear( sizeof *el + strlen(fname) ); + strcpy(el->name, fname ); + } + /* check whether we have a class hint */ + if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] ) { + *p = *pe = 0; + el->hintstr = p+1; + } + else + el->hintstr = NULL; + + /* check that it is not already registered */ + intex = NULL; + for(r = extensions; r; r = r->next ) { + if( !compare_filenames(r->name, el->name) ) { + log_info("extension `%s' already registered\n", el->name ); + m_free(el); + return; + } + else if( r->internal ) + intex = r; + } + /* and register */ + /* we put them after the internal extension modules */ + /* this is so that the external modules do not get loaded */ + /* as soon as the internal modules are requested */ + if( intex ) { + el->next = intex->next; + intex->next = el; + } + else { + el->next = extensions; + extensions = el; + } +} + +void +register_internal_cipher_extension( + const char *module_id, + void * (*enumfunc)(int, int*, int*, int*) + ) +{ + EXTLIST r, el; + + el = m_alloc_clear( sizeof *el + strlen(module_id) ); + strcpy(el->name, module_id ); + el->internal = 1; + + /* check that it is not already registered */ + for(r = extensions; r; r = r->next ) { + if( !compare_filenames(r->name, el->name) ) { + log_info("extension `%s' already registered\n", el->name ); + m_free(el); + return; + } + } + /* and register */ + el->enumfunc = enumfunc; + #ifdef HAVE_DL_DLOPEN + el->handle = (void*)1; + #else + el->handle = 1; + #endif + el->next = extensions; + extensions = el; +} + + +static int +load_extension( EXTLIST el ) +{ + #ifdef USE_DYNAMIC_LINKING + char **name; + #ifdef HAVE_DL_DLOPEN + const char *err; + int seq = 0; + int class, vers; + void *sym; + #else + unsigned long addr; + int rc; + #endif + + #ifndef __MINGW32__ + /* make sure we are not setuid */ + if( getuid() != geteuid() ) + log_bug("trying to load an extension while still setuid\n"); + #endif + + /* now that we are not setuid anymore, we can safely load modules */ + #ifdef HAVE_DL_DLOPEN + el->handle = dlopen(el->name, RTLD_NOW); + if( !el->handle ) { + log_error("%s: error loading extension: %s\n", el->name, dlerror() ); + goto failure; + } + name = (char**)dlsym(el->handle, SYMBOL_VERSION); + if( (err=dlerror()) ) { + log_error("%s: not a gnupg extension: %s\n", el->name, err ); + goto failure; + } + #else /* have dld */ + if( !did_dld_init ) { + did_dld_init = 1; + if( !mainpgm_path ) + log_error("DLD is not correctly initialized\n"); + else { + rc = dld_init( dld_find_executable(mainpgm_path) ); + if( rc ) + log_error("DLD init failed: %s\n", dld_strerror(rc) ); + else + dld_available = 1; + } + } + if( !dld_available ) { + log_error("%s: DLD not available\n", el->name ); + goto failure; + } + + rc = dld_link( el->name ); + if( rc ) { + log_error("%s: error loading extension: %s\n", + el->name, dld_strerror(rc) ); + goto failure; + } + addr = dld_get_symbol(SYMBOL_VERSION); + if( !addr ) { + log_error("%s: not a gnupg extension: %s\n", + el->name, dld_strerror(dld_errno) ); + goto failure; + } + name = (char**)addr; + #endif + + if( g10_opt_verbose > 1 ) + log_info("%s: %s%s%s%s\n", el->name, *name, + el->hintstr? " (":"", + el->hintstr? el->hintstr:"", + el->hintstr? ")":""); + + #ifdef HAVE_DL_DLOPEN + sym = dlsym(el->handle, SYMBOL_ENUM); + if( (err=dlerror()) ) { + log_error("%s: invalid gnupg extension: %s\n", el->name, err ); + goto failure; + } + el->enumfunc = (void *(*)(int,int*,int*,int*))sym; + #else /* dld */ + addr = dld_get_func(SYMBOL_ENUM); + if( !addr ) { + log_error("%s: invalid gnupg extension: %s\n", + el->name, dld_strerror(dld_errno) ); + goto failure; + } + rc = dld_function_executable_p(SYMBOL_ENUM); + if( rc ) { + log_error("%s: extension function is not executable: %s\n", + el->name, dld_strerror(rc) ); + goto failure; + } + el->enumfunc = (void *(*)(int,int*,int*,int*))addr; + el->handle = 1; /* mark as usable */ + #endif + + #ifdef HAVE_DL_DLOPEN + if( g10_opt_verbose > 2 ) { + /* list the contents of the module */ + while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) { + if( vers != 1 ) { + log_info("%s: ignoring func with version %d\n",el->name,vers); + continue; + } + switch( class ) { + case 11: + case 21: + case 31: + log_info("%s: provides %s algorithm %d\n", el->name, + class == 11? "md" : + class == 21? "cipher" : "pubkey", + *(int*)sym); + break; + default: + /*log_debug("%s: skipping class %d\n", el->name, class);*/ + break; + } + } + } + #endif + return 0; + + failure: + #ifdef HAVE_DL_DLOPEN + if( el->handle ) { + dlclose(el->handle); + el->handle = NULL; + } + #endif + el->failed = 1; + #endif /*USE_DYNAMIC_LINKING*/ + return -1; +} + +#ifdef __riscos__ +typedef +const char *(*DIGESTS_CAST)(int, size_t*,byte**, int*, int*, + void (**)(void*), + void (**)(void*,byte*,size_t), + void (**)(void*),byte *(**)(void*)); +#endif /* __riscos__ */ + +int +enum_gnupgext_digests( void **enum_context, + int *algo, + const char *(**r_get_info)( int, size_t*,byte**, int*, int*, + void (**)(void*), + void (**)(void*,byte*,size_t), + void (**)(void*),byte *(**)(void*)) ) +{ + EXTLIST r; + ENUMCONTEXT *ctx; + + if( !*enum_context ) { /* init context */ + ctx = m_alloc_clear( sizeof( *ctx ) ); + ctx->r = extensions; + ctx->reqalgo = *algo; + *enum_context = ctx; + } + else if( !algo ) { /* release the context */ + m_free(*enum_context); + *enum_context = NULL; + return 0; + } + else + ctx = *enum_context; + + for( r = ctx->r; r; r = r->next ) { + int class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + /* get a digest info function */ + if( ctx->sym ) + goto inner_loop; + while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) { + void *sym; + /* must check class because enumfunc may be wrong coded */ + if( vers != 1 || class != 10 ) + continue; + inner_loop: +#ifndef __riscos__ + *r_get_info = ctx->sym; +#else /* __riscos__ */ + *r_get_info = (DIGESTS_CAST) ctx->sym; +#endif /* __riscos__ */ + while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) { + if( vers != 1 || class != 11 ) + continue; + *algo = *(int*)sym; + ctx->r = r; + return 1; + } + ctx->seq2 = 0; + } + ctx->seq1 = 0; + } + ctx->r = r; + return 0; +} + +#ifdef __riscos__ +typedef +const char *(*CIPHERS_CAST)(int, size_t*, size_t*, size_t*, + int (**)( void *, byte *, unsigned), + void (**)( void *, byte *, byte *), + void (**)( void *, byte *, byte *)); +#endif /* __riscos__ */ + +const char * +enum_gnupgext_ciphers( void **enum_context, int *algo, + size_t *keylen, size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ) +{ + EXTLIST r; + ENUMCONTEXT *ctx; + const char * (*finfo)(int, size_t*, size_t*, size_t*, + int (**)( void *, byte *, unsigned), + void (**)( void *, byte *, byte *), + void (**)( void *, byte *, byte *)); + + if( !*enum_context ) { /* init context */ + ctx = m_alloc_clear( sizeof( *ctx ) ); + ctx->r = extensions; + *enum_context = ctx; + } + else if( !algo ) { /* release the context */ + m_free(*enum_context); + *enum_context = NULL; + return NULL; + } + else + ctx = *enum_context; + + for( r = ctx->r; r; r = r->next ) { + int class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + /* get a cipher info function */ + if( ctx->sym ) + goto inner_loop; + while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) { + void *sym; + /* must check class because enumfunc may be wrong coded */ + if( vers != 1 || class != 20 ) + continue; + inner_loop: +#ifndef __riscos__ + finfo = ctx->sym; +#else /* __riscos__ */ + finfo = (CIPHERS_CAST) ctx->sym; +#endif /* __riscos__ */ + while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) { + const char *algname; + if( vers != 1 || class != 21 ) + continue; + *algo = *(int*)sym; + algname = (*finfo)( *algo, keylen, blocksize, contextsize, + setkeyf, encryptf, decryptf ); + if( algname ) { + ctx->r = r; + return algname; + } + } + ctx->seq2 = 0; + } + ctx->seq1 = 0; + } + ctx->r = r; + return NULL; +} + +#ifdef __riscos__ +typedef +const char *(*PUBKEYS_CAST)(int, int *, int *, int *, int *, int *, + int (**)(int, unsigned, MPI *, MPI **), + int (**)(int, MPI *), + int (**)(int, MPI *, MPI , MPI *), + int (**)(int, MPI *, MPI *, MPI *), + int (**)(int, MPI *, MPI , MPI *), + int (**)(int, MPI , MPI *, MPI *, + int (*)(void*,MPI), void *), + unsigned (**)( int , MPI *)); +#endif /* __riscos__ */ + +const char * +enum_gnupgext_pubkeys( void **enum_context, 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 (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey ), + int (**decryptf)( 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 ) ) +{ + EXTLIST r; + ENUMCONTEXT *ctx; + const char * (*finfo)( int, int *, int *, int *, int *, int *, + int (**)( int, unsigned, MPI *, MPI **), + int (**)( int, MPI * ), + int (**)( int, MPI *, MPI , MPI * ), + int (**)( int, MPI *, MPI *, MPI * ), + int (**)( int, MPI *, MPI , MPI * ), + int (**)( int, MPI , MPI *, MPI *, + int (*)(void*,MPI), void *), + unsigned (**)( int , MPI * ) ); + + if( !*enum_context ) { /* init context */ + ctx = m_alloc_clear( sizeof( *ctx ) ); + ctx->r = extensions; + *enum_context = ctx; + } + else if( !algo ) { /* release the context */ + m_free(*enum_context); + *enum_context = NULL; + return NULL; + } + else + ctx = *enum_context; + + for( r = ctx->r; r; r = r->next ) { + int class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + /* get a pubkey info function */ + if( ctx->sym ) + goto inner_loop; + while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) { + void *sym; + if( vers != 1 || class != 30 ) + continue; + inner_loop: +#ifndef __riscos__ + finfo = ctx->sym; +#else /* __riscos__ */ + finfo = (PUBKEYS_CAST) ctx->sym; +#endif /* __riscos__ */ + while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) { + const char *algname; + if( vers != 1 || class != 31 ) + continue; + *algo = *(int*)sym; + algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, use, + generate, check_secret_key, encryptf, + decryptf, sign, verify, get_nbits ); + if( algname ) { + ctx->r = r; + return algname; + } + } + ctx->seq2 = 0; + } + ctx->seq1 = 0; + } + ctx->r = r; + return NULL; +} + + +int (* +dynload_getfnc_gather_random())(void (*)(const void*, size_t, int), int, + size_t, int) +{ + EXTLIST r; + void *sym; + + for( r = extensions; r; r = r->next ) { + int seq, class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + seq = 0; + while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) { + if( vers != 1 || class != 40 ) + continue; + return (int (*)(void (*)(const void*, size_t, int), int, + size_t, int))sym; + } + } + return NULL; +} + + +void (* +dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int), int) +{ + EXTLIST r; + void *sym; + + for( r = extensions; r; r = r->next ) { + int seq, class, vers; + + if( r->failed ) + continue; + if( !r->handle && load_extension(r) ) + continue; + seq = 0; + while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) { + if( vers != 1 || class != 41 ) + continue; + return (void (*)( void (*)(const void*, size_t, int), int))sym; + } + } + return NULL; +} + diff --git a/cipher/dynload.h b/cipher/dynload.h new file mode 100644 index 000000000..328a7197b --- /dev/null +++ b/cipher/dynload.h @@ -0,0 +1,68 @@ +/* dynload.h + * 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 G10_CIPHER_DYNLOAD_H +#define G10_CIPHER_DYNLOAD_H + +#include "mpi.h" + + +void register_internal_cipher_extension( const char *module_id, + void * (*enumfunc)(int, int*, int*, int*) ); + +int +enum_gnupgext_digests( void **enum_context, + int *algo, + const char *(**r_get_info)( int, size_t*,byte**, int*, int*, + void (**)(void*), + void (**)(void*,byte*,size_t), + void (**)(void*),byte *(**)(void*)) ); + +const char * +enum_gnupgext_ciphers( void **enum_context, int *algo, + size_t *keylen, size_t *blocksize, size_t *contextsize, + int (**setkeyf)( void *c, byte *key, unsigned keylen ), + void (**encryptf)( void *c, byte *outbuf, byte *inbuf ), + void (**decryptf)( void *c, byte *outbuf, byte *inbuf ) + ); + + +const char * +enum_gnupgext_pubkeys( void **enum_context, 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 (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey ), + int (**decryptf)( 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 ) ); + + +int (*dynload_getfnc_gather_random(void))( void (*)(const void*, size_t, int), + int, size_t, int); +void (*dynload_getfnc_fast_random_poll(void) + )( void (*)(const void*, size_t, int), int ); + + +/** This function is in construct.c **/ +void cipher_modules_constructor(void); + +#endif /*G10_CIPHER_DYNLOAD_H*/ diff --git a/cipher/elgamal.c b/cipher/elgamal.c new file mode 100644 index 000000000..b4563cd58 --- /dev/null +++ b/cipher/elgamal.c @@ -0,0 +1,666 @@ +/* elgamal.c - ElGamal Public Key encryption + * Copyright (C) 1998, 2000, 2001 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 +#include +#include +#include +#include "util.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 do_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 ) +{ + if ( progress_cb ) + progress_cb ( progress_cb_data, c ); + else + fputc( c, stderr ); +} + + +/**************** + * Michael Wiener's table about 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; + + /*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/ + { char *p = get_random_bits( nbits, 0, 0 ); + mpi_set_buffer( test, p, (nbits+7)/8, 0 ); + m_free(p); + } + + do_encrypt( out1_a, out1_b, test, &pk ); + decrypt( out2, out1_a, out1_b, sk ); + if( mpi_cmp( test, out2 ) ) + log_fatal("ElGamal operation: encrypt, decrypt failed\n"); + + 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 orig_nbits = mpi_get_nbits(p); + unsigned int nbits; + unsigned int 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 of %u bits", nbits); + mpi_sub_ui( p_1, p, 1); + for(;;) { + if( !rndbuf || nbits < 32 ) { + m_free(rndbuf); + rndbuf = get_random_bits( nbits, 1, 1 ); + } + else { /* change only some of the higher bits */ + /* we could impprove this by directly requesting more memory + * at the first call to get_random_bits() and use this the here + * 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 = get_random_bits( 32, 1, 1 ); + memcpy( rndbuf,pp, 4 ); + m_free(pp); + log_debug("gen_k: tsss, never expected to reach this\n"); + } + mpi_set_buffer( k, rndbuf, nbytes, 0 ); + + for(;;) { + /* 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: + m_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 int nbits, MPI **ret_factors ) +{ + MPI p; /* the prime */ + MPI p_min1; + MPI g; + MPI x; /* the secret exponent */ + MPI y; + MPI temp; + 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 ); + 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. + */ + 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 of size %u", xbits ); + rndbuf = NULL; + do { + if( DBG_CIPHER ) + progress('.'); + if( rndbuf ) { /* change only some of the higher bits */ + if( xbits < 16 ) {/* should never happen ... */ + m_free(rndbuf); + rndbuf = get_random_bits( xbits, 2, 1 ); + } + else { + char *r = get_random_bits( 16, 2, 1 ); + memcpy(rndbuf, r, 16/8 ); + m_free(r); + } + } + else + rndbuf = get_random_bits( xbits, 2, 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 ) ); + m_free(rndbuf); + + y = mpi_alloc(nbits/BITS_PER_MPI_LIMB); + 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) ); + + mpi_powm( y, sk->g, sk->x, sk->p ); + rc = !mpi_cmp( y, sk->y ); + mpi_free( y ); + return rc; +} + + +static void +do_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 ); + 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 + */ + 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 */ + 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 ); + 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 */ + mpi_powm( t1, pkey->y, a, pkey->p ); + mpi_powm( t2, a, b, pkey->p ); + mpi_mulm( t1, t1, t2, pkey->p ); + + /* t2 = g ^ input mod p */ + 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 */ + 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 G10ERR_PUBKEY_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 G10ERR_PUBKEY_ALGO; + if( !skey[0] || !skey[1] || !skey[2] || !skey[3] ) + return G10ERR_BAD_MPI; + + sk.p = skey[0]; + sk.g = skey[1]; + sk.y = skey[2]; + sk.x = skey[3]; + if( !check_secret_key( &sk ) ) + return G10ERR_BAD_SECKEY; + + return 0; +} + + + +int +elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) +{ + ELG_public_key pk; + + if( !is_ELGAMAL(algo) ) + return G10ERR_PUBKEY_ALGO; + if( !data || !pkey[0] || !pkey[1] || !pkey[2] ) + return G10ERR_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 ) ); + do_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 G10ERR_PUBKEY_ALGO; + if( !data[0] || !data[1] + || !skey[0] || !skey[1] || !skey[2] || !skey[3] ) + return G10ERR_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 G10ERR_PUBKEY_ALGO; + if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] ) + return G10ERR_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 G10ERR_PUBKEY_ALGO; + if( !data[0] || !data[1] || !hash + || !pkey[0] || !pkey[1] || !pkey[2] ) + return G10ERR_BAD_MPI; + + pk.p = pkey[0]; + pk.g = pkey[1]; + pk.y = pkey[2]; + if( !verify( data[0], data[1], hash, &pk ) ) + return G10ERR_BAD_SIGN; + return 0; +} + + + +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: + *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC; + return "ELG"; + case PUBKEY_ALGO_ELGAMAL_E: + *use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC; + return "ELG-E"; + default: *use = 0; return NULL; + } +} + + diff --git a/cipher/elgamal.h b/cipher/elgamal.h new file mode 100644 index 000000000..f104c2a52 --- /dev/null +++ b/cipher/elgamal.h @@ -0,0 +1,35 @@ +/* elgamal.h + * 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 G10_ELGAMAL_H +#define G10_ELGAMAL_H + +int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int elg_check_secret_key( int algo, MPI *skey ); +int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); +int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); +int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey ); +int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey, + int (*cmp)(void *, MPI), void *opaquev ); +unsigned elg_get_nbits( int algo, MPI *pkey ); +const char *elg_get_info( int algo, int *npkey, int *nskey, + int *nenc, int *nsig, int *use ); + + +#endif /*G10_ELGAMAL_H*/ diff --git a/cipher/g10c.c b/cipher/g10c.c new file mode 100644 index 000000000..7b0f4fa61 --- /dev/null +++ b/cipher/g10c.c @@ -0,0 +1,46 @@ +/* g10c.c - Wrapper for cipher functions + * 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 +#include +#include +#include "mpi.h" +#include "random.h" +#include "cipher.h" + + +/* FIXME: The modules should use functions from libgcrypt */ + + +const char *g10c_revision_string(int dummy) { return "$Revision$"; } + +MPI +g10c_generate_secret_prime( unsigned nbits ) +{ + return generate_secret_prime( nbits ); +} + + +char * +g10c_get_random_bits( unsigned nbits, int level, int secure ) +{ + return (char*)get_random_bits( nbits, level, secure ); +} + diff --git a/cipher/gost.c b/cipher/gost.c new file mode 100644 index 000000000..4a527722f --- /dev/null +++ b/cipher/gost.c @@ -0,0 +1,76 @@ +/* gost.c - GOST encryption + * Copyright (C) 1998 Free Software Foundation, Inc. + * + * The description of GOST (and the used S-boxes) are taken from: + * Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996. + * ISBN 0-471-11709-9. . + * + * 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 +#include +#include +#include +#include "util.h" +#include "types.h" +#include "gost.h" + +#error don't use this + + +void +gost_setkey( GOST_context *c, byte *key ) +{ +} + +void +gost_setiv( GOST_context *c, byte *iv ) +{ +} + + +void +gost_encode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ +} + + +void +gost_decode( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nblocks ) +{ +} + + +static void +cfbshift( byte *iv, byte *buf, unsigned count) +{ +} + + + +void +gost_encode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ +} + + +void +gost_decode_cfb( GOST_context *c, byte *outbuf, byte *inbuf, unsigned nbytes) +{ +} + diff --git a/cipher/gost.h b/cipher/gost.h new file mode 100644 index 000000000..d8e7ebfc5 --- /dev/null +++ b/cipher/gost.h @@ -0,0 +1,46 @@ +/* gost.h + * 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 G10_GOST_H +#define G10_GOST_H + +#include "types.h" + +#define GOST_KEYSIZE 16 +#define GOST_BLOCKSIZE 8 +#define GOST_ROUNDS 8 +#define GOST_KEYLEN (6*GOST_ROUNDS+4) + +typedef struct { + u16 ek[GOST_KEYLEN]; + u16 dk[GOST_KEYLEN]; + byte iv[GOST_BLOCKSIZE]; +} GOST_context; + +void gost_setkey( GOST_context *c, byte *key ); +void gost_setiv( GOST_context *c, byte *iv ); +void gost_encode( GOST_context *c, byte *out, byte *in, unsigned nblocks ); +void gost_decode( GOST_context *c, byte *out, byte *in, unsigned nblocks ); +void gost_encode_cfb( GOST_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); +void gost_decode_cfb( GOST_context *c, byte *outbuf, + byte *inbuf, unsigned nbytes); + + +#endif /*G10_GOST_H*/ diff --git a/cipher/md.c b/cipher/md.c new file mode 100644 index 000000000..49728638b --- /dev/null +++ b/cipher/md.c @@ -0,0 +1,524 @@ +/* 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 +#include +#include +#include +#include +#include +#include "util.h" +#include "cipher.h" +#include "errors.h" +#include "dynload.h" +#include "rmd.h" + + +/**************** + * This structure is used for the list of available algorithms + * and for the list of algorithms in MD_HANDLE. + */ +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 = m_alloc_clear( 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 ) { + m_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_opt_verbose > 1 ) + 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 +string_to_digest_algo( const char *string ) +{ + struct md_digest_list_s *r; + + do { + for(r = digest_list; r; r = r->next ) + if( !ascii_strcasecmp( r->name, string ) ) + return r->algo; + } while( !r && load_digest_module(-1) ); + return 0; +} + + +/**************** + * Map a digest algo to a string + */ +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; +} + + +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 G10ERR_DIGEST_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. + */ +MD_HANDLE +md_open( int algo, int secure ) +{ + MD_HANDLE hd; + int bufsize; + + if( secure ) { + bufsize = 512 - sizeof( *hd ); + hd = m_alloc_secure_clear( sizeof *hd + bufsize ); + } + else { + bufsize = 1024 - sizeof( *hd ); + hd = m_alloc_clear( sizeof *hd + bufsize ); + } + + hd->bufsize = bufsize+1; /* hd has already one byte allocated */ + hd->secure = secure; + if( algo ) + md_enable( hd, algo ); + fast_random_poll(); + return hd; +} + +void +md_enable( MD_HANDLE h, int algo ) +{ + struct md_digest_list_s *r, *ac; + + for( ac=h->list; ac; ac = ac->next ) + if( ac->algo == algo ) + return ; /* 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_error("md_enable: algorithm %d not available\n", algo ); + return; + } + /* and allocate a new list entry */ + ac = h->secure? m_alloc_secure( sizeof *ac + r->contextsize + - sizeof(r->context) ) + : m_alloc( sizeof *ac + r->contextsize + - sizeof(r->context) ); + *ac = *r; + ac->next = h->list; + h->list = ac; + /* and init this instance */ + (*ac->init)( &ac->context.c ); +} + + +MD_HANDLE +md_copy( MD_HANDLE a ) +{ + MD_HANDLE b; + struct md_digest_list_s *ar, *br; + + if( a->bufcount ) + md_write( a, NULL, 0 ); + b = a->secure ? m_alloc_secure( sizeof *b + a->bufsize - 1 ) + : m_alloc( sizeof *b + a->bufsize - 1 ); + memcpy( b, a, sizeof *a + a->bufsize - 1 ); + b->list = NULL; + b->debug = NULL; + /* 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 ? m_alloc_secure( sizeof *br + ar->contextsize + - sizeof(ar->context) ) + : m_alloc( 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( b, "unknown" ); + return b; +} + + +/**************** + * Reset all contexts and discard any buffered stuff. This may be used + * instead of a md_close(); md_open(). + */ +void +md_reset( MD_HANDLE a ) +{ + struct md_digest_list_s *r; + + a->bufcount = a->finalized = 0; + for( r=a->list; r; r = r->next ) { + memset( r->context.c, 0, r->contextsize ); + (*r->init)( &r->context.c ); + } +} + + +void +md_close(MD_HANDLE a) +{ + struct md_digest_list_s *r, *r2; + + if( !a ) + return; + if( a->debug ) + md_stop_debug(a); + for(r=a->list; r; r = r2 ) { + r2 = r->next; + m_free(r); + } + m_free(a); +} + + +void +md_write( MD_HANDLE a, const byte *inbuf, size_t inlen) +{ + struct md_digest_list_s *r; + + if( a->debug ) { + if( a->bufcount && fwrite(a->buffer, a->bufcount, 1, a->debug ) != 1 ) + BUG(); + if( inlen && fwrite(inbuf, inlen, 1, a->debug ) != 1 ) + BUG(); + } + for(r=a->list; r; r = r->next ) { + (*r->write)( &r->context.c, a->buffer, a->bufcount ); + /* Fixme: all ->write fnc should take a const byte* */ + (*r->write)( &r->context.c, (byte*)inbuf, inlen ); + } + a->bufcount = 0; +} + + + +void +md_final(MD_HANDLE a) +{ + struct md_digest_list_s *r; + + if( a->finalized ) + return; + + if( a->bufcount ) + md_write( a, NULL, 0 ); + + for(r=a->list; r; r = r->next ) { + (*r->final)( &r->context.c ); + } + a->finalized = 1; +} + + +/**************** + * if ALGO is null get the digest for the used algo (which should be only one) + */ +byte * +md_read( MD_HANDLE a, int algo ) +{ + struct md_digest_list_s *r; + + if( !algo ) { /* return the first algorithm */ + if( (r=a->list) ) { + if( r->next ) + log_debug("more than algorithm in md_read(0)\n"); + return (*r->read)( &r->context.c ); + } + } + else { + for(r=a->list; r; r = r->next ) + if( r->algo == algo ) + return (*r->read)( &r->context.c ); + } + BUG(); + return NULL; +} + + +/**************** + * 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. + */ +int +md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen ) +{ + struct md_digest_list_s *r = NULL; + char *context; + char *digest; + + if( a->bufcount ) + md_write( a, NULL, 0 ); + + if( !algo ) { /* return digest for the first algorithm */ + if( (r=a->list) && r->next ) + log_debug("more than algorithm in md_digest(0)\n"); + } + else { + for(r=a->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 + * the context (extra overhead - should be fixed)*/ + context = a->secure ? m_alloc_secure( r->contextsize ) + : m_alloc( 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 ); + + m_free(context); + return buflen; +} + + +int +md_get_algo( MD_HANDLE a ) +{ + struct md_digest_list_s *r; + + if( (r=a->list) ) { + if( r->next ) + log_error("WARNING: more than algorithm in md_get_algo()\n"); + return r->algo; + } + return 0; +} + +/**************** + * Return the length of the digest + */ +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 ) ); + log_error("WARNING: no length for md algo %d\n", algo); + return 0; +} + + +/* Hmmm: add a mode to enumerate the OIDs + * to make g10/sig-check.c more portable */ +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; +} + + +void +md_start_debug( MD_HANDLE md, const char *suffix ) +{ + static int idx=0; + char buf[25]; + + if( md->debug ) { + log_debug("Oops: md debug already started\n"); + return; + } + idx++; + sprintf(buf, "dbgmd-%05d" EXTSEP_S "%.10s", idx, suffix ); + md->debug = fopen(buf, "w"); + if( !md->debug ) + log_debug("md debug: can't open %s\n", buf ); +} + +void +md_stop_debug( MD_HANDLE md ) +{ + if( md->debug ) { + if( md->bufcount ) + md_write( md, NULL, 0 ); + fclose(md->debug); + md->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 +} + diff --git a/cipher/md5.c b/cipher/md5.c new file mode 100644 index 000000000..ef6886eb4 --- /dev/null +++ b/cipher/md5.c @@ -0,0 +1,427 @@ +/* md5.c - MD5 Message-Digest Algorithm + * Copyright (C) 1995, 1996, 1998, 1999, + * 2000, 2001 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, 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. + * + * According to the definition of MD5 in RFC 1321 from April 1992. + * NOTE: This is *not* the same file as the one from glibc. + */ +/* Written by Ulrich Drepper , 1995. */ +/* Heavily modified for GnuPG by */ + +/* 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 +#include +#include +#include +#include +#include "util.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)) + +static void +burn_stack (int bytes) +{ + char buf[128]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + + +/**************** + * 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 ); + burn_stack (80+6*sizeof(void*)); + 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; + } + burn_stack (80+6*sizeof(void*)); + 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 */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if( (lsb += hd->count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + 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 ); + burn_stack (80+6*sizeof(void*)); + + 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) + #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; + *(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; +#ifndef __riscos__ + default: ret = func_table[i].func; break; +#else /* __riscos__ */ + default: ret = (void *) func_table[i].func; break; +#endif /* __riscos__ */ + } + 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 new file mode 100644 index 000000000..bb7138a84 --- /dev/null +++ b/cipher/primegen.c @@ -0,0 +1,583 @@ +/* primegen.c - prime number generator + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include "util.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 ) +{ + 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, 0 ); + q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL; + + /* allocate an array to hold the factors + 2 for later usage */ + factors = m_alloc_clear( (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 = m_alloc_clear( 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 = m_alloc_clear( m ); + for(i=0; i < n; i++ ) { + perms[i] = 1; + pool[i] = gen_prime( fbits, 0, 0 ); + 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, 0 ); + factors[j++] = pool[i]; + } + if( i == n ) { + m_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('>'); + mpi_free (q); + q = gen_prime( qbits, 0, 0 ); + goto next_try; + } + } + else + count1 = 0; + if( nprime > pbits ) { + if( ++count2 > 20 ) { + count2 = 0; + qbits--; + progress('<'); + mpi_free (q); + 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 = m_alloc_clear( (n+2) * sizeof **ret_factors); + i = 0; + if( mode == 1 ) { + (*ret_factors)[i++] = mpi_copy( q_factor ); + for(; i <= n; i++ ) + (*ret_factors)[i] = mpi_copy( factors[i] ); + } + else { + for(; 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 ); + } + 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) */ + 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'); + + m_free( factors ); /* (factors are shallow copies) */ + for(i=0; i < m; i++ ) + mpi_free( pool[i] ); + m_free( pool ); + m_free(perms); + mpi_free(val_2); + mpi_free(q); + 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; + int 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 = m_alloc( 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 */ + { char *p = get_random_bits( nbits, randomlevel, secret ); + mpi_set_buffer( prime, p, (nbits+7)/8, 0 ); + m_free(p); + } + + /* Set high order bit to 1, set low order bit to 0. + If we are generating a secret prime we are most probably + doing that for RSA, to make sure that the modulus does have + the requested keysize we set the 2 high order bits */ + mpi_set_highbit( prime, nbits-1 ); + if (secret) + mpi_set_bit (prime, nbits-2); + 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); + 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); + m_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); + 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 { + /*mpi_set_bytes( x, nbits-1, get_random_byte, 0 );*/ + { char *p = get_random_bits( nbits, 0, 0 ); + mpi_set_buffer( x, p, (nbits+7)/8, 0 ); + m_free(p); + } + /* 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 ); + } + 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++ ) { + 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 new file mode 100644 index 000000000..9136fa544 --- /dev/null +++ b/cipher/pubkey.c @@ -0,0 +1,618 @@ +/* pubkey.c - pubkey dispatcher + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include +#include "util.h" +#include "errors.h" +#include "mpi.h" +#include "cipher.h" +#include "elgamal.h" +#include "dsa.h" +#include "rsa.h" +#include "dynload.h" + + +#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 int +dummy_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ) +{ log_bug("no generate() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_check_secret_key( int algo, MPI *skey ) +{ log_bug("no check_secret_key() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) +{ log_bug("no encrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) +{ log_bug("no decrypt() for %d\n", algo ); return G10ERR_PUBKEY_ALGO; } + +static int +dummy_sign( int algo, MPI *resarr, MPI data, MPI *skey ) +{ log_bug("no sign() for %d\n", algo ); return G10ERR_PUBKEY_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 G10ERR_PUBKEY_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++; + + 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++; + + for( ; i < TABLE_SIZE; i++ ) + pubkey_table[i].name = 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_opt_verbose > 1 ) + 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 +string_to_pubkey_algo( const char *string ) +{ + int i; + const char *s; + + do { + for(i=0; (s=pubkey_table[i].name); i++ ) + if( !ascii_strcasecmp( s, string ) ) + return pubkey_table[i].algo; + } while( load_pubkey_modules() ); + return 0; +} + + +/**************** + * Map a pubkey algo to a string + */ +const char * +pubkey_algo_to_string( 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; +} + + +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 ); +} + + +int +check_pubkey_algo( int algo ) +{ + return check_pubkey_algo2( algo, 0 ); +} + +/**************** + * a use of 0 means: don't care + */ +int +check_pubkey_algo2( int algo, unsigned use ) +{ + int i; + + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) { + if( (use & PUBKEY_USAGE_SIG) + && !(pubkey_table[i].use & PUBKEY_USAGE_SIG) ) + return G10ERR_WR_PUBKEY_ALGO; + if( (use & PUBKEY_USAGE_ENC) + && !(pubkey_table[i].use & PUBKEY_USAGE_ENC) ) + return G10ERR_WR_PUBKEY_ALGO; + + for(i=0; i < DIM(disabled_algos); i++ ) { + if( disabled_algos[i] == algo ) + return G10ERR_PUBKEY_ALGO; + } + return 0; /* okay */ + } + } while( load_pubkey_modules() ); + return G10ERR_PUBKEY_ALGO; +} + + + + +/**************** + * Return the number of public key material numbers + */ +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() ); + return 0; +} + +/**************** + * Return the number of secret key material numbers + */ +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 + */ +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 + */ +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; +} + +/**************** + * Get the number of nbits from the public key + */ +unsigned +pubkey_nbits( int algo, MPI *pkey ) +{ + int i; + + do { + for(i=0; pubkey_table[i].name; i++ ) + if( pubkey_table[i].algo == algo ) + return (*pubkey_table[i].get_nbits)( algo, pkey ); + } while( load_pubkey_modules() ); + if( is_RSA(algo) ) /* we always wanna see the length of a key :-) */ + return mpi_get_nbits( pkey[0] ); + return 0; +} + + +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 G10ERR_PUBKEY_ALGO; +} + + +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 G10ERR_PUBKEY_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() ) + */ +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 = G10ERR_PUBKEY_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. + */ +int +pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ) +{ + int i, rc; + + *result = NULL; /* so the caller can always do an 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 = G10ERR_PUBKEY_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() ) + */ +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 = G10ERR_PUBKEY_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 + */ +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 = G10ERR_PUBKEY_ALGO; + ready: + return rc; +} + diff --git a/cipher/rand-internal.h b/cipher/rand-internal.h new file mode 100644 index 000000000..6f5b52bae --- /dev/null +++ b/cipher/rand-internal.h @@ -0,0 +1,31 @@ +/* rand-internal.h - header to glue the random functions + * Copyright (C) 1998, 1999, 2000, 2001 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_RAND_INTERNAL_H +#define G10_RAND_INTERNAL_H + +void rndlinux_constructor(void); +void rndunix_constructor(void); +void rndw32_constructor(void); +void rndos2_constructor(void); +void rndatari_constructor(void); +void rndmvs_constructor(void); +void rndriscos_constructor(void); + +#endif /*G10_RAND_INTERNAL_H*/ diff --git a/cipher/random.c b/cipher/random.c new file mode 100644 index 000000000..8c552bd3b --- /dev/null +++ b/cipher/random.c @@ -0,0 +1,687 @@ +/* random.c - random number generator + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GETHRTIME + #include +#endif +#ifdef HAVE_GETTIMEOFDAY + #include +#endif +#ifdef HAVE_GETRUSAGE + #include +#endif +#ifdef __MINGW32__ + #include +#endif +#include "util.h" +#include "rmd.h" +#include "ttyio.h" +#include "i18n.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 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 ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN) + : m_alloc_clear(POOLSIZE+BLOCKLEN); + keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN) + : m_alloc_clear(POOLSIZE+BLOCKLEN); + is_initialized = 1; + cipher_modules_constructor(); +} + +static void +burn_stack (int bytes) +{ + char buf[128]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + +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 +randomize_buffer( byte *buffer, size_t length, int level ) +{ + char *p = get_random_bits( length*8, level, 1 ); + memcpy( buffer, p, length ); + m_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. + */ +byte * +get_random_bits( size_t nbits, int level, int secure ) +{ + byte *buf, *p; + size_t nbytes = (nbits+7)/8; + + 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 ? m_alloc_secure( nbytes ) : m_alloc( nbytes ); + for( p = buf; nbytes > 0; ) { + size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes; + read_pool( p, n, level ); + nbytes -= n; + p += n; + } + return buf; +} + + +/**************** + * 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 ); + } + burn_stack (384); /* for the rmd160_mixblock() */ +} + + +void +set_random_seed_file( const char *name ) +{ + if( seed_file_name ) + BUG(); + seed_file_name = m_strdup( name ); +} + +/**************** + * Read in a seed form the random_seed file + * and return true if this was successful + */ +static int +read_seed_file(void) +{ + 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 ) { + log_bug("too many random bits requested\n"); + } + + if( !pool_filled ) { + if( read_seed_file() ) + pool_filled = 1; + } + + /* For level 2 quality (key generation) we 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 defined(HAVE_GETHRTIME) && !defined(HAVE_BROKEN_GETHRTIME) + { hrtime_t tv; + /* On some Solaris and HPUX system gethrtime raises an SIGILL, but we + * checked this with configure */ + tv = gethrtime(); + add_randomness( &tv, sizeof(tv), 1 ); + } + #elif defined (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 defined (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; + /* QNX/Neutrino does return ENOSYS - so we just ignore it and + * add whatever is in buf. In a chroot environment it might not + * work at all (i.e. because /proc/ is not accessible), so we better + * ignore all error codes and hope for the best + */ + getrusage( RUSAGE_SELF, &buf ); + + add_randomness( &buf, sizeof buf, 1 ); + memset( &buf, 0, sizeof buf ); + } + #endif + #endif + /* time and clock are available 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")); + 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")); + initialized=1; + #ifdef HAVE_RAND + srand(make_timestamp()*getpid()); + #else + srandom(make_timestamp()*getpid()); + #endif + } + + p = buffer = m_alloc( 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 ); + m_free(buffer); + return 0; /* okay */ +} + diff --git a/cipher/random.h b/cipher/random.h new file mode 100644 index 000000000..f4ba918bd --- /dev/null +++ b/cipher/random.h @@ -0,0 +1,41 @@ +/* random.h - random functions + * Copyright (C) 1998, 1999, 2000, 2001 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_RANDOM_H +#define G10_RANDOM_H + +#include "types.h" + +/*-- random.c --*/ +void random_dump_stats(void); +void secure_random_alloc(void); +void set_random_seed_file(const char *); +void update_random_seed_file(void); +int quick_random_gen( int onoff ); +int random_is_faked(void); +void randomize_buffer( byte *buffer, size_t length, int level ); +byte *get_random_bits( size_t nbits, int level, int secure ); +void fast_random_poll( void ); + +/*-- rndw32.c --*/ +#ifdef USE_STATIC_RNDW32 +void rndw32_set_dll_name( const char *name ); +#endif + +#endif /*G10_RANDOM_H*/ diff --git a/cipher/rijndael.c b/cipher/rijndael.c new file mode 100644 index 000000000..cd29beaad --- /dev/null +++ b/cipher/rijndael.c @@ -0,0 +1,2234 @@ +/* Rijndael (AES) for GnuPG + * Copyright (C) 2000, 2001 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 code here is based on the optimized implementation taken from + * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/ on Oct 2, 2000, + * which carries this notice: + *------------------------------------------ + * rijndael-alg-fst.c v2.3 April '2000 + * + * Optimised ANSI C code + * + * authors: v1.0: Antoon Bosselaers + * v2.0: Vincent Rijmen + * v2.3: Paulo Barreto + * + * This code is placed in the public domain. + *------------------------------------------ + */ + +#include +#include +#include +#include /* for memcmp() */ + +#include "types.h" /* for byte and u32 typedefs */ +#include "util.h" +#include "errors.h" +#include "dynload.h" + +#define MAXKC (256/32) +#define MAXROUNDS 14 + + +static const char *selftest(void); + +typedef struct { + int ROUNDS; /* key-length-dependent number of rounds */ + int decryption_prepared; + byte keySched[MAXROUNDS+1][4][4]; /* key schedule */ + byte keySched2[MAXROUNDS+1][4][4]; /* key schedule */ +} RIJNDAEL_context; + + +static const byte S[256] = { + 99, 124, 119, 123, 242, 107, 111, 197, + 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, + 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, + 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, + 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, + 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, + 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, + 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, + 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, + 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, + 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, + 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, + 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, + 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, + 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, + 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, + 65, 153, 45, 15, 176, 84, 187, 22 +}; + + +static const byte T1[256][4] = { + { 0xc6,0x63,0x63,0xa5 }, { 0xf8,0x7c,0x7c,0x84 }, + { 0xee,0x77,0x77,0x99 }, { 0xf6,0x7b,0x7b,0x8d }, + { 0xff,0xf2,0xf2,0x0d }, { 0xd6,0x6b,0x6b,0xbd }, + { 0xde,0x6f,0x6f,0xb1 }, { 0x91,0xc5,0xc5,0x54 }, + { 0x60,0x30,0x30,0x50 }, { 0x02,0x01,0x01,0x03 }, + { 0xce,0x67,0x67,0xa9 }, { 0x56,0x2b,0x2b,0x7d }, + { 0xe7,0xfe,0xfe,0x19 }, { 0xb5,0xd7,0xd7,0x62 }, + { 0x4d,0xab,0xab,0xe6 }, { 0xec,0x76,0x76,0x9a }, + { 0x8f,0xca,0xca,0x45 }, { 0x1f,0x82,0x82,0x9d }, + { 0x89,0xc9,0xc9,0x40 }, { 0xfa,0x7d,0x7d,0x87 }, + { 0xef,0xfa,0xfa,0x15 }, { 0xb2,0x59,0x59,0xeb }, + { 0x8e,0x47,0x47,0xc9 }, { 0xfb,0xf0,0xf0,0x0b }, + { 0x41,0xad,0xad,0xec }, { 0xb3,0xd4,0xd4,0x67 }, + { 0x5f,0xa2,0xa2,0xfd }, { 0x45,0xaf,0xaf,0xea }, + { 0x23,0x9c,0x9c,0xbf }, { 0x53,0xa4,0xa4,0xf7 }, + { 0xe4,0x72,0x72,0x96 }, { 0x9b,0xc0,0xc0,0x5b }, + { 0x75,0xb7,0xb7,0xc2 }, { 0xe1,0xfd,0xfd,0x1c }, + { 0x3d,0x93,0x93,0xae }, { 0x4c,0x26,0x26,0x6a }, + { 0x6c,0x36,0x36,0x5a }, { 0x7e,0x3f,0x3f,0x41 }, + { 0xf5,0xf7,0xf7,0x02 }, { 0x83,0xcc,0xcc,0x4f }, + { 0x68,0x34,0x34,0x5c }, { 0x51,0xa5,0xa5,0xf4 }, + { 0xd1,0xe5,0xe5,0x34 }, { 0xf9,0xf1,0xf1,0x08 }, + { 0xe2,0x71,0x71,0x93 }, { 0xab,0xd8,0xd8,0x73 }, + { 0x62,0x31,0x31,0x53 }, { 0x2a,0x15,0x15,0x3f }, + { 0x08,0x04,0x04,0x0c }, { 0x95,0xc7,0xc7,0x52 }, + { 0x46,0x23,0x23,0x65 }, { 0x9d,0xc3,0xc3,0x5e }, + { 0x30,0x18,0x18,0x28 }, { 0x37,0x96,0x96,0xa1 }, + { 0x0a,0x05,0x05,0x0f }, { 0x2f,0x9a,0x9a,0xb5 }, + { 0x0e,0x07,0x07,0x09 }, { 0x24,0x12,0x12,0x36 }, + { 0x1b,0x80,0x80,0x9b }, { 0xdf,0xe2,0xe2,0x3d }, + { 0xcd,0xeb,0xeb,0x26 }, { 0x4e,0x27,0x27,0x69 }, + { 0x7f,0xb2,0xb2,0xcd }, { 0xea,0x75,0x75,0x9f }, + { 0x12,0x09,0x09,0x1b }, { 0x1d,0x83,0x83,0x9e }, + { 0x58,0x2c,0x2c,0x74 }, { 0x34,0x1a,0x1a,0x2e }, + { 0x36,0x1b,0x1b,0x2d }, { 0xdc,0x6e,0x6e,0xb2 }, + { 0xb4,0x5a,0x5a,0xee }, { 0x5b,0xa0,0xa0,0xfb }, + { 0xa4,0x52,0x52,0xf6 }, { 0x76,0x3b,0x3b,0x4d }, + { 0xb7,0xd6,0xd6,0x61 }, { 0x7d,0xb3,0xb3,0xce }, + { 0x52,0x29,0x29,0x7b }, { 0xdd,0xe3,0xe3,0x3e }, + { 0x5e,0x2f,0x2f,0x71 }, { 0x13,0x84,0x84,0x97 }, + { 0xa6,0x53,0x53,0xf5 }, { 0xb9,0xd1,0xd1,0x68 }, + { 0x00,0x00,0x00,0x00 }, { 0xc1,0xed,0xed,0x2c }, + { 0x40,0x20,0x20,0x60 }, { 0xe3,0xfc,0xfc,0x1f }, + { 0x79,0xb1,0xb1,0xc8 }, { 0xb6,0x5b,0x5b,0xed }, + { 0xd4,0x6a,0x6a,0xbe }, { 0x8d,0xcb,0xcb,0x46 }, + { 0x67,0xbe,0xbe,0xd9 }, { 0x72,0x39,0x39,0x4b }, + { 0x94,0x4a,0x4a,0xde }, { 0x98,0x4c,0x4c,0xd4 }, + { 0xb0,0x58,0x58,0xe8 }, { 0x85,0xcf,0xcf,0x4a }, + { 0xbb,0xd0,0xd0,0x6b }, { 0xc5,0xef,0xef,0x2a }, + { 0x4f,0xaa,0xaa,0xe5 }, { 0xed,0xfb,0xfb,0x16 }, + { 0x86,0x43,0x43,0xc5 }, { 0x9a,0x4d,0x4d,0xd7 }, + { 0x66,0x33,0x33,0x55 }, { 0x11,0x85,0x85,0x94 }, + { 0x8a,0x45,0x45,0xcf }, { 0xe9,0xf9,0xf9,0x10 }, + { 0x04,0x02,0x02,0x06 }, { 0xfe,0x7f,0x7f,0x81 }, + { 0xa0,0x50,0x50,0xf0 }, { 0x78,0x3c,0x3c,0x44 }, + { 0x25,0x9f,0x9f,0xba }, { 0x4b,0xa8,0xa8,0xe3 }, + { 0xa2,0x51,0x51,0xf3 }, { 0x5d,0xa3,0xa3,0xfe }, + { 0x80,0x40,0x40,0xc0 }, { 0x05,0x8f,0x8f,0x8a }, + { 0x3f,0x92,0x92,0xad }, { 0x21,0x9d,0x9d,0xbc }, + { 0x70,0x38,0x38,0x48 }, { 0xf1,0xf5,0xf5,0x04 }, + { 0x63,0xbc,0xbc,0xdf }, { 0x77,0xb6,0xb6,0xc1 }, + { 0xaf,0xda,0xda,0x75 }, { 0x42,0x21,0x21,0x63 }, + { 0x20,0x10,0x10,0x30 }, { 0xe5,0xff,0xff,0x1a }, + { 0xfd,0xf3,0xf3,0x0e }, { 0xbf,0xd2,0xd2,0x6d }, + { 0x81,0xcd,0xcd,0x4c }, { 0x18,0x0c,0x0c,0x14 }, + { 0x26,0x13,0x13,0x35 }, { 0xc3,0xec,0xec,0x2f }, + { 0xbe,0x5f,0x5f,0xe1 }, { 0x35,0x97,0x97,0xa2 }, + { 0x88,0x44,0x44,0xcc }, { 0x2e,0x17,0x17,0x39 }, + { 0x93,0xc4,0xc4,0x57 }, { 0x55,0xa7,0xa7,0xf2 }, + { 0xfc,0x7e,0x7e,0x82 }, { 0x7a,0x3d,0x3d,0x47 }, + { 0xc8,0x64,0x64,0xac }, { 0xba,0x5d,0x5d,0xe7 }, + { 0x32,0x19,0x19,0x2b }, { 0xe6,0x73,0x73,0x95 }, + { 0xc0,0x60,0x60,0xa0 }, { 0x19,0x81,0x81,0x98 }, + { 0x9e,0x4f,0x4f,0xd1 }, { 0xa3,0xdc,0xdc,0x7f }, + { 0x44,0x22,0x22,0x66 }, { 0x54,0x2a,0x2a,0x7e }, + { 0x3b,0x90,0x90,0xab }, { 0x0b,0x88,0x88,0x83 }, + { 0x8c,0x46,0x46,0xca }, { 0xc7,0xee,0xee,0x29 }, + { 0x6b,0xb8,0xb8,0xd3 }, { 0x28,0x14,0x14,0x3c }, + { 0xa7,0xde,0xde,0x79 }, { 0xbc,0x5e,0x5e,0xe2 }, + { 0x16,0x0b,0x0b,0x1d }, { 0xad,0xdb,0xdb,0x76 }, + { 0xdb,0xe0,0xe0,0x3b }, { 0x64,0x32,0x32,0x56 }, + { 0x74,0x3a,0x3a,0x4e }, { 0x14,0x0a,0x0a,0x1e }, + { 0x92,0x49,0x49,0xdb }, { 0x0c,0x06,0x06,0x0a }, + { 0x48,0x24,0x24,0x6c }, { 0xb8,0x5c,0x5c,0xe4 }, + { 0x9f,0xc2,0xc2,0x5d }, { 0xbd,0xd3,0xd3,0x6e }, + { 0x43,0xac,0xac,0xef }, { 0xc4,0x62,0x62,0xa6 }, + { 0x39,0x91,0x91,0xa8 }, { 0x31,0x95,0x95,0xa4 }, + { 0xd3,0xe4,0xe4,0x37 }, { 0xf2,0x79,0x79,0x8b }, + { 0xd5,0xe7,0xe7,0x32 }, { 0x8b,0xc8,0xc8,0x43 }, + { 0x6e,0x37,0x37,0x59 }, { 0xda,0x6d,0x6d,0xb7 }, + { 0x01,0x8d,0x8d,0x8c }, { 0xb1,0xd5,0xd5,0x64 }, + { 0x9c,0x4e,0x4e,0xd2 }, { 0x49,0xa9,0xa9,0xe0 }, + { 0xd8,0x6c,0x6c,0xb4 }, { 0xac,0x56,0x56,0xfa }, + { 0xf3,0xf4,0xf4,0x07 }, { 0xcf,0xea,0xea,0x25 }, + { 0xca,0x65,0x65,0xaf }, { 0xf4,0x7a,0x7a,0x8e }, + { 0x47,0xae,0xae,0xe9 }, { 0x10,0x08,0x08,0x18 }, + { 0x6f,0xba,0xba,0xd5 }, { 0xf0,0x78,0x78,0x88 }, + { 0x4a,0x25,0x25,0x6f }, { 0x5c,0x2e,0x2e,0x72 }, + { 0x38,0x1c,0x1c,0x24 }, { 0x57,0xa6,0xa6,0xf1 }, + { 0x73,0xb4,0xb4,0xc7 }, { 0x97,0xc6,0xc6,0x51 }, + { 0xcb,0xe8,0xe8,0x23 }, { 0xa1,0xdd,0xdd,0x7c }, + { 0xe8,0x74,0x74,0x9c }, { 0x3e,0x1f,0x1f,0x21 }, + { 0x96,0x4b,0x4b,0xdd }, { 0x61,0xbd,0xbd,0xdc }, + { 0x0d,0x8b,0x8b,0x86 }, { 0x0f,0x8a,0x8a,0x85 }, + { 0xe0,0x70,0x70,0x90 }, { 0x7c,0x3e,0x3e,0x42 }, + { 0x71,0xb5,0xb5,0xc4 }, { 0xcc,0x66,0x66,0xaa }, + { 0x90,0x48,0x48,0xd8 }, { 0x06,0x03,0x03,0x05 }, + { 0xf7,0xf6,0xf6,0x01 }, { 0x1c,0x0e,0x0e,0x12 }, + { 0xc2,0x61,0x61,0xa3 }, { 0x6a,0x35,0x35,0x5f }, + { 0xae,0x57,0x57,0xf9 }, { 0x69,0xb9,0xb9,0xd0 }, + { 0x17,0x86,0x86,0x91 }, { 0x99,0xc1,0xc1,0x58 }, + { 0x3a,0x1d,0x1d,0x27 }, { 0x27,0x9e,0x9e,0xb9 }, + { 0xd9,0xe1,0xe1,0x38 }, { 0xeb,0xf8,0xf8,0x13 }, + { 0x2b,0x98,0x98,0xb3 }, { 0x22,0x11,0x11,0x33 }, + { 0xd2,0x69,0x69,0xbb }, { 0xa9,0xd9,0xd9,0x70 }, + { 0x07,0x8e,0x8e,0x89 }, { 0x33,0x94,0x94,0xa7 }, + { 0x2d,0x9b,0x9b,0xb6 }, { 0x3c,0x1e,0x1e,0x22 }, + { 0x15,0x87,0x87,0x92 }, { 0xc9,0xe9,0xe9,0x20 }, + { 0x87,0xce,0xce,0x49 }, { 0xaa,0x55,0x55,0xff }, + { 0x50,0x28,0x28,0x78 }, { 0xa5,0xdf,0xdf,0x7a }, + { 0x03,0x8c,0x8c,0x8f }, { 0x59,0xa1,0xa1,0xf8 }, + { 0x09,0x89,0x89,0x80 }, { 0x1a,0x0d,0x0d,0x17 }, + { 0x65,0xbf,0xbf,0xda }, { 0xd7,0xe6,0xe6,0x31 }, + { 0x84,0x42,0x42,0xc6 }, { 0xd0,0x68,0x68,0xb8 }, + { 0x82,0x41,0x41,0xc3 }, { 0x29,0x99,0x99,0xb0 }, + { 0x5a,0x2d,0x2d,0x77 }, { 0x1e,0x0f,0x0f,0x11 }, + { 0x7b,0xb0,0xb0,0xcb }, { 0xa8,0x54,0x54,0xfc }, + { 0x6d,0xbb,0xbb,0xd6 }, { 0x2c,0x16,0x16,0x3a } +}; + +static const byte T2[256][4] = { + { 0xa5,0xc6,0x63,0x63 }, { 0x84,0xf8,0x7c,0x7c }, + { 0x99,0xee,0x77,0x77 }, { 0x8d,0xf6,0x7b,0x7b }, + { 0x0d,0xff,0xf2,0xf2 }, { 0xbd,0xd6,0x6b,0x6b }, + { 0xb1,0xde,0x6f,0x6f }, { 0x54,0x91,0xc5,0xc5 }, + { 0x50,0x60,0x30,0x30 }, { 0x03,0x02,0x01,0x01 }, + { 0xa9,0xce,0x67,0x67 }, { 0x7d,0x56,0x2b,0x2b }, + { 0x19,0xe7,0xfe,0xfe }, { 0x62,0xb5,0xd7,0xd7 }, + { 0xe6,0x4d,0xab,0xab }, { 0x9a,0xec,0x76,0x76 }, + { 0x45,0x8f,0xca,0xca }, { 0x9d,0x1f,0x82,0x82 }, + { 0x40,0x89,0xc9,0xc9 }, { 0x87,0xfa,0x7d,0x7d }, + { 0x15,0xef,0xfa,0xfa }, { 0xeb,0xb2,0x59,0x59 }, + { 0xc9,0x8e,0x47,0x47 }, { 0x0b,0xfb,0xf0,0xf0 }, + { 0xec,0x41,0xad,0xad }, { 0x67,0xb3,0xd4,0xd4 }, + { 0xfd,0x5f,0xa2,0xa2 }, { 0xea,0x45,0xaf,0xaf }, + { 0xbf,0x23,0x9c,0x9c }, { 0xf7,0x53,0xa4,0xa4 }, + { 0x96,0xe4,0x72,0x72 }, { 0x5b,0x9b,0xc0,0xc0 }, + { 0xc2,0x75,0xb7,0xb7 }, { 0x1c,0xe1,0xfd,0xfd }, + { 0xae,0x3d,0x93,0x93 }, { 0x6a,0x4c,0x26,0x26 }, + { 0x5a,0x6c,0x36,0x36 }, { 0x41,0x7e,0x3f,0x3f }, + { 0x02,0xf5,0xf7,0xf7 }, { 0x4f,0x83,0xcc,0xcc }, + { 0x5c,0x68,0x34,0x34 }, { 0xf4,0x51,0xa5,0xa5 }, + { 0x34,0xd1,0xe5,0xe5 }, { 0x08,0xf9,0xf1,0xf1 }, + { 0x93,0xe2,0x71,0x71 }, { 0x73,0xab,0xd8,0xd8 }, + { 0x53,0x62,0x31,0x31 }, { 0x3f,0x2a,0x15,0x15 }, + { 0x0c,0x08,0x04,0x04 }, { 0x52,0x95,0xc7,0xc7 }, + { 0x65,0x46,0x23,0x23 }, { 0x5e,0x9d,0xc3,0xc3 }, + { 0x28,0x30,0x18,0x18 }, { 0xa1,0x37,0x96,0x96 }, + { 0x0f,0x0a,0x05,0x05 }, { 0xb5,0x2f,0x9a,0x9a }, + { 0x09,0x0e,0x07,0x07 }, { 0x36,0x24,0x12,0x12 }, + { 0x9b,0x1b,0x80,0x80 }, { 0x3d,0xdf,0xe2,0xe2 }, + { 0x26,0xcd,0xeb,0xeb }, { 0x69,0x4e,0x27,0x27 }, + { 0xcd,0x7f,0xb2,0xb2 }, { 0x9f,0xea,0x75,0x75 }, + { 0x1b,0x12,0x09,0x09 }, { 0x9e,0x1d,0x83,0x83 }, + { 0x74,0x58,0x2c,0x2c }, { 0x2e,0x34,0x1a,0x1a }, + { 0x2d,0x36,0x1b,0x1b }, { 0xb2,0xdc,0x6e,0x6e }, + { 0xee,0xb4,0x5a,0x5a }, { 0xfb,0x5b,0xa0,0xa0 }, + { 0xf6,0xa4,0x52,0x52 }, { 0x4d,0x76,0x3b,0x3b }, + { 0x61,0xb7,0xd6,0xd6 }, { 0xce,0x7d,0xb3,0xb3 }, + { 0x7b,0x52,0x29,0x29 }, { 0x3e,0xdd,0xe3,0xe3 }, + { 0x71,0x5e,0x2f,0x2f }, { 0x97,0x13,0x84,0x84 }, + { 0xf5,0xa6,0x53,0x53 }, { 0x68,0xb9,0xd1,0xd1 }, + { 0x00,0x00,0x00,0x00 }, { 0x2c,0xc1,0xed,0xed }, + { 0x60,0x40,0x20,0x20 }, { 0x1f,0xe3,0xfc,0xfc }, + { 0xc8,0x79,0xb1,0xb1 }, { 0xed,0xb6,0x5b,0x5b }, + { 0xbe,0xd4,0x6a,0x6a }, { 0x46,0x8d,0xcb,0xcb }, + { 0xd9,0x67,0xbe,0xbe }, { 0x4b,0x72,0x39,0x39 }, + { 0xde,0x94,0x4a,0x4a }, { 0xd4,0x98,0x4c,0x4c }, + { 0xe8,0xb0,0x58,0x58 }, { 0x4a,0x85,0xcf,0xcf }, + { 0x6b,0xbb,0xd0,0xd0 }, { 0x2a,0xc5,0xef,0xef }, + { 0xe5,0x4f,0xaa,0xaa }, { 0x16,0xed,0xfb,0xfb }, + { 0xc5,0x86,0x43,0x43 }, { 0xd7,0x9a,0x4d,0x4d }, + { 0x55,0x66,0x33,0x33 }, { 0x94,0x11,0x85,0x85 }, + { 0xcf,0x8a,0x45,0x45 }, { 0x10,0xe9,0xf9,0xf9 }, + { 0x06,0x04,0x02,0x02 }, { 0x81,0xfe,0x7f,0x7f }, + { 0xf0,0xa0,0x50,0x50 }, { 0x44,0x78,0x3c,0x3c }, + { 0xba,0x25,0x9f,0x9f }, { 0xe3,0x4b,0xa8,0xa8 }, + { 0xf3,0xa2,0x51,0x51 }, { 0xfe,0x5d,0xa3,0xa3 }, + { 0xc0,0x80,0x40,0x40 }, { 0x8a,0x05,0x8f,0x8f }, + { 0xad,0x3f,0x92,0x92 }, { 0xbc,0x21,0x9d,0x9d }, + { 0x48,0x70,0x38,0x38 }, { 0x04,0xf1,0xf5,0xf5 }, + { 0xdf,0x63,0xbc,0xbc }, { 0xc1,0x77,0xb6,0xb6 }, + { 0x75,0xaf,0xda,0xda }, { 0x63,0x42,0x21,0x21 }, + { 0x30,0x20,0x10,0x10 }, { 0x1a,0xe5,0xff,0xff }, + { 0x0e,0xfd,0xf3,0xf3 }, { 0x6d,0xbf,0xd2,0xd2 }, + { 0x4c,0x81,0xcd,0xcd }, { 0x14,0x18,0x0c,0x0c }, + { 0x35,0x26,0x13,0x13 }, { 0x2f,0xc3,0xec,0xec }, + { 0xe1,0xbe,0x5f,0x5f }, { 0xa2,0x35,0x97,0x97 }, + { 0xcc,0x88,0x44,0x44 }, { 0x39,0x2e,0x17,0x17 }, + { 0x57,0x93,0xc4,0xc4 }, { 0xf2,0x55,0xa7,0xa7 }, + { 0x82,0xfc,0x7e,0x7e }, { 0x47,0x7a,0x3d,0x3d }, + { 0xac,0xc8,0x64,0x64 }, { 0xe7,0xba,0x5d,0x5d }, + { 0x2b,0x32,0x19,0x19 }, { 0x95,0xe6,0x73,0x73 }, + { 0xa0,0xc0,0x60,0x60 }, { 0x98,0x19,0x81,0x81 }, + { 0xd1,0x9e,0x4f,0x4f }, { 0x7f,0xa3,0xdc,0xdc }, + { 0x66,0x44,0x22,0x22 }, { 0x7e,0x54,0x2a,0x2a }, + { 0xab,0x3b,0x90,0x90 }, { 0x83,0x0b,0x88,0x88 }, + { 0xca,0x8c,0x46,0x46 }, { 0x29,0xc7,0xee,0xee }, + { 0xd3,0x6b,0xb8,0xb8 }, { 0x3c,0x28,0x14,0x14 }, + { 0x79,0xa7,0xde,0xde }, { 0xe2,0xbc,0x5e,0x5e }, + { 0x1d,0x16,0x0b,0x0b }, { 0x76,0xad,0xdb,0xdb }, + { 0x3b,0xdb,0xe0,0xe0 }, { 0x56,0x64,0x32,0x32 }, + { 0x4e,0x74,0x3a,0x3a }, { 0x1e,0x14,0x0a,0x0a }, + { 0xdb,0x92,0x49,0x49 }, { 0x0a,0x0c,0x06,0x06 }, + { 0x6c,0x48,0x24,0x24 }, { 0xe4,0xb8,0x5c,0x5c }, + { 0x5d,0x9f,0xc2,0xc2 }, { 0x6e,0xbd,0xd3,0xd3 }, + { 0xef,0x43,0xac,0xac }, { 0xa6,0xc4,0x62,0x62 }, + { 0xa8,0x39,0x91,0x91 }, { 0xa4,0x31,0x95,0x95 }, + { 0x37,0xd3,0xe4,0xe4 }, { 0x8b,0xf2,0x79,0x79 }, + { 0x32,0xd5,0xe7,0xe7 }, { 0x43,0x8b,0xc8,0xc8 }, + { 0x59,0x6e,0x37,0x37 }, { 0xb7,0xda,0x6d,0x6d }, + { 0x8c,0x01,0x8d,0x8d }, { 0x64,0xb1,0xd5,0xd5 }, + { 0xd2,0x9c,0x4e,0x4e }, { 0xe0,0x49,0xa9,0xa9 }, + { 0xb4,0xd8,0x6c,0x6c }, { 0xfa,0xac,0x56,0x56 }, + { 0x07,0xf3,0xf4,0xf4 }, { 0x25,0xcf,0xea,0xea }, + { 0xaf,0xca,0x65,0x65 }, { 0x8e,0xf4,0x7a,0x7a }, + { 0xe9,0x47,0xae,0xae }, { 0x18,0x10,0x08,0x08 }, + { 0xd5,0x6f,0xba,0xba }, { 0x88,0xf0,0x78,0x78 }, + { 0x6f,0x4a,0x25,0x25 }, { 0x72,0x5c,0x2e,0x2e }, + { 0x24,0x38,0x1c,0x1c }, { 0xf1,0x57,0xa6,0xa6 }, + { 0xc7,0x73,0xb4,0xb4 }, { 0x51,0x97,0xc6,0xc6 }, + { 0x23,0xcb,0xe8,0xe8 }, { 0x7c,0xa1,0xdd,0xdd }, + { 0x9c,0xe8,0x74,0x74 }, { 0x21,0x3e,0x1f,0x1f }, + { 0xdd,0x96,0x4b,0x4b }, { 0xdc,0x61,0xbd,0xbd }, + { 0x86,0x0d,0x8b,0x8b }, { 0x85,0x0f,0x8a,0x8a }, + { 0x90,0xe0,0x70,0x70 }, { 0x42,0x7c,0x3e,0x3e }, + { 0xc4,0x71,0xb5,0xb5 }, { 0xaa,0xcc,0x66,0x66 }, + { 0xd8,0x90,0x48,0x48 }, { 0x05,0x06,0x03,0x03 }, + { 0x01,0xf7,0xf6,0xf6 }, { 0x12,0x1c,0x0e,0x0e }, + { 0xa3,0xc2,0x61,0x61 }, { 0x5f,0x6a,0x35,0x35 }, + { 0xf9,0xae,0x57,0x57 }, { 0xd0,0x69,0xb9,0xb9 }, + { 0x91,0x17,0x86,0x86 }, { 0x58,0x99,0xc1,0xc1 }, + { 0x27,0x3a,0x1d,0x1d }, { 0xb9,0x27,0x9e,0x9e }, + { 0x38,0xd9,0xe1,0xe1 }, { 0x13,0xeb,0xf8,0xf8 }, + { 0xb3,0x2b,0x98,0x98 }, { 0x33,0x22,0x11,0x11 }, + { 0xbb,0xd2,0x69,0x69 }, { 0x70,0xa9,0xd9,0xd9 }, + { 0x89,0x07,0x8e,0x8e }, { 0xa7,0x33,0x94,0x94 }, + { 0xb6,0x2d,0x9b,0x9b }, { 0x22,0x3c,0x1e,0x1e }, + { 0x92,0x15,0x87,0x87 }, { 0x20,0xc9,0xe9,0xe9 }, + { 0x49,0x87,0xce,0xce }, { 0xff,0xaa,0x55,0x55 }, + { 0x78,0x50,0x28,0x28 }, { 0x7a,0xa5,0xdf,0xdf }, + { 0x8f,0x03,0x8c,0x8c }, { 0xf8,0x59,0xa1,0xa1 }, + { 0x80,0x09,0x89,0x89 }, { 0x17,0x1a,0x0d,0x0d }, + { 0xda,0x65,0xbf,0xbf }, { 0x31,0xd7,0xe6,0xe6 }, + { 0xc6,0x84,0x42,0x42 }, { 0xb8,0xd0,0x68,0x68 }, + { 0xc3,0x82,0x41,0x41 }, { 0xb0,0x29,0x99,0x99 }, + { 0x77,0x5a,0x2d,0x2d }, { 0x11,0x1e,0x0f,0x0f }, + { 0xcb,0x7b,0xb0,0xb0 }, { 0xfc,0xa8,0x54,0x54 }, + { 0xd6,0x6d,0xbb,0xbb }, { 0x3a,0x2c,0x16,0x16 } +}; + +static const byte T3[256][4] = { + { 0x63,0xa5,0xc6,0x63 }, { 0x7c,0x84,0xf8,0x7c }, + { 0x77,0x99,0xee,0x77 }, { 0x7b,0x8d,0xf6,0x7b }, + { 0xf2,0x0d,0xff,0xf2 }, { 0x6b,0xbd,0xd6,0x6b }, + { 0x6f,0xb1,0xde,0x6f }, { 0xc5,0x54,0x91,0xc5 }, + { 0x30,0x50,0x60,0x30 }, { 0x01,0x03,0x02,0x01 }, + { 0x67,0xa9,0xce,0x67 }, { 0x2b,0x7d,0x56,0x2b }, + { 0xfe,0x19,0xe7,0xfe }, { 0xd7,0x62,0xb5,0xd7 }, + { 0xab,0xe6,0x4d,0xab }, { 0x76,0x9a,0xec,0x76 }, + { 0xca,0x45,0x8f,0xca }, { 0x82,0x9d,0x1f,0x82 }, + { 0xc9,0x40,0x89,0xc9 }, { 0x7d,0x87,0xfa,0x7d }, + { 0xfa,0x15,0xef,0xfa }, { 0x59,0xeb,0xb2,0x59 }, + { 0x47,0xc9,0x8e,0x47 }, { 0xf0,0x0b,0xfb,0xf0 }, + { 0xad,0xec,0x41,0xad }, { 0xd4,0x67,0xb3,0xd4 }, + { 0xa2,0xfd,0x5f,0xa2 }, { 0xaf,0xea,0x45,0xaf }, + { 0x9c,0xbf,0x23,0x9c }, { 0xa4,0xf7,0x53,0xa4 }, + { 0x72,0x96,0xe4,0x72 }, { 0xc0,0x5b,0x9b,0xc0 }, + { 0xb7,0xc2,0x75,0xb7 }, { 0xfd,0x1c,0xe1,0xfd }, + { 0x93,0xae,0x3d,0x93 }, { 0x26,0x6a,0x4c,0x26 }, + { 0x36,0x5a,0x6c,0x36 }, { 0x3f,0x41,0x7e,0x3f }, + { 0xf7,0x02,0xf5,0xf7 }, { 0xcc,0x4f,0x83,0xcc }, + { 0x34,0x5c,0x68,0x34 }, { 0xa5,0xf4,0x51,0xa5 }, + { 0xe5,0x34,0xd1,0xe5 }, { 0xf1,0x08,0xf9,0xf1 }, + { 0x71,0x93,0xe2,0x71 }, { 0xd8,0x73,0xab,0xd8 }, + { 0x31,0x53,0x62,0x31 }, { 0x15,0x3f,0x2a,0x15 }, + { 0x04,0x0c,0x08,0x04 }, { 0xc7,0x52,0x95,0xc7 }, + { 0x23,0x65,0x46,0x23 }, { 0xc3,0x5e,0x9d,0xc3 }, + { 0x18,0x28,0x30,0x18 }, { 0x96,0xa1,0x37,0x96 }, + { 0x05,0x0f,0x0a,0x05 }, { 0x9a,0xb5,0x2f,0x9a }, + { 0x07,0x09,0x0e,0x07 }, { 0x12,0x36,0x24,0x12 }, + { 0x80,0x9b,0x1b,0x80 }, { 0xe2,0x3d,0xdf,0xe2 }, + { 0xeb,0x26,0xcd,0xeb }, { 0x27,0x69,0x4e,0x27 }, + { 0xb2,0xcd,0x7f,0xb2 }, { 0x75,0x9f,0xea,0x75 }, + { 0x09,0x1b,0x12,0x09 }, { 0x83,0x9e,0x1d,0x83 }, + { 0x2c,0x74,0x58,0x2c }, { 0x1a,0x2e,0x34,0x1a }, + { 0x1b,0x2d,0x36,0x1b }, { 0x6e,0xb2,0xdc,0x6e }, + { 0x5a,0xee,0xb4,0x5a }, { 0xa0,0xfb,0x5b,0xa0 }, + { 0x52,0xf6,0xa4,0x52 }, { 0x3b,0x4d,0x76,0x3b }, + { 0xd6,0x61,0xb7,0xd6 }, { 0xb3,0xce,0x7d,0xb3 }, + { 0x29,0x7b,0x52,0x29 }, { 0xe3,0x3e,0xdd,0xe3 }, + { 0x2f,0x71,0x5e,0x2f }, { 0x84,0x97,0x13,0x84 }, + { 0x53,0xf5,0xa6,0x53 }, { 0xd1,0x68,0xb9,0xd1 }, + { 0x00,0x00,0x00,0x00 }, { 0xed,0x2c,0xc1,0xed }, + { 0x20,0x60,0x40,0x20 }, { 0xfc,0x1f,0xe3,0xfc }, + { 0xb1,0xc8,0x79,0xb1 }, { 0x5b,0xed,0xb6,0x5b }, + { 0x6a,0xbe,0xd4,0x6a }, { 0xcb,0x46,0x8d,0xcb }, + { 0xbe,0xd9,0x67,0xbe }, { 0x39,0x4b,0x72,0x39 }, + { 0x4a,0xde,0x94,0x4a }, { 0x4c,0xd4,0x98,0x4c }, + { 0x58,0xe8,0xb0,0x58 }, { 0xcf,0x4a,0x85,0xcf }, + { 0xd0,0x6b,0xbb,0xd0 }, { 0xef,0x2a,0xc5,0xef }, + { 0xaa,0xe5,0x4f,0xaa }, { 0xfb,0x16,0xed,0xfb }, + { 0x43,0xc5,0x86,0x43 }, { 0x4d,0xd7,0x9a,0x4d }, + { 0x33,0x55,0x66,0x33 }, { 0x85,0x94,0x11,0x85 }, + { 0x45,0xcf,0x8a,0x45 }, { 0xf9,0x10,0xe9,0xf9 }, + { 0x02,0x06,0x04,0x02 }, { 0x7f,0x81,0xfe,0x7f }, + { 0x50,0xf0,0xa0,0x50 }, { 0x3c,0x44,0x78,0x3c }, + { 0x9f,0xba,0x25,0x9f }, { 0xa8,0xe3,0x4b,0xa8 }, + { 0x51,0xf3,0xa2,0x51 }, { 0xa3,0xfe,0x5d,0xa3 }, + { 0x40,0xc0,0x80,0x40 }, { 0x8f,0x8a,0x05,0x8f }, + { 0x92,0xad,0x3f,0x92 }, { 0x9d,0xbc,0x21,0x9d }, + { 0x38,0x48,0x70,0x38 }, { 0xf5,0x04,0xf1,0xf5 }, + { 0xbc,0xdf,0x63,0xbc }, { 0xb6,0xc1,0x77,0xb6 }, + { 0xda,0x75,0xaf,0xda }, { 0x21,0x63,0x42,0x21 }, + { 0x10,0x30,0x20,0x10 }, { 0xff,0x1a,0xe5,0xff }, + { 0xf3,0x0e,0xfd,0xf3 }, { 0xd2,0x6d,0xbf,0xd2 }, + { 0xcd,0x4c,0x81,0xcd }, { 0x0c,0x14,0x18,0x0c }, + { 0x13,0x35,0x26,0x13 }, { 0xec,0x2f,0xc3,0xec }, + { 0x5f,0xe1,0xbe,0x5f }, { 0x97,0xa2,0x35,0x97 }, + { 0x44,0xcc,0x88,0x44 }, { 0x17,0x39,0x2e,0x17 }, + { 0xc4,0x57,0x93,0xc4 }, { 0xa7,0xf2,0x55,0xa7 }, + { 0x7e,0x82,0xfc,0x7e }, { 0x3d,0x47,0x7a,0x3d }, + { 0x64,0xac,0xc8,0x64 }, { 0x5d,0xe7,0xba,0x5d }, + { 0x19,0x2b,0x32,0x19 }, { 0x73,0x95,0xe6,0x73 }, + { 0x60,0xa0,0xc0,0x60 }, { 0x81,0x98,0x19,0x81 }, + { 0x4f,0xd1,0x9e,0x4f }, { 0xdc,0x7f,0xa3,0xdc }, + { 0x22,0x66,0x44,0x22 }, { 0x2a,0x7e,0x54,0x2a }, + { 0x90,0xab,0x3b,0x90 }, { 0x88,0x83,0x0b,0x88 }, + { 0x46,0xca,0x8c,0x46 }, { 0xee,0x29,0xc7,0xee }, + { 0xb8,0xd3,0x6b,0xb8 }, { 0x14,0x3c,0x28,0x14 }, + { 0xde,0x79,0xa7,0xde }, { 0x5e,0xe2,0xbc,0x5e }, + { 0x0b,0x1d,0x16,0x0b }, { 0xdb,0x76,0xad,0xdb }, + { 0xe0,0x3b,0xdb,0xe0 }, { 0x32,0x56,0x64,0x32 }, + { 0x3a,0x4e,0x74,0x3a }, { 0x0a,0x1e,0x14,0x0a }, + { 0x49,0xdb,0x92,0x49 }, { 0x06,0x0a,0x0c,0x06 }, + { 0x24,0x6c,0x48,0x24 }, { 0x5c,0xe4,0xb8,0x5c }, + { 0xc2,0x5d,0x9f,0xc2 }, { 0xd3,0x6e,0xbd,0xd3 }, + { 0xac,0xef,0x43,0xac }, { 0x62,0xa6,0xc4,0x62 }, + { 0x91,0xa8,0x39,0x91 }, { 0x95,0xa4,0x31,0x95 }, + { 0xe4,0x37,0xd3,0xe4 }, { 0x79,0x8b,0xf2,0x79 }, + { 0xe7,0x32,0xd5,0xe7 }, { 0xc8,0x43,0x8b,0xc8 }, + { 0x37,0x59,0x6e,0x37 }, { 0x6d,0xb7,0xda,0x6d }, + { 0x8d,0x8c,0x01,0x8d }, { 0xd5,0x64,0xb1,0xd5 }, + { 0x4e,0xd2,0x9c,0x4e }, { 0xa9,0xe0,0x49,0xa9 }, + { 0x6c,0xb4,0xd8,0x6c }, { 0x56,0xfa,0xac,0x56 }, + { 0xf4,0x07,0xf3,0xf4 }, { 0xea,0x25,0xcf,0xea }, + { 0x65,0xaf,0xca,0x65 }, { 0x7a,0x8e,0xf4,0x7a }, + { 0xae,0xe9,0x47,0xae }, { 0x08,0x18,0x10,0x08 }, + { 0xba,0xd5,0x6f,0xba }, { 0x78,0x88,0xf0,0x78 }, + { 0x25,0x6f,0x4a,0x25 }, { 0x2e,0x72,0x5c,0x2e }, + { 0x1c,0x24,0x38,0x1c }, { 0xa6,0xf1,0x57,0xa6 }, + { 0xb4,0xc7,0x73,0xb4 }, { 0xc6,0x51,0x97,0xc6 }, + { 0xe8,0x23,0xcb,0xe8 }, { 0xdd,0x7c,0xa1,0xdd }, + { 0x74,0x9c,0xe8,0x74 }, { 0x1f,0x21,0x3e,0x1f }, + { 0x4b,0xdd,0x96,0x4b }, { 0xbd,0xdc,0x61,0xbd }, + { 0x8b,0x86,0x0d,0x8b }, { 0x8a,0x85,0x0f,0x8a }, + { 0x70,0x90,0xe0,0x70 }, { 0x3e,0x42,0x7c,0x3e }, + { 0xb5,0xc4,0x71,0xb5 }, { 0x66,0xaa,0xcc,0x66 }, + { 0x48,0xd8,0x90,0x48 }, { 0x03,0x05,0x06,0x03 }, + { 0xf6,0x01,0xf7,0xf6 }, { 0x0e,0x12,0x1c,0x0e }, + { 0x61,0xa3,0xc2,0x61 }, { 0x35,0x5f,0x6a,0x35 }, + { 0x57,0xf9,0xae,0x57 }, { 0xb9,0xd0,0x69,0xb9 }, + { 0x86,0x91,0x17,0x86 }, { 0xc1,0x58,0x99,0xc1 }, + { 0x1d,0x27,0x3a,0x1d }, { 0x9e,0xb9,0x27,0x9e }, + { 0xe1,0x38,0xd9,0xe1 }, { 0xf8,0x13,0xeb,0xf8 }, + { 0x98,0xb3,0x2b,0x98 }, { 0x11,0x33,0x22,0x11 }, + { 0x69,0xbb,0xd2,0x69 }, { 0xd9,0x70,0xa9,0xd9 }, + { 0x8e,0x89,0x07,0x8e }, { 0x94,0xa7,0x33,0x94 }, + { 0x9b,0xb6,0x2d,0x9b }, { 0x1e,0x22,0x3c,0x1e }, + { 0x87,0x92,0x15,0x87 }, { 0xe9,0x20,0xc9,0xe9 }, + { 0xce,0x49,0x87,0xce }, { 0x55,0xff,0xaa,0x55 }, + { 0x28,0x78,0x50,0x28 }, { 0xdf,0x7a,0xa5,0xdf }, + { 0x8c,0x8f,0x03,0x8c }, { 0xa1,0xf8,0x59,0xa1 }, + { 0x89,0x80,0x09,0x89 }, { 0x0d,0x17,0x1a,0x0d }, + { 0xbf,0xda,0x65,0xbf }, { 0xe6,0x31,0xd7,0xe6 }, + { 0x42,0xc6,0x84,0x42 }, { 0x68,0xb8,0xd0,0x68 }, + { 0x41,0xc3,0x82,0x41 }, { 0x99,0xb0,0x29,0x99 }, + { 0x2d,0x77,0x5a,0x2d }, { 0x0f,0x11,0x1e,0x0f }, + { 0xb0,0xcb,0x7b,0xb0 }, { 0x54,0xfc,0xa8,0x54 }, + { 0xbb,0xd6,0x6d,0xbb }, { 0x16,0x3a,0x2c,0x16 } +}; + +static const byte T4[256][4] = { + { 0x63,0x63,0xa5,0xc6 }, { 0x7c,0x7c,0x84,0xf8 }, + { 0x77,0x77,0x99,0xee }, { 0x7b,0x7b,0x8d,0xf6 }, + { 0xf2,0xf2,0x0d,0xff }, { 0x6b,0x6b,0xbd,0xd6 }, + { 0x6f,0x6f,0xb1,0xde }, { 0xc5,0xc5,0x54,0x91 }, + { 0x30,0x30,0x50,0x60 }, { 0x01,0x01,0x03,0x02 }, + { 0x67,0x67,0xa9,0xce }, { 0x2b,0x2b,0x7d,0x56 }, + { 0xfe,0xfe,0x19,0xe7 }, { 0xd7,0xd7,0x62,0xb5 }, + { 0xab,0xab,0xe6,0x4d }, { 0x76,0x76,0x9a,0xec }, + { 0xca,0xca,0x45,0x8f }, { 0x82,0x82,0x9d,0x1f }, + { 0xc9,0xc9,0x40,0x89 }, { 0x7d,0x7d,0x87,0xfa }, + { 0xfa,0xfa,0x15,0xef }, { 0x59,0x59,0xeb,0xb2 }, + { 0x47,0x47,0xc9,0x8e }, { 0xf0,0xf0,0x0b,0xfb }, + { 0xad,0xad,0xec,0x41 }, { 0xd4,0xd4,0x67,0xb3 }, + { 0xa2,0xa2,0xfd,0x5f }, { 0xaf,0xaf,0xea,0x45 }, + { 0x9c,0x9c,0xbf,0x23 }, { 0xa4,0xa4,0xf7,0x53 }, + { 0x72,0x72,0x96,0xe4 }, { 0xc0,0xc0,0x5b,0x9b }, + { 0xb7,0xb7,0xc2,0x75 }, { 0xfd,0xfd,0x1c,0xe1 }, + { 0x93,0x93,0xae,0x3d }, { 0x26,0x26,0x6a,0x4c }, + { 0x36,0x36,0x5a,0x6c }, { 0x3f,0x3f,0x41,0x7e }, + { 0xf7,0xf7,0x02,0xf5 }, { 0xcc,0xcc,0x4f,0x83 }, + { 0x34,0x34,0x5c,0x68 }, { 0xa5,0xa5,0xf4,0x51 }, + { 0xe5,0xe5,0x34,0xd1 }, { 0xf1,0xf1,0x08,0xf9 }, + { 0x71,0x71,0x93,0xe2 }, { 0xd8,0xd8,0x73,0xab }, + { 0x31,0x31,0x53,0x62 }, { 0x15,0x15,0x3f,0x2a }, + { 0x04,0x04,0x0c,0x08 }, { 0xc7,0xc7,0x52,0x95 }, + { 0x23,0x23,0x65,0x46 }, { 0xc3,0xc3,0x5e,0x9d }, + { 0x18,0x18,0x28,0x30 }, { 0x96,0x96,0xa1,0x37 }, + { 0x05,0x05,0x0f,0x0a }, { 0x9a,0x9a,0xb5,0x2f }, + { 0x07,0x07,0x09,0x0e }, { 0x12,0x12,0x36,0x24 }, + { 0x80,0x80,0x9b,0x1b }, { 0xe2,0xe2,0x3d,0xdf }, + { 0xeb,0xeb,0x26,0xcd }, { 0x27,0x27,0x69,0x4e }, + { 0xb2,0xb2,0xcd,0x7f }, { 0x75,0x75,0x9f,0xea }, + { 0x09,0x09,0x1b,0x12 }, { 0x83,0x83,0x9e,0x1d }, + { 0x2c,0x2c,0x74,0x58 }, { 0x1a,0x1a,0x2e,0x34 }, + { 0x1b,0x1b,0x2d,0x36 }, { 0x6e,0x6e,0xb2,0xdc }, + { 0x5a,0x5a,0xee,0xb4 }, { 0xa0,0xa0,0xfb,0x5b }, + { 0x52,0x52,0xf6,0xa4 }, { 0x3b,0x3b,0x4d,0x76 }, + { 0xd6,0xd6,0x61,0xb7 }, { 0xb3,0xb3,0xce,0x7d }, + { 0x29,0x29,0x7b,0x52 }, { 0xe3,0xe3,0x3e,0xdd }, + { 0x2f,0x2f,0x71,0x5e }, { 0x84,0x84,0x97,0x13 }, + { 0x53,0x53,0xf5,0xa6 }, { 0xd1,0xd1,0x68,0xb9 }, + { 0x00,0x00,0x00,0x00 }, { 0xed,0xed,0x2c,0xc1 }, + { 0x20,0x20,0x60,0x40 }, { 0xfc,0xfc,0x1f,0xe3 }, + { 0xb1,0xb1,0xc8,0x79 }, { 0x5b,0x5b,0xed,0xb6 }, + { 0x6a,0x6a,0xbe,0xd4 }, { 0xcb,0xcb,0x46,0x8d }, + { 0xbe,0xbe,0xd9,0x67 }, { 0x39,0x39,0x4b,0x72 }, + { 0x4a,0x4a,0xde,0x94 }, { 0x4c,0x4c,0xd4,0x98 }, + { 0x58,0x58,0xe8,0xb0 }, { 0xcf,0xcf,0x4a,0x85 }, + { 0xd0,0xd0,0x6b,0xbb }, { 0xef,0xef,0x2a,0xc5 }, + { 0xaa,0xaa,0xe5,0x4f }, { 0xfb,0xfb,0x16,0xed }, + { 0x43,0x43,0xc5,0x86 }, { 0x4d,0x4d,0xd7,0x9a }, + { 0x33,0x33,0x55,0x66 }, { 0x85,0x85,0x94,0x11 }, + { 0x45,0x45,0xcf,0x8a }, { 0xf9,0xf9,0x10,0xe9 }, + { 0x02,0x02,0x06,0x04 }, { 0x7f,0x7f,0x81,0xfe }, + { 0x50,0x50,0xf0,0xa0 }, { 0x3c,0x3c,0x44,0x78 }, + { 0x9f,0x9f,0xba,0x25 }, { 0xa8,0xa8,0xe3,0x4b }, + { 0x51,0x51,0xf3,0xa2 }, { 0xa3,0xa3,0xfe,0x5d }, + { 0x40,0x40,0xc0,0x80 }, { 0x8f,0x8f,0x8a,0x05 }, + { 0x92,0x92,0xad,0x3f }, { 0x9d,0x9d,0xbc,0x21 }, + { 0x38,0x38,0x48,0x70 }, { 0xf5,0xf5,0x04,0xf1 }, + { 0xbc,0xbc,0xdf,0x63 }, { 0xb6,0xb6,0xc1,0x77 }, + { 0xda,0xda,0x75,0xaf }, { 0x21,0x21,0x63,0x42 }, + { 0x10,0x10,0x30,0x20 }, { 0xff,0xff,0x1a,0xe5 }, + { 0xf3,0xf3,0x0e,0xfd }, { 0xd2,0xd2,0x6d,0xbf }, + { 0xcd,0xcd,0x4c,0x81 }, { 0x0c,0x0c,0x14,0x18 }, + { 0x13,0x13,0x35,0x26 }, { 0xec,0xec,0x2f,0xc3 }, + { 0x5f,0x5f,0xe1,0xbe }, { 0x97,0x97,0xa2,0x35 }, + { 0x44,0x44,0xcc,0x88 }, { 0x17,0x17,0x39,0x2e }, + { 0xc4,0xc4,0x57,0x93 }, { 0xa7,0xa7,0xf2,0x55 }, + { 0x7e,0x7e,0x82,0xfc }, { 0x3d,0x3d,0x47,0x7a }, + { 0x64,0x64,0xac,0xc8 }, { 0x5d,0x5d,0xe7,0xba }, + { 0x19,0x19,0x2b,0x32 }, { 0x73,0x73,0x95,0xe6 }, + { 0x60,0x60,0xa0,0xc0 }, { 0x81,0x81,0x98,0x19 }, + { 0x4f,0x4f,0xd1,0x9e }, { 0xdc,0xdc,0x7f,0xa3 }, + { 0x22,0x22,0x66,0x44 }, { 0x2a,0x2a,0x7e,0x54 }, + { 0x90,0x90,0xab,0x3b }, { 0x88,0x88,0x83,0x0b }, + { 0x46,0x46,0xca,0x8c }, { 0xee,0xee,0x29,0xc7 }, + { 0xb8,0xb8,0xd3,0x6b }, { 0x14,0x14,0x3c,0x28 }, + { 0xde,0xde,0x79,0xa7 }, { 0x5e,0x5e,0xe2,0xbc }, + { 0x0b,0x0b,0x1d,0x16 }, { 0xdb,0xdb,0x76,0xad }, + { 0xe0,0xe0,0x3b,0xdb }, { 0x32,0x32,0x56,0x64 }, + { 0x3a,0x3a,0x4e,0x74 }, { 0x0a,0x0a,0x1e,0x14 }, + { 0x49,0x49,0xdb,0x92 }, { 0x06,0x06,0x0a,0x0c }, + { 0x24,0x24,0x6c,0x48 }, { 0x5c,0x5c,0xe4,0xb8 }, + { 0xc2,0xc2,0x5d,0x9f }, { 0xd3,0xd3,0x6e,0xbd }, + { 0xac,0xac,0xef,0x43 }, { 0x62,0x62,0xa6,0xc4 }, + { 0x91,0x91,0xa8,0x39 }, { 0x95,0x95,0xa4,0x31 }, + { 0xe4,0xe4,0x37,0xd3 }, { 0x79,0x79,0x8b,0xf2 }, + { 0xe7,0xe7,0x32,0xd5 }, { 0xc8,0xc8,0x43,0x8b }, + { 0x37,0x37,0x59,0x6e }, { 0x6d,0x6d,0xb7,0xda }, + { 0x8d,0x8d,0x8c,0x01 }, { 0xd5,0xd5,0x64,0xb1 }, + { 0x4e,0x4e,0xd2,0x9c }, { 0xa9,0xa9,0xe0,0x49 }, + { 0x6c,0x6c,0xb4,0xd8 }, { 0x56,0x56,0xfa,0xac }, + { 0xf4,0xf4,0x07,0xf3 }, { 0xea,0xea,0x25,0xcf }, + { 0x65,0x65,0xaf,0xca }, { 0x7a,0x7a,0x8e,0xf4 }, + { 0xae,0xae,0xe9,0x47 }, { 0x08,0x08,0x18,0x10 }, + { 0xba,0xba,0xd5,0x6f }, { 0x78,0x78,0x88,0xf0 }, + { 0x25,0x25,0x6f,0x4a }, { 0x2e,0x2e,0x72,0x5c }, + { 0x1c,0x1c,0x24,0x38 }, { 0xa6,0xa6,0xf1,0x57 }, + { 0xb4,0xb4,0xc7,0x73 }, { 0xc6,0xc6,0x51,0x97 }, + { 0xe8,0xe8,0x23,0xcb }, { 0xdd,0xdd,0x7c,0xa1 }, + { 0x74,0x74,0x9c,0xe8 }, { 0x1f,0x1f,0x21,0x3e }, + { 0x4b,0x4b,0xdd,0x96 }, { 0xbd,0xbd,0xdc,0x61 }, + { 0x8b,0x8b,0x86,0x0d }, { 0x8a,0x8a,0x85,0x0f }, + { 0x70,0x70,0x90,0xe0 }, { 0x3e,0x3e,0x42,0x7c }, + { 0xb5,0xb5,0xc4,0x71 }, { 0x66,0x66,0xaa,0xcc }, + { 0x48,0x48,0xd8,0x90 }, { 0x03,0x03,0x05,0x06 }, + { 0xf6,0xf6,0x01,0xf7 }, { 0x0e,0x0e,0x12,0x1c }, + { 0x61,0x61,0xa3,0xc2 }, { 0x35,0x35,0x5f,0x6a }, + { 0x57,0x57,0xf9,0xae }, { 0xb9,0xb9,0xd0,0x69 }, + { 0x86,0x86,0x91,0x17 }, { 0xc1,0xc1,0x58,0x99 }, + { 0x1d,0x1d,0x27,0x3a }, { 0x9e,0x9e,0xb9,0x27 }, + { 0xe1,0xe1,0x38,0xd9 }, { 0xf8,0xf8,0x13,0xeb }, + { 0x98,0x98,0xb3,0x2b }, { 0x11,0x11,0x33,0x22 }, + { 0x69,0x69,0xbb,0xd2 }, { 0xd9,0xd9,0x70,0xa9 }, + { 0x8e,0x8e,0x89,0x07 }, { 0x94,0x94,0xa7,0x33 }, + { 0x9b,0x9b,0xb6,0x2d }, { 0x1e,0x1e,0x22,0x3c }, + { 0x87,0x87,0x92,0x15 }, { 0xe9,0xe9,0x20,0xc9 }, + { 0xce,0xce,0x49,0x87 }, { 0x55,0x55,0xff,0xaa }, + { 0x28,0x28,0x78,0x50 }, { 0xdf,0xdf,0x7a,0xa5 }, + { 0x8c,0x8c,0x8f,0x03 }, { 0xa1,0xa1,0xf8,0x59 }, + { 0x89,0x89,0x80,0x09 }, { 0x0d,0x0d,0x17,0x1a }, + { 0xbf,0xbf,0xda,0x65 }, { 0xe6,0xe6,0x31,0xd7 }, + { 0x42,0x42,0xc6,0x84 }, { 0x68,0x68,0xb8,0xd0 }, + { 0x41,0x41,0xc3,0x82 }, { 0x99,0x99,0xb0,0x29 }, + { 0x2d,0x2d,0x77,0x5a }, { 0x0f,0x0f,0x11,0x1e }, + { 0xb0,0xb0,0xcb,0x7b }, { 0x54,0x54,0xfc,0xa8 }, + { 0xbb,0xbb,0xd6,0x6d }, { 0x16,0x16,0x3a,0x2c } +}; + +static const byte T5[256][4] = { + { 0x51,0xf4,0xa7,0x50 }, { 0x7e,0x41,0x65,0x53 }, + { 0x1a,0x17,0xa4,0xc3 }, { 0x3a,0x27,0x5e,0x96 }, + { 0x3b,0xab,0x6b,0xcb }, { 0x1f,0x9d,0x45,0xf1 }, + { 0xac,0xfa,0x58,0xab }, { 0x4b,0xe3,0x03,0x93 }, + { 0x20,0x30,0xfa,0x55 }, { 0xad,0x76,0x6d,0xf6 }, + { 0x88,0xcc,0x76,0x91 }, { 0xf5,0x02,0x4c,0x25 }, + { 0x4f,0xe5,0xd7,0xfc }, { 0xc5,0x2a,0xcb,0xd7 }, + { 0x26,0x35,0x44,0x80 }, { 0xb5,0x62,0xa3,0x8f }, + { 0xde,0xb1,0x5a,0x49 }, { 0x25,0xba,0x1b,0x67 }, + { 0x45,0xea,0x0e,0x98 }, { 0x5d,0xfe,0xc0,0xe1 }, + { 0xc3,0x2f,0x75,0x02 }, { 0x81,0x4c,0xf0,0x12 }, + { 0x8d,0x46,0x97,0xa3 }, { 0x6b,0xd3,0xf9,0xc6 }, + { 0x03,0x8f,0x5f,0xe7 }, { 0x15,0x92,0x9c,0x95 }, + { 0xbf,0x6d,0x7a,0xeb }, { 0x95,0x52,0x59,0xda }, + { 0xd4,0xbe,0x83,0x2d }, { 0x58,0x74,0x21,0xd3 }, + { 0x49,0xe0,0x69,0x29 }, { 0x8e,0xc9,0xc8,0x44 }, + { 0x75,0xc2,0x89,0x6a }, { 0xf4,0x8e,0x79,0x78 }, + { 0x99,0x58,0x3e,0x6b }, { 0x27,0xb9,0x71,0xdd }, + { 0xbe,0xe1,0x4f,0xb6 }, { 0xf0,0x88,0xad,0x17 }, + { 0xc9,0x20,0xac,0x66 }, { 0x7d,0xce,0x3a,0xb4 }, + { 0x63,0xdf,0x4a,0x18 }, { 0xe5,0x1a,0x31,0x82 }, + { 0x97,0x51,0x33,0x60 }, { 0x62,0x53,0x7f,0x45 }, + { 0xb1,0x64,0x77,0xe0 }, { 0xbb,0x6b,0xae,0x84 }, + { 0xfe,0x81,0xa0,0x1c }, { 0xf9,0x08,0x2b,0x94 }, + { 0x70,0x48,0x68,0x58 }, { 0x8f,0x45,0xfd,0x19 }, + { 0x94,0xde,0x6c,0x87 }, { 0x52,0x7b,0xf8,0xb7 }, + { 0xab,0x73,0xd3,0x23 }, { 0x72,0x4b,0x02,0xe2 }, + { 0xe3,0x1f,0x8f,0x57 }, { 0x66,0x55,0xab,0x2a }, + { 0xb2,0xeb,0x28,0x07 }, { 0x2f,0xb5,0xc2,0x03 }, + { 0x86,0xc5,0x7b,0x9a }, { 0xd3,0x37,0x08,0xa5 }, + { 0x30,0x28,0x87,0xf2 }, { 0x23,0xbf,0xa5,0xb2 }, + { 0x02,0x03,0x6a,0xba }, { 0xed,0x16,0x82,0x5c }, + { 0x8a,0xcf,0x1c,0x2b }, { 0xa7,0x79,0xb4,0x92 }, + { 0xf3,0x07,0xf2,0xf0 }, { 0x4e,0x69,0xe2,0xa1 }, + { 0x65,0xda,0xf4,0xcd }, { 0x06,0x05,0xbe,0xd5 }, + { 0xd1,0x34,0x62,0x1f }, { 0xc4,0xa6,0xfe,0x8a }, + { 0x34,0x2e,0x53,0x9d }, { 0xa2,0xf3,0x55,0xa0 }, + { 0x05,0x8a,0xe1,0x32 }, { 0xa4,0xf6,0xeb,0x75 }, + { 0x0b,0x83,0xec,0x39 }, { 0x40,0x60,0xef,0xaa }, + { 0x5e,0x71,0x9f,0x06 }, { 0xbd,0x6e,0x10,0x51 }, + { 0x3e,0x21,0x8a,0xf9 }, { 0x96,0xdd,0x06,0x3d }, + { 0xdd,0x3e,0x05,0xae }, { 0x4d,0xe6,0xbd,0x46 }, + { 0x91,0x54,0x8d,0xb5 }, { 0x71,0xc4,0x5d,0x05 }, + { 0x04,0x06,0xd4,0x6f }, { 0x60,0x50,0x15,0xff }, + { 0x19,0x98,0xfb,0x24 }, { 0xd6,0xbd,0xe9,0x97 }, + { 0x89,0x40,0x43,0xcc }, { 0x67,0xd9,0x9e,0x77 }, + { 0xb0,0xe8,0x42,0xbd }, { 0x07,0x89,0x8b,0x88 }, + { 0xe7,0x19,0x5b,0x38 }, { 0x79,0xc8,0xee,0xdb }, + { 0xa1,0x7c,0x0a,0x47 }, { 0x7c,0x42,0x0f,0xe9 }, + { 0xf8,0x84,0x1e,0xc9 }, { 0x00,0x00,0x00,0x00 }, + { 0x09,0x80,0x86,0x83 }, { 0x32,0x2b,0xed,0x48 }, + { 0x1e,0x11,0x70,0xac }, { 0x6c,0x5a,0x72,0x4e }, + { 0xfd,0x0e,0xff,0xfb }, { 0x0f,0x85,0x38,0x56 }, + { 0x3d,0xae,0xd5,0x1e }, { 0x36,0x2d,0x39,0x27 }, + { 0x0a,0x0f,0xd9,0x64 }, { 0x68,0x5c,0xa6,0x21 }, + { 0x9b,0x5b,0x54,0xd1 }, { 0x24,0x36,0x2e,0x3a }, + { 0x0c,0x0a,0x67,0xb1 }, { 0x93,0x57,0xe7,0x0f }, + { 0xb4,0xee,0x96,0xd2 }, { 0x1b,0x9b,0x91,0x9e }, + { 0x80,0xc0,0xc5,0x4f }, { 0x61,0xdc,0x20,0xa2 }, + { 0x5a,0x77,0x4b,0x69 }, { 0x1c,0x12,0x1a,0x16 }, + { 0xe2,0x93,0xba,0x0a }, { 0xc0,0xa0,0x2a,0xe5 }, + { 0x3c,0x22,0xe0,0x43 }, { 0x12,0x1b,0x17,0x1d }, + { 0x0e,0x09,0x0d,0x0b }, { 0xf2,0x8b,0xc7,0xad }, + { 0x2d,0xb6,0xa8,0xb9 }, { 0x14,0x1e,0xa9,0xc8 }, + { 0x57,0xf1,0x19,0x85 }, { 0xaf,0x75,0x07,0x4c }, + { 0xee,0x99,0xdd,0xbb }, { 0xa3,0x7f,0x60,0xfd }, + { 0xf7,0x01,0x26,0x9f }, { 0x5c,0x72,0xf5,0xbc }, + { 0x44,0x66,0x3b,0xc5 }, { 0x5b,0xfb,0x7e,0x34 }, + { 0x8b,0x43,0x29,0x76 }, { 0xcb,0x23,0xc6,0xdc }, + { 0xb6,0xed,0xfc,0x68 }, { 0xb8,0xe4,0xf1,0x63 }, + { 0xd7,0x31,0xdc,0xca }, { 0x42,0x63,0x85,0x10 }, + { 0x13,0x97,0x22,0x40 }, { 0x84,0xc6,0x11,0x20 }, + { 0x85,0x4a,0x24,0x7d }, { 0xd2,0xbb,0x3d,0xf8 }, + { 0xae,0xf9,0x32,0x11 }, { 0xc7,0x29,0xa1,0x6d }, + { 0x1d,0x9e,0x2f,0x4b }, { 0xdc,0xb2,0x30,0xf3 }, + { 0x0d,0x86,0x52,0xec }, { 0x77,0xc1,0xe3,0xd0 }, + { 0x2b,0xb3,0x16,0x6c }, { 0xa9,0x70,0xb9,0x99 }, + { 0x11,0x94,0x48,0xfa }, { 0x47,0xe9,0x64,0x22 }, + { 0xa8,0xfc,0x8c,0xc4 }, { 0xa0,0xf0,0x3f,0x1a }, + { 0x56,0x7d,0x2c,0xd8 }, { 0x22,0x33,0x90,0xef }, + { 0x87,0x49,0x4e,0xc7 }, { 0xd9,0x38,0xd1,0xc1 }, + { 0x8c,0xca,0xa2,0xfe }, { 0x98,0xd4,0x0b,0x36 }, + { 0xa6,0xf5,0x81,0xcf }, { 0xa5,0x7a,0xde,0x28 }, + { 0xda,0xb7,0x8e,0x26 }, { 0x3f,0xad,0xbf,0xa4 }, + { 0x2c,0x3a,0x9d,0xe4 }, { 0x50,0x78,0x92,0x0d }, + { 0x6a,0x5f,0xcc,0x9b }, { 0x54,0x7e,0x46,0x62 }, + { 0xf6,0x8d,0x13,0xc2 }, { 0x90,0xd8,0xb8,0xe8 }, + { 0x2e,0x39,0xf7,0x5e }, { 0x82,0xc3,0xaf,0xf5 }, + { 0x9f,0x5d,0x80,0xbe }, { 0x69,0xd0,0x93,0x7c }, + { 0x6f,0xd5,0x2d,0xa9 }, { 0xcf,0x25,0x12,0xb3 }, + { 0xc8,0xac,0x99,0x3b }, { 0x10,0x18,0x7d,0xa7 }, + { 0xe8,0x9c,0x63,0x6e }, { 0xdb,0x3b,0xbb,0x7b }, + { 0xcd,0x26,0x78,0x09 }, { 0x6e,0x59,0x18,0xf4 }, + { 0xec,0x9a,0xb7,0x01 }, { 0x83,0x4f,0x9a,0xa8 }, + { 0xe6,0x95,0x6e,0x65 }, { 0xaa,0xff,0xe6,0x7e }, + { 0x21,0xbc,0xcf,0x08 }, { 0xef,0x15,0xe8,0xe6 }, + { 0xba,0xe7,0x9b,0xd9 }, { 0x4a,0x6f,0x36,0xce }, + { 0xea,0x9f,0x09,0xd4 }, { 0x29,0xb0,0x7c,0xd6 }, + { 0x31,0xa4,0xb2,0xaf }, { 0x2a,0x3f,0x23,0x31 }, + { 0xc6,0xa5,0x94,0x30 }, { 0x35,0xa2,0x66,0xc0 }, + { 0x74,0x4e,0xbc,0x37 }, { 0xfc,0x82,0xca,0xa6 }, + { 0xe0,0x90,0xd0,0xb0 }, { 0x33,0xa7,0xd8,0x15 }, + { 0xf1,0x04,0x98,0x4a }, { 0x41,0xec,0xda,0xf7 }, + { 0x7f,0xcd,0x50,0x0e }, { 0x17,0x91,0xf6,0x2f }, + { 0x76,0x4d,0xd6,0x8d }, { 0x43,0xef,0xb0,0x4d }, + { 0xcc,0xaa,0x4d,0x54 }, { 0xe4,0x96,0x04,0xdf }, + { 0x9e,0xd1,0xb5,0xe3 }, { 0x4c,0x6a,0x88,0x1b }, + { 0xc1,0x2c,0x1f,0xb8 }, { 0x46,0x65,0x51,0x7f }, + { 0x9d,0x5e,0xea,0x04 }, { 0x01,0x8c,0x35,0x5d }, + { 0xfa,0x87,0x74,0x73 }, { 0xfb,0x0b,0x41,0x2e }, + { 0xb3,0x67,0x1d,0x5a }, { 0x92,0xdb,0xd2,0x52 }, + { 0xe9,0x10,0x56,0x33 }, { 0x6d,0xd6,0x47,0x13 }, + { 0x9a,0xd7,0x61,0x8c }, { 0x37,0xa1,0x0c,0x7a }, + { 0x59,0xf8,0x14,0x8e }, { 0xeb,0x13,0x3c,0x89 }, + { 0xce,0xa9,0x27,0xee }, { 0xb7,0x61,0xc9,0x35 }, + { 0xe1,0x1c,0xe5,0xed }, { 0x7a,0x47,0xb1,0x3c }, + { 0x9c,0xd2,0xdf,0x59 }, { 0x55,0xf2,0x73,0x3f }, + { 0x18,0x14,0xce,0x79 }, { 0x73,0xc7,0x37,0xbf }, + { 0x53,0xf7,0xcd,0xea }, { 0x5f,0xfd,0xaa,0x5b }, + { 0xdf,0x3d,0x6f,0x14 }, { 0x78,0x44,0xdb,0x86 }, + { 0xca,0xaf,0xf3,0x81 }, { 0xb9,0x68,0xc4,0x3e }, + { 0x38,0x24,0x34,0x2c }, { 0xc2,0xa3,0x40,0x5f }, + { 0x16,0x1d,0xc3,0x72 }, { 0xbc,0xe2,0x25,0x0c }, + { 0x28,0x3c,0x49,0x8b }, { 0xff,0x0d,0x95,0x41 }, + { 0x39,0xa8,0x01,0x71 }, { 0x08,0x0c,0xb3,0xde }, + { 0xd8,0xb4,0xe4,0x9c }, { 0x64,0x56,0xc1,0x90 }, + { 0x7b,0xcb,0x84,0x61 }, { 0xd5,0x32,0xb6,0x70 }, + { 0x48,0x6c,0x5c,0x74 }, { 0xd0,0xb8,0x57,0x42 } +}; + +static const byte T6[256][4] = { + { 0x50,0x51,0xf4,0xa7 }, { 0x53,0x7e,0x41,0x65 }, + { 0xc3,0x1a,0x17,0xa4 }, { 0x96,0x3a,0x27,0x5e }, + { 0xcb,0x3b,0xab,0x6b }, { 0xf1,0x1f,0x9d,0x45 }, + { 0xab,0xac,0xfa,0x58 }, { 0x93,0x4b,0xe3,0x03 }, + { 0x55,0x20,0x30,0xfa }, { 0xf6,0xad,0x76,0x6d }, + { 0x91,0x88,0xcc,0x76 }, { 0x25,0xf5,0x02,0x4c }, + { 0xfc,0x4f,0xe5,0xd7 }, { 0xd7,0xc5,0x2a,0xcb }, + { 0x80,0x26,0x35,0x44 }, { 0x8f,0xb5,0x62,0xa3 }, + { 0x49,0xde,0xb1,0x5a }, { 0x67,0x25,0xba,0x1b }, + { 0x98,0x45,0xea,0x0e }, { 0xe1,0x5d,0xfe,0xc0 }, + { 0x02,0xc3,0x2f,0x75 }, { 0x12,0x81,0x4c,0xf0 }, + { 0xa3,0x8d,0x46,0x97 }, { 0xc6,0x6b,0xd3,0xf9 }, + { 0xe7,0x03,0x8f,0x5f }, { 0x95,0x15,0x92,0x9c }, + { 0xeb,0xbf,0x6d,0x7a }, { 0xda,0x95,0x52,0x59 }, + { 0x2d,0xd4,0xbe,0x83 }, { 0xd3,0x58,0x74,0x21 }, + { 0x29,0x49,0xe0,0x69 }, { 0x44,0x8e,0xc9,0xc8 }, + { 0x6a,0x75,0xc2,0x89 }, { 0x78,0xf4,0x8e,0x79 }, + { 0x6b,0x99,0x58,0x3e }, { 0xdd,0x27,0xb9,0x71 }, + { 0xb6,0xbe,0xe1,0x4f }, { 0x17,0xf0,0x88,0xad }, + { 0x66,0xc9,0x20,0xac }, { 0xb4,0x7d,0xce,0x3a }, + { 0x18,0x63,0xdf,0x4a }, { 0x82,0xe5,0x1a,0x31 }, + { 0x60,0x97,0x51,0x33 }, { 0x45,0x62,0x53,0x7f }, + { 0xe0,0xb1,0x64,0x77 }, { 0x84,0xbb,0x6b,0xae }, + { 0x1c,0xfe,0x81,0xa0 }, { 0x94,0xf9,0x08,0x2b }, + { 0x58,0x70,0x48,0x68 }, { 0x19,0x8f,0x45,0xfd }, + { 0x87,0x94,0xde,0x6c }, { 0xb7,0x52,0x7b,0xf8 }, + { 0x23,0xab,0x73,0xd3 }, { 0xe2,0x72,0x4b,0x02 }, + { 0x57,0xe3,0x1f,0x8f }, { 0x2a,0x66,0x55,0xab }, + { 0x07,0xb2,0xeb,0x28 }, { 0x03,0x2f,0xb5,0xc2 }, + { 0x9a,0x86,0xc5,0x7b }, { 0xa5,0xd3,0x37,0x08 }, + { 0xf2,0x30,0x28,0x87 }, { 0xb2,0x23,0xbf,0xa5 }, + { 0xba,0x02,0x03,0x6a }, { 0x5c,0xed,0x16,0x82 }, + { 0x2b,0x8a,0xcf,0x1c }, { 0x92,0xa7,0x79,0xb4 }, + { 0xf0,0xf3,0x07,0xf2 }, { 0xa1,0x4e,0x69,0xe2 }, + { 0xcd,0x65,0xda,0xf4 }, { 0xd5,0x06,0x05,0xbe }, + { 0x1f,0xd1,0x34,0x62 }, { 0x8a,0xc4,0xa6,0xfe }, + { 0x9d,0x34,0x2e,0x53 }, { 0xa0,0xa2,0xf3,0x55 }, + { 0x32,0x05,0x8a,0xe1 }, { 0x75,0xa4,0xf6,0xeb }, + { 0x39,0x0b,0x83,0xec }, { 0xaa,0x40,0x60,0xef }, + { 0x06,0x5e,0x71,0x9f }, { 0x51,0xbd,0x6e,0x10 }, + { 0xf9,0x3e,0x21,0x8a }, { 0x3d,0x96,0xdd,0x06 }, + { 0xae,0xdd,0x3e,0x05 }, { 0x46,0x4d,0xe6,0xbd }, + { 0xb5,0x91,0x54,0x8d }, { 0x05,0x71,0xc4,0x5d }, + { 0x6f,0x04,0x06,0xd4 }, { 0xff,0x60,0x50,0x15 }, + { 0x24,0x19,0x98,0xfb }, { 0x97,0xd6,0xbd,0xe9 }, + { 0xcc,0x89,0x40,0x43 }, { 0x77,0x67,0xd9,0x9e }, + { 0xbd,0xb0,0xe8,0x42 }, { 0x88,0x07,0x89,0x8b }, + { 0x38,0xe7,0x19,0x5b }, { 0xdb,0x79,0xc8,0xee }, + { 0x47,0xa1,0x7c,0x0a }, { 0xe9,0x7c,0x42,0x0f }, + { 0xc9,0xf8,0x84,0x1e }, { 0x00,0x00,0x00,0x00 }, + { 0x83,0x09,0x80,0x86 }, { 0x48,0x32,0x2b,0xed }, + { 0xac,0x1e,0x11,0x70 }, { 0x4e,0x6c,0x5a,0x72 }, + { 0xfb,0xfd,0x0e,0xff }, { 0x56,0x0f,0x85,0x38 }, + { 0x1e,0x3d,0xae,0xd5 }, { 0x27,0x36,0x2d,0x39 }, + { 0x64,0x0a,0x0f,0xd9 }, { 0x21,0x68,0x5c,0xa6 }, + { 0xd1,0x9b,0x5b,0x54 }, { 0x3a,0x24,0x36,0x2e }, + { 0xb1,0x0c,0x0a,0x67 }, { 0x0f,0x93,0x57,0xe7 }, + { 0xd2,0xb4,0xee,0x96 }, { 0x9e,0x1b,0x9b,0x91 }, + { 0x4f,0x80,0xc0,0xc5 }, { 0xa2,0x61,0xdc,0x20 }, + { 0x69,0x5a,0x77,0x4b }, { 0x16,0x1c,0x12,0x1a }, + { 0x0a,0xe2,0x93,0xba }, { 0xe5,0xc0,0xa0,0x2a }, + { 0x43,0x3c,0x22,0xe0 }, { 0x1d,0x12,0x1b,0x17 }, + { 0x0b,0x0e,0x09,0x0d }, { 0xad,0xf2,0x8b,0xc7 }, + { 0xb9,0x2d,0xb6,0xa8 }, { 0xc8,0x14,0x1e,0xa9 }, + { 0x85,0x57,0xf1,0x19 }, { 0x4c,0xaf,0x75,0x07 }, + { 0xbb,0xee,0x99,0xdd }, { 0xfd,0xa3,0x7f,0x60 }, + { 0x9f,0xf7,0x01,0x26 }, { 0xbc,0x5c,0x72,0xf5 }, + { 0xc5,0x44,0x66,0x3b }, { 0x34,0x5b,0xfb,0x7e }, + { 0x76,0x8b,0x43,0x29 }, { 0xdc,0xcb,0x23,0xc6 }, + { 0x68,0xb6,0xed,0xfc }, { 0x63,0xb8,0xe4,0xf1 }, + { 0xca,0xd7,0x31,0xdc }, { 0x10,0x42,0x63,0x85 }, + { 0x40,0x13,0x97,0x22 }, { 0x20,0x84,0xc6,0x11 }, + { 0x7d,0x85,0x4a,0x24 }, { 0xf8,0xd2,0xbb,0x3d }, + { 0x11,0xae,0xf9,0x32 }, { 0x6d,0xc7,0x29,0xa1 }, + { 0x4b,0x1d,0x9e,0x2f }, { 0xf3,0xdc,0xb2,0x30 }, + { 0xec,0x0d,0x86,0x52 }, { 0xd0,0x77,0xc1,0xe3 }, + { 0x6c,0x2b,0xb3,0x16 }, { 0x99,0xa9,0x70,0xb9 }, + { 0xfa,0x11,0x94,0x48 }, { 0x22,0x47,0xe9,0x64 }, + { 0xc4,0xa8,0xfc,0x8c }, { 0x1a,0xa0,0xf0,0x3f }, + { 0xd8,0x56,0x7d,0x2c }, { 0xef,0x22,0x33,0x90 }, + { 0xc7,0x87,0x49,0x4e }, { 0xc1,0xd9,0x38,0xd1 }, + { 0xfe,0x8c,0xca,0xa2 }, { 0x36,0x98,0xd4,0x0b }, + { 0xcf,0xa6,0xf5,0x81 }, { 0x28,0xa5,0x7a,0xde }, + { 0x26,0xda,0xb7,0x8e }, { 0xa4,0x3f,0xad,0xbf }, + { 0xe4,0x2c,0x3a,0x9d }, { 0x0d,0x50,0x78,0x92 }, + { 0x9b,0x6a,0x5f,0xcc }, { 0x62,0x54,0x7e,0x46 }, + { 0xc2,0xf6,0x8d,0x13 }, { 0xe8,0x90,0xd8,0xb8 }, + { 0x5e,0x2e,0x39,0xf7 }, { 0xf5,0x82,0xc3,0xaf }, + { 0xbe,0x9f,0x5d,0x80 }, { 0x7c,0x69,0xd0,0x93 }, + { 0xa9,0x6f,0xd5,0x2d }, { 0xb3,0xcf,0x25,0x12 }, + { 0x3b,0xc8,0xac,0x99 }, { 0xa7,0x10,0x18,0x7d }, + { 0x6e,0xe8,0x9c,0x63 }, { 0x7b,0xdb,0x3b,0xbb }, + { 0x09,0xcd,0x26,0x78 }, { 0xf4,0x6e,0x59,0x18 }, + { 0x01,0xec,0x9a,0xb7 }, { 0xa8,0x83,0x4f,0x9a }, + { 0x65,0xe6,0x95,0x6e }, { 0x7e,0xaa,0xff,0xe6 }, + { 0x08,0x21,0xbc,0xcf }, { 0xe6,0xef,0x15,0xe8 }, + { 0xd9,0xba,0xe7,0x9b }, { 0xce,0x4a,0x6f,0x36 }, + { 0xd4,0xea,0x9f,0x09 }, { 0xd6,0x29,0xb0,0x7c }, + { 0xaf,0x31,0xa4,0xb2 }, { 0x31,0x2a,0x3f,0x23 }, + { 0x30,0xc6,0xa5,0x94 }, { 0xc0,0x35,0xa2,0x66 }, + { 0x37,0x74,0x4e,0xbc }, { 0xa6,0xfc,0x82,0xca }, + { 0xb0,0xe0,0x90,0xd0 }, { 0x15,0x33,0xa7,0xd8 }, + { 0x4a,0xf1,0x04,0x98 }, { 0xf7,0x41,0xec,0xda }, + { 0x0e,0x7f,0xcd,0x50 }, { 0x2f,0x17,0x91,0xf6 }, + { 0x8d,0x76,0x4d,0xd6 }, { 0x4d,0x43,0xef,0xb0 }, + { 0x54,0xcc,0xaa,0x4d }, { 0xdf,0xe4,0x96,0x04 }, + { 0xe3,0x9e,0xd1,0xb5 }, { 0x1b,0x4c,0x6a,0x88 }, + { 0xb8,0xc1,0x2c,0x1f }, { 0x7f,0x46,0x65,0x51 }, + { 0x04,0x9d,0x5e,0xea }, { 0x5d,0x01,0x8c,0x35 }, + { 0x73,0xfa,0x87,0x74 }, { 0x2e,0xfb,0x0b,0x41 }, + { 0x5a,0xb3,0x67,0x1d }, { 0x52,0x92,0xdb,0xd2 }, + { 0x33,0xe9,0x10,0x56 }, { 0x13,0x6d,0xd6,0x47 }, + { 0x8c,0x9a,0xd7,0x61 }, { 0x7a,0x37,0xa1,0x0c }, + { 0x8e,0x59,0xf8,0x14 }, { 0x89,0xeb,0x13,0x3c }, + { 0xee,0xce,0xa9,0x27 }, { 0x35,0xb7,0x61,0xc9 }, + { 0xed,0xe1,0x1c,0xe5 }, { 0x3c,0x7a,0x47,0xb1 }, + { 0x59,0x9c,0xd2,0xdf }, { 0x3f,0x55,0xf2,0x73 }, + { 0x79,0x18,0x14,0xce }, { 0xbf,0x73,0xc7,0x37 }, + { 0xea,0x53,0xf7,0xcd }, { 0x5b,0x5f,0xfd,0xaa }, + { 0x14,0xdf,0x3d,0x6f }, { 0x86,0x78,0x44,0xdb }, + { 0x81,0xca,0xaf,0xf3 }, { 0x3e,0xb9,0x68,0xc4 }, + { 0x2c,0x38,0x24,0x34 }, { 0x5f,0xc2,0xa3,0x40 }, + { 0x72,0x16,0x1d,0xc3 }, { 0x0c,0xbc,0xe2,0x25 }, + { 0x8b,0x28,0x3c,0x49 }, { 0x41,0xff,0x0d,0x95 }, + { 0x71,0x39,0xa8,0x01 }, { 0xde,0x08,0x0c,0xb3 }, + { 0x9c,0xd8,0xb4,0xe4 }, { 0x90,0x64,0x56,0xc1 }, + { 0x61,0x7b,0xcb,0x84 }, { 0x70,0xd5,0x32,0xb6 }, + { 0x74,0x48,0x6c,0x5c }, { 0x42,0xd0,0xb8,0x57 } +}; + +static const byte T7[256][4] = { + { 0xa7,0x50,0x51,0xf4 }, { 0x65,0x53,0x7e,0x41 }, + { 0xa4,0xc3,0x1a,0x17 }, { 0x5e,0x96,0x3a,0x27 }, + { 0x6b,0xcb,0x3b,0xab }, { 0x45,0xf1,0x1f,0x9d }, + { 0x58,0xab,0xac,0xfa }, { 0x03,0x93,0x4b,0xe3 }, + { 0xfa,0x55,0x20,0x30 }, { 0x6d,0xf6,0xad,0x76 }, + { 0x76,0x91,0x88,0xcc }, { 0x4c,0x25,0xf5,0x02 }, + { 0xd7,0xfc,0x4f,0xe5 }, { 0xcb,0xd7,0xc5,0x2a }, + { 0x44,0x80,0x26,0x35 }, { 0xa3,0x8f,0xb5,0x62 }, + { 0x5a,0x49,0xde,0xb1 }, { 0x1b,0x67,0x25,0xba }, + { 0x0e,0x98,0x45,0xea }, { 0xc0,0xe1,0x5d,0xfe }, + { 0x75,0x02,0xc3,0x2f }, { 0xf0,0x12,0x81,0x4c }, + { 0x97,0xa3,0x8d,0x46 }, { 0xf9,0xc6,0x6b,0xd3 }, + { 0x5f,0xe7,0x03,0x8f }, { 0x9c,0x95,0x15,0x92 }, + { 0x7a,0xeb,0xbf,0x6d }, { 0x59,0xda,0x95,0x52 }, + { 0x83,0x2d,0xd4,0xbe }, { 0x21,0xd3,0x58,0x74 }, + { 0x69,0x29,0x49,0xe0 }, { 0xc8,0x44,0x8e,0xc9 }, + { 0x89,0x6a,0x75,0xc2 }, { 0x79,0x78,0xf4,0x8e }, + { 0x3e,0x6b,0x99,0x58 }, { 0x71,0xdd,0x27,0xb9 }, + { 0x4f,0xb6,0xbe,0xe1 }, { 0xad,0x17,0xf0,0x88 }, + { 0xac,0x66,0xc9,0x20 }, { 0x3a,0xb4,0x7d,0xce }, + { 0x4a,0x18,0x63,0xdf }, { 0x31,0x82,0xe5,0x1a }, + { 0x33,0x60,0x97,0x51 }, { 0x7f,0x45,0x62,0x53 }, + { 0x77,0xe0,0xb1,0x64 }, { 0xae,0x84,0xbb,0x6b }, + { 0xa0,0x1c,0xfe,0x81 }, { 0x2b,0x94,0xf9,0x08 }, + { 0x68,0x58,0x70,0x48 }, { 0xfd,0x19,0x8f,0x45 }, + { 0x6c,0x87,0x94,0xde }, { 0xf8,0xb7,0x52,0x7b }, + { 0xd3,0x23,0xab,0x73 }, { 0x02,0xe2,0x72,0x4b }, + { 0x8f,0x57,0xe3,0x1f }, { 0xab,0x2a,0x66,0x55 }, + { 0x28,0x07,0xb2,0xeb }, { 0xc2,0x03,0x2f,0xb5 }, + { 0x7b,0x9a,0x86,0xc5 }, { 0x08,0xa5,0xd3,0x37 }, + { 0x87,0xf2,0x30,0x28 }, { 0xa5,0xb2,0x23,0xbf }, + { 0x6a,0xba,0x02,0x03 }, { 0x82,0x5c,0xed,0x16 }, + { 0x1c,0x2b,0x8a,0xcf }, { 0xb4,0x92,0xa7,0x79 }, + { 0xf2,0xf0,0xf3,0x07 }, { 0xe2,0xa1,0x4e,0x69 }, + { 0xf4,0xcd,0x65,0xda }, { 0xbe,0xd5,0x06,0x05 }, + { 0x62,0x1f,0xd1,0x34 }, { 0xfe,0x8a,0xc4,0xa6 }, + { 0x53,0x9d,0x34,0x2e }, { 0x55,0xa0,0xa2,0xf3 }, + { 0xe1,0x32,0x05,0x8a }, { 0xeb,0x75,0xa4,0xf6 }, + { 0xec,0x39,0x0b,0x83 }, { 0xef,0xaa,0x40,0x60 }, + { 0x9f,0x06,0x5e,0x71 }, { 0x10,0x51,0xbd,0x6e }, + { 0x8a,0xf9,0x3e,0x21 }, { 0x06,0x3d,0x96,0xdd }, + { 0x05,0xae,0xdd,0x3e }, { 0xbd,0x46,0x4d,0xe6 }, + { 0x8d,0xb5,0x91,0x54 }, { 0x5d,0x05,0x71,0xc4 }, + { 0xd4,0x6f,0x04,0x06 }, { 0x15,0xff,0x60,0x50 }, + { 0xfb,0x24,0x19,0x98 }, { 0xe9,0x97,0xd6,0xbd }, + { 0x43,0xcc,0x89,0x40 }, { 0x9e,0x77,0x67,0xd9 }, + { 0x42,0xbd,0xb0,0xe8 }, { 0x8b,0x88,0x07,0x89 }, + { 0x5b,0x38,0xe7,0x19 }, { 0xee,0xdb,0x79,0xc8 }, + { 0x0a,0x47,0xa1,0x7c }, { 0x0f,0xe9,0x7c,0x42 }, + { 0x1e,0xc9,0xf8,0x84 }, { 0x00,0x00,0x00,0x00 }, + { 0x86,0x83,0x09,0x80 }, { 0xed,0x48,0x32,0x2b }, + { 0x70,0xac,0x1e,0x11 }, { 0x72,0x4e,0x6c,0x5a }, + { 0xff,0xfb,0xfd,0x0e }, { 0x38,0x56,0x0f,0x85 }, + { 0xd5,0x1e,0x3d,0xae }, { 0x39,0x27,0x36,0x2d }, + { 0xd9,0x64,0x0a,0x0f }, { 0xa6,0x21,0x68,0x5c }, + { 0x54,0xd1,0x9b,0x5b }, { 0x2e,0x3a,0x24,0x36 }, + { 0x67,0xb1,0x0c,0x0a }, { 0xe7,0x0f,0x93,0x57 }, + { 0x96,0xd2,0xb4,0xee }, { 0x91,0x9e,0x1b,0x9b }, + { 0xc5,0x4f,0x80,0xc0 }, { 0x20,0xa2,0x61,0xdc }, + { 0x4b,0x69,0x5a,0x77 }, { 0x1a,0x16,0x1c,0x12 }, + { 0xba,0x0a,0xe2,0x93 }, { 0x2a,0xe5,0xc0,0xa0 }, + { 0xe0,0x43,0x3c,0x22 }, { 0x17,0x1d,0x12,0x1b }, + { 0x0d,0x0b,0x0e,0x09 }, { 0xc7,0xad,0xf2,0x8b }, + { 0xa8,0xb9,0x2d,0xb6 }, { 0xa9,0xc8,0x14,0x1e }, + { 0x19,0x85,0x57,0xf1 }, { 0x07,0x4c,0xaf,0x75 }, + { 0xdd,0xbb,0xee,0x99 }, { 0x60,0xfd,0xa3,0x7f }, + { 0x26,0x9f,0xf7,0x01 }, { 0xf5,0xbc,0x5c,0x72 }, + { 0x3b,0xc5,0x44,0x66 }, { 0x7e,0x34,0x5b,0xfb }, + { 0x29,0x76,0x8b,0x43 }, { 0xc6,0xdc,0xcb,0x23 }, + { 0xfc,0x68,0xb6,0xed }, { 0xf1,0x63,0xb8,0xe4 }, + { 0xdc,0xca,0xd7,0x31 }, { 0x85,0x10,0x42,0x63 }, + { 0x22,0x40,0x13,0x97 }, { 0x11,0x20,0x84,0xc6 }, + { 0x24,0x7d,0x85,0x4a }, { 0x3d,0xf8,0xd2,0xbb }, + { 0x32,0x11,0xae,0xf9 }, { 0xa1,0x6d,0xc7,0x29 }, + { 0x2f,0x4b,0x1d,0x9e }, { 0x30,0xf3,0xdc,0xb2 }, + { 0x52,0xec,0x0d,0x86 }, { 0xe3,0xd0,0x77,0xc1 }, + { 0x16,0x6c,0x2b,0xb3 }, { 0xb9,0x99,0xa9,0x70 }, + { 0x48,0xfa,0x11,0x94 }, { 0x64,0x22,0x47,0xe9 }, + { 0x8c,0xc4,0xa8,0xfc }, { 0x3f,0x1a,0xa0,0xf0 }, + { 0x2c,0xd8,0x56,0x7d }, { 0x90,0xef,0x22,0x33 }, + { 0x4e,0xc7,0x87,0x49 }, { 0xd1,0xc1,0xd9,0x38 }, + { 0xa2,0xfe,0x8c,0xca }, { 0x0b,0x36,0x98,0xd4 }, + { 0x81,0xcf,0xa6,0xf5 }, { 0xde,0x28,0xa5,0x7a }, + { 0x8e,0x26,0xda,0xb7 }, { 0xbf,0xa4,0x3f,0xad }, + { 0x9d,0xe4,0x2c,0x3a }, { 0x92,0x0d,0x50,0x78 }, + { 0xcc,0x9b,0x6a,0x5f }, { 0x46,0x62,0x54,0x7e }, + { 0x13,0xc2,0xf6,0x8d }, { 0xb8,0xe8,0x90,0xd8 }, + { 0xf7,0x5e,0x2e,0x39 }, { 0xaf,0xf5,0x82,0xc3 }, + { 0x80,0xbe,0x9f,0x5d }, { 0x93,0x7c,0x69,0xd0 }, + { 0x2d,0xa9,0x6f,0xd5 }, { 0x12,0xb3,0xcf,0x25 }, + { 0x99,0x3b,0xc8,0xac }, { 0x7d,0xa7,0x10,0x18 }, + { 0x63,0x6e,0xe8,0x9c }, { 0xbb,0x7b,0xdb,0x3b }, + { 0x78,0x09,0xcd,0x26 }, { 0x18,0xf4,0x6e,0x59 }, + { 0xb7,0x01,0xec,0x9a }, { 0x9a,0xa8,0x83,0x4f }, + { 0x6e,0x65,0xe6,0x95 }, { 0xe6,0x7e,0xaa,0xff }, + { 0xcf,0x08,0x21,0xbc }, { 0xe8,0xe6,0xef,0x15 }, + { 0x9b,0xd9,0xba,0xe7 }, { 0x36,0xce,0x4a,0x6f }, + { 0x09,0xd4,0xea,0x9f }, { 0x7c,0xd6,0x29,0xb0 }, + { 0xb2,0xaf,0x31,0xa4 }, { 0x23,0x31,0x2a,0x3f }, + { 0x94,0x30,0xc6,0xa5 }, { 0x66,0xc0,0x35,0xa2 }, + { 0xbc,0x37,0x74,0x4e }, { 0xca,0xa6,0xfc,0x82 }, + { 0xd0,0xb0,0xe0,0x90 }, { 0xd8,0x15,0x33,0xa7 }, + { 0x98,0x4a,0xf1,0x04 }, { 0xda,0xf7,0x41,0xec }, + { 0x50,0x0e,0x7f,0xcd }, { 0xf6,0x2f,0x17,0x91 }, + { 0xd6,0x8d,0x76,0x4d }, { 0xb0,0x4d,0x43,0xef }, + { 0x4d,0x54,0xcc,0xaa }, { 0x04,0xdf,0xe4,0x96 }, + { 0xb5,0xe3,0x9e,0xd1 }, { 0x88,0x1b,0x4c,0x6a }, + { 0x1f,0xb8,0xc1,0x2c }, { 0x51,0x7f,0x46,0x65 }, + { 0xea,0x04,0x9d,0x5e }, { 0x35,0x5d,0x01,0x8c }, + { 0x74,0x73,0xfa,0x87 }, { 0x41,0x2e,0xfb,0x0b }, + { 0x1d,0x5a,0xb3,0x67 }, { 0xd2,0x52,0x92,0xdb }, + { 0x56,0x33,0xe9,0x10 }, { 0x47,0x13,0x6d,0xd6 }, + { 0x61,0x8c,0x9a,0xd7 }, { 0x0c,0x7a,0x37,0xa1 }, + { 0x14,0x8e,0x59,0xf8 }, { 0x3c,0x89,0xeb,0x13 }, + { 0x27,0xee,0xce,0xa9 }, { 0xc9,0x35,0xb7,0x61 }, + { 0xe5,0xed,0xe1,0x1c }, { 0xb1,0x3c,0x7a,0x47 }, + { 0xdf,0x59,0x9c,0xd2 }, { 0x73,0x3f,0x55,0xf2 }, + { 0xce,0x79,0x18,0x14 }, { 0x37,0xbf,0x73,0xc7 }, + { 0xcd,0xea,0x53,0xf7 }, { 0xaa,0x5b,0x5f,0xfd }, + { 0x6f,0x14,0xdf,0x3d }, { 0xdb,0x86,0x78,0x44 }, + { 0xf3,0x81,0xca,0xaf }, { 0xc4,0x3e,0xb9,0x68 }, + { 0x34,0x2c,0x38,0x24 }, { 0x40,0x5f,0xc2,0xa3 }, + { 0xc3,0x72,0x16,0x1d }, { 0x25,0x0c,0xbc,0xe2 }, + { 0x49,0x8b,0x28,0x3c }, { 0x95,0x41,0xff,0x0d }, + { 0x01,0x71,0x39,0xa8 }, { 0xb3,0xde,0x08,0x0c }, + { 0xe4,0x9c,0xd8,0xb4 }, { 0xc1,0x90,0x64,0x56 }, + { 0x84,0x61,0x7b,0xcb }, { 0xb6,0x70,0xd5,0x32 }, + { 0x5c,0x74,0x48,0x6c }, { 0x57,0x42,0xd0,0xb8 } +}; + +static const byte T8[256][4] = { + { 0xf4,0xa7,0x50,0x51 }, { 0x41,0x65,0x53,0x7e }, + { 0x17,0xa4,0xc3,0x1a }, { 0x27,0x5e,0x96,0x3a }, + { 0xab,0x6b,0xcb,0x3b }, { 0x9d,0x45,0xf1,0x1f }, + { 0xfa,0x58,0xab,0xac }, { 0xe3,0x03,0x93,0x4b }, + { 0x30,0xfa,0x55,0x20 }, { 0x76,0x6d,0xf6,0xad }, + { 0xcc,0x76,0x91,0x88 }, { 0x02,0x4c,0x25,0xf5 }, + { 0xe5,0xd7,0xfc,0x4f }, { 0x2a,0xcb,0xd7,0xc5 }, + { 0x35,0x44,0x80,0x26 }, { 0x62,0xa3,0x8f,0xb5 }, + { 0xb1,0x5a,0x49,0xde }, { 0xba,0x1b,0x67,0x25 }, + { 0xea,0x0e,0x98,0x45 }, { 0xfe,0xc0,0xe1,0x5d }, + { 0x2f,0x75,0x02,0xc3 }, { 0x4c,0xf0,0x12,0x81 }, + { 0x46,0x97,0xa3,0x8d }, { 0xd3,0xf9,0xc6,0x6b }, + { 0x8f,0x5f,0xe7,0x03 }, { 0x92,0x9c,0x95,0x15 }, + { 0x6d,0x7a,0xeb,0xbf }, { 0x52,0x59,0xda,0x95 }, + { 0xbe,0x83,0x2d,0xd4 }, { 0x74,0x21,0xd3,0x58 }, + { 0xe0,0x69,0x29,0x49 }, { 0xc9,0xc8,0x44,0x8e }, + { 0xc2,0x89,0x6a,0x75 }, { 0x8e,0x79,0x78,0xf4 }, + { 0x58,0x3e,0x6b,0x99 }, { 0xb9,0x71,0xdd,0x27 }, + { 0xe1,0x4f,0xb6,0xbe }, { 0x88,0xad,0x17,0xf0 }, + { 0x20,0xac,0x66,0xc9 }, { 0xce,0x3a,0xb4,0x7d }, + { 0xdf,0x4a,0x18,0x63 }, { 0x1a,0x31,0x82,0xe5 }, + { 0x51,0x33,0x60,0x97 }, { 0x53,0x7f,0x45,0x62 }, + { 0x64,0x77,0xe0,0xb1 }, { 0x6b,0xae,0x84,0xbb }, + { 0x81,0xa0,0x1c,0xfe }, { 0x08,0x2b,0x94,0xf9 }, + { 0x48,0x68,0x58,0x70 }, { 0x45,0xfd,0x19,0x8f }, + { 0xde,0x6c,0x87,0x94 }, { 0x7b,0xf8,0xb7,0x52 }, + { 0x73,0xd3,0x23,0xab }, { 0x4b,0x02,0xe2,0x72 }, + { 0x1f,0x8f,0x57,0xe3 }, { 0x55,0xab,0x2a,0x66 }, + { 0xeb,0x28,0x07,0xb2 }, { 0xb5,0xc2,0x03,0x2f }, + { 0xc5,0x7b,0x9a,0x86 }, { 0x37,0x08,0xa5,0xd3 }, + { 0x28,0x87,0xf2,0x30 }, { 0xbf,0xa5,0xb2,0x23 }, + { 0x03,0x6a,0xba,0x02 }, { 0x16,0x82,0x5c,0xed }, + { 0xcf,0x1c,0x2b,0x8a }, { 0x79,0xb4,0x92,0xa7 }, + { 0x07,0xf2,0xf0,0xf3 }, { 0x69,0xe2,0xa1,0x4e }, + { 0xda,0xf4,0xcd,0x65 }, { 0x05,0xbe,0xd5,0x06 }, + { 0x34,0x62,0x1f,0xd1 }, { 0xa6,0xfe,0x8a,0xc4 }, + { 0x2e,0x53,0x9d,0x34 }, { 0xf3,0x55,0xa0,0xa2 }, + { 0x8a,0xe1,0x32,0x05 }, { 0xf6,0xeb,0x75,0xa4 }, + { 0x83,0xec,0x39,0x0b }, { 0x60,0xef,0xaa,0x40 }, + { 0x71,0x9f,0x06,0x5e }, { 0x6e,0x10,0x51,0xbd }, + { 0x21,0x8a,0xf9,0x3e }, { 0xdd,0x06,0x3d,0x96 }, + { 0x3e,0x05,0xae,0xdd }, { 0xe6,0xbd,0x46,0x4d }, + { 0x54,0x8d,0xb5,0x91 }, { 0xc4,0x5d,0x05,0x71 }, + { 0x06,0xd4,0x6f,0x04 }, { 0x50,0x15,0xff,0x60 }, + { 0x98,0xfb,0x24,0x19 }, { 0xbd,0xe9,0x97,0xd6 }, + { 0x40,0x43,0xcc,0x89 }, { 0xd9,0x9e,0x77,0x67 }, + { 0xe8,0x42,0xbd,0xb0 }, { 0x89,0x8b,0x88,0x07 }, + { 0x19,0x5b,0x38,0xe7 }, { 0xc8,0xee,0xdb,0x79 }, + { 0x7c,0x0a,0x47,0xa1 }, { 0x42,0x0f,0xe9,0x7c }, + { 0x84,0x1e,0xc9,0xf8 }, { 0x00,0x00,0x00,0x00 }, + { 0x80,0x86,0x83,0x09 }, { 0x2b,0xed,0x48,0x32 }, + { 0x11,0x70,0xac,0x1e }, { 0x5a,0x72,0x4e,0x6c }, + { 0x0e,0xff,0xfb,0xfd }, { 0x85,0x38,0x56,0x0f }, + { 0xae,0xd5,0x1e,0x3d }, { 0x2d,0x39,0x27,0x36 }, + { 0x0f,0xd9,0x64,0x0a }, { 0x5c,0xa6,0x21,0x68 }, + { 0x5b,0x54,0xd1,0x9b }, { 0x36,0x2e,0x3a,0x24 }, + { 0x0a,0x67,0xb1,0x0c }, { 0x57,0xe7,0x0f,0x93 }, + { 0xee,0x96,0xd2,0xb4 }, { 0x9b,0x91,0x9e,0x1b }, + { 0xc0,0xc5,0x4f,0x80 }, { 0xdc,0x20,0xa2,0x61 }, + { 0x77,0x4b,0x69,0x5a }, { 0x12,0x1a,0x16,0x1c }, + { 0x93,0xba,0x0a,0xe2 }, { 0xa0,0x2a,0xe5,0xc0 }, + { 0x22,0xe0,0x43,0x3c }, { 0x1b,0x17,0x1d,0x12 }, + { 0x09,0x0d,0x0b,0x0e }, { 0x8b,0xc7,0xad,0xf2 }, + { 0xb6,0xa8,0xb9,0x2d }, { 0x1e,0xa9,0xc8,0x14 }, + { 0xf1,0x19,0x85,0x57 }, { 0x75,0x07,0x4c,0xaf }, + { 0x99,0xdd,0xbb,0xee }, { 0x7f,0x60,0xfd,0xa3 }, + { 0x01,0x26,0x9f,0xf7 }, { 0x72,0xf5,0xbc,0x5c }, + { 0x66,0x3b,0xc5,0x44 }, { 0xfb,0x7e,0x34,0x5b }, + { 0x43,0x29,0x76,0x8b }, { 0x23,0xc6,0xdc,0xcb }, + { 0xed,0xfc,0x68,0xb6 }, { 0xe4,0xf1,0x63,0xb8 }, + { 0x31,0xdc,0xca,0xd7 }, { 0x63,0x85,0x10,0x42 }, + { 0x97,0x22,0x40,0x13 }, { 0xc6,0x11,0x20,0x84 }, + { 0x4a,0x24,0x7d,0x85 }, { 0xbb,0x3d,0xf8,0xd2 }, + { 0xf9,0x32,0x11,0xae }, { 0x29,0xa1,0x6d,0xc7 }, + { 0x9e,0x2f,0x4b,0x1d }, { 0xb2,0x30,0xf3,0xdc }, + { 0x86,0x52,0xec,0x0d }, { 0xc1,0xe3,0xd0,0x77 }, + { 0xb3,0x16,0x6c,0x2b }, { 0x70,0xb9,0x99,0xa9 }, + { 0x94,0x48,0xfa,0x11 }, { 0xe9,0x64,0x22,0x47 }, + { 0xfc,0x8c,0xc4,0xa8 }, { 0xf0,0x3f,0x1a,0xa0 }, + { 0x7d,0x2c,0xd8,0x56 }, { 0x33,0x90,0xef,0x22 }, + { 0x49,0x4e,0xc7,0x87 }, { 0x38,0xd1,0xc1,0xd9 }, + { 0xca,0xa2,0xfe,0x8c }, { 0xd4,0x0b,0x36,0x98 }, + { 0xf5,0x81,0xcf,0xa6 }, { 0x7a,0xde,0x28,0xa5 }, + { 0xb7,0x8e,0x26,0xda }, { 0xad,0xbf,0xa4,0x3f }, + { 0x3a,0x9d,0xe4,0x2c }, { 0x78,0x92,0x0d,0x50 }, + { 0x5f,0xcc,0x9b,0x6a }, { 0x7e,0x46,0x62,0x54 }, + { 0x8d,0x13,0xc2,0xf6 }, { 0xd8,0xb8,0xe8,0x90 }, + { 0x39,0xf7,0x5e,0x2e }, { 0xc3,0xaf,0xf5,0x82 }, + { 0x5d,0x80,0xbe,0x9f }, { 0xd0,0x93,0x7c,0x69 }, + { 0xd5,0x2d,0xa9,0x6f }, { 0x25,0x12,0xb3,0xcf }, + { 0xac,0x99,0x3b,0xc8 }, { 0x18,0x7d,0xa7,0x10 }, + { 0x9c,0x63,0x6e,0xe8 }, { 0x3b,0xbb,0x7b,0xdb }, + { 0x26,0x78,0x09,0xcd }, { 0x59,0x18,0xf4,0x6e }, + { 0x9a,0xb7,0x01,0xec }, { 0x4f,0x9a,0xa8,0x83 }, + { 0x95,0x6e,0x65,0xe6 }, { 0xff,0xe6,0x7e,0xaa }, + { 0xbc,0xcf,0x08,0x21 }, { 0x15,0xe8,0xe6,0xef }, + { 0xe7,0x9b,0xd9,0xba }, { 0x6f,0x36,0xce,0x4a }, + { 0x9f,0x09,0xd4,0xea }, { 0xb0,0x7c,0xd6,0x29 }, + { 0xa4,0xb2,0xaf,0x31 }, { 0x3f,0x23,0x31,0x2a }, + { 0xa5,0x94,0x30,0xc6 }, { 0xa2,0x66,0xc0,0x35 }, + { 0x4e,0xbc,0x37,0x74 }, { 0x82,0xca,0xa6,0xfc }, + { 0x90,0xd0,0xb0,0xe0 }, { 0xa7,0xd8,0x15,0x33 }, + { 0x04,0x98,0x4a,0xf1 }, { 0xec,0xda,0xf7,0x41 }, + { 0xcd,0x50,0x0e,0x7f }, { 0x91,0xf6,0x2f,0x17 }, + { 0x4d,0xd6,0x8d,0x76 }, { 0xef,0xb0,0x4d,0x43 }, + { 0xaa,0x4d,0x54,0xcc }, { 0x96,0x04,0xdf,0xe4 }, + { 0xd1,0xb5,0xe3,0x9e }, { 0x6a,0x88,0x1b,0x4c }, + { 0x2c,0x1f,0xb8,0xc1 }, { 0x65,0x51,0x7f,0x46 }, + { 0x5e,0xea,0x04,0x9d }, { 0x8c,0x35,0x5d,0x01 }, + { 0x87,0x74,0x73,0xfa }, { 0x0b,0x41,0x2e,0xfb }, + { 0x67,0x1d,0x5a,0xb3 }, { 0xdb,0xd2,0x52,0x92 }, + { 0x10,0x56,0x33,0xe9 }, { 0xd6,0x47,0x13,0x6d }, + { 0xd7,0x61,0x8c,0x9a }, { 0xa1,0x0c,0x7a,0x37 }, + { 0xf8,0x14,0x8e,0x59 }, { 0x13,0x3c,0x89,0xeb }, + { 0xa9,0x27,0xee,0xce }, { 0x61,0xc9,0x35,0xb7 }, + { 0x1c,0xe5,0xed,0xe1 }, { 0x47,0xb1,0x3c,0x7a }, + { 0xd2,0xdf,0x59,0x9c }, { 0xf2,0x73,0x3f,0x55 }, + { 0x14,0xce,0x79,0x18 }, { 0xc7,0x37,0xbf,0x73 }, + { 0xf7,0xcd,0xea,0x53 }, { 0xfd,0xaa,0x5b,0x5f }, + { 0x3d,0x6f,0x14,0xdf }, { 0x44,0xdb,0x86,0x78 }, + { 0xaf,0xf3,0x81,0xca }, { 0x68,0xc4,0x3e,0xb9 }, + { 0x24,0x34,0x2c,0x38 }, { 0xa3,0x40,0x5f,0xc2 }, + { 0x1d,0xc3,0x72,0x16 }, { 0xe2,0x25,0x0c,0xbc }, + { 0x3c,0x49,0x8b,0x28 }, { 0x0d,0x95,0x41,0xff }, + { 0xa8,0x01,0x71,0x39 }, { 0x0c,0xb3,0xde,0x08 }, + { 0xb4,0xe4,0x9c,0xd8 }, { 0x56,0xc1,0x90,0x64 }, + { 0xcb,0x84,0x61,0x7b }, { 0x32,0xb6,0x70,0xd5 }, + { 0x6c,0x5c,0x74,0x48 }, { 0xb8,0x57,0x42,0xd0 } +}; + +static const byte S5[256] = { + 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38, + 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb, + 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87, + 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb, + 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d, + 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e, + 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2, + 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25, + 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16, + 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92, + 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda, + 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84, + 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a, + 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06, + 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02, + 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b, + 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea, + 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73, + 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85, + 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e, + 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89, + 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b, + 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20, + 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4, + 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31, + 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f, + 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d, + 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef, + 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0, + 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61, + 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26, + 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d +}; + +static const byte U1[256][4] = { + { 0x00,0x00,0x00,0x00 }, { 0x0e,0x09,0x0d,0x0b }, + { 0x1c,0x12,0x1a,0x16 }, { 0x12,0x1b,0x17,0x1d }, + { 0x38,0x24,0x34,0x2c }, { 0x36,0x2d,0x39,0x27 }, + { 0x24,0x36,0x2e,0x3a }, { 0x2a,0x3f,0x23,0x31 }, + { 0x70,0x48,0x68,0x58 }, { 0x7e,0x41,0x65,0x53 }, + { 0x6c,0x5a,0x72,0x4e }, { 0x62,0x53,0x7f,0x45 }, + { 0x48,0x6c,0x5c,0x74 }, { 0x46,0x65,0x51,0x7f }, + { 0x54,0x7e,0x46,0x62 }, { 0x5a,0x77,0x4b,0x69 }, + { 0xe0,0x90,0xd0,0xb0 }, { 0xee,0x99,0xdd,0xbb }, + { 0xfc,0x82,0xca,0xa6 }, { 0xf2,0x8b,0xc7,0xad }, + { 0xd8,0xb4,0xe4,0x9c }, { 0xd6,0xbd,0xe9,0x97 }, + { 0xc4,0xa6,0xfe,0x8a }, { 0xca,0xaf,0xf3,0x81 }, + { 0x90,0xd8,0xb8,0xe8 }, { 0x9e,0xd1,0xb5,0xe3 }, + { 0x8c,0xca,0xa2,0xfe }, { 0x82,0xc3,0xaf,0xf5 }, + { 0xa8,0xfc,0x8c,0xc4 }, { 0xa6,0xf5,0x81,0xcf }, + { 0xb4,0xee,0x96,0xd2 }, { 0xba,0xe7,0x9b,0xd9 }, + { 0xdb,0x3b,0xbb,0x7b }, { 0xd5,0x32,0xb6,0x70 }, + { 0xc7,0x29,0xa1,0x6d }, { 0xc9,0x20,0xac,0x66 }, + { 0xe3,0x1f,0x8f,0x57 }, { 0xed,0x16,0x82,0x5c }, + { 0xff,0x0d,0x95,0x41 }, { 0xf1,0x04,0x98,0x4a }, + { 0xab,0x73,0xd3,0x23 }, { 0xa5,0x7a,0xde,0x28 }, + { 0xb7,0x61,0xc9,0x35 }, { 0xb9,0x68,0xc4,0x3e }, + { 0x93,0x57,0xe7,0x0f }, { 0x9d,0x5e,0xea,0x04 }, + { 0x8f,0x45,0xfd,0x19 }, { 0x81,0x4c,0xf0,0x12 }, + { 0x3b,0xab,0x6b,0xcb }, { 0x35,0xa2,0x66,0xc0 }, + { 0x27,0xb9,0x71,0xdd }, { 0x29,0xb0,0x7c,0xd6 }, + { 0x03,0x8f,0x5f,0xe7 }, { 0x0d,0x86,0x52,0xec }, + { 0x1f,0x9d,0x45,0xf1 }, { 0x11,0x94,0x48,0xfa }, + { 0x4b,0xe3,0x03,0x93 }, { 0x45,0xea,0x0e,0x98 }, + { 0x57,0xf1,0x19,0x85 }, { 0x59,0xf8,0x14,0x8e }, + { 0x73,0xc7,0x37,0xbf }, { 0x7d,0xce,0x3a,0xb4 }, + { 0x6f,0xd5,0x2d,0xa9 }, { 0x61,0xdc,0x20,0xa2 }, + { 0xad,0x76,0x6d,0xf6 }, { 0xa3,0x7f,0x60,0xfd }, + { 0xb1,0x64,0x77,0xe0 }, { 0xbf,0x6d,0x7a,0xeb }, + { 0x95,0x52,0x59,0xda }, { 0x9b,0x5b,0x54,0xd1 }, + { 0x89,0x40,0x43,0xcc }, { 0x87,0x49,0x4e,0xc7 }, + { 0xdd,0x3e,0x05,0xae }, { 0xd3,0x37,0x08,0xa5 }, + { 0xc1,0x2c,0x1f,0xb8 }, { 0xcf,0x25,0x12,0xb3 }, + { 0xe5,0x1a,0x31,0x82 }, { 0xeb,0x13,0x3c,0x89 }, + { 0xf9,0x08,0x2b,0x94 }, { 0xf7,0x01,0x26,0x9f }, + { 0x4d,0xe6,0xbd,0x46 }, { 0x43,0xef,0xb0,0x4d }, + { 0x51,0xf4,0xa7,0x50 }, { 0x5f,0xfd,0xaa,0x5b }, + { 0x75,0xc2,0x89,0x6a }, { 0x7b,0xcb,0x84,0x61 }, + { 0x69,0xd0,0x93,0x7c }, { 0x67,0xd9,0x9e,0x77 }, + { 0x3d,0xae,0xd5,0x1e }, { 0x33,0xa7,0xd8,0x15 }, + { 0x21,0xbc,0xcf,0x08 }, { 0x2f,0xb5,0xc2,0x03 }, + { 0x05,0x8a,0xe1,0x32 }, { 0x0b,0x83,0xec,0x39 }, + { 0x19,0x98,0xfb,0x24 }, { 0x17,0x91,0xf6,0x2f }, + { 0x76,0x4d,0xd6,0x8d }, { 0x78,0x44,0xdb,0x86 }, + { 0x6a,0x5f,0xcc,0x9b }, { 0x64,0x56,0xc1,0x90 }, + { 0x4e,0x69,0xe2,0xa1 }, { 0x40,0x60,0xef,0xaa }, + { 0x52,0x7b,0xf8,0xb7 }, { 0x5c,0x72,0xf5,0xbc }, + { 0x06,0x05,0xbe,0xd5 }, { 0x08,0x0c,0xb3,0xde }, + { 0x1a,0x17,0xa4,0xc3 }, { 0x14,0x1e,0xa9,0xc8 }, + { 0x3e,0x21,0x8a,0xf9 }, { 0x30,0x28,0x87,0xf2 }, + { 0x22,0x33,0x90,0xef }, { 0x2c,0x3a,0x9d,0xe4 }, + { 0x96,0xdd,0x06,0x3d }, { 0x98,0xd4,0x0b,0x36 }, + { 0x8a,0xcf,0x1c,0x2b }, { 0x84,0xc6,0x11,0x20 }, + { 0xae,0xf9,0x32,0x11 }, { 0xa0,0xf0,0x3f,0x1a }, + { 0xb2,0xeb,0x28,0x07 }, { 0xbc,0xe2,0x25,0x0c }, + { 0xe6,0x95,0x6e,0x65 }, { 0xe8,0x9c,0x63,0x6e }, + { 0xfa,0x87,0x74,0x73 }, { 0xf4,0x8e,0x79,0x78 }, + { 0xde,0xb1,0x5a,0x49 }, { 0xd0,0xb8,0x57,0x42 }, + { 0xc2,0xa3,0x40,0x5f }, { 0xcc,0xaa,0x4d,0x54 }, + { 0x41,0xec,0xda,0xf7 }, { 0x4f,0xe5,0xd7,0xfc }, + { 0x5d,0xfe,0xc0,0xe1 }, { 0x53,0xf7,0xcd,0xea }, + { 0x79,0xc8,0xee,0xdb }, { 0x77,0xc1,0xe3,0xd0 }, + { 0x65,0xda,0xf4,0xcd }, { 0x6b,0xd3,0xf9,0xc6 }, + { 0x31,0xa4,0xb2,0xaf }, { 0x3f,0xad,0xbf,0xa4 }, + { 0x2d,0xb6,0xa8,0xb9 }, { 0x23,0xbf,0xa5,0xb2 }, + { 0x09,0x80,0x86,0x83 }, { 0x07,0x89,0x8b,0x88 }, + { 0x15,0x92,0x9c,0x95 }, { 0x1b,0x9b,0x91,0x9e }, + { 0xa1,0x7c,0x0a,0x47 }, { 0xaf,0x75,0x07,0x4c }, + { 0xbd,0x6e,0x10,0x51 }, { 0xb3,0x67,0x1d,0x5a }, + { 0x99,0x58,0x3e,0x6b }, { 0x97,0x51,0x33,0x60 }, + { 0x85,0x4a,0x24,0x7d }, { 0x8b,0x43,0x29,0x76 }, + { 0xd1,0x34,0x62,0x1f }, { 0xdf,0x3d,0x6f,0x14 }, + { 0xcd,0x26,0x78,0x09 }, { 0xc3,0x2f,0x75,0x02 }, + { 0xe9,0x10,0x56,0x33 }, { 0xe7,0x19,0x5b,0x38 }, + { 0xf5,0x02,0x4c,0x25 }, { 0xfb,0x0b,0x41,0x2e }, + { 0x9a,0xd7,0x61,0x8c }, { 0x94,0xde,0x6c,0x87 }, + { 0x86,0xc5,0x7b,0x9a }, { 0x88,0xcc,0x76,0x91 }, + { 0xa2,0xf3,0x55,0xa0 }, { 0xac,0xfa,0x58,0xab }, + { 0xbe,0xe1,0x4f,0xb6 }, { 0xb0,0xe8,0x42,0xbd }, + { 0xea,0x9f,0x09,0xd4 }, { 0xe4,0x96,0x04,0xdf }, + { 0xf6,0x8d,0x13,0xc2 }, { 0xf8,0x84,0x1e,0xc9 }, + { 0xd2,0xbb,0x3d,0xf8 }, { 0xdc,0xb2,0x30,0xf3 }, + { 0xce,0xa9,0x27,0xee }, { 0xc0,0xa0,0x2a,0xe5 }, + { 0x7a,0x47,0xb1,0x3c }, { 0x74,0x4e,0xbc,0x37 }, + { 0x66,0x55,0xab,0x2a }, { 0x68,0x5c,0xa6,0x21 }, + { 0x42,0x63,0x85,0x10 }, { 0x4c,0x6a,0x88,0x1b }, + { 0x5e,0x71,0x9f,0x06 }, { 0x50,0x78,0x92,0x0d }, + { 0x0a,0x0f,0xd9,0x64 }, { 0x04,0x06,0xd4,0x6f }, + { 0x16,0x1d,0xc3,0x72 }, { 0x18,0x14,0xce,0x79 }, + { 0x32,0x2b,0xed,0x48 }, { 0x3c,0x22,0xe0,0x43 }, + { 0x2e,0x39,0xf7,0x5e }, { 0x20,0x30,0xfa,0x55 }, + { 0xec,0x9a,0xb7,0x01 }, { 0xe2,0x93,0xba,0x0a }, + { 0xf0,0x88,0xad,0x17 }, { 0xfe,0x81,0xa0,0x1c }, + { 0xd4,0xbe,0x83,0x2d }, { 0xda,0xb7,0x8e,0x26 }, + { 0xc8,0xac,0x99,0x3b }, { 0xc6,0xa5,0x94,0x30 }, + { 0x9c,0xd2,0xdf,0x59 }, { 0x92,0xdb,0xd2,0x52 }, + { 0x80,0xc0,0xc5,0x4f }, { 0x8e,0xc9,0xc8,0x44 }, + { 0xa4,0xf6,0xeb,0x75 }, { 0xaa,0xff,0xe6,0x7e }, + { 0xb8,0xe4,0xf1,0x63 }, { 0xb6,0xed,0xfc,0x68 }, + { 0x0c,0x0a,0x67,0xb1 }, { 0x02,0x03,0x6a,0xba }, + { 0x10,0x18,0x7d,0xa7 }, { 0x1e,0x11,0x70,0xac }, + { 0x34,0x2e,0x53,0x9d }, { 0x3a,0x27,0x5e,0x96 }, + { 0x28,0x3c,0x49,0x8b }, { 0x26,0x35,0x44,0x80 }, + { 0x7c,0x42,0x0f,0xe9 }, { 0x72,0x4b,0x02,0xe2 }, + { 0x60,0x50,0x15,0xff }, { 0x6e,0x59,0x18,0xf4 }, + { 0x44,0x66,0x3b,0xc5 }, { 0x4a,0x6f,0x36,0xce }, + { 0x58,0x74,0x21,0xd3 }, { 0x56,0x7d,0x2c,0xd8 }, + { 0x37,0xa1,0x0c,0x7a }, { 0x39,0xa8,0x01,0x71 }, + { 0x2b,0xb3,0x16,0x6c }, { 0x25,0xba,0x1b,0x67 }, + { 0x0f,0x85,0x38,0x56 }, { 0x01,0x8c,0x35,0x5d }, + { 0x13,0x97,0x22,0x40 }, { 0x1d,0x9e,0x2f,0x4b }, + { 0x47,0xe9,0x64,0x22 }, { 0x49,0xe0,0x69,0x29 }, + { 0x5b,0xfb,0x7e,0x34 }, { 0x55,0xf2,0x73,0x3f }, + { 0x7f,0xcd,0x50,0x0e }, { 0x71,0xc4,0x5d,0x05 }, + { 0x63,0xdf,0x4a,0x18 }, { 0x6d,0xd6,0x47,0x13 }, + { 0xd7,0x31,0xdc,0xca }, { 0xd9,0x38,0xd1,0xc1 }, + { 0xcb,0x23,0xc6,0xdc }, { 0xc5,0x2a,0xcb,0xd7 }, + { 0xef,0x15,0xe8,0xe6 }, { 0xe1,0x1c,0xe5,0xed }, + { 0xf3,0x07,0xf2,0xf0 }, { 0xfd,0x0e,0xff,0xfb }, + { 0xa7,0x79,0xb4,0x92 }, { 0xa9,0x70,0xb9,0x99 }, + { 0xbb,0x6b,0xae,0x84 }, { 0xb5,0x62,0xa3,0x8f }, + { 0x9f,0x5d,0x80,0xbe }, { 0x91,0x54,0x8d,0xb5 }, + { 0x83,0x4f,0x9a,0xa8 }, { 0x8d,0x46,0x97,0xa3 } +}; + +static const byte U2[256][4] = { + { 0x00,0x00,0x00,0x00 }, { 0x0b,0x0e,0x09,0x0d }, + { 0x16,0x1c,0x12,0x1a }, { 0x1d,0x12,0x1b,0x17 }, + { 0x2c,0x38,0x24,0x34 }, { 0x27,0x36,0x2d,0x39 }, + { 0x3a,0x24,0x36,0x2e }, { 0x31,0x2a,0x3f,0x23 }, + { 0x58,0x70,0x48,0x68 }, { 0x53,0x7e,0x41,0x65 }, + { 0x4e,0x6c,0x5a,0x72 }, { 0x45,0x62,0x53,0x7f }, + { 0x74,0x48,0x6c,0x5c }, { 0x7f,0x46,0x65,0x51 }, + { 0x62,0x54,0x7e,0x46 }, { 0x69,0x5a,0x77,0x4b }, + { 0xb0,0xe0,0x90,0xd0 }, { 0xbb,0xee,0x99,0xdd }, + { 0xa6,0xfc,0x82,0xca }, { 0xad,0xf2,0x8b,0xc7 }, + { 0x9c,0xd8,0xb4,0xe4 }, { 0x97,0xd6,0xbd,0xe9 }, + { 0x8a,0xc4,0xa6,0xfe }, { 0x81,0xca,0xaf,0xf3 }, + { 0xe8,0x90,0xd8,0xb8 }, { 0xe3,0x9e,0xd1,0xb5 }, + { 0xfe,0x8c,0xca,0xa2 }, { 0xf5,0x82,0xc3,0xaf }, + { 0xc4,0xa8,0xfc,0x8c }, { 0xcf,0xa6,0xf5,0x81 }, + { 0xd2,0xb4,0xee,0x96 }, { 0xd9,0xba,0xe7,0x9b }, + { 0x7b,0xdb,0x3b,0xbb }, { 0x70,0xd5,0x32,0xb6 }, + { 0x6d,0xc7,0x29,0xa1 }, { 0x66,0xc9,0x20,0xac }, + { 0x57,0xe3,0x1f,0x8f }, { 0x5c,0xed,0x16,0x82 }, + { 0x41,0xff,0x0d,0x95 }, { 0x4a,0xf1,0x04,0x98 }, + { 0x23,0xab,0x73,0xd3 }, { 0x28,0xa5,0x7a,0xde }, + { 0x35,0xb7,0x61,0xc9 }, { 0x3e,0xb9,0x68,0xc4 }, + { 0x0f,0x93,0x57,0xe7 }, { 0x04,0x9d,0x5e,0xea }, + { 0x19,0x8f,0x45,0xfd }, { 0x12,0x81,0x4c,0xf0 }, + { 0xcb,0x3b,0xab,0x6b }, { 0xc0,0x35,0xa2,0x66 }, + { 0xdd,0x27,0xb9,0x71 }, { 0xd6,0x29,0xb0,0x7c }, + { 0xe7,0x03,0x8f,0x5f }, { 0xec,0x0d,0x86,0x52 }, + { 0xf1,0x1f,0x9d,0x45 }, { 0xfa,0x11,0x94,0x48 }, + { 0x93,0x4b,0xe3,0x03 }, { 0x98,0x45,0xea,0x0e }, + { 0x85,0x57,0xf1,0x19 }, { 0x8e,0x59,0xf8,0x14 }, + { 0xbf,0x73,0xc7,0x37 }, { 0xb4,0x7d,0xce,0x3a }, + { 0xa9,0x6f,0xd5,0x2d }, { 0xa2,0x61,0xdc,0x20 }, + { 0xf6,0xad,0x76,0x6d }, { 0xfd,0xa3,0x7f,0x60 }, + { 0xe0,0xb1,0x64,0x77 }, { 0xeb,0xbf,0x6d,0x7a }, + { 0xda,0x95,0x52,0x59 }, { 0xd1,0x9b,0x5b,0x54 }, + { 0xcc,0x89,0x40,0x43 }, { 0xc7,0x87,0x49,0x4e }, + { 0xae,0xdd,0x3e,0x05 }, { 0xa5,0xd3,0x37,0x08 }, + { 0xb8,0xc1,0x2c,0x1f }, { 0xb3,0xcf,0x25,0x12 }, + { 0x82,0xe5,0x1a,0x31 }, { 0x89,0xeb,0x13,0x3c }, + { 0x94,0xf9,0x08,0x2b }, { 0x9f,0xf7,0x01,0x26 }, + { 0x46,0x4d,0xe6,0xbd }, { 0x4d,0x43,0xef,0xb0 }, + { 0x50,0x51,0xf4,0xa7 }, { 0x5b,0x5f,0xfd,0xaa }, + { 0x6a,0x75,0xc2,0x89 }, { 0x61,0x7b,0xcb,0x84 }, + { 0x7c,0x69,0xd0,0x93 }, { 0x77,0x67,0xd9,0x9e }, + { 0x1e,0x3d,0xae,0xd5 }, { 0x15,0x33,0xa7,0xd8 }, + { 0x08,0x21,0xbc,0xcf }, { 0x03,0x2f,0xb5,0xc2 }, + { 0x32,0x05,0x8a,0xe1 }, { 0x39,0x0b,0x83,0xec }, + { 0x24,0x19,0x98,0xfb }, { 0x2f,0x17,0x91,0xf6 }, + { 0x8d,0x76,0x4d,0xd6 }, { 0x86,0x78,0x44,0xdb }, + { 0x9b,0x6a,0x5f,0xcc }, { 0x90,0x64,0x56,0xc1 }, + { 0xa1,0x4e,0x69,0xe2 }, { 0xaa,0x40,0x60,0xef }, + { 0xb7,0x52,0x7b,0xf8 }, { 0xbc,0x5c,0x72,0xf5 }, + { 0xd5,0x06,0x05,0xbe }, { 0xde,0x08,0x0c,0xb3 }, + { 0xc3,0x1a,0x17,0xa4 }, { 0xc8,0x14,0x1e,0xa9 }, + { 0xf9,0x3e,0x21,0x8a }, { 0xf2,0x30,0x28,0x87 }, + { 0xef,0x22,0x33,0x90 }, { 0xe4,0x2c,0x3a,0x9d }, + { 0x3d,0x96,0xdd,0x06 }, { 0x36,0x98,0xd4,0x0b }, + { 0x2b,0x8a,0xcf,0x1c }, { 0x20,0x84,0xc6,0x11 }, + { 0x11,0xae,0xf9,0x32 }, { 0x1a,0xa0,0xf0,0x3f }, + { 0x07,0xb2,0xeb,0x28 }, { 0x0c,0xbc,0xe2,0x25 }, + { 0x65,0xe6,0x95,0x6e }, { 0x6e,0xe8,0x9c,0x63 }, + { 0x73,0xfa,0x87,0x74 }, { 0x78,0xf4,0x8e,0x79 }, + { 0x49,0xde,0xb1,0x5a }, { 0x42,0xd0,0xb8,0x57 }, + { 0x5f,0xc2,0xa3,0x40 }, { 0x54,0xcc,0xaa,0x4d }, + { 0xf7,0x41,0xec,0xda }, { 0xfc,0x4f,0xe5,0xd7 }, + { 0xe1,0x5d,0xfe,0xc0 }, { 0xea,0x53,0xf7,0xcd }, + { 0xdb,0x79,0xc8,0xee }, { 0xd0,0x77,0xc1,0xe3 }, + { 0xcd,0x65,0xda,0xf4 }, { 0xc6,0x6b,0xd3,0xf9 }, + { 0xaf,0x31,0xa4,0xb2 }, { 0xa4,0x3f,0xad,0xbf }, + { 0xb9,0x2d,0xb6,0xa8 }, { 0xb2,0x23,0xbf,0xa5 }, + { 0x83,0x09,0x80,0x86 }, { 0x88,0x07,0x89,0x8b }, + { 0x95,0x15,0x92,0x9c }, { 0x9e,0x1b,0x9b,0x91 }, + { 0x47,0xa1,0x7c,0x0a }, { 0x4c,0xaf,0x75,0x07 }, + { 0x51,0xbd,0x6e,0x10 }, { 0x5a,0xb3,0x67,0x1d }, + { 0x6b,0x99,0x58,0x3e }, { 0x60,0x97,0x51,0x33 }, + { 0x7d,0x85,0x4a,0x24 }, { 0x76,0x8b,0x43,0x29 }, + { 0x1f,0xd1,0x34,0x62 }, { 0x14,0xdf,0x3d,0x6f }, + { 0x09,0xcd,0x26,0x78 }, { 0x02,0xc3,0x2f,0x75 }, + { 0x33,0xe9,0x10,0x56 }, { 0x38,0xe7,0x19,0x5b }, + { 0x25,0xf5,0x02,0x4c }, { 0x2e,0xfb,0x0b,0x41 }, + { 0x8c,0x9a,0xd7,0x61 }, { 0x87,0x94,0xde,0x6c }, + { 0x9a,0x86,0xc5,0x7b }, { 0x91,0x88,0xcc,0x76 }, + { 0xa0,0xa2,0xf3,0x55 }, { 0xab,0xac,0xfa,0x58 }, + { 0xb6,0xbe,0xe1,0x4f }, { 0xbd,0xb0,0xe8,0x42 }, + { 0xd4,0xea,0x9f,0x09 }, { 0xdf,0xe4,0x96,0x04 }, + { 0xc2,0xf6,0x8d,0x13 }, { 0xc9,0xf8,0x84,0x1e }, + { 0xf8,0xd2,0xbb,0x3d }, { 0xf3,0xdc,0xb2,0x30 }, + { 0xee,0xce,0xa9,0x27 }, { 0xe5,0xc0,0xa0,0x2a }, + { 0x3c,0x7a,0x47,0xb1 }, { 0x37,0x74,0x4e,0xbc }, + { 0x2a,0x66,0x55,0xab }, { 0x21,0x68,0x5c,0xa6 }, + { 0x10,0x42,0x63,0x85 }, { 0x1b,0x4c,0x6a,0x88 }, + { 0x06,0x5e,0x71,0x9f }, { 0x0d,0x50,0x78,0x92 }, + { 0x64,0x0a,0x0f,0xd9 }, { 0x6f,0x04,0x06,0xd4 }, + { 0x72,0x16,0x1d,0xc3 }, { 0x79,0x18,0x14,0xce }, + { 0x48,0x32,0x2b,0xed }, { 0x43,0x3c,0x22,0xe0 }, + { 0x5e,0x2e,0x39,0xf7 }, { 0x55,0x20,0x30,0xfa }, + { 0x01,0xec,0x9a,0xb7 }, { 0x0a,0xe2,0x93,0xba }, + { 0x17,0xf0,0x88,0xad }, { 0x1c,0xfe,0x81,0xa0 }, + { 0x2d,0xd4,0xbe,0x83 }, { 0x26,0xda,0xb7,0x8e }, + { 0x3b,0xc8,0xac,0x99 }, { 0x30,0xc6,0xa5,0x94 }, + { 0x59,0x9c,0xd2,0xdf }, { 0x52,0x92,0xdb,0xd2 }, + { 0x4f,0x80,0xc0,0xc5 }, { 0x44,0x8e,0xc9,0xc8 }, + { 0x75,0xa4,0xf6,0xeb }, { 0x7e,0xaa,0xff,0xe6 }, + { 0x63,0xb8,0xe4,0xf1 }, { 0x68,0xb6,0xed,0xfc }, + { 0xb1,0x0c,0x0a,0x67 }, { 0xba,0x02,0x03,0x6a }, + { 0xa7,0x10,0x18,0x7d }, { 0xac,0x1e,0x11,0x70 }, + { 0x9d,0x34,0x2e,0x53 }, { 0x96,0x3a,0x27,0x5e }, + { 0x8b,0x28,0x3c,0x49 }, { 0x80,0x26,0x35,0x44 }, + { 0xe9,0x7c,0x42,0x0f }, { 0xe2,0x72,0x4b,0x02 }, + { 0xff,0x60,0x50,0x15 }, { 0xf4,0x6e,0x59,0x18 }, + { 0xc5,0x44,0x66,0x3b }, { 0xce,0x4a,0x6f,0x36 }, + { 0xd3,0x58,0x74,0x21 }, { 0xd8,0x56,0x7d,0x2c }, + { 0x7a,0x37,0xa1,0x0c }, { 0x71,0x39,0xa8,0x01 }, + { 0x6c,0x2b,0xb3,0x16 }, { 0x67,0x25,0xba,0x1b }, + { 0x56,0x0f,0x85,0x38 }, { 0x5d,0x01,0x8c,0x35 }, + { 0x40,0x13,0x97,0x22 }, { 0x4b,0x1d,0x9e,0x2f }, + { 0x22,0x47,0xe9,0x64 }, { 0x29,0x49,0xe0,0x69 }, + { 0x34,0x5b,0xfb,0x7e }, { 0x3f,0x55,0xf2,0x73 }, + { 0x0e,0x7f,0xcd,0x50 }, { 0x05,0x71,0xc4,0x5d }, + { 0x18,0x63,0xdf,0x4a }, { 0x13,0x6d,0xd6,0x47 }, + { 0xca,0xd7,0x31,0xdc }, { 0xc1,0xd9,0x38,0xd1 }, + { 0xdc,0xcb,0x23,0xc6 }, { 0xd7,0xc5,0x2a,0xcb }, + { 0xe6,0xef,0x15,0xe8 }, { 0xed,0xe1,0x1c,0xe5 }, + { 0xf0,0xf3,0x07,0xf2 }, { 0xfb,0xfd,0x0e,0xff }, + { 0x92,0xa7,0x79,0xb4 }, { 0x99,0xa9,0x70,0xb9 }, + { 0x84,0xbb,0x6b,0xae }, { 0x8f,0xb5,0x62,0xa3 }, + { 0xbe,0x9f,0x5d,0x80 }, { 0xb5,0x91,0x54,0x8d }, + { 0xa8,0x83,0x4f,0x9a }, { 0xa3,0x8d,0x46,0x97 } +}; + +static const byte U3[256][4] = { + { 0x00,0x00,0x00,0x00 }, { 0x0d,0x0b,0x0e,0x09 }, + { 0x1a,0x16,0x1c,0x12 }, { 0x17,0x1d,0x12,0x1b }, + { 0x34,0x2c,0x38,0x24 }, { 0x39,0x27,0x36,0x2d }, + { 0x2e,0x3a,0x24,0x36 }, { 0x23,0x31,0x2a,0x3f }, + { 0x68,0x58,0x70,0x48 }, { 0x65,0x53,0x7e,0x41 }, + { 0x72,0x4e,0x6c,0x5a }, { 0x7f,0x45,0x62,0x53 }, + { 0x5c,0x74,0x48,0x6c }, { 0x51,0x7f,0x46,0x65 }, + { 0x46,0x62,0x54,0x7e }, { 0x4b,0x69,0x5a,0x77 }, + { 0xd0,0xb0,0xe0,0x90 }, { 0xdd,0xbb,0xee,0x99 }, + { 0xca,0xa6,0xfc,0x82 }, { 0xc7,0xad,0xf2,0x8b }, + { 0xe4,0x9c,0xd8,0xb4 }, { 0xe9,0x97,0xd6,0xbd }, + { 0xfe,0x8a,0xc4,0xa6 }, { 0xf3,0x81,0xca,0xaf }, + { 0xb8,0xe8,0x90,0xd8 }, { 0xb5,0xe3,0x9e,0xd1 }, + { 0xa2,0xfe,0x8c,0xca }, { 0xaf,0xf5,0x82,0xc3 }, + { 0x8c,0xc4,0xa8,0xfc }, { 0x81,0xcf,0xa6,0xf5 }, + { 0x96,0xd2,0xb4,0xee }, { 0x9b,0xd9,0xba,0xe7 }, + { 0xbb,0x7b,0xdb,0x3b }, { 0xb6,0x70,0xd5,0x32 }, + { 0xa1,0x6d,0xc7,0x29 }, { 0xac,0x66,0xc9,0x20 }, + { 0x8f,0x57,0xe3,0x1f }, { 0x82,0x5c,0xed,0x16 }, + { 0x95,0x41,0xff,0x0d }, { 0x98,0x4a,0xf1,0x04 }, + { 0xd3,0x23,0xab,0x73 }, { 0xde,0x28,0xa5,0x7a }, + { 0xc9,0x35,0xb7,0x61 }, { 0xc4,0x3e,0xb9,0x68 }, + { 0xe7,0x0f,0x93,0x57 }, { 0xea,0x04,0x9d,0x5e }, + { 0xfd,0x19,0x8f,0x45 }, { 0xf0,0x12,0x81,0x4c }, + { 0x6b,0xcb,0x3b,0xab }, { 0x66,0xc0,0x35,0xa2 }, + { 0x71,0xdd,0x27,0xb9 }, { 0x7c,0xd6,0x29,0xb0 }, + { 0x5f,0xe7,0x03,0x8f }, { 0x52,0xec,0x0d,0x86 }, + { 0x45,0xf1,0x1f,0x9d }, { 0x48,0xfa,0x11,0x94 }, + { 0x03,0x93,0x4b,0xe3 }, { 0x0e,0x98,0x45,0xea }, + { 0x19,0x85,0x57,0xf1 }, { 0x14,0x8e,0x59,0xf8 }, + { 0x37,0xbf,0x73,0xc7 }, { 0x3a,0xb4,0x7d,0xce }, + { 0x2d,0xa9,0x6f,0xd5 }, { 0x20,0xa2,0x61,0xdc }, + { 0x6d,0xf6,0xad,0x76 }, { 0x60,0xfd,0xa3,0x7f }, + { 0x77,0xe0,0xb1,0x64 }, { 0x7a,0xeb,0xbf,0x6d }, + { 0x59,0xda,0x95,0x52 }, { 0x54,0xd1,0x9b,0x5b }, + { 0x43,0xcc,0x89,0x40 }, { 0x4e,0xc7,0x87,0x49 }, + { 0x05,0xae,0xdd,0x3e }, { 0x08,0xa5,0xd3,0x37 }, + { 0x1f,0xb8,0xc1,0x2c }, { 0x12,0xb3,0xcf,0x25 }, + { 0x31,0x82,0xe5,0x1a }, { 0x3c,0x89,0xeb,0x13 }, + { 0x2b,0x94,0xf9,0x08 }, { 0x26,0x9f,0xf7,0x01 }, + { 0xbd,0x46,0x4d,0xe6 }, { 0xb0,0x4d,0x43,0xef }, + { 0xa7,0x50,0x51,0xf4 }, { 0xaa,0x5b,0x5f,0xfd }, + { 0x89,0x6a,0x75,0xc2 }, { 0x84,0x61,0x7b,0xcb }, + { 0x93,0x7c,0x69,0xd0 }, { 0x9e,0x77,0x67,0xd9 }, + { 0xd5,0x1e,0x3d,0xae }, { 0xd8,0x15,0x33,0xa7 }, + { 0xcf,0x08,0x21,0xbc }, { 0xc2,0x03,0x2f,0xb5 }, + { 0xe1,0x32,0x05,0x8a }, { 0xec,0x39,0x0b,0x83 }, + { 0xfb,0x24,0x19,0x98 }, { 0xf6,0x2f,0x17,0x91 }, + { 0xd6,0x8d,0x76,0x4d }, { 0xdb,0x86,0x78,0x44 }, + { 0xcc,0x9b,0x6a,0x5f }, { 0xc1,0x90,0x64,0x56 }, + { 0xe2,0xa1,0x4e,0x69 }, { 0xef,0xaa,0x40,0x60 }, + { 0xf8,0xb7,0x52,0x7b }, { 0xf5,0xbc,0x5c,0x72 }, + { 0xbe,0xd5,0x06,0x05 }, { 0xb3,0xde,0x08,0x0c }, + { 0xa4,0xc3,0x1a,0x17 }, { 0xa9,0xc8,0x14,0x1e }, + { 0x8a,0xf9,0x3e,0x21 }, { 0x87,0xf2,0x30,0x28 }, + { 0x90,0xef,0x22,0x33 }, { 0x9d,0xe4,0x2c,0x3a }, + { 0x06,0x3d,0x96,0xdd }, { 0x0b,0x36,0x98,0xd4 }, + { 0x1c,0x2b,0x8a,0xcf }, { 0x11,0x20,0x84,0xc6 }, + { 0x32,0x11,0xae,0xf9 }, { 0x3f,0x1a,0xa0,0xf0 }, + { 0x28,0x07,0xb2,0xeb }, { 0x25,0x0c,0xbc,0xe2 }, + { 0x6e,0x65,0xe6,0x95 }, { 0x63,0x6e,0xe8,0x9c }, + { 0x74,0x73,0xfa,0x87 }, { 0x79,0x78,0xf4,0x8e }, + { 0x5a,0x49,0xde,0xb1 }, { 0x57,0x42,0xd0,0xb8 }, + { 0x40,0x5f,0xc2,0xa3 }, { 0x4d,0x54,0xcc,0xaa }, + { 0xda,0xf7,0x41,0xec }, { 0xd7,0xfc,0x4f,0xe5 }, + { 0xc0,0xe1,0x5d,0xfe }, { 0xcd,0xea,0x53,0xf7 }, + { 0xee,0xdb,0x79,0xc8 }, { 0xe3,0xd0,0x77,0xc1 }, + { 0xf4,0xcd,0x65,0xda }, { 0xf9,0xc6,0x6b,0xd3 }, + { 0xb2,0xaf,0x31,0xa4 }, { 0xbf,0xa4,0x3f,0xad }, + { 0xa8,0xb9,0x2d,0xb6 }, { 0xa5,0xb2,0x23,0xbf }, + { 0x86,0x83,0x09,0x80 }, { 0x8b,0x88,0x07,0x89 }, + { 0x9c,0x95,0x15,0x92 }, { 0x91,0x9e,0x1b,0x9b }, + { 0x0a,0x47,0xa1,0x7c }, { 0x07,0x4c,0xaf,0x75 }, + { 0x10,0x51,0xbd,0x6e }, { 0x1d,0x5a,0xb3,0x67 }, + { 0x3e,0x6b,0x99,0x58 }, { 0x33,0x60,0x97,0x51 }, + { 0x24,0x7d,0x85,0x4a }, { 0x29,0x76,0x8b,0x43 }, + { 0x62,0x1f,0xd1,0x34 }, { 0x6f,0x14,0xdf,0x3d }, + { 0x78,0x09,0xcd,0x26 }, { 0x75,0x02,0xc3,0x2f }, + { 0x56,0x33,0xe9,0x10 }, { 0x5b,0x38,0xe7,0x19 }, + { 0x4c,0x25,0xf5,0x02 }, { 0x41,0x2e,0xfb,0x0b }, + { 0x61,0x8c,0x9a,0xd7 }, { 0x6c,0x87,0x94,0xde }, + { 0x7b,0x9a,0x86,0xc5 }, { 0x76,0x91,0x88,0xcc }, + { 0x55,0xa0,0xa2,0xf3 }, { 0x58,0xab,0xac,0xfa }, + { 0x4f,0xb6,0xbe,0xe1 }, { 0x42,0xbd,0xb0,0xe8 }, + { 0x09,0xd4,0xea,0x9f }, { 0x04,0xdf,0xe4,0x96 }, + { 0x13,0xc2,0xf6,0x8d }, { 0x1e,0xc9,0xf8,0x84 }, + { 0x3d,0xf8,0xd2,0xbb }, { 0x30,0xf3,0xdc,0xb2 }, + { 0x27,0xee,0xce,0xa9 }, { 0x2a,0xe5,0xc0,0xa0 }, + { 0xb1,0x3c,0x7a,0x47 }, { 0xbc,0x37,0x74,0x4e }, + { 0xab,0x2a,0x66,0x55 }, { 0xa6,0x21,0x68,0x5c }, + { 0x85,0x10,0x42,0x63 }, { 0x88,0x1b,0x4c,0x6a }, + { 0x9f,0x06,0x5e,0x71 }, { 0x92,0x0d,0x50,0x78 }, + { 0xd9,0x64,0x0a,0x0f }, { 0xd4,0x6f,0x04,0x06 }, + { 0xc3,0x72,0x16,0x1d }, { 0xce,0x79,0x18,0x14 }, + { 0xed,0x48,0x32,0x2b }, { 0xe0,0x43,0x3c,0x22 }, + { 0xf7,0x5e,0x2e,0x39 }, { 0xfa,0x55,0x20,0x30 }, + { 0xb7,0x01,0xec,0x9a }, { 0xba,0x0a,0xe2,0x93 }, + { 0xad,0x17,0xf0,0x88 }, { 0xa0,0x1c,0xfe,0x81 }, + { 0x83,0x2d,0xd4,0xbe }, { 0x8e,0x26,0xda,0xb7 }, + { 0x99,0x3b,0xc8,0xac }, { 0x94,0x30,0xc6,0xa5 }, + { 0xdf,0x59,0x9c,0xd2 }, { 0xd2,0x52,0x92,0xdb }, + { 0xc5,0x4f,0x80,0xc0 }, { 0xc8,0x44,0x8e,0xc9 }, + { 0xeb,0x75,0xa4,0xf6 }, { 0xe6,0x7e,0xaa,0xff }, + { 0xf1,0x63,0xb8,0xe4 }, { 0xfc,0x68,0xb6,0xed }, + { 0x67,0xb1,0x0c,0x0a }, { 0x6a,0xba,0x02,0x03 }, + { 0x7d,0xa7,0x10,0x18 }, { 0x70,0xac,0x1e,0x11 }, + { 0x53,0x9d,0x34,0x2e }, { 0x5e,0x96,0x3a,0x27 }, + { 0x49,0x8b,0x28,0x3c }, { 0x44,0x80,0x26,0x35 }, + { 0x0f,0xe9,0x7c,0x42 }, { 0x02,0xe2,0x72,0x4b }, + { 0x15,0xff,0x60,0x50 }, { 0x18,0xf4,0x6e,0x59 }, + { 0x3b,0xc5,0x44,0x66 }, { 0x36,0xce,0x4a,0x6f }, + { 0x21,0xd3,0x58,0x74 }, { 0x2c,0xd8,0x56,0x7d }, + { 0x0c,0x7a,0x37,0xa1 }, { 0x01,0x71,0x39,0xa8 }, + { 0x16,0x6c,0x2b,0xb3 }, { 0x1b,0x67,0x25,0xba }, + { 0x38,0x56,0x0f,0x85 }, { 0x35,0x5d,0x01,0x8c }, + { 0x22,0x40,0x13,0x97 }, { 0x2f,0x4b,0x1d,0x9e }, + { 0x64,0x22,0x47,0xe9 }, { 0x69,0x29,0x49,0xe0 }, + { 0x7e,0x34,0x5b,0xfb }, { 0x73,0x3f,0x55,0xf2 }, + { 0x50,0x0e,0x7f,0xcd }, { 0x5d,0x05,0x71,0xc4 }, + { 0x4a,0x18,0x63,0xdf }, { 0x47,0x13,0x6d,0xd6 }, + { 0xdc,0xca,0xd7,0x31 }, { 0xd1,0xc1,0xd9,0x38 }, + { 0xc6,0xdc,0xcb,0x23 }, { 0xcb,0xd7,0xc5,0x2a }, + { 0xe8,0xe6,0xef,0x15 }, { 0xe5,0xed,0xe1,0x1c }, + { 0xf2,0xf0,0xf3,0x07 }, { 0xff,0xfb,0xfd,0x0e }, + { 0xb4,0x92,0xa7,0x79 }, { 0xb9,0x99,0xa9,0x70 }, + { 0xae,0x84,0xbb,0x6b }, { 0xa3,0x8f,0xb5,0x62 }, + { 0x80,0xbe,0x9f,0x5d }, { 0x8d,0xb5,0x91,0x54 }, + { 0x9a,0xa8,0x83,0x4f }, { 0x97,0xa3,0x8d,0x46 } +}; + +static const byte U4[256][4] = { + { 0x00,0x00,0x00,0x00 }, { 0x09,0x0d,0x0b,0x0e }, + { 0x12,0x1a,0x16,0x1c }, { 0x1b,0x17,0x1d,0x12 }, + { 0x24,0x34,0x2c,0x38 }, { 0x2d,0x39,0x27,0x36 }, + { 0x36,0x2e,0x3a,0x24 }, { 0x3f,0x23,0x31,0x2a }, + { 0x48,0x68,0x58,0x70 }, { 0x41,0x65,0x53,0x7e }, + { 0x5a,0x72,0x4e,0x6c }, { 0x53,0x7f,0x45,0x62 }, + { 0x6c,0x5c,0x74,0x48 }, { 0x65,0x51,0x7f,0x46 }, + { 0x7e,0x46,0x62,0x54 }, { 0x77,0x4b,0x69,0x5a }, + { 0x90,0xd0,0xb0,0xe0 }, { 0x99,0xdd,0xbb,0xee }, + { 0x82,0xca,0xa6,0xfc }, { 0x8b,0xc7,0xad,0xf2 }, + { 0xb4,0xe4,0x9c,0xd8 }, { 0xbd,0xe9,0x97,0xd6 }, + { 0xa6,0xfe,0x8a,0xc4 }, { 0xaf,0xf3,0x81,0xca }, + { 0xd8,0xb8,0xe8,0x90 }, { 0xd1,0xb5,0xe3,0x9e }, + { 0xca,0xa2,0xfe,0x8c }, { 0xc3,0xaf,0xf5,0x82 }, + { 0xfc,0x8c,0xc4,0xa8 }, { 0xf5,0x81,0xcf,0xa6 }, + { 0xee,0x96,0xd2,0xb4 }, { 0xe7,0x9b,0xd9,0xba }, + { 0x3b,0xbb,0x7b,0xdb }, { 0x32,0xb6,0x70,0xd5 }, + { 0x29,0xa1,0x6d,0xc7 }, { 0x20,0xac,0x66,0xc9 }, + { 0x1f,0x8f,0x57,0xe3 }, { 0x16,0x82,0x5c,0xed }, + { 0x0d,0x95,0x41,0xff }, { 0x04,0x98,0x4a,0xf1 }, + { 0x73,0xd3,0x23,0xab }, { 0x7a,0xde,0x28,0xa5 }, + { 0x61,0xc9,0x35,0xb7 }, { 0x68,0xc4,0x3e,0xb9 }, + { 0x57,0xe7,0x0f,0x93 }, { 0x5e,0xea,0x04,0x9d }, + { 0x45,0xfd,0x19,0x8f }, { 0x4c,0xf0,0x12,0x81 }, + { 0xab,0x6b,0xcb,0x3b }, { 0xa2,0x66,0xc0,0x35 }, + { 0xb9,0x71,0xdd,0x27 }, { 0xb0,0x7c,0xd6,0x29 }, + { 0x8f,0x5f,0xe7,0x03 }, { 0x86,0x52,0xec,0x0d }, + { 0x9d,0x45,0xf1,0x1f }, { 0x94,0x48,0xfa,0x11 }, + { 0xe3,0x03,0x93,0x4b }, { 0xea,0x0e,0x98,0x45 }, + { 0xf1,0x19,0x85,0x57 }, { 0xf8,0x14,0x8e,0x59 }, + { 0xc7,0x37,0xbf,0x73 }, { 0xce,0x3a,0xb4,0x7d }, + { 0xd5,0x2d,0xa9,0x6f }, { 0xdc,0x20,0xa2,0x61 }, + { 0x76,0x6d,0xf6,0xad }, { 0x7f,0x60,0xfd,0xa3 }, + { 0x64,0x77,0xe0,0xb1 }, { 0x6d,0x7a,0xeb,0xbf }, + { 0x52,0x59,0xda,0x95 }, { 0x5b,0x54,0xd1,0x9b }, + { 0x40,0x43,0xcc,0x89 }, { 0x49,0x4e,0xc7,0x87 }, + { 0x3e,0x05,0xae,0xdd }, { 0x37,0x08,0xa5,0xd3 }, + { 0x2c,0x1f,0xb8,0xc1 }, { 0x25,0x12,0xb3,0xcf }, + { 0x1a,0x31,0x82,0xe5 }, { 0x13,0x3c,0x89,0xeb }, + { 0x08,0x2b,0x94,0xf9 }, { 0x01,0x26,0x9f,0xf7 }, + { 0xe6,0xbd,0x46,0x4d }, { 0xef,0xb0,0x4d,0x43 }, + { 0xf4,0xa7,0x50,0x51 }, { 0xfd,0xaa,0x5b,0x5f }, + { 0xc2,0x89,0x6a,0x75 }, { 0xcb,0x84,0x61,0x7b }, + { 0xd0,0x93,0x7c,0x69 }, { 0xd9,0x9e,0x77,0x67 }, + { 0xae,0xd5,0x1e,0x3d }, { 0xa7,0xd8,0x15,0x33 }, + { 0xbc,0xcf,0x08,0x21 }, { 0xb5,0xc2,0x03,0x2f }, + { 0x8a,0xe1,0x32,0x05 }, { 0x83,0xec,0x39,0x0b }, + { 0x98,0xfb,0x24,0x19 }, { 0x91,0xf6,0x2f,0x17 }, + { 0x4d,0xd6,0x8d,0x76 }, { 0x44,0xdb,0x86,0x78 }, + { 0x5f,0xcc,0x9b,0x6a }, { 0x56,0xc1,0x90,0x64 }, + { 0x69,0xe2,0xa1,0x4e }, { 0x60,0xef,0xaa,0x40 }, + { 0x7b,0xf8,0xb7,0x52 }, { 0x72,0xf5,0xbc,0x5c }, + { 0x05,0xbe,0xd5,0x06 }, { 0x0c,0xb3,0xde,0x08 }, + { 0x17,0xa4,0xc3,0x1a }, { 0x1e,0xa9,0xc8,0x14 }, + { 0x21,0x8a,0xf9,0x3e }, { 0x28,0x87,0xf2,0x30 }, + { 0x33,0x90,0xef,0x22 }, { 0x3a,0x9d,0xe4,0x2c }, + { 0xdd,0x06,0x3d,0x96 }, { 0xd4,0x0b,0x36,0x98 }, + { 0xcf,0x1c,0x2b,0x8a }, { 0xc6,0x11,0x20,0x84 }, + { 0xf9,0x32,0x11,0xae }, { 0xf0,0x3f,0x1a,0xa0 }, + { 0xeb,0x28,0x07,0xb2 }, { 0xe2,0x25,0x0c,0xbc }, + { 0x95,0x6e,0x65,0xe6 }, { 0x9c,0x63,0x6e,0xe8 }, + { 0x87,0x74,0x73,0xfa }, { 0x8e,0x79,0x78,0xf4 }, + { 0xb1,0x5a,0x49,0xde }, { 0xb8,0x57,0x42,0xd0 }, + { 0xa3,0x40,0x5f,0xc2 }, { 0xaa,0x4d,0x54,0xcc }, + { 0xec,0xda,0xf7,0x41 }, { 0xe5,0xd7,0xfc,0x4f }, + { 0xfe,0xc0,0xe1,0x5d }, { 0xf7,0xcd,0xea,0x53 }, + { 0xc8,0xee,0xdb,0x79 }, { 0xc1,0xe3,0xd0,0x77 }, + { 0xda,0xf4,0xcd,0x65 }, { 0xd3,0xf9,0xc6,0x6b }, + { 0xa4,0xb2,0xaf,0x31 }, { 0xad,0xbf,0xa4,0x3f }, + { 0xb6,0xa8,0xb9,0x2d }, { 0xbf,0xa5,0xb2,0x23 }, + { 0x80,0x86,0x83,0x09 }, { 0x89,0x8b,0x88,0x07 }, + { 0x92,0x9c,0x95,0x15 }, { 0x9b,0x91,0x9e,0x1b }, + { 0x7c,0x0a,0x47,0xa1 }, { 0x75,0x07,0x4c,0xaf }, + { 0x6e,0x10,0x51,0xbd }, { 0x67,0x1d,0x5a,0xb3 }, + { 0x58,0x3e,0x6b,0x99 }, { 0x51,0x33,0x60,0x97 }, + { 0x4a,0x24,0x7d,0x85 }, { 0x43,0x29,0x76,0x8b }, + { 0x34,0x62,0x1f,0xd1 }, { 0x3d,0x6f,0x14,0xdf }, + { 0x26,0x78,0x09,0xcd }, { 0x2f,0x75,0x02,0xc3 }, + { 0x10,0x56,0x33,0xe9 }, { 0x19,0x5b,0x38,0xe7 }, + { 0x02,0x4c,0x25,0xf5 }, { 0x0b,0x41,0x2e,0xfb }, + { 0xd7,0x61,0x8c,0x9a }, { 0xde,0x6c,0x87,0x94 }, + { 0xc5,0x7b,0x9a,0x86 }, { 0xcc,0x76,0x91,0x88 }, + { 0xf3,0x55,0xa0,0xa2 }, { 0xfa,0x58,0xab,0xac }, + { 0xe1,0x4f,0xb6,0xbe }, { 0xe8,0x42,0xbd,0xb0 }, + { 0x9f,0x09,0xd4,0xea }, { 0x96,0x04,0xdf,0xe4 }, + { 0x8d,0x13,0xc2,0xf6 }, { 0x84,0x1e,0xc9,0xf8 }, + { 0xbb,0x3d,0xf8,0xd2 }, { 0xb2,0x30,0xf3,0xdc }, + { 0xa9,0x27,0xee,0xce }, { 0xa0,0x2a,0xe5,0xc0 }, + { 0x47,0xb1,0x3c,0x7a }, { 0x4e,0xbc,0x37,0x74 }, + { 0x55,0xab,0x2a,0x66 }, { 0x5c,0xa6,0x21,0x68 }, + { 0x63,0x85,0x10,0x42 }, { 0x6a,0x88,0x1b,0x4c }, + { 0x71,0x9f,0x06,0x5e }, { 0x78,0x92,0x0d,0x50 }, + { 0x0f,0xd9,0x64,0x0a }, { 0x06,0xd4,0x6f,0x04 }, + { 0x1d,0xc3,0x72,0x16 }, { 0x14,0xce,0x79,0x18 }, + { 0x2b,0xed,0x48,0x32 }, { 0x22,0xe0,0x43,0x3c }, + { 0x39,0xf7,0x5e,0x2e }, { 0x30,0xfa,0x55,0x20 }, + { 0x9a,0xb7,0x01,0xec }, { 0x93,0xba,0x0a,0xe2 }, + { 0x88,0xad,0x17,0xf0 }, { 0x81,0xa0,0x1c,0xfe }, + { 0xbe,0x83,0x2d,0xd4 }, { 0xb7,0x8e,0x26,0xda }, + { 0xac,0x99,0x3b,0xc8 }, { 0xa5,0x94,0x30,0xc6 }, + { 0xd2,0xdf,0x59,0x9c }, { 0xdb,0xd2,0x52,0x92 }, + { 0xc0,0xc5,0x4f,0x80 }, { 0xc9,0xc8,0x44,0x8e }, + { 0xf6,0xeb,0x75,0xa4 }, { 0xff,0xe6,0x7e,0xaa }, + { 0xe4,0xf1,0x63,0xb8 }, { 0xed,0xfc,0x68,0xb6 }, + { 0x0a,0x67,0xb1,0x0c }, { 0x03,0x6a,0xba,0x02 }, + { 0x18,0x7d,0xa7,0x10 }, { 0x11,0x70,0xac,0x1e }, + { 0x2e,0x53,0x9d,0x34 }, { 0x27,0x5e,0x96,0x3a }, + { 0x3c,0x49,0x8b,0x28 }, { 0x35,0x44,0x80,0x26 }, + { 0x42,0x0f,0xe9,0x7c }, { 0x4b,0x02,0xe2,0x72 }, + { 0x50,0x15,0xff,0x60 }, { 0x59,0x18,0xf4,0x6e }, + { 0x66,0x3b,0xc5,0x44 }, { 0x6f,0x36,0xce,0x4a }, + { 0x74,0x21,0xd3,0x58 }, { 0x7d,0x2c,0xd8,0x56 }, + { 0xa1,0x0c,0x7a,0x37 }, { 0xa8,0x01,0x71,0x39 }, + { 0xb3,0x16,0x6c,0x2b }, { 0xba,0x1b,0x67,0x25 }, + { 0x85,0x38,0x56,0x0f }, { 0x8c,0x35,0x5d,0x01 }, + { 0x97,0x22,0x40,0x13 }, { 0x9e,0x2f,0x4b,0x1d }, + { 0xe9,0x64,0x22,0x47 }, { 0xe0,0x69,0x29,0x49 }, + { 0xfb,0x7e,0x34,0x5b }, { 0xf2,0x73,0x3f,0x55 }, + { 0xcd,0x50,0x0e,0x7f }, { 0xc4,0x5d,0x05,0x71 }, + { 0xdf,0x4a,0x18,0x63 }, { 0xd6,0x47,0x13,0x6d }, + { 0x31,0xdc,0xca,0xd7 }, { 0x38,0xd1,0xc1,0xd9 }, + { 0x23,0xc6,0xdc,0xcb }, { 0x2a,0xcb,0xd7,0xc5 }, + { 0x15,0xe8,0xe6,0xef }, { 0x1c,0xe5,0xed,0xe1 }, + { 0x07,0xf2,0xf0,0xf3 }, { 0x0e,0xff,0xfb,0xfd }, + { 0x79,0xb4,0x92,0xa7 }, { 0x70,0xb9,0x99,0xa9 }, + { 0x6b,0xae,0x84,0xbb }, { 0x62,0xa3,0x8f,0xb5 }, + { 0x5d,0x80,0xbe,0x9f }, { 0x54,0x8d,0xb5,0x91 }, + { 0x4f,0x9a,0xa8,0x83 }, { 0x46,0x97,0xa3,0x8d } +}; + +static const u32 rcon[30] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, + 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, + 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 +}; + + + +static void +burn_stack (int bytes) +{ + char buf[64]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + +/* Perform the key setup. + */ +static int +do_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) +{ + static int initialized = 0; + static const char *selftest_failed=0; + int ROUNDS; + byte k[MAXKC][4]; + int i,j, r, t, rconpointer = 0; + byte tk[MAXKC][4]; + int KC; + /* space for automatic variables is about 64 + 11*int */ + + if (!initialized) { + initialized = 1; + selftest_failed = selftest (); + if( selftest_failed ) + fprintf(stderr, "%s\n", selftest_failed ); + } + if( selftest_failed ) + return G10ERR_SELFTEST_FAILED; + + if( keylen == 128/8 ) { + ROUNDS = 10; + KC = 4; + } + else if ( keylen == 192/8 ) { + ROUNDS = 12; + KC = 6; + } + else if ( keylen == 256/8 ) { + ROUNDS = 14; + KC = 8; + } + else + return G10ERR_WRONG_KEYLEN; + + ctx->ROUNDS = ROUNDS; + ctx->decryption_prepared = 0; + + for (i = 0; i < keylen; i++) { + k[i >> 2][i & 3] = key[i]; + } + #define W (ctx->keySched) + + for (j = KC-1; j >= 0; j--) { + *((u32*)tk[j]) = *((u32*)k[j]); + } + r = 0; + t = 0; + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((u32*)W[r][t]) = *((u32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + + while (r < ROUNDS + 1) { + /* while not enough round key material calculated */ + /* calculate new values */ + tk[0][0] ^= S[tk[KC-1][1]]; + tk[0][1] ^= S[tk[KC-1][2]]; + tk[0][2] ^= S[tk[KC-1][3]]; + tk[0][3] ^= S[tk[KC-1][0]]; + tk[0][0] ^= rcon[rconpointer++]; + + if (KC != 8) { + for (j = 1; j < KC; j++) { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + } else { + for (j = 1; j < KC/2; j++) { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + tk[KC/2][0] ^= S[tk[KC/2 - 1][0]]; + tk[KC/2][1] ^= S[tk[KC/2 - 1][1]]; + tk[KC/2][2] ^= S[tk[KC/2 - 1][2]]; + tk[KC/2][3] ^= S[tk[KC/2 - 1][3]]; + for (j = KC/2 + 1; j < KC; j++) { + *((u32*)tk[j]) ^= *((u32*)tk[j-1]); + } + } + /* copy values into round key array */ + for (j = 0; (j < KC) && (r < ROUNDS + 1); ) { + for (; (j < KC) && (t < 4); j++, t++) { + *((u32*)W[r][t]) = *((u32*)tk[j]); + } + if (t == 4) { + r++; + t = 0; + } + } + } + + #undef W + return 0; +} + +static int +rijndael_setkey (RIJNDAEL_context *ctx, const byte *key, const unsigned keylen) +{ + int rc = do_setkey (ctx, key, keylen); + burn_stack ( 100 + 16*sizeof(int)); + return rc; +} + +/* make a decryption key from an encryption key */ +static void +prepare_decryption( RIJNDAEL_context *ctx ) +{ + int r; + byte *w; + + for (r=0; r < MAXROUNDS+1; r++ ) { + *((u32*)ctx->keySched2[r][0]) = *((u32*)ctx->keySched[r][0]); + *((u32*)ctx->keySched2[r][1]) = *((u32*)ctx->keySched[r][1]); + *((u32*)ctx->keySched2[r][2]) = *((u32*)ctx->keySched[r][2]); + *((u32*)ctx->keySched2[r][3]) = *((u32*)ctx->keySched[r][3]); + } + #define W (ctx->keySched2) + for (r = 1; r < ctx->ROUNDS; r++) { + w = W[r][0]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][1]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][2]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + + w = W[r][3]; + *((u32*)w) = *((u32*)U1[w[0]]) ^ *((u32*)U2[w[1]]) + ^ *((u32*)U3[w[2]]) ^ *((u32*)U4[w[3]]); + } + #undef W +} + + + +/* Encrypt one block. A and B may be the same. */ +static void +do_encrypt (const RIJNDAEL_context *ctx, byte *b, const byte *a) +{ + int r; + byte temp[4][4]; + int ROUNDS = ctx->ROUNDS; + #define rk (ctx->keySched) + + *((u32*)temp[0]) = *((u32*)(a )) ^ *((u32*)rk[0][0]); + *((u32*)temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[0][1]); + *((u32*)temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[0][2]); + *((u32*)temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[0][3]); + *((u32*)(b )) = *((u32*)T1[temp[0][0]]) + ^ *((u32*)T2[temp[1][1]]) + ^ *((u32*)T3[temp[2][2]]) + ^ *((u32*)T4[temp[3][3]]); + *((u32*)(b + 4)) = *((u32*)T1[temp[1][0]]) + ^ *((u32*)T2[temp[2][1]]) + ^ *((u32*)T3[temp[3][2]]) + ^ *((u32*)T4[temp[0][3]]); + *((u32*)(b + 8)) = *((u32*)T1[temp[2][0]]) + ^ *((u32*)T2[temp[3][1]]) + ^ *((u32*)T3[temp[0][2]]) + ^ *((u32*)T4[temp[1][3]]); + *((u32*)(b +12)) = *((u32*)T1[temp[3][0]]) + ^ *((u32*)T2[temp[0][1]]) + ^ *((u32*)T3[temp[1][2]]) + ^ *((u32*)T4[temp[2][3]]); + for (r = 1; r < ROUNDS-1; r++) { + *((u32*)temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); + *((u32*)temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); + *((u32*)temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); + *((u32*)temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); + + *((u32*)(b )) = *((u32*)T1[temp[0][0]]) + ^ *((u32*)T2[temp[1][1]]) + ^ *((u32*)T3[temp[2][2]]) + ^ *((u32*)T4[temp[3][3]]); + *((u32*)(b + 4)) = *((u32*)T1[temp[1][0]]) + ^ *((u32*)T2[temp[2][1]]) + ^ *((u32*)T3[temp[3][2]]) + ^ *((u32*)T4[temp[0][3]]); + *((u32*)(b + 8)) = *((u32*)T1[temp[2][0]]) + ^ *((u32*)T2[temp[3][1]]) + ^ *((u32*)T3[temp[0][2]]) + ^ *((u32*)T4[temp[1][3]]); + *((u32*)(b +12)) = *((u32*)T1[temp[3][0]]) + ^ *((u32*)T2[temp[0][1]]) + ^ *((u32*)T3[temp[1][2]]) + ^ *((u32*)T4[temp[2][3]]); + } + /* last round is special */ + *((u32*)temp[0]) = *((u32*)(b )) ^ *((u32*)rk[ROUNDS-1][0]); + *((u32*)temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[ROUNDS-1][1]); + *((u32*)temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[ROUNDS-1][2]); + *((u32*)temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[ROUNDS-1][3]); + b[ 0] = T1[temp[0][0]][1]; + b[ 1] = T1[temp[1][1]][1]; + b[ 2] = T1[temp[2][2]][1]; + b[ 3] = T1[temp[3][3]][1]; + b[ 4] = T1[temp[1][0]][1]; + b[ 5] = T1[temp[2][1]][1]; + b[ 6] = T1[temp[3][2]][1]; + b[ 7] = T1[temp[0][3]][1]; + b[ 8] = T1[temp[2][0]][1]; + b[ 9] = T1[temp[3][1]][1]; + b[10] = T1[temp[0][2]][1]; + b[11] = T1[temp[1][3]][1]; + b[12] = T1[temp[3][0]][1]; + b[13] = T1[temp[0][1]][1]; + b[14] = T1[temp[1][2]][1]; + b[15] = T1[temp[2][3]][1]; + *((u32*)(b )) ^= *((u32*)rk[ROUNDS][0]); + *((u32*)(b+ 4)) ^= *((u32*)rk[ROUNDS][1]); + *((u32*)(b+ 8)) ^= *((u32*)rk[ROUNDS][2]); + *((u32*)(b+12)) ^= *((u32*)rk[ROUNDS][3]); + #undef rk +} + +static void +rijndael_encrypt (const RIJNDAEL_context *ctx, byte *b, const byte *a) +{ + do_encrypt (ctx, b, a); + burn_stack (16 + 2*sizeof(int)); +} + + +/* Decrypt one block. a and b may be the same. */ +static void +do_decrypt (RIJNDAEL_context *ctx, byte *b, const byte *a) +{ + #define rk (ctx->keySched2) + int ROUNDS = ctx->ROUNDS; + int r; + byte temp[4][4]; + + if ( !ctx->decryption_prepared ) { + prepare_decryption ( ctx ); + burn_stack (64); + ctx->decryption_prepared = 1; + } + + *((u32*)temp[0]) = *((u32*)(a )) ^ *((u32*)rk[ROUNDS][0]); + *((u32*)temp[1]) = *((u32*)(a+ 4)) ^ *((u32*)rk[ROUNDS][1]); + *((u32*)temp[2]) = *((u32*)(a+ 8)) ^ *((u32*)rk[ROUNDS][2]); + *((u32*)temp[3]) = *((u32*)(a+12)) ^ *((u32*)rk[ROUNDS][3]); + + *((u32*)(b )) = *((u32*)T5[temp[0][0]]) + ^ *((u32*)T6[temp[3][1]]) + ^ *((u32*)T7[temp[2][2]]) + ^ *((u32*)T8[temp[1][3]]); + *((u32*)(b+ 4)) = *((u32*)T5[temp[1][0]]) + ^ *((u32*)T6[temp[0][1]]) + ^ *((u32*)T7[temp[3][2]]) + ^ *((u32*)T8[temp[2][3]]); + *((u32*)(b+ 8)) = *((u32*)T5[temp[2][0]]) + ^ *((u32*)T6[temp[1][1]]) + ^ *((u32*)T7[temp[0][2]]) + ^ *((u32*)T8[temp[3][3]]); + *((u32*)(b+12)) = *((u32*)T5[temp[3][0]]) + ^ *((u32*)T6[temp[2][1]]) + ^ *((u32*)T7[temp[1][2]]) + ^ *((u32*)T8[temp[0][3]]); + for (r = ROUNDS-1; r > 1; r--) { + *((u32*)temp[0]) = *((u32*)(b )) ^ *((u32*)rk[r][0]); + *((u32*)temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[r][1]); + *((u32*)temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[r][2]); + *((u32*)temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[r][3]); + *((u32*)(b )) = *((u32*)T5[temp[0][0]]) + ^ *((u32*)T6[temp[3][1]]) + ^ *((u32*)T7[temp[2][2]]) + ^ *((u32*)T8[temp[1][3]]); + *((u32*)(b+ 4)) = *((u32*)T5[temp[1][0]]) + ^ *((u32*)T6[temp[0][1]]) + ^ *((u32*)T7[temp[3][2]]) + ^ *((u32*)T8[temp[2][3]]); + *((u32*)(b+ 8)) = *((u32*)T5[temp[2][0]]) + ^ *((u32*)T6[temp[1][1]]) + ^ *((u32*)T7[temp[0][2]]) + ^ *((u32*)T8[temp[3][3]]); + *((u32*)(b+12)) = *((u32*)T5[temp[3][0]]) + ^ *((u32*)T6[temp[2][1]]) + ^ *((u32*)T7[temp[1][2]]) + ^ *((u32*)T8[temp[0][3]]); + } + /* last round is special */ + *((u32*)temp[0]) = *((u32*)(b )) ^ *((u32*)rk[1][0]); + *((u32*)temp[1]) = *((u32*)(b+ 4)) ^ *((u32*)rk[1][1]); + *((u32*)temp[2]) = *((u32*)(b+ 8)) ^ *((u32*)rk[1][2]); + *((u32*)temp[3]) = *((u32*)(b+12)) ^ *((u32*)rk[1][3]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + *((u32*)(b )) ^= *((u32*)rk[0][0]); + *((u32*)(b+ 4)) ^= *((u32*)rk[0][1]); + *((u32*)(b+ 8)) ^= *((u32*)rk[0][2]); + *((u32*)(b+12)) ^= *((u32*)rk[0][3]); + #undef rk +} + +static void +rijndael_decrypt (RIJNDAEL_context *ctx, byte *b, const byte *a) +{ + do_decrypt (ctx, b, a); + burn_stack (16+2*sizeof(int)); +} + +/* Test a single encryption and decryption with each key size. */ + +static const char* +selftest (void) +{ + RIJNDAEL_context ctx; + byte scratch[16]; + + /* The test vectors are from the AES supplied ones; more or less + * randomly taken from ecb_tbl.txt (I=42,81,14) + */ + static const byte plaintext[16] = { + 0x01,0x4B,0xAF,0x22,0x78,0xA6,0x9D,0x33, + 0x1D,0x51,0x80,0x10,0x36,0x43,0xE9,0x9A + }; + static const byte key[16] = { + 0xE8,0xE9,0xEA,0xEB,0xED,0xEE,0xEF,0xF0, + 0xF2,0xF3,0xF4,0xF5,0xF7,0xF8,0xF9,0xFA + }; + static const byte ciphertext[16] = { + 0x67,0x43,0xC3,0xD1,0x51,0x9A,0xB4,0xF2, + 0xCD,0x9A,0x78,0xAB,0x09,0xA5,0x11,0xBD + }; + + static const byte plaintext_192[16] = { + 0x76,0x77,0x74,0x75,0xF1,0xF2,0xF3,0xF4, + 0xF8,0xF9,0xE6,0xE7,0x77,0x70,0x71,0x72 + }; + static const byte key_192[24] = { + 0x04,0x05,0x06,0x07,0x09,0x0A,0x0B,0x0C, + 0x0E,0x0F,0x10,0x11,0x13,0x14,0x15,0x16, + 0x18,0x19,0x1A,0x1B,0x1D,0x1E,0x1F,0x20 + }; + static const byte ciphertext_192[16] = { + 0x5D,0x1E,0xF2,0x0D,0xCE,0xD6,0xBC,0xBC, + 0x12,0x13,0x1A,0xC7,0xC5,0x47,0x88,0xAA + }; + + static const byte plaintext_256[16] = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 + }; + static const byte key_256[32] = { + 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10, + 0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, + 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24, + 0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E + }; + static const byte ciphertext_256[16] = { + 0x08,0x0E,0x95,0x17,0xEB,0x16,0x77,0x71, + 0x9A,0xCF,0x72,0x80,0x86,0x04,0x0A,0xE3 + }; + + rijndael_setkey (&ctx, key, sizeof(key)); + rijndael_encrypt (&ctx, scratch, plaintext); + if (memcmp (scratch, ciphertext, sizeof (ciphertext))) + return "Rijndael-128 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext, sizeof (plaintext))) + return "Rijndael-128 test decryption failed."; + + rijndael_setkey (&ctx, key_192, sizeof(key_192)); + rijndael_encrypt (&ctx, scratch, plaintext_192); + if (memcmp (scratch, ciphertext_192, sizeof (ciphertext_192))) + return "Rijndael-192 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext_192, sizeof (plaintext_192))) + return "Rijndael-192 test decryption failed."; + + rijndael_setkey (&ctx, key_256, sizeof(key_256)); + rijndael_encrypt (&ctx, scratch, plaintext_256); + if (memcmp (scratch, ciphertext_256, sizeof (ciphertext_256))) + return "Rijndael-256 test encryption failed."; + rijndael_decrypt (&ctx, scratch, scratch); + if (memcmp (scratch, plaintext_256, sizeof (plaintext_256))) + return "Rijndael-256 test decryption failed."; + + return NULL; +} + +#ifdef IS_MODULE +static +#endif + const char * +rijndael_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==7? 128 : algo==8? 192 : 256; + *blocksize = 16; + *contextsize = sizeof (RIJNDAEL_context); + + *(int (**)(RIJNDAEL_context*, const byte*, const unsigned))r_setkey + = rijndael_setkey; + *(void (**)(const RIJNDAEL_context*, byte*, const byte*))r_encrypt + = rijndael_encrypt; + *(void (**)(RIJNDAEL_context*, byte*, const byte*))r_decrypt + = rijndael_decrypt; + + if( algo == 7 ) + return "AES"; + if (algo == 8) + return "AES192"; + if (algo == 9) + return "AES256"; + return NULL; +} + + +#ifdef IS_MODULE +static +const char * const gnupgext_version = "RIJNDAEL ($Revision$)"; + +static struct { + int class; + int version; + int value; + void (*func)(void); +} func_table[] = { + { 20, 1, 0, (void(*)(void))rijndael_get_info }, + { 21, 1, 7 }, + { 21, 1, 8 }, + { 21, 1, 9 }, +}; + + + +/**************** + * 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) + */ +static +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; +} +#endif + + + + + + + + + diff --git a/cipher/rmd.h b/cipher/rmd.h new file mode 100644 index 000000000..917e04a26 --- /dev/null +++ b/cipher/rmd.h @@ -0,0 +1,35 @@ +/* rmd.h - RIPE-MD hash functions + * Copyright (C) 1998, 1999, 2000, 2001 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_RMD_H +#define G10_RMD_H + + +/* we need this here because random.c must have direct access */ +typedef struct { + u32 h0,h1,h2,h3,h4; + u32 nblocks; + byte buf[64]; + int count; +} RMD160_CONTEXT; + +void rmd160_init( RMD160_CONTEXT *hd ); +void rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer ); + +#endif /*G10_RMD_H*/ diff --git a/cipher/rmd160.c b/cipher/rmd160.c new file mode 100644 index 000000000..e35647af6 --- /dev/null +++ b/cipher/rmd160.c @@ -0,0 +1,652 @@ +/* rmd160.c - RIPE-MD160 + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include "util.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 + */ + +static void +burn_stack (int bytes) +{ + char buf[150]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + + +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 ); + burn_stack (108+5*sizeof(void*)); + 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; + } + burn_stack (108+5*sizeof(void*)); + 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 */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if( (lsb += hd->count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + 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 ); + burn_stack (108+5*sizeof(void*)); + + 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; + *(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: +#ifndef __riscos__ + ret = func_table[i].func; +#else /* __riscos__ */ + ret = (void *) func_table[i].func; +#endif /* __riscos__ */ + 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/rmd160test.c b/cipher/rmd160test.c new file mode 100644 index 000000000..14afb435b --- /dev/null +++ b/cipher/rmd160test.c @@ -0,0 +1,63 @@ +/* rmd160test.c - ripe md160 test program + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include + +#include "util.h" +#include "rmd.h" + +static void +usage(void) +{ + fprintf(stderr, "usage: rmd160test\n"); + exit(1); +} + + +int +main(int argc, char **argv) +{ + RMDHANDLE rmdhd; + int i, n; + byte buf[100], *p; + + if( argc > 1 ) + usage(); + + rmdhd = rmd160_open(0); + #if 1 + while( (n = fread( buf, 1, 100, stdin )) > 0 ) + rmd160_write(rmdhd, buf, n); + #else + for(i=0; i < 1000000; i++ ) + rmd160_putchar(rmdhd, 'a'); + #endif + p = rmd160_final(rmdhd); + for(i=0; i < 20; i++, p++ ) + printf("%02x", *p ); + putchar('\n'); + + rmd160_close(rmdhd); + return 0; +} + diff --git a/cipher/rndegd.c b/cipher/rndegd.c new file mode 100644 index 000000000..64226eabb --- /dev/null +++ b/cipher/rndegd.c @@ -0,0 +1,255 @@ +/* rndegd.c - interface to the EGD + * Copyright (C) 1999, 2000, 2001 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "types.h" +#include "util.h" +#include "ttyio.h" +#include "dynload.h" +#include "cipher.h" + +#ifdef IS_MODULE + #define _(a) (a) +#else + #include "i18n.h" +#endif + +#ifndef offsetof +#define offsetof(type, member) ((size_t) &((type *)0)->member) +#endif + +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. + * 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 ) { + const char *bname = NULL; + char *name; + struct sockaddr_un addr; + int addr_len; + + #ifdef EGD_SOCKET_NAME + bname = EGD_SOCKET_NAME; + #endif + if ( !bname || !*bname ) + bname = "=entropy"; + + if ( *bname == '=' && bname[1] ) + name = make_filename( g10_opt_homedir, bname+1 , NULL ); + else + name = make_filename( bname , NULL ); + + if ( strlen(name)+1 >= sizeof addr.sun_path ) + g10_log_fatal ("EGD socketname is too long\n"); + + memset( &addr, 0, sizeof addr ); + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, name ); + addr_len = offsetof( struct sockaddr_un, sun_path ) + + strlen( addr.sun_path ); + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if( fd == -1 ) + 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) ); + m_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; + int (*func)(void); +} func_table[] = { + { 40, 1, (int (*)(void))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/rndlinux.c b/cipher/rndlinux.c new file mode 100644 index 000000000..be333d2b3 --- /dev/null +++ b/cipher/rndlinux.c @@ -0,0 +1,242 @@ +/* rndlinux.c - raw random number for OSes with /dev/random + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_GETTIMEOFDAY + #include +#endif +#include +#include +#include +#if 0 + #ifdef HAVE_LINUX_RANDOM_H + #include + #include + #include + #endif +#endif +#include "types.h" +#include "util.h" +#include "ttyio.h" +#include "dynload.h" + +#ifdef IS_MODULE + #define _(a) (a) +#else + #include "i18n.h" +#endif + +static int open_device( const char *name, int minor ); +static int gather_random( void (*add)(const void*, size_t, int), int requester, + size_t length, int level ); + +#if 0 +#ifdef HAVE_DEV_RANDOM_IOCTL +static ulong +get_entropy_count( int fd ) +{ + ulong count; + + if( ioctl( fd, RNDGETENTCNT, &count ) == -1 ) + g10_log_fatal("ioctl(RNDGETENTCNT) failed: %s\n", strerror(errno) ); + return count; +} +#endif +#endif + +/**************** + * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists), ...) + */ +static int +open_device( const char *name, int minor ) +{ + int fd; + struct stat sb; + + fd = open( name, O_RDONLY ); + if( fd == -1 ) + g10_log_fatal("can't open %s: %s\n", name, strerror(errno) ); + if( fstat( fd, &sb ) ) + g10_log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); + /* Don't check device type for better portability */ + /* if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) + g10_log_fatal("invalid random device!\n" ); */ + return fd; +} + + +/**************** + * Note: Using a level of 0 should never block and better add nothing + * to the pool. This is easy to accomplish with /dev/urandom. + */ +static int +gather_random( void (*add)(const void*, size_t, int), int requester, + size_t length, int level ) +{ + static int fd_urandom = -1; + static int fd_random = -1; + int fd; + int n; + int warn=0; + byte buffer[768]; + + if( level >= 2 ) { + if( fd_random == -1 ) + fd_random = open_device( NAME_OF_DEV_RANDOM, 8 ); + fd = fd_random; + } + else { + /* this will also be used for elve 0 but by using /dev/urandom + * we can be sure that oit will never block. */ + if( fd_urandom == -1 ) + fd_urandom = open_device( NAME_OF_DEV_URANDOM, 9 ); + fd = fd_urandom; + } + + #if 0 + #ifdef HAVE_DEV_RANDOM_IOCTL + g10_log_info("entropy count of %d is %lu\n", fd, get_entropy_count(fd) ); + #endif + #endif + while( length ) { + fd_set rfds; + struct timeval tv; + int rc; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + tv.tv_sec = 3; + tv.tv_usec = 0; + if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) { + if( !warn ) + #ifdef IS_MODULE + fprintf(stderr, + #else + tty_printf( + #endif +_("\n" +"Not enough random bytes available. Please do some other work to give\n" +"the OS a chance to collect more entropy! (Need %d more bytes)\n"), (int)length ); + warn = 1; + continue; + } + else if( rc == -1 ) { + #ifdef IS_MODULE + fprintf(stderr, + #else + tty_printf( + #endif + "select() error: %s\n", strerror(errno)); + continue; + } + + do { + int nbytes = length < sizeof(buffer)? length : sizeof(buffer); + n = read(fd, buffer, nbytes ); + if( n >= 0 && n > nbytes ) { + g10_log_error("bogus read from random device (n=%d)\n", n ); + n = nbytes; + } + } while( n == -1 && errno == EINTR ); + if( n == -1 ) + g10_log_fatal("read error on random device: %s\n", strerror(errno)); + (*add)( buffer, n, requester ); + length -= n; + } + memset(buffer, 0, sizeof(buffer) ); + + return 0; /* success */ +} + + + +#ifndef IS_MODULE +static +#endif +const char * const gnupgext_version = "RNDLINUX ($Revision$)"; + +static struct { + int class; + int version; + int (*func)(void); +} func_table[] = { + { 40, 1, (int (*)(void))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 gather_random 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 +rndlinux_constructor(void) +{ + register_internal_cipher_extension( gnupgext_version, + gnupgext_enum_func ); +} +#endif + diff --git a/cipher/rndriscos.c b/cipher/rndriscos.c new file mode 100644 index 000000000..47144517a --- /dev/null +++ b/cipher/rndriscos.c @@ -0,0 +1,147 @@ +/* rndriscos.c - raw random number for RISC OS + * Copyright (C) 2001 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 +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "dynload.h" + +static int init_device(void); +static int gather_random(void (*add)(const void*, size_t, int), int requester, + size_t length, int level); + +#define CryptRandom_Byte 0x51980 + +/**************** + * Used to load the CryptRandom module if it isn't already loaded + */ +static int +init_device(void) +{ + _kernel_swi_regs r; + + /* Is CryptRandom already loaded? */ + r.r[0] = 18; + r.r[1] = (int) "CryptRandom"; + if (!_kernel_swi(OS_Module, &r, &r)) + return 1; + + /* Is it named CryptRand and inside GnuPG$Path? */ + r.r[0] = 1; + r.r[1] = (int) "GnuPG:CryptRand"; + if (!_kernel_swi(OS_Module, &r, &r)) + return 1; + + /* Is it named CryptRandom and inside GnuPG$Path? */ + r.r[0] = 1; + r.r[1] = (int) "GnuPG:CryptRandom"; + if (!_kernel_swi(OS_Module, &r, &r)) + return 1; + + /* Can't find CryptRandom in the default locations */ + g10_log_fatal("Can't load module CryptRandom.\n"); +} + + +/**************** + */ +static int +gather_random(void (*add)(const void*, size_t, int), int requester, + size_t length, int level) +{ + static int initialized = 0; + int n; + byte buffer[768]; + _kernel_swi_regs r; + _kernel_oserror *e; + + if (!initialized) + initialized = init_device(); + + while (length) { + int nbytes = length < sizeof(buffer) ? length : sizeof(buffer); + + for (n = 0; n < nbytes; n++) { + if (e = _kernel_swi(CryptRandom_Byte, &r, &r)) + g10_log_fatal("CryptRandom module isn't working as expected!\n"); + buffer[n] = (byte) r.r[0]; + } + + (*add)(buffer, n, requester); + length -= n; + } + memset(buffer, 0, sizeof(buffer)); + + return 0; /* success */ +} + + + +#ifndef IS_MODULE +static +#endif +const char * const gnupgext_version = "RNDRISCOS ($Revision$)"; + +static struct { + int class; + int version; + int (*func)(void); +} func_table[] = { + { 40, 1, (int (*)(void))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 = (void*) func_table[i].func; + i++; + } while ( what && what != *class ); + + *sequence = i; + return ret; +} + +#ifndef IS_MODULE +void +rndriscos_constructor(void) +{ + register_internal_cipher_extension( gnupgext_version, + gnupgext_enum_func ); +} +#endif + diff --git a/cipher/rndunix.c b/cipher/rndunix.c new file mode 100644 index 000000000..a46b5ec97 --- /dev/null +++ b/cipher/rndunix.c @@ -0,0 +1,915 @@ +/**************************************************************************** + * * + * * + * 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, 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 */ + + + +/* General includes */ + +#include +#include +#include +#include +#include + +/* 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 +#include +#include +#ifndef __QNX__ +#include +#include +#endif /* __QNX__ */ +#include /* SCO and SunOS need this before resource.h */ +#ifndef __QNX__ +#include +#endif /* __QNX__ */ +#if defined( _AIX ) || defined( __QNX__ ) +#include +#endif /* _AIX || __QNX__ */ +#ifndef __QNX__ +#include +#include +#include +#endif /* __QNX__ */ +#include +#include /* Verschiedene komische Typen */ +#if defined( __hpux ) && ( OS_VERSION == 9 ) +#include +#endif /* __hpux 9.x, after that it's in unistd.h */ +#include +/* #include */ +#ifdef __QNX__ +#include +#include +#endif /* __QNX__ */ +#include + +#include "types.h" /* for byte and u32 typedefs */ +#ifndef IS_MODULE +#include "dynload.h" +#endif +#include "util.h" + +#ifndef EAGAIN +#define EAGAIN EWOULDBLOCK +#endif +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#endif +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 +#endif + +#define GATHER_BUFSIZE 49152 /* Usually about 25K are filled */ + +/* The structure containing information on random-data sources. Each + * record contains the source and a relative estimate of its usefulness + * (weighting) which is used to scale the number of kB of output from the + * source (total = data_bytes / usefulness). Usually the weighting is in the + * range 1-3 (or 0 for especially useless sources), resulting in a usefulness + * rating of 1...3 for each kB of source output (or 0 for the useless + * sources). + * + * If the source is constantly changing (certain types of network statistics + * have this characteristic) but the amount of output is small, the weighting + * is given as a negative value to indicate that the output should be treated + * as if a minimum of 1K of output had been obtained. If the source produces + * a lot of output then the scale factor is fractional, resulting in a + * usefulness rating of < 1 for each kB of source output. + * + * In order to provide enough randomness to satisfy the requirements for a + * slow poll, we need to accumulate at least 20 points of usefulness (a + * typical system should get about 30 points). + * + * Some potential options are missed out because of special considerations. + * pstat -i and pstat -f can produce amazing amounts of output (the record + * is 600K on an Oracle server) which floods the buffer and doesn't yield + * anything useful (apart from perhaps increasing the entropy of the vmstat + * output a bit), so we don't bother with this. pstat in general produces + * quite a bit of output, but it doesn't change much over time, so it gets + * very low weightings. netstat -s produces constantly-changing output but + * also produces quite a bit of it, so it only gets a weighting of 2 rather + * than 3. The same holds for netstat -in, which gets 1 rather than 2. + * + * Some binaries are stored in different locations on different systems so + * alternative paths are given for them. The code sorts out which one to + * run by itself, once it finds an exectable somewhere it moves on to the + * next source. The sources are arranged roughly in their order of + * usefulness, occasionally sources which provide a tiny amount of + * relatively useless data are placed ahead of ones which provide a large + * amount of possibly useful data because another 100 bytes can't hurt, and + * it means the buffer won't be swamped by one or two high-output sources. + * All the high-output sources are clustered towards the end of the list + * for this reason. Some binaries are checked for in a certain order, for + * example under Slowaris /usr/ucb/ps understands aux as an arg, but the + * others don't. Some systems have conditional defines enabling alternatives + * to commands which don't understand the usual options but will provide + * enough output (in the form of error messages) to look like they're the + * real thing, causing alternative options to be skipped (we can't check the + * return either because some commands return peculiar, non-zero status even + * when they're working correctly). + * + * In order to maximise use of the buffer, the code performs a form of run- + * length compression on its input where a repeated sequence of bytes is + * replaced by the occurrence count mod 256. Some commands output an awful + * lot of whitespace, this measure greatly increases the amount of data we + * can fit in the buffer. + * + * When we scale the weighting using the SC() macro, some preprocessors may + * give a division by zero warning for the most obvious expression + * 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero + * trap), so we define a value SC_0 which evaluates to zero when fed to + * '1024 / SC_0' */ + +#define SC( weight ) ( 1024 / weight ) /* Scale factor */ +#define SC_0 16384 /* SC( SC_0 ) evalutes to 0 */ + +static struct RI { + const char *path; /* Path to check for existence of source */ + const char *arg; /* Args for source */ + const int usefulness; /* Usefulness of source */ + FILE *pipe; /* Pipe to source as FILE * */ + int pipeFD; /* Pipe to source as FD */ + pid_t pid; /* pid of child for waitpid() */ + int length; /* Quantity of output produced */ + const int hasAlternative; /* Whether source has alt.location */ +} dataSources[] = { + + { "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 0}, + { "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, 0}, + { "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, 0}, + { "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, 0}, + { "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, 0 }, + { "/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1}, + { "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, 0}, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP in */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* UDP out */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* IP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0", + SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */ + { "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, 1 }, + { "/bin/df", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 1 }, + { "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 }, + { "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 0 }, +#if defined( __sgi ) || defined( __hpux ) + { "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, 1 }, +#endif /* __sgi || __hpux */ + { "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 }, + { "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/bin/ps", "-A", SC(0.3), NULL, 0, 0, 0, 0 }, /*QNX*/ + { "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0 }, + /* Unreliable source, depends on system usage */ + { "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 0 }, + { "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + /* pstat is your friend */ + { "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 1 }, +#ifdef __sgi + { "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __sgi */ +#ifdef __hpux + { "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 }, +#endif /* __hpux */ + { "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0", + SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */ + { "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/sbin/ripquery", "-nw 1 127.0.0.1", + SC(0.1), NULL, 0, 0, 0, 0 }, + { "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 }, + { "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 }, + { "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, 0 }, + /* This is very environment-dependant. If network traffic is low, it'll + * probably time out before delivering 5 packets, which is OK because + * it'll probably be fixed stuff like ARP anyway */ + { "/usr/sbin/advfsstat", "-b usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-l 2 usr_domain", + SC(0.5), NULL, 0, 0, 0, 0}, + { "/usr/sbin/advfsstat", "-p usr_domain", + SC(SC_0), NULL, 0, 0, 0, 0}, + /* This is a complex and screwball program. Some systems have things + * like rX_dmn, x = integer, for RAID systems, but the statistics are + * pretty dodgy */ +#ifdef __QNXNTO__ + { "/bin/pidin", "-F%A%B%c%d%E%I%J%K%m%M%n%N%p%P%S%s%T", SC(0.3), + NULL, 0, 0, 0, 0 }, +#endif +#if 0 + /* The following aren't enabled since they're somewhat slow and not very + * unpredictable, however they give an indication of the sort of sources + * you can use (for example the finger might be more useful on a + * firewalled internal network) */ + { "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, 0 }, + { "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html", + SC(0.9), NULL, 0, 0, 0, 0 }, + { "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, 0 }, +#endif /* 0 */ + { NULL, NULL, 0, NULL, 0, 0, 0, 0 } +}; + +static byte *gather_buffer; /* buffer for gathering random noise */ +static int gather_buffer_size; /* size of the memory buffer */ +static uid_t gatherer_uid; + +/* The message structure used to communicate with the parent */ +typedef struct { + int usefulness; /* usefulness of data */ + int ndata; /* valid bytes in data */ + char data[500]; /* gathered data */ +} GATHER_MSG; + + +#ifndef HAVE_WAITPID +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); + #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; + int (*func)(void); +} func_table[] = { + { 40, 1, (int (*)(void))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 new file mode 100644 index 000000000..484b11c52 --- /dev/null +++ b/cipher/rndw32.c @@ -0,0 +1,969 @@ +/* rndw32.c - W32 entropy gatherer + * Copyright (C) 1999, 2000, 2001 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, 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 +#include +#include +#include +#include +#include + +#include +#ifdef __CYGWIN32__ +# include +#endif + + +#include "types.h" +#include "util.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; + +/**************** + * 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 ) +{ + HANDLE hInstance; + void *addr; + unsigned int reason = 0; + unsigned int n1, n2; + 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; + } + n1 = get_internal_seed_size( slow_seeder ); + /*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);*/ + + entropy_buffer_size = n1 > n2? n1: n2; + 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 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 );*/ + (*add)( entropy_buffer, nbytes, requester ); + if( length <= nbytes ) + return 0; /* okay */ + length -= nbytes; + } +} + +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 + */ + +#ifndef TH32CS_SNAPHEAPLIST +#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 +#endif /*TH32CS_SNAPHEAPLIST*/ + +#ifndef IOCTL_DISK_PERFORMANCE +#define IOCTL_DISK_PERFORMANCE 0x00070020 +#endif +#ifndef VER_PLATFORM_WIN32_WINDOWS +#define VER_PLATFORM_WIN32_WINDOWS 1 +#endif + +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 + && ascii_strcasecmp (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_windowsNT, has_toolhelp; + + + 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_windowsNT = platform == VER_PLATFORM_WIN32_NT; + has_toolhelp = (platform == VER_PLATFORM_WIN32_WINDOWS + || (is_windowsNT && osvi.dwMajorVersion >= 5)); + + 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 ( has_toolhelp ) { + slow_gatherer_windows95 ( add, requester ); + } + if ( is_windowsNT ) { + 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; +} + +#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 000000000..e438b39cf --- /dev/null +++ b/cipher/rsa.c @@ -0,0 +1,494 @@ +/* rsa.c - RSA function + * Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn) + * Copyright (C) 2000, 2001 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 code uses an algorithm protected by U.S. Patent #4,405,829 + which expires on September 20, 2000. The patent holder placed that + patent into the public domain on Sep 6th, 2000. +*/ + +#include +#include +#include +#include +#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 filled 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-1)(q-1) */ + MPI g; + MPI f; + + /* make sure that nbits is even so that we generate p, q of equal size */ + if ( (nbits&1) ) + nbits++; + + n = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); + + p = q = NULL; + do { + /* select two (very secret) primes */ + if (p) + mpi_free (p); + if (q) + mpi_free (q); + 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 the modulus */ + mpi_mul( n, p, q ); + } while ( mpi_get_nbits(n) != nbits ); + + /* 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); + + /* find an public exponent. + We use 41 as this is quite fast and more secure than the + commonly used 17. Benchmarking the RSA verify function + with a 1024 bit key yields (2001-11-08): + e=17 0.54 ms + e=41 0.75 ms + e=257 0.95 ms + e=65537 1.80 ms + */ + e = mpi_alloc( (32+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); + mpi_set_ui( e, 41); + if( !mpi_gcd(t1, e, phi) ) { + mpi_set_ui( e, 257); + if( !mpi_gcd(t1, e, phi) ) { + mpi_set_ui( e, 65537); + 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 ); +} + +#if 0 +static void +stronger_key_check ( RSA_secret_key *skey ) +{ + MPI t = mpi_alloc_secure ( 0 ); + MPI t1 = mpi_alloc_secure ( 0 ); + MPI t2 = mpi_alloc_secure ( 0 ); + MPI phi = mpi_alloc_secure ( 0 ); + + /* check that n == p * q */ + mpi_mul( t, skey->p, skey->q); + if (mpi_cmp( t, skey->n) ) + log_info ( "RSA Oops: n != p * q\n" ); + + /* check that p is less than q */ + if( mpi_cmp( skey->p, skey->q ) > 0 ) + log_info ("RSA Oops: p >= q\n"); + + + /* check that e divides neither p-1 nor q-1 */ + mpi_sub_ui(t, skey->p, 1 ); + mpi_fdiv_r(t, t, skey->e ); + if ( !mpi_cmp_ui( t, 0) ) + log_info ( "RSA Oops: e divides p-1\n" ); + mpi_sub_ui(t, skey->q, 1 ); + mpi_fdiv_r(t, t, skey->e ); + if ( !mpi_cmp_ui( t, 0) ) + log_info ( "RSA Oops: e divides q-1\n" ); + + /* check that d is correct */ + mpi_sub_ui( t1, skey->p, 1 ); + mpi_sub_ui( t2, skey->q, 1 ); + mpi_mul( phi, t1, t2 ); + mpi_gcd(t, t1, t2); + mpi_fdiv_q(t, phi, t); + mpi_invm(t, skey->e, t ); + if ( mpi_cmp(t, skey->d ) ) + log_info ( "RSA Oops: d is wrong\n"); + + /* check for crrectness of u */ + mpi_invm(t, skey->p, skey->q ); + if ( mpi_cmp(t, skey->u ) ) + log_info ( "RSA Oops: u is wrong\n"); + + log_info ( "RSA secret key check finished\n"); + + mpi_free (t); + mpi_free (t1); + mpi_free (t2); + mpi_free (phi); +} +#endif + + +/**************** + * Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT. + * + * m = c^d mod n + * + * Or faster: + * + * m1 = c ^ (d mod (p-1)) mod p + * m2 = c ^ (d mod (q-1)) mod q + * h = u * (m2 - m1) mod q + * m = m1 + h * p + * + * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY. + */ +static void +secret(MPI output, MPI input, RSA_secret_key *skey ) +{ + #if 0 + mpi_powm( output, input, skey->d, skey->n ); + #else + MPI m1 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); + MPI m2 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); + MPI h = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 ); + + /* m1 = c ^ (d mod (p-1)) mod p */ + mpi_sub_ui( h, skey->p, 1 ); + mpi_fdiv_r( h, skey->d, h ); + mpi_powm( m1, input, h, skey->p ); + /* m2 = c ^ (d mod (q-1)) mod q */ + mpi_sub_ui( h, skey->q, 1 ); + mpi_fdiv_r( h, skey->d, h ); + mpi_powm( m2, input, h, skey->q ); + /* h = u * ( m2 - m1 ) mod q */ + mpi_sub( h, m2, m1 ); + if ( mpi_is_neg( h ) ) + mpi_add ( h, h, skey->q ); + mpi_mulm( h, skey->u, h, skey->q ); + /* m = m2 + h * p */ + mpi_mul ( h, h, skey->p ); + mpi_add ( output, m1, h ); + /* ready */ + + mpi_free ( h ); + mpi_free ( m1 ); + mpi_free ( m2 ); + #endif +} + + +/********************************************* + ************** 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 *r_usage ) +{ + *npkey = 2; + *nskey = 6; + *nenc = 1; + *nsig = 1; + + switch( algo ) { + case 1: *r_usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA"; + case 2: *r_usage = PUBKEY_USAGE_ENC; return "RSA-E"; + case 3: *r_usage = PUBKEY_USAGE_SIG; return "RSA-S"; + default:*r_usage = 0; return NULL; + } +} + + + diff --git a/cipher/rsa.h b/cipher/rsa.h new file mode 100644 index 000000000..350a373ec --- /dev/null +++ b/cipher/rsa.h @@ -0,0 +1,36 @@ +/* rsa.h + * Copyright (C) 1997,1998 by Werner Koch (dd9jn) + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#ifndef G10_RSA_H +#define G10_RSA_H + +int rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int rsa_check_secret_key( int algo, MPI *skey ); +int rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); +int rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); +int rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey ); +int rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey, + int (*cmp)(void *, MPI), void *opaquev ); +unsigned rsa_get_nbits( int algo, MPI *pkey ); +const char *rsa_get_info( int algo, int *npkey, int *nskey, + int *nenc, int *nsig, int *use ); + + +#endif /*G10_RSA_H*/ diff --git a/cipher/sha1.c b/cipher/sha1.c new file mode 100644 index 000000000..77749e4ee --- /dev/null +++ b/cipher/sha1.c @@ -0,0 +1,425 @@ +/* sha1.c - SHA1 hash function + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include "util.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; + +static void +burn_stack (int bytes) +{ + char buf[128]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + +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] = rol(tm,1)) ) + +#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 ); + burn_stack (88+4*sizeof(void*)); + 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; + } + burn_stack (88+4*sizeof(void*)); + 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 */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if( (lsb += hd->count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + 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 ); + burn_stack (88+4*sizeof(void*)); + + 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; + *(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: +#ifndef __riscos__ + ret = func_table[i].func; +#else /* __riscos__ */ + ret = (void *) func_table[i].func; +#endif /* __riscos__ */ + 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/smallprime.c b/cipher/smallprime.c new file mode 100644 index 000000000..941f4ce9a --- /dev/null +++ b/cipher/smallprime.c @@ -0,0 +1,114 @@ +/* smallprime.c - List of small primes + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include "util.h" +#include "types.h" + +/* Note: 2 is not included because it can be tested more easily + * by looking at bit 0. The last entry in this list is marked by a zero + */ +ushort +small_prime_numbers[] = { + 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, + 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, + 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, + 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, + 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, + 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, + 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, + 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, + 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, + 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, + 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, + 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, + 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, + 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, + 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, + 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, + 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, + 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, + 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, + 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, + 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, + 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, + 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, + 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, + 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, + 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, + 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, + 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, + 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, + 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, + 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, + 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, + 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, + 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, + 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, + 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, + 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, + 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, + 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, + 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, + 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, + 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, + 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, + 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, + 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, + 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, + 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, + 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, + 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, + 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, + 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, + 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, + 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, + 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, + 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, + 4957, 4967, 4969, 4973, 4987, 4993, 4999, + 0 +}; + + diff --git a/cipher/tiger.c b/cipher/tiger.c new file mode 100644 index 000000000..6da715d48 --- /dev/null +++ b/cipher/tiger.c @@ -0,0 +1,1008 @@ +/* tiger.c - The TIGER hash function + * Copyright (C) 1998, 1999, 2000, 2001 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 +#include +#include +#include +#include +#include "util.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 +burn_stack (int bytes) +{ + char buf[256]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + + +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 ); + burn_stack (21*8+11*sizeof(void*)); + 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; + } + burn_stack (21*8+11*sizeof(void*)); + 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 */; + + t = hd->nblocks; + /* multiply by 64 to make a byte count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if( (lsb += hd->count) < t ) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + 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 ); + burn_stack (21*8+11*sizeof(void*)); + + 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; + *(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 "TIGER192"; +} + + + +#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 new file mode 100644 index 000000000..175f7c414 --- /dev/null +++ b/cipher/twofish.c @@ -0,0 +1,1136 @@ +/* Twofish for GPG + * By Matthew Skala , 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 +#include +#include +#include /* for memcmp() */ + +#include "types.h" /* for byte and u32 typedefs */ +#include "util.h" +#include "errors.h" +#include "dynload.h" + + +/* Prototype for the self-test function. */ +static const char *selftest(void); + +/* 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) + + +static void +burn_stack (int bytes) +{ + char buf[64]; + + memset (buf, 0, sizeof buf); + bytes -= sizeof buf; + if (bytes > 0) + burn_stack (bytes); +} + + + +/* 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. */ + +#ifdef __riscos__ +/* need to switch off CSE optimisation for Norcroft C (Acorn/Pace) */ +#pragma no_optimise_cse +#endif /* __riscos__ */ + +static int +do_twofish_setkey (TWOFISH_context *ctx, const byte *key, unsigned int 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 G10ERR_WRONG_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 G10ERR_SELFTEST_FAILED; + + /* 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; +} + +#ifdef __riscos__ +#pragma optimise_cse +#endif /* __riscos__ */ + +static int +twofish_setkey (TWOFISH_context *ctx, const byte *key, unsigned int keylen) +{ + int rc = do_twofish_setkey (ctx, key, keylen); + burn_stack (23+6*sizeof(void*)); + return rc; +} + + + +/* 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. */ + +#ifdef __riscos__ +/* need to switch off CSE optimisation for Norcroft C (Acorn/Pace) */ +#pragma no_optimise_cse +#endif /* __riscos__ */ + +static void +do_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); +} + +#ifdef __riscos__ +#pragma optimise_cse +#endif /* __riscos__ */ + +static void +twofish_encrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +{ + do_twofish_encrypt (ctx, out, in); + burn_stack (24+3*sizeof (void*)); +} + +/* Decrypt one block. in and out may be the same. */ + +#ifdef __riscos__ +/* need to switch off CSE optimisation for Norcroft C (Acorn/Pace) - bug */ +#pragma no_optimise_cse +#endif /* __riscos__ */ + +static void +do_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); +} + +#ifdef __riscos__ +#pragma optimise_cse +#endif /* __riscos__ */ + +static void +twofish_decrypt (const TWOFISH_context *ctx, byte *out, const byte *in) +{ + do_twofish_decrypt (ctx, out, in); + burn_stack (24+3*sizeof (void*)); +} + +/* 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 +#include +#include + +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); + + *(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; +} + + +#ifdef IS_MODULE +static +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) + */ +static 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: +#ifndef __riscos__ + ret = func_table[i].func; +#else /* __riscos__ */ + ret = (void *) func_table[i].func; +#endif /* __riscos__ */ + break; + } + i++; + } while ( what && what != *class ); + + *sequence = i; + return ret; +} +#endif diff --git a/contrib/UTF-8-test.txt b/contrib/UTF-8-test.txt new file mode 100644 index 000000000..2510f779c Binary files /dev/null and b/contrib/UTF-8-test.txt differ diff --git a/contrib/changes-in-2000 b/contrib/changes-in-2000 new file mode 100644 index 000000000..d9a18d09f --- /dev/null +++ b/contrib/changes-in-2000 @@ -0,0 +1,114 @@ +New features since 1.0.0 +------------------------ + + * The default symmetric cipher algorithm is now AES (aka + Rijndael). OpenPGP uses preferences to figure out the algorithm + to use, so this is only used if the recipient knows how to + handles AES. + + * RSA keys can now be used (either old PGP 2 or new OpenPGP ones). + RSA key generation is not yet available. + + * Unattended key generation. + + * Faster and more robust random number generator under W32. + + * Encryption is now much faster: About 2 times for 1k bit keys + and 8 times for 4k keys. + + * New encryption keys are generated in a way which allows a much + faster decryption. + + * GnuPG knows what the primary user ID is. + + * Large File Support (LFS) is working. + + * Ability to run gpg as a full controlled inferior process to speed up + mass verification of signatures. + + * Rewritten key selection code so that GnuPG can better cope with + multiple subkeys, expiration dates and so on. The drawback is that it + is slower. + + * New utility gpgv which is a stripped down version of gpg to + be used to verify signatures against a list of trusted keys. + + * New command --export-secret-subkeys which outputs the + the _primary_ key with it's secret parts deleted. This is + useful for automated decryption/signature creation as it + allows to keep the real secret primary key offline and + thereby protecting the key certificates and allowing to + create revocations for the subkeys. See the FAQ for a + procedure to install such secret keys. + + * New options --show-session-key and --override-session-key + to help the British folks to somewhat minimize the danger + of this Orwellian RIP bill. + + * New option --no-auto-key-retrieve to disable retrieving of a + missing public key from a keyserver, even when a keyserver has + been configured. Useful for dial-up connections. + + * HTTP proxy support for keyservers. + + * Keyserver support is how also available for W32 platforms (MS + Windows 95, 98, 2000, NT, ME). + + * Experimental gpg-agent support to get the passphrase from a + daemon which can pop up a query window. + + +rfc2440bis support (PGP 6.5.8 does also handle them) +------------------- + + * MDC enhanced encryption is now used with the AES and Twofish + algorithms to detect manipulated messages. + + * The user is now asked for the reason of a revocation. + + +Translations: +------------ + + * Enhanced UTF-8 support + + * New translations: Danish, Estonian, Indonesian, Portuguese and + Turkish. + +Serious bug fixes: +------------------ + + * Fixed a serious bug which could lead to false signature + verification results when more than one signature is fed to gpg. + This is the primary reason for releasing this version. + + * Protection against the recent Klima/Rosa attck on secret key + rings. + + * Corrected hash calculation for input data larger than 512M - it + was just wrong, so you might notice bad signature in some very + big files. It may be wise to keep an old copy of GnuPG around. + + * Secret keys are no longer imported unless you use the new option + --allow-secret-key-import. + +PGP quirks +---------- + + * Can handle (but not display) PGP's photo IDs. + + * Better default values to increase compatibilty with PGP. + + * Many other small enhancements to support the not fully-OpenPGP + compliant PGP versions. + +Manual +------ + + * The manual called GNU Privacy Handbook (GPH) is a separate + package and available preformatted in English, German, Italian, + Russian and Spanish at http://www.gnupg.org/docs.html. + [Due to the complicated build process, the source is currently + on available from CVS] + + diff --git a/contrib/why-gnupg b/contrib/why-gnupg new file mode 100644 index 000000000..289b9af8c --- /dev/null +++ b/contrib/why-gnupg @@ -0,0 +1,80 @@ +Why to use GnuPG and not PGP. +----------------------------- + + * PGP 2 is nearly Free Software but encumbered by the IDEA patent. + + * PGP 2 is old, hard to maintain and limited to one set of + encryption algorithms (RSA + IDEA) + + * PGP 2 is not a GNU or Unix Program and threfore not easy to use in + those environments + + * PGP 2 has a couple of minor security flaws + + * PGP 5 and 6 are more or less OpenPGP conform but proprietray + software. Source code is available but there is no way to be sure + that the distributed binary versions do match the source code. + Parts of the source code are not published. It is illegal to + build versions of PGP from source and distribute them (IIRC, there + is an exception for private users). + + * PGP 5 and 6 are not fullty OpenPGP compliant + + * PGP 7 is claimed to be OpenPGP compliant but the source code is + not anymore published. + + * At least versions before 6.5.8 had severe coding bugs. We don't + know about PGP 7. + + * PGP 5, 6 and 7 implement complicated methods for key recovering in + corporate environments. Although this is not a hidden feature, + this leads to more code and bugs. + + * NAI as the vendor of PGP seems to be a major government contractor. + + * Given the history of known backdoors in other proprietary software + (e.g. Lotus Notes), some folks claim that there might also be + backdoors in PGP 5, 6 and 7. Now there are even more rumors after + Phil Zimmermann left NAI. + + * GnuPG is Free Software under the GNU GPL. It does not use + patented algorithms. + + * Everyone is able to scrutinize the source code, build, distribute + and use versions of his own or from a trusted party he chooses. + + * The build environment is also Free Software and therefore less + likely tampered with malicious code. The exception here is the MS + Windows version of GnuPG where the OS is proprietary. The binary + version however is build using an entirely Free Software OS and + toolchain (cross-platfrom development under GNU/Linux). + + * Security fixes are provided very fast. + + * GnuPG is a standard tool in all GNU/Linux systems and used in many + different environments. + + * GnuPG gives reasonable messages and not just "Error encrypting". + + * GnuPG supports most of the optional features of the OpenPGP standard. + + * GnuPG comes with internationalization support for 16 languages. + + * Graphical frontends are available and they divert the task of + the actual cryptographic operations to GnuPG as a specialized tool + for this. A library called GPGME is available which makes + interfacing of GnuPG with other programs quite easy. + + * GnuPG is available for all GNU and Unix platforms as well as for + all MS Windows Operating systems. Porting to VMS, MAC OSX and + OS/2 is nearly finished. + + + + + + + + + + diff --git a/debian/README.Debian b/debian/README.Debian index f59643715..854a2e43a 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -1,7 +1,18 @@ +GDBM keyring support +-------------------- + +GDBM-based keyring support is (and always) was an experimental feature +which is likely to be removed in future versions. For that reason it +is not compiled into the Debian package and won't be until and unless +GDBM support stabilises. + +Upgrading from old (<= 0.3.3) versions GnuPG +-------------------------------------------- + Due to a bug in the way secret keys were encrypted in versions prior -to 0.3.3, later version of gnupg are not backwards compatible and you +to 0.3.3, later version of GnuPG are not backwards compatible and you will have to convert your secret keys before using old secret keys -with recent versions of gnupg. +with recent versions of GnuPG. The upgrade strategy is described in /usr/doc/gnupg/NEWS.gz, please refer to it for more details, but it requires an old copy of the gpg @@ -9,8 +20,9 @@ and gpgm binaries. They may be on your system as gpg.old and gpgm.old, but if they're not you can find gnupg 0.3.2 source and binaries for i386, m68k, alpha, powerpc and hurd-i386 at: - + -- -James Troup , Bradford, UK -Sun, 8 Nov 1998 19:11:40 +0000 +James Troup , Horsforth, UK +Sun, 1 Oct 2000 13:53:12 +0100 + diff --git a/debian/changelog b/debian/changelog index 5cf71aec8..8d33a87ae 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,155 @@ +gnupg (1.0.5-1) unstable; urgency=low + + * New upstream version. + * debian/README.Debian: fix spelling and update URL. + * debian/rules (binary): remove the new info files. + * scripts/config.{guess,sub}: sync with subversions, closes: #95729. + + -- James Troup Mon, 30 Apr 2001 02:12:38 +0100 + +gnupg (1.0.4-4) unstable; urgency=low + + * po/ru.po: patch by Ilya Martynov to replace German + entries and add missing translations, closes: #93987. + * g10/revoke.c (ask_revocation_reason): typo fix (s/non longer/no + longer/g); noticed by Colin Watson , closes: + #93664. + + * Deprecated depreciated; noticed by Vincent Broman + . + + * Following two patches are from Vincent Broman. + * g10/mainproc.c (proc_tree): use iobuf_get_real_fname() in preference + to iobuf_get_fname(). + * g10/openfile.c (open_sigfile): handle .sign prefixed files correctly. + + -- James Troup Fri, 20 Apr 2001 23:32:44 +0100 + +gnupg (1.0.4-3) unstable; urgency=medium + + * debian/rules (binary): make gpg binary suid, closes: #86433. + * debian/postinst: don't use suidregister. + * debian/postrm: removed (only called suidunregister). + * debian/control: conflict with suidmanager << 0.50. + * mpi/longlong.h: apply fix for ARM long long artimetic from Philip + Blundell , closes: #87487. + * debian/preinst: the old GnuPG debs have moved to people.debian.org. + * cipher/random.c: #include as well as + * g10/misc.c: likewise. + * debian/rules: define a strip alias which removes the .comment and + .note sections. + * debian/rules (binary-arch): use it. + * debian/lintian.override: new file; override the SUID warning from + lintian. + * debian/rules (binary-arch): install it. + + -- James Troup Sun, 25 Feb 2001 05:24:58 +0000 + +gnupg (1.0.4-2) stable unstable; urgency=high + + * Apply security fix patch from Werner. + * Apply another patch from Werner to fix bogus warning on Rijndael + usage. + * Change section to 'non-US'. + + -- James Troup Mon, 12 Feb 2001 07:47:02 +0000 + +gnupg (1.0.4-1) stable unstable; urgency=high + + * New upstream version. + * Fixes a serious bug which could lead to false signature verification + results when more than one signature is fed to gpg. + + -- James Troup Tue, 17 Oct 2000 17:26:17 +0100 + +gnupg (1.0.3b-1) unstable; urgency=low + + * New upstream snapshot version. + + -- James Troup Fri, 13 Oct 2000 18:08:14 +0100 + +gnupg (1.0.3-2) unstable; urgency=low + + * debian/control: Conflict, Replace and Provide gpg-rsa & gpg-rsaref. + Fix long description to reflect the fact that RSA is no longer + patented and now included. [#72177] + * debian/rules: move faq.html to /usr/share/doc/gnupg/ and remove FAQ + from /usr/share/gnupg/. Thanks to Robert Luberda + for noticing. [#72151] + * debian/control: Suggest new package gnupg-doc. [#64323, #65560] + * utils/secmem.c (lock_pool): don't bomb out if mlock() returns ENOMEM, + as Linux will do this if resource limits (or other reasons) prevent + memory from being locked, instead treat it like permission was denied + and warn but continue. Thanks to Topi Miettinen + . [#70446] + * g10/hkp.c (not_implemented): s/ist/is/ in error message. + * debian/README.Debian: add a note about GDBM support and why it is + disabled. Upstream already fixed the manpage. [#65913] + * debian/rules (binary-arch): fix the Spanish translation to be 'es' not + 'es_ES' at Nicolás Lichtmaier 's request. [#57314] + + -- James Troup Sun, 1 Oct 2000 14:55:03 +0100 + +gnupg (1.0.3-1) unstable; urgency=low + + * New upstream version. + + -- James Troup Mon, 18 Sep 2000 15:56:54 +0100 + +gnupg (1.0.2-1) unstable; urgency=low + + * New upstream version. + + -- James Troup Thu, 13 Jul 2000 20:26:50 +0100 + +gnupg (1.0.1-2) unstable; urgency=low + + * debian/control (Build-Depends): added. + * debian/copyright: corrected location of copyright file. Removed + references to Linux. Removed warnings about beta nature of GnuPG. + * debian/rules (binary-arch): install documentation into + /usr/share/doc/gnupg/ and pass mandir to make install to ensure the + manpages go to /usr/share/man/. + * debian/postinst: create /usr/doc/gnupg symlink. + * debian/prerm: new file; remove /usr/doc/gnupg symlink. + * debian/rules (binary-arch): install prerm. + * debian/control (Standards-Version): updated to 3.1.1.1. + + -- James Troup Thu, 30 Dec 1999 16:16:49 +0000 + +gnupg (1.0.1-1) unstable; urgency=low + + * New upstream version. + * doc/gpg.1: updated to something usable from + ftp://ftp.gnupg.org/pub/gcrypt/gnupg/gpg.1.gz. + + -- James Troup Sun, 19 Dec 1999 23:47:10 +0000 + +gnupg (1.0.0-3) unstable; urgency=low + + * debian/rules (build): remove the stunningly ill-advised --host option + to configure. [#44698, #48212, #48281] + + -- James Troup Tue, 26 Oct 1999 01:12:59 +0100 + +gnupg (1.0.0-2) unstable; urgency=low + + * debian/rules (binary-arch): fix the permissions on the + modules. [#47280] + * debian/postinst, debian/postrm: fix the package name passed to + suidregister. [#45013] + * debian/control: update long description. [#44636] + * debian/rules (build): pass the host explicitly to configure to avoid + problems on sparc64. [(Should fix) #44698]. + + -- James Troup Wed, 20 Oct 1999 23:39:05 +0100 + +gnupg (1.0.0-1) unstable; urgency=low + + * New upstream release. [#44545] + + -- James Troup Wed, 8 Sep 1999 00:53:02 +0100 + gnupg (0.9.10-2) unstable; urgency=low * debian/rules (binary-arch): install lspgpot. Requested by Kai diff --git a/debian/control b/debian/control index 0b6120ea6..5b158daf5 100644 --- a/debian/control +++ b/debian/control @@ -1,23 +1,24 @@ Source: gnupg -Section: utils +Section: non-US Priority: optional Maintainer: James Troup -Standards-Version: 2.5.0.0 +Standards-Version: 3.1.1.1 +Build-Depends: gettext, libgdbmg1-dev, libz-dev Package: gnupg Architecture: any Depends: ${shlibs:Depends}, makedev (>= 2.3.1-13) +Suggests: gnupg-doc +Conflicts: gpg-rsa, gpg-rsaref, suidmanager (<< 0.50) +Replaces: gpg-rsa, gpg-rsaref +Provides: gpg-rsa, gpg-rsaref Description: GNU privacy guard - a free PGP replacement. - GnuPG is the GNU encryption and signing tool. As you can see from the - version number, the program may have some bugs and some features may not - work at all. + GnuPG is GNU's tool for secure communication and data storage. + It can be used to encrypt data and to create digital signatures. + It includes an advanced key management facility and is compliant + with the proposed OpenPGP Internet standard as described in RFC2440. . - Due to the fact that GnuPG does not use use any patented algorithm, - it cannot be compatible to old PGP versions, because those use - IDEA (which is worldwide patented) and RSA (which is patented in - the United States until Sep 20, 2000). - . - GnuPG is in almost all aspects compatible with other OpenPGP - implementations. The default algorithms are DSA and ELGamal. - Symmetric algorithms are: Blowfish and CAST5, Digest algorithms are - MD5, RIPEMD160, SHA1 and TIGER/192. + GnuPG does not use use any patented algorithms so it cannot be + compatible with PGP2 because it uses IDEA (which is patented + worldwide) and RSA. RSA's patent expired on the 20th September 2000, + and it is now included in GnuPG. diff --git a/debian/copyright b/debian/copyright index 6c08adfc7..e5d99f688 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,30 +1,29 @@ -This is Debian/GNU Linux's prepackaged version of GNUPG, a free PGP -replacement. As you can see from the version number, the program may -have some bugs and some features may not work at all. +This is Debian GNU's prepackaged version of GnuPG, a free PGP +replacement. -This package was put together by me, James Troup -, from the sources, which I obtained from -ftp://ftp.gnupg.org/pub/gcrypt/gnupg-0.9.10.tar.gz. The changes were -minimal, namely: +This package was put together by me, James Troup , +from the sources, which I obtained from +ftp://ftp.gnupg.org/pub/gcrypt/gnupg/gnupg-1.0.5.tar.gz. The changes +were minimal, namely: - adding support for the Debian package maintenance scheme, by adding various debian/* files. -Program Copyright (C) 1998, 1999 Free Software Foundation, Inc. -Modifications for Debian Copyright (C) 1998,1999 James Troup. +Program Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. +Modifications for Debian Copyright (C) 1998, 1999, 2000, 2001 James Troup. -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, or (at your option) -any later version. +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, 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. +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 with -your Debian GNU/Linux system, in /usr/doc/copyright/GPL, or with the -Debian GNU/Linux gnupg source package as the file COPYING. If not, -write to the Free Software Foundation, Inc., 59 Temple Place, Suite -330, Boston, MA 02111-1307, USA. +your Debian GNU system, in /usr/share/common-licenses/GPL, or with the +Debian GNU gnupg source package as the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place, Suite 330, +Boston, MA 02111-1307, USA. diff --git a/debian/lintian.override b/debian/lintian.override new file mode 100644 index 000000000..c35ed27b3 --- /dev/null +++ b/debian/lintian.override @@ -0,0 +1 @@ +gnupg: setuid-binary usr/bin/gpg 4755 root/root diff --git a/debian/postinst b/debian/postinst deleted file mode 100644 index 98825f605..000000000 --- a/debian/postinst +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -set -e - -case "$1" in - configure|abort-upgrade|abort-remove|abort-deconfigure) - if [ -x /usr/sbin/suidregister ]; then - suidregister -s gpg /usr/bin/gpg root root 4755 - else - chmod 4755 /usr/bin/gpg - fi - ;; -esac - diff --git a/debian/postrm b/debian/postrm deleted file mode 100644 index f640fb0b4..000000000 --- a/debian/postrm +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -e - -case "$1" in - purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) - if [ -x /usr/sbin/suidunregister ]; then - suidunregister -s gpg /usr/bin/gpg - fi - ;; -esac diff --git a/debian/preinst b/debian/preinst index 8369e2013..607944c7c 100644 --- a/debian/preinst +++ b/debian/preinst @@ -34,7 +34,7 @@ EOF If at any stage you need a pre-0.3.3 gnupg, you can find source and binaries for i386, m68k, alpha, powerpc and hurd-i386 at - http://james.nocrew.org/gnupg/ + http://people.debian.org/~troup/gnupg/ Press return to continue EOF diff --git a/debian/rules b/debian/rules index 3583ed4f7..400472edf 100644 --- a/debian/rules +++ b/debian/rules @@ -1,5 +1,5 @@ #!/usr/bin/make -f -# debian/rules file - for GNUPG (0.9.10) +# debian/rules file - for GNUPG (1.0.5) # Based on sample debian/rules file - for GNU Hello (1.3). # Copyright 1994,1995 by Ian Jackson. # Copyright 1998 James Troup @@ -9,6 +9,8 @@ # paternity under the Copyright, Designs and Patents Act 1988.) # This file may have to be extensively modified +STRIP=strip --remove-section=.comment --remove-section=.note + build: $(checkdir) ./configure --prefix=/usr --with-included-gettext @@ -32,26 +34,36 @@ binary-arch: checkroot build # test $(checkdir) -rm -rf debian/tmp install -d debian/tmp/DEBIAN/ - install -m 755 debian/preinst debian/postinst debian/postrm debian/tmp/DEBIAN/ - $(MAKE) prefix=`pwd`/debian/tmp/usr install - strip debian/tmp/usr/bin/* + install -m 755 debian/preinst debian/prerm debian/postinst debian/tmp/DEBIAN/ + $(MAKE) prefix=`pwd`/debian/tmp/usr mandir=`pwd`/debian/tmp/usr/share/man install + # copies of the manpage which can't be grokked by install-info + rm debian/tmp/usr/info/* + $(STRIP) debian/tmp/usr/bin/* + chmod 4755 debian/tmp/usr/bin/gpg + chmod 644 debian/tmp/usr/lib/gnupg/* sed -e "s#../g10/gpg#gpg#" < tools/lspgpot > debian/tmp/usr/bin/lspgpot chmod 755 debian/tmp/usr/bin/lspgpot - strip --strip-unneeded debian/tmp/usr/lib/gnupg/* - sed -e "s#/usr/local/#/usr/#" < debian/tmp/usr/man/man1/gpg.1 \ - > debian/tmp/usr/man/man1/gpg.1.new - mv debian/tmp/usr/man/man1/gpg.1.new debian/tmp/usr/man/man1/gpg.1 - gzip -9v debian/tmp/usr/man/man1/* - install -d debian/tmp/usr/doc/gnupg/ - install -m 644 debian/changelog debian/tmp/usr/doc/gnupg/changelog.Debian + $(STRIP) --strip-unneeded debian/tmp/usr/lib/gnupg/* + # In response to #53714... no idea if it's correct, will check with upstream + mv debian/tmp/usr/share/locale/es_ES debian/tmp/usr/share/locale/es + sed -e "s#/usr/local/#/usr/#" < debian/tmp/usr/share/man/man1/gpg.1 \ + > debian/tmp/usr/share/man/man1/gpg.1.new + mv debian/tmp/usr/share/man/man1/gpg.1.new debian/tmp/usr/share/man/man1/gpg.1 + gzip -9v debian/tmp/usr/share/man/man1/* + # Remove from /usr/share/gnupg that we install into /usr/share/doc/gnupg/ + rm debian/tmp/usr/share/gnupg/FAQ debian/tmp/usr/share/gnupg/faq.html + install -d debian/tmp/usr/share/doc/gnupg/ + install -m 644 debian/changelog debian/tmp/usr/share/doc/gnupg/changelog.Debian install -m 644 debian/README.Debian README NEWS THANKS TODO doc/DETAILS \ - doc/FAQ doc/OpenPGP debian/tmp/usr/doc/gnupg/ + doc/FAQ doc/faq.html doc/OpenPGP debian/tmp/usr/share/doc/gnupg/ for i in po util mpi cipher tools g10 checks include; do \ - install -m 644 $$i/ChangeLog debian/tmp/usr/doc/gnupg/changelog.$$i; done - install -m 644 ChangeLog debian/tmp/usr/doc/gnupg/changelog.toplevel - gzip -9v debian/tmp/usr/doc/gnupg/* - ln -s changelog.g10.gz debian/tmp/usr/doc/gnupg/changelog.gz - install -m 644 debian/copyright debian/tmp/usr/doc/gnupg/ + install -m 644 $$i/ChangeLog debian/tmp/usr/share/doc/gnupg/changelog.$$i; done + install -m 644 ChangeLog debian/tmp/usr/share/doc/gnupg/changelog.toplevel + gzip -9v debian/tmp/usr/share/doc/gnupg/* + ln -s changelog.g10.gz debian/tmp/usr/share/doc/gnupg/changelog.gz + install -m 644 debian/copyright debian/tmp/usr/share/doc/gnupg/ + install -d debian/tmp/usr/share/lintian/overrides/ + install -m 644 debian/lintian.override debian/tmp/usr/share/lintian/overrides/gnupg dpkg-shlibdeps g10/gpg dpkg-gencontrol -isp chown -R root.root debian/tmp diff --git a/doc/ChangeLog b/doc/ChangeLog index b83adc839..1832da00a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,27 +1,365 @@ -Tue Oct 26 14:10:21 CEST 1999 Werner Koch +2002-06-21 David Shaw - * Makefile.am (SUBDIRS): Removed gph from this development series + * DETAILS: Document "uat". + + * gpg.sgml: Document + --personal-{compress|digest|compress}-preferences, --group, and + add comments to --expert. + +2002-06-17 Werner Koch + + * gpg.sgml: Grammar fix. + +2002-06-03 David Shaw + + * DETAILS: Details of ATTRIBUTE. + + * gpg.sgml: Document --attribute-fd + +2002-06-03 Timo Schulz + + * DETAILS: Add ATTRIBUTE. + +2002-05-31 David Shaw + + * gpg.sgml: Add "edit/addrevoker". Document --desig-revoke. Note + that -z and --compress are the same option. Note that + --digest-algo can no longer violate OpenPGP with a non-160 bit + hash with DSA. Document --cert-digest-algo with suitable warnings + not to use it. Note the default s2k-cipher-algo is now CAST5. + Note that --force-v3-sigs overrides --ask-sig-expire. Revise + --expert documentation, as it is now definitely legal to have more + than one photo ID on a key. --preference-list is now + --default-preference-list with the new meaning. Document + --personal-preference-list. + + * DETAILS: Document "Revoker" for batch key generation. + +2002-05-22 Werner Koch + + * gpg.sgml: sgml syntax fix. + +2002-05-12 Werner Koch + + * gpg.sgml: Fixed URL in the description section. + + * faq.raw: Minor typo fixes noted by kromJx@myrealbox.com. + +2002-05-11 Werner Koch + + * gpg.sgml: Typo fix. + +2002-05-07 David Shaw + + * gpg.sgml: Add entries for --sk-comments, --no-sk-comments, + --pgp7, and --no-pgp7. Fix --pgp2 and --pgp6: the proper name is + --escape-from-lines and not --escape-from. + +2002-04-30 Timo Schulz + + * gpg.sgml: Add an entry for --encrypt-files and --decrypt-files. + +2002-04-29 David Shaw + + * gpg.sgml: Fix minor error in --pgp6 documentation: it does not + imply --digest-algo MD5 + +2002-04-29 Werner Koch + + * samplekeys.asc: Added gnupg distribution key 57548DCD. + + * faq.raw: Inserted Douglas Calvert as new maintainer. Acknowledge + Nils. Add entry about trust packet parsing problems. + +2002-04-24 David Shaw + + * gpg.sgml: Add some documentation for + --edit/{addphoto|showphoto|nrsign|nrlsign}, and the difference + between %t and %T in photo viewer command lines. + +2002-04-23 Stefan Bellon + + * gpg.sgml: Moved options from section "COMMANDS" to + section "OPTIONS". + +2002-04-20 David Shaw + + * samplekeys.asc: Added 0x5B0358A2 + +2002-04-19 David Shaw + + * gpg.sgml: Add "%t" flag for photo IDs, a note about primary + having different meanings for photo and regular IDs, rename + --default-check-level to --default-cert-check-level, add + --auto-check-trustdb, and --pgp6. + + * DETAILS: Add EXPSIG, EXPKEYSIG, and KEYEXPIRED. Add notes to + SIGEXPIRED (deprecated), and VALIDSIG (added expiration date). + Add "Preferences" command to unattended key generation + instructions. Also fixed a few typos. + + * samplekeys.asc: new (added to EXTRA_DIST in Makefile.am as well) + +2002-01-31 Marcus Brinkmann + + * DETAILS: Fix a spelling error, correct IMPORTED_RES to IMPORT_RES, + correct INV_RECP (the second occurence) to NO_RECP. + +2002-04-03 David Shaw + + * gpg.sgml: auto-key-retrieve is a keyserver-option (noted by + Roger Sondermann). + +2002-03-27 David Shaw + + * gpg.sgml: --pgp2 also means --disable-mdc, --no-ask-sig-expire, + and --no-ask-cert-expire. It does not mean --no-force-v3-sigs + (noted by Timo). + +2002-03-27 David Shaw + + * gpg.sgml: Add a few notes about --pgp2 meaning MIT PGP 2.6.2, + and keyserver details about HKP and NAI HKP. + +2002-03-18 David Shaw + + * gpg.sgml: Change meaning of --allow-non-selfsigned-uid to match + change in code, and add --no-allow-non-selfsigned-uid. + +2002-03-13 Werner Koch + + * faq.raw: Due to a lack of time Nils can't serve anymore as a + maintainer. Removed his address and setup a generic address. + +2002-03-06 Werner Koch + + * gpg.sgml: Add an entry for --export-ownertrust. Suggested by + Bernhard Reiter. + +2002-01-26 Timo Schulz + + * gnupg-w32.reg: New. Registry file for W32 in registry format. + +2002-01-26 Werner Koch + + * gpg.sgml: A few words about --gpg-agent-info and GPG_AGENT_INFO. + +2002-01-25 Timo Schulz + + * README.W32: Modify the filename because now the .exe extension + is automatically added to the binary. + +2002-01-14 Werner Koch + + * gpg.sgml: Talk about PGP 5 and higher. + +2002-01-11 David Shaw + + * gpg.sgml: Added documentation for --{no-}ask-cert-expire, + --{no-}ask-sig-expire, and revise --expert (it doesn't switch on + the expiration prompt anymore) and --default-check-level (to be + clearer as to what makes a good key check before signing). + +2002-01-07 Werner Koch + + * DETAILS: Removed the comment that unattended key generation is + experimental. It is now a standard feature. + +2001-12-22 David Shaw + + * gpg.sgml: Fixed a few typos. + + * gpg.sgml: Added documentation for --show-photos, + --no-show-photos, --photo-viewer, --nrsign-key, + --default-check-level, --search-keys, --keyserver-options, + --show-notation, --no-show-notation, --show-policy-url, + --no-show-policy-url, --for-your-eyes-only, + --no-for-your-eyes-only, --pgp2, --no-pgp2, + --no-permission-warning, --expert, --no-expert. + +2001-10-31 Werner Koch + + * gpg.sgml: Add a remark on how to get the long key ID. Suggested + by Sebastian Klemke. + +2001-10-23 Werner Koch + + * gpg.sgml: Add missing tag. + +2001-09-28 Werner Koch + + * gpg.sgml: Add a note on option parsing. + +2001-09-24 Werner Koch + + * gpg.sgml: Described --{update,check}-trustdb. + +2001-09-03 Werner Koch + + * gpg.sgml, gpgv.sgml: Removed GDBM stuff. + +2001-08-29 Werner Koch + + * faq.raw: Described how to delete a secret key w/o a public key + and changed the entry on updating the preferences. + +2001-08-08 Werner Koch + + * gpg.sgml: Documented --print-mds and marked the --print-md * as + deprecated because it does not work in the W32 version. Suggested + by John Kane. + (WARNINGS): Typo fix. + (--with-colons): Clarified that the output is in UTF-8. + +2001-08-01 Werner Koch + + * gpg.sgml: Added --ignore-valid-from + +2001-04-20 Werner Koch + + * faq.raw (Maintained-by): Removed note that load-extension is not + available under Windoze. + + * gpg.sgml: Add new --charset UTF-8. + +2001-04-19 Werner Koch + + * faq.raw: Add a note about dates displayed as ????-??-??. + +2001-04-17 Werner Koch + + * Makefile.am (%.texi): Add rules to create .texi from .sgml. + However we can't automate this because automake does not like + .texi files as BUILT_SOURCES. + (%.dvi,%.ps): Removed these rules, because they are not needed + and get in the way of automake's dvi target + + * HACKING: Changed CVS description. + +2001-04-06 Werner Koch + + * gpg.sgml: Small typo fixes by Florian Weimer. + +2001-03-27 Werner Koch + + * gpg.sgml: Add --no-sig-cache and --no-sig-create-check. + +2001-03-23 Werner Koch + + * DETAILS: New status UNEXPECTED. + +2001-03-13 Werner Koch + + * gpg.sgml: Described --fixed-list-mode. + +2001-03-06 Werner Koch + + * gpgv.sgml: Changed some gpg to gpgv. Thanks to John A. Murdie. + +2001-03-03 Werner Koch + + * gpg.sgml: Tell something about the 0x12345678! key ID syntax. + +2001-01-18 Werner Koch + + * README.W32: Changed building instructions for MinGW32/CPD 0.3 + +2001-01-09 Werner Koch + + * DETAILS: Fixed docs for NEED_PASSPHRASE and added USERID_HINT. + +2000-11-30 Werner Koch + + * gpg.sgml: Fixed the description of --verify. Add a short note + the warnings sections. + +2000-10-19 Werner Koch + + * gpg.sgml: Fixed doc for --allow-non-selfsigned-uid. + Add entry for --ignore-crc-error. + +2000-10-18 Werner Koch + + * OpenPGP: Dropped the paragraph that RSA is not implemented. + +2000-10-14 Werner Koch + + * faq.raw: Add an answer to the problem of multiple signatures. + +Wed Oct 4 15:50:18 CEST 2000 Werner Koch + + * gpgv.sgml: New. + * Makefile.am: build it. + +Thu Sep 14 14:20:38 CEST 2000 Werner Koch + + * faq.raw: New. + * Makefile.am: Support to build FAQs + +Wed Jul 12 13:32:06 CEST 2000 Werner Koch + + * gpg.sgml: Add a note about the availability of the GPH. + +2000-07-03 13:59:24 Werner Koch (wk@habibti.openit.de) + + * DETAILS, FAQ: Typo fixes by Yosiaki IIDA. + +2000-05-12 10:57:21 Werner Koch (wk@habibti.openit.de) + + * gpg.sgml: Documented --no-tty. + +2000-03-09 15:01:51 Werner Koch (wk@habibti.openit.de) + + * DETAILS: Ad a short blurb about unattended key generation. + +Wed Feb 9 15:33:44 CET 2000 Werner Koch + + * gpg.sgml: Describe --ignore-time-conflict. + + * gpg.sgml: Fixed a few typos. Thanks to Holger Trapp. + +Wed Jan 5 11:51:17 CET 2000 Werner Koch + + * FAQ: Enhanced answer for the 3des-s2k bug. + +Sat Dec 4 12:30:28 CET 1999 Werner Koch + + * gpg.sgml: Add section about the user ID + +Mon Nov 22 11:14:53 CET 1999 Werner Koch + + * gph: Removed the directory from the dist becuase it will + go into it's own package. + +Thu Sep 23 09:52:58 CEST 1999 Werner Koch + + * README.W32: New. Mon Sep 6 19:59:08 CEST 1999 Werner Koch + * Makefile.am (SUBDIRS): New subdir gph for the manual. Thu Jul 22 20:03:03 CEST 1999 Werner Koch + * gpg.sgml (--always-trust): Added. Wed Jul 14 19:42:08 CEST 1999 Werner Koch + * Makefile.am: Create a dummy man page if docbook-to-man is missing. Wed Jun 16 20:16:21 CEST 1999 Werner Koch + * gpg1.pod: Removed. * gpg.sgml: New. Replaces the pod file * Makefile.am: Add rule to make a man file from sgml Tue Jun 15 12:21:08 CEST 1999 Werner Koch + * Makefile.in.in: Use DESTDIR. Mon May 31 19:41:10 CEST 1999 Werner Koch @@ -30,7 +368,20 @@ Mon May 31 19:41:10 CEST 1999 Werner Koch Wed Feb 10 17:15:39 CET 1999 Werner Koch + * gpg.1pod: Spelling and grammar corrections (John A. Martin) * FAQ: Ditto. * DETAILS: Ditto. + + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/doc/DETAILS b/doc/DETAILS index a06b5888e..9170d5b93 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1,23 +1,47 @@ -Format of "---with-colons" listings -=================================== +Format of colon listings +======================== +First an example: + +$ gpg --fixed-list-mode --with-colons --list-keys \ + --with-fingerprint --with-fingerprint wk@gnupg.org + +pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC: +fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013: +uid:f::::::::Werner Koch : +uid:f::::::::Werner Koch : +sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e: +fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1: +sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc: +fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4: + +The double --with-fingerprint prints the fingerprint for the subkeys +too, --fixed-list-mode is themodern listing way printing dates in +seconds since Epoch and does not merge the first userID with the pub +record. -sec::1024:17:6C7EE1B8621CC013:1998-07-07:0:::Werner Koch : -ssb::1536:20:5CE086B5B5A18FF4:1998-07-07:0::: 1. Field: Type of record pub = public key + crt = X.509 certificate + crs = X.509 certificate and private key available sub = subkey (secondary key) sec = secret key ssb = secret subkey (secondary key) uid = user id (only field 10 is used). + uat = user attribute (same as user id except for field 10). + sig = signature + rev = revocation signature fpr = fingerprint: (fingerprint is in field 10) pkd = public key data (special field format, see below) + grp = reserved for gpgsm + rvk = revocation key 2. Field: A letter describing the calculated trust. This is a single letter, but be prepared that additional information may follow in some future versions. (not used for secret keys) o = Unknown (this key is new to the system) + i = The key is invalid (e.g. due to a missing self-signature) d = The key has been disabled r = The key has been revoked e = The key has expired @@ -33,21 +57,51 @@ ssb::1536:20:5CE086B5B5A18FF4:1998-07-07:0::: 17 = DSA (sometimes called DH, sign only) 20 = ElGamal (sign and encrypt) (for other id's see include/cipher.h) - 5. Field: KeyID + 5. Field: KeyID either of 6. Field: Creation Date (in UTC) 7. Field: Key expiration date or empty if none. - 8. Field: Local ID: record number of the dir record in the trustdb. - This value is only valid as long as the trustdb is not - deleted. You can use "# as the user id when - specifying a key. This is needed because keyids may not be - unique - a program may use this number to access keys later. + 8. Field: Used for serial number in crt records (used to be the Local-ID) 9. Field: Ownertrust (primary public keys only) This is a single letter, but be prepared that additional information may follow in some future versions. 10. Field: User-ID. The value is quoted like a C string to avoid control characters (the colon is quoted "\x3a"). + This is not used with --fixed-list-mode in gpg. + A UAT record puts the attribute subpacket count here, a + space, and then the total attribute subpacket size. + In gpgsm the issuer name comes here + An FPR record stores the fingerprint here. + The fingerprint of an revocation key is stored here. +11. Field: Signature class. This is a 2 digit hexnumber followed by + either the letter 'x' for an exportable signature or the + letter 'l' for a local-only signature. + The class byte of an revocation key is also given here, + 'x' and 'l' ist used the same way. +12. Field: Key capabilities: + e = encrypt + s = sign + c = certify + A key may have any combination of them. The primary key has in + addition to these letters, uppercase version of the letter to + denote the _usable_ capabilities of the entire key. +13. Field: Used in FPR records for S/MIME keys to store the fingerprint of + the issuer certificate. This is useful to build the + certificate path based on certificates stored in the local + keyDB; it is only filled if the issue certificate is + available. The advantage of using this value is that it is + guaranteed to have been been build by the same lookup + algorithm as gpgsm uses. + For "uid" recods this lists the preferences n the sameway the + -edit menu does. +14. Field Flag field used in the --edit menu output: -More fields may be added later. + +All dates are displayed in the format yyyy-mm-dd unless you use the +option --fixed-list-mode in which case they are displayed as seconds +since Epoch. More fields may be added later, so parsers should be +prepared for this. When parsing a number the parser should stop at the +first non-number character so that additional information can later be +added. If field 1 has the tag "pkd", a listing looks like this: pkd:0:1024:B665B1435F4C2 .... FF26ABB: @@ -55,7 +109,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB: ! !------ for information number of bits in the value !--------- index (eg. DSA goes from 0 to 3: p,q,g,y) - + Format of the "--status-fd" output ================================== @@ -66,10 +120,26 @@ more arguments in future versions. GOODSIG - The signature with the keyid is good. + The signature with the keyid is good. For each signature only + one of the three codes GOODSIG, BADSIG or ERRSIG will be + emitted and they may be used as a marker for a new signature. + The username is the primary one encoded in UTF-8 and %XX + escaped. + + EXPSIG + The signature with the keyid is good, but the signature is + expired. The username is the primary one encoded in UTF-8 and + %XX escaped. + + EXPKEYSIG + The signature with the keyid is good, but the signature was + made by an expired key. The username is the primary one + encoded in UTF-8 and %XX escaped. BADSIG The signature with the keyid has not been verified okay. + The username is the primary one encoded in UTF-8 and %XX + escaped. ERRSIG \ @@ -80,11 +150,14 @@ more arguments in future versions. this signature. sig_class is a 2 byte hex-value. VALIDSIG + + The signature with the keyid is good. This is the same as GOODSIG but has the fingerprint as the argument. Both - status lines ere emitted for a good signature. + status lines are emitted for a good signature. sig-timestamp is the signature creation time in seconds after - the epoch. + the epoch. expire-timestamp is the signature expiration time + in seconds after the epoch (zero means "does not expire"). SIG_ID This is emitted only for signatures of class 0 or 1 which @@ -107,34 +180,51 @@ more arguments in future versions. 3 - Invalid packet found, this may indicate a non OpenPGP message. You may see more than one of these status lines. - TRUST_UNDEFINED - TRUST_NEVER + UNEXPECTED + Unexpected data has been encountered + 0 - not further specified 1 + + + TRUST_UNDEFINED + TRUST_NEVER TRUST_MARGINAL TRUST_FULLY TRUST_ULTIMATE For good signatures one of these status lines are emitted - to indicate how trustworthy the signature is. No arguments yet. + to indicate how trustworthy the signature is. The error token + values are currently only emiited by gpgsm. SIGEXPIRED - The signature key has expired. No arguments yet. + This is deprecated in favor of KEYEXPIRED. + + KEYEXPIRED + The key has expired. expire-timestamp is the expiration time + in seconds after the epoch. KEYREVOKED - The used key has been revoked by his owner. No arguments yet. + The used key has been revoked by its owner. No arguments yet. BADARMOR The ASCII armor is corrupted. No arguments yet. RSA_OR_IDEA - The RSA or IDEA algorithms has been used in the data. A + The IDEA algorithms has been used in the data. A program might want to fallback to another program to handle - the data if GnuPG failed. + the data if GnuPG failed. This status message used to be emitted + also for RSA but this has been dropped after the RSA patent expired. + However we can't change the name of the message. SHM_INFO SHM_GET SHM_GET_BOOL SHM_GET_HIDDEN - NEED_PASSPHRASE + GET_BOOL + GET_LINE + GET_HIDDEN + GOT_IT + + NEED_PASSPHRASE Issued whenever a passphrase is needed. keytype is the numerical value of the public key algorithm or 0 if this is not applicable, keylength is the length @@ -149,7 +239,7 @@ more arguments in future versions. will probably be a BAD_PASSPHRASE. However, if the application is a wrapper around the key edit menu functionality it might not make sense to stop parsing but simply ignoring the following - PAD_PASSPHRASE. + BAD_PASSPHRASE. BAD_PASSPHRASE The supplied passphrase was wrong or not given. In the latter case @@ -177,7 +267,7 @@ more arguments in future versions. IMPORTED The keyid and name of the signature just imported - IMPORTED_RES + IMPORT_RES Final statistics on import process (this is one long line) @@ -185,11 +275,108 @@ more arguments in future versions. Start processing a file . indicates the performed operation: 1 - verify + 2 - encrypt + 3 - decrypt FILE_DONE Marks the end of a file processing which has been started by FILE_START. + BEGIN_DECRYPTION + END_DECRYPTION + Mark the start and end of the actual decryption process. These + are also emitted when in --list-only mode. + + BEGIN_ENCRYPTION + END_ENCRYPTION + Mark the start and end of the actual encryption process. + + DELETE_PROBLEM reason_code + Deleting a key failed. Reason codes are: + 1 - No such key + 2 - Must delete secret key first + + PROGRESS what char cur total + Used by the primegen and Public key functions to indicate progress. + "char" is the character displayed with no --status-fd enabled, with + the linefeed replaced by an 'X'. "cur" is the current amount + done and "total" is amount to be done; a "total" of 0 indicates that + the total amount is not known. 100/100 may be used to detect the + end of operation. + + SIG_CREATED + A signature has been created using these parameters. + type: 'D' = detached + 'C' = cleartext + 'S' = standard + (only the first character should be checked) + class: 2 hex digits with the signature class + + KEY_CREATED + A key has been created + type: 'B' = primary and subkey + 'P' = primary + 'S' = subkey + + SESSION_KEY : + The session key used to decrypt the message. This message will + only be emmited when the special option --show-session-key + is used. The format is suitable to be passed to the option + --override-session-key + + NOTATION_NAME + NOTATION_DATA + name and string are %XX escaped; the data may be splitted + among several notation_data lines. + + USERID_HINT + Give a hint about the user ID for a certain keyID. + + POLICY_URL + string is %XX escaped + + BEGIN_STREAM + END_STREAM + Issued by pipemode. + + INV_RECP + Issued for each unusable recipient. The reasons codes + currently in use are: + 0 := "No specific reason given". + 1 := "Not Found" + 2 := "Ambigious specification" + + NO_RECP + Issued when no recipients are usable. + + ALREADY_SIGNED + Warning: This is experimental and might be removed at any time. + + TRUNCATED + The output was truncated to MAXNO items. This status code is issued + for certain external requests + + ERROR + This is a generic error status message, it might be followed + by error location specific data. and + should not contain a space. + + ATTRIBUTE + + This is one long line issued for each attribute subpacket when + an attribute packet is seen during key listing. is the + fingerprint of the key. is the length of the + attribute subpacket. is the attribute type + (1==image). / indicates that this is the Nth + indexed subpacket of count total subpackets in this attribute + packet. and are from the + self-signature on the attribute packet. If the attribute + packet does not have a valid self-signature, then the + timestamp is 0. are a bitwise OR of: + 0x01 = this attribute packet is a primary uid + 0x02 = this attribute packet is revoked + 0x04 = this attribute packet is expired + Key generation ============== @@ -222,6 +409,121 @@ Key generation Crypto '97 proceedings p. 260. +Unattended key generation +========================= +This feature allows unattended generation of keys controlled by a +parameter file. To use this feature, you use --gen-key together with +--batch and feed the parameters either from stdin or from a file given +on the commandline. + +The format of this file is as follows: + o Text only, line length is limited to about 1000 chars. + o You must use UTF-8 encoding to specify non-ascii characters. + o Empty lines are ignored. + o Leading and trailing spaces are ignored. + o A hash sign as the first non white space character indicates a comment line. + o Control statements are indicated by a leading percent sign, the + arguments are separated by white space from the keyword. + o Parameters are specified by a keyword, followed by a colon. Arguments + are separated by white space. + o The first parameter must be "Key-Type", control statements + may be placed anywhere. + o Key generation takes place when either the end of the parameter file + is reached, the next "Key-Type" parameter is encountered or at the + control statement "%commit" + o Control statements: + %echo + Print . + %dry-run + Suppress actual key generation (useful for syntax checking). + %commit + Perform the key generation. An implicit commit is done + at the next "Key-Type" parameter. + %pubring + %secring + Do not write the key to the default or commandline given + keyring but to . This must be given before the first + commit to take place, duplicate specification of the same filename + is ignored, the last filename before a commit is used. + The filename is used until a new filename is used (at commit points) + and all keys are written to that file. If a new filename is given, + this file is created (and overwrites an existing one). + Both control statements must be given. + o The order of the parameters does not matter except for "Key-Type" + which must be the first parameter. The parameters are only for the + generated keyblock and parameters from previous key generations are not + used. Some syntactically checks may be performed. + The currently defined parameters are: + Key-Type: | + Starts a new parameter block by giving the type of the + primary key. The algorithm must be capable of signing. + This is a required parameter. + Key-Length: + Length of the key in bits. Default is 1024. + Key-Usage: + Space or comma delimited list of key usage, allowed values are + "encrypt" and "sign". This is used to generate the key flags. + Please make sure that the algorithm is capable of this usage. + Subkey-Type: | + This generates a secondary key. Currently only one subkey + can be handled. + Subkey-Length: + Length of the subkey in bits. Default is 1024. + Subkey-Usage: + Similar to Key-Usage. + Passphrase: + If you want to specify a passphrase for the secret key, + enter it here. Default is not to use any passphrase. + Name-Real: + Name-Comment: + Name-Email: + The 3 parts of a key. Remember to use UTF-8 here. + If you don't give any of them, no user ID is created. + Expire-Date: |([d|w|m|y]) + Set the expiration date for the key (and the subkey). It + may either be entered in ISO date format (2000-08-15) or as + number of days, weeks, month or years. Without a letter days + are assumed. + Preferences: + Set the cipher, hash, and compression preference values for + this key. This expects the same type of string as "setpref" + in the --edit menu. + Revoker: : [sensitive] + Add a designated revoker to the generated key. Algo is the + public key algorithm of the designated revoker (i.e. RSA=1, + DSA=17, etc.) Fpr is the fingerprint of the designated + revoker. The optional "sensitive" flag marks the designated + revoker as sensitive information. Only v4 keys may be + designated revokers. + +Here is an example: +$ cat >foo < +ssb 1024g/8F70E2C0 2000-03-09 + + Layout of the TrustDB ===================== @@ -230,6 +532,8 @@ describes the record type. All numeric values are stored in network byte order. The length of each record is 40 bytes. The first record of the DB is always of type 1 and this is the only record of this type. +FIXME: The layout changed, document it here. + Record type 0: -------------- Unused record, can be reused for any purpose. @@ -259,7 +563,7 @@ the DB is always of type 1 and this is the only record of this type. 1 u32 record number of shadow directory hash table It does not make sense to combine this table with the key table because the keyid is not in every case a part of the fingerprint. - 4 bytes reserved for version extension record + 1 u32 record number of the trusthashtbale Record type 2: (directory record) @@ -316,7 +620,7 @@ the DB is always of type 1 and this is the only record of this type. Record type 5: (pref record) -------------- - Informations about preferences + This record type is not anymore used. 1 byte value 5 1 byte reserved @@ -339,16 +643,16 @@ the DB is always of type 1 and this is the only record of this type. 1 u32 next next sigrec of this uid or 0 to indicate the last sigrec. 6 times - 1 u32 Local_id of signators dir or shadow dir record + 1 u32 Local_id of signatures dir or shadow dir record 1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real directory record for this) - 1 = valid is set (but my be revoked) + 1 = valid is set (but may be revoked) Record type 8: (shadow directory record) -------------- - This record is used to reserved a LID for a public key. We + This record is used to reserve a LID for a public key. We need this to create the sig records of other keys, even if we do not yet have the public key of the signature. This record (the record number to be more precise) will be reused @@ -477,7 +781,7 @@ There is one enhancement used with the old style packet headers: + future extensions. These length markers must be inserted into the data + stream just before writing the data out. + -+ This 2 byte filed is large enough, because the application must buffer ++ This 2 byte field is large enough, because the application must buffer + this amount of data to prepend the length marker before writing it out. + Data block sizes larger than about 32k doesn't make any sense. Note + that this may also be used for compressed data streams, but we must use @@ -485,10 +789,19 @@ There is one enhancement used with the old style packet headers: + that this is the last packet. +GNU extensions to the S2K algorithm +=================================== +S2K mode 101 is used to identify these extensions. +After the hash algorithm the 3 bytes "GNU" are used to make +clear that these are extensions for GNU, the next bytes gives the +GNU protection mode - 1000. Defined modes are: + 1001 - do not store the secret part at all + + Usage of gdbm files for keyrings ================================ - The key to store the keyblock is it's fingerprint, other records - are used for secondary keys. fingerprints are always 20 bytes + The key to store the keyblock is its fingerprint, other records + are used for secondary keys. Fingerprints are always 20 bytes where 16 bit fingerprints are appended with zero. The first byte of the key gives some information on the type of the key. @@ -508,6 +821,41 @@ Usage of gdbm files for keyrings +Pipemode +======== +This mode can be used to perform multiple operations with one call to +gpg. It comes handy in cases where you have to verify a lot of +signatures. Currently we support only detached signatures. This mode +is a kludge to avoid running gpg n daemon mode and using Unix Domain +Sockets to pass the data to it. There is no easy portable way to do +this under Windows, so we use plain old pipes which do work well under +Windows. Because there is no way to signal multiple EOFs in a pipe we +have to embed control commands in the data stream: We distinguish +between a data state and a control state. Initially the system is in +data state but it won't accept any data. Instead it waits for +transition to control state which is done by sending a single '@' +character. While in control state the control command os expected and +this command is just a single byte after which the system falls back +to data state (but does not necesary accept data now). The simplest +control command is a '@' which just inserts this character into the +data stream. + +Here is the format we use for detached signatures: +"@<" - Begin of new stream +"@B" - Detached signature follows. + This emits a control packet (1,'B') + +"@t" - Signed text follows. + This emits the control packet (2, 'B') + +"@." - End of operation. The final control packet forces signature + verification +"@>" - End of stream + + + + + Other Notes =========== @@ -596,11 +944,11 @@ The keyserver also recognizes http-POSTs to /pks/add. Use this to upload keys. -A better way to to this would be a request like: +A better way to do this would be a request like: /pks/lookup/?op= -this can be implemented using Hurd's translator mechanism. +This can be implemented using Hurd's translator mechanism. However, I think the whole key server stuff has to be re-thought; I have some ideas and probably create a white paper. diff --git a/doc/FAQ b/doc/FAQ deleted file mode 100644 index 788b85751..000000000 --- a/doc/FAQ +++ /dev/null @@ -1,352 +0,0 @@ - GNU Privacy Guard -- Frequently Asked Questions - ================================================= - - This FAQ is partly compiled from messages of the developers mailing list. - - Many thanks to Kirk Fort, Brian Warner, ... - - - Q: How does this whole thing work? - A: To generate a secret/public keypair, run - - gpg --gen-key - - and choose the default values. - - Data that is encrypted with a public key can only be decrypted by the - matching secret key. The secret key is protected by a password, the - public key is not. - - So to send your friend a message, you would encrypt your message with his - public key, and he would only be able to decrypt it by having the secret - key and putting in the password to use his secret key. - - GnuPG is also useful for signing things. Things that are encrypted with - the secret key can be decrypted with the public key. To sign something, a - hash is taken of the data, and then the hash is in some form encoded with - the secret key. If someone has your public key, they can verify that it - is from you and that it hasn't changed by checking the encoded form of - the hash with the public key. - - A keyring is just a large file that stores keys. You have a public keyring - where you store yours and your friend's public keys. You have a secret - keyring that you keep your secret key on, and be very careful with this - secret keyring: Never ever give anyone else access to it and use a *good* - passphrase to protect the data in it. - - You can 'conventionally' encrypt something by using the option 'gpg -c'. - It is encrypted using a passphrase, and does not use public and secret - keys. If the person you send the data to knows that passphrase, they can - decrypt it. This is usually most useful for encrypting things to - yourself, although you can encrypt things to your own public key in the - same way. It should be used for communication with partners you know and - where it is easy to exchange the passphrases (e.g. with your boy friend or - your wife). The advantage is that you can change the passphrase from time - to time and decrease the risk, that many old messages may be decrypted by - people who accidently got your passphrase. - - You can add and copy keys to and from your keyring with the 'gpg --import' - and 'gpg --export' option. 'gpg --export-secret-keys' will export secret - keys. This is normally not useful, but you can generate the key on one - machine then move it to another machine. - - Keys can be signed under the 'gpg --edit-key' option. When you sign a - key, you are saying that you are certain that the key belongs to the - person it says it comes from. You should be very sure that is really - that person: You should verify the key fingerprint - - gpg --fingerprint user-id - - over phone (if you really know the voice of the other person) or at - a key signing party (which are often held at computer conferences) - or at a meeting of your local GNU/Linux User Group. - - Hmm, what else. You may use the option "-o filename" to force output - to this filename (use "-" to force output to stdout). "-r" just lets you - specify the recipient (which public key you encrypt with) on the command - line instead of typing it interactively. - - Oh yeah, this is important. By default all data is encrypted in some weird - binary format. If you want to have things appear in ASCII text that is - readable, just add the '-a' option. But the preferred method is to use - a MIME aware mail reader (Mutt, Pine and many more). - - There is a small security glitch in the OpenPGP (and therefore GnuPG) system; - to avoid this you should always sign and encrypt a message instead of only - encrypting it. - - - Q: What is the recommended key size? - A: 1024 bit for DSA signatures; even for plain ElGamal - signatures this is sufficient as the size of the hash - is probably the weakest link if the keysize is larger - than 1024 bits. Encryption keys may have greater sizes, - but you should than check the fingerprint of this key: - "gpg --fingerprint --fingerprint ". - - Q: Why are some signatures with an ELG-E key valid? - A: These are ElGamal Key generated by GnuPG in v3 (rfc1991) - packets. The OpenPGP draft later changed the algorithm - identifier for ElGamal keys which are usable for signatures - and encryption from 16 to 20. GnuPG now uses 20 when it - generates new ElGamal keys but still accept 16 (which is - according to OpenPGP "encryption only") if this key is in - a v3 packet. GnuPG is the only program which had used - these v3 ElGamal keys - so this assumption is quite safe. - - Q: Why is PGP 5.x not able to encrypt messages with some keys? - A: PGP Inc refuses to accept ElGamal keys of type 20 even for - encryption. They only support type 16 (which is identical - at least for decryption). To be more inter-operable, GnuPG - (starting with version 0.3.3) now also uses type 16 for the - ElGamal subkey which is created if the default key algorithm - is chosen. You may add an type 16 ElGamal key to your public - key which is easy as your key signatures are still valid. - - Q: Why is PGP 5.x not able to verify my messages? - A: PGP 5.x does not accept V4 signatures for data material but - OpenPGP requires generation of V4 signatures for all kind of - data. Use the option "--force-v3-sigs" to generate V3 signatures - for data. - - Q: I can't delete an user id because it is already deleted on my - public keyring? - A: Because you can only select from the public key ring, there is - no direct way to do this. However it is not very complicated - to do it anyway. Create a new user id with exactly the same name - and you will see that there are now two identical user ids on the - secret ring. Now select this user id and delete it. Both user - ids will be removed from the secret ring. - - Q: How can I encrypt a message so that pgp 2.x is able to decrypt it? - A: You can't do that because pgp 2.x normally uses IDEA which is not - supported by GnuPG because it is patented, but if you have a modified - version of PGP you can try this: - - gpg --rfc1991 --cipher-algo 3des ... - - Please don't pipe the data to encrypt to gpg but give it as a filename; - other wise, pgp 2 will not be able to handle it. - - Q: How can I conventional encrypt a message, so that PGP can decrypt it? - A: You can't do this for PGP 2. For PGP 5 you should use this: - - gpg -c --cipher-algo 3des --compress-algo 1 myfile - - You may replace "3des" by "cast5". "blowfish" does not work with - all versions of pgp5. You may also want to put - compress-algo 1 - into your ~/.gnupg/options file - this does not affect normal - gnupg operation. - - - Q: Why does it sometimes take so long to create keys? - A: The problem here is that we need a lot of random bytes and for that - we (on Linux the /dev/random device) must collect some random data. - It is really not easy to fill the Linux internal entropy buffer; I - talked to Ted Ts'o and he commented that the best way to fill the buffer - is to play with your keyboard. Good security has it's price. What I do - is to hit several times on the shift, control, alternate, and capslock - keys, because these keys do not produce output to the screen. This way - you get your keys really fast (it's the same thing pgp2 does). - - Another problem might be another program which eats up your random bytes - (a program (look at your daemons) that reads from /dev/[u]random). - - Q: And it really takes long when I work on a remote system. Why? - A: Don't do this at all! You should never create keys or even use GnuPG - on a remote system because you normally have no physical control over - your secret keyring (which is in most cases vulnerable to advanced - dictionary attacks) - I strongly encourage everyone to only create keys - on a local computer (a disconnected laptop is probably the best choice) - and if you need it on your connected box (I know: We all do this) be - sure to have a strong password for your account and for your secret key - and that you can trust your system administrator. - - When I check GnuPG on a remote system via ssh (I have no Alpha here ;-) - I have the same problem. It takes a *very* long time to create the - keys, so I use a special option, --quick-random, to generate insecure - keys which are only good for some tests. - - - Q: How does the whole trust thing work? - A: It works more or less like PGP. The difference is that the trust is - computed at the time it is needed. This is one of the reasons for the - trustdb which holds a list of valid key signatures. If you are not - running in batch mode you will be asked to assign a trust parameter - (ownertrust) to a key. - - You can see the validity (calculated trust value) using this command. - - gpg --list-keys --with-colons - - If the first field is "pub" or "uid", the second field shows you the trust: - - o = Unknown (this key is new to the system) - e = The key has expired - q = Undefined (no value assigned) - n = Don't trust this key at all - m = There is marginal trust in this key - f = The key is full trusted. - u = The key is ultimately trusted; this - is only used for keys for which - the secret key is also available. - r = The key has been revoked - d = The key has been disabled - - The value in the "pub" record is the best one of all "uid" records. - - You can get a list of the assigned trust values (how much you trust - the owner to correctly sign another person's key) - - gpg --list-ownertrust - - The first field is the fingerprint of the primary key, the second field - is the assigned value: - - - = No Ownertrust value yet assigned. - n = Never trust this keyholder to correctly verify others signatures. - m = Have marginal trust in the keyholders capability to sign other keys. - f = Assume that the key holder really knows how to sign keys. - u = No need to trust ourself because we have the secret key. - - Keep these values confidential because they express your opinions - about others. PGP stores this information with the keyring thus - it is not a good idea to publish a PGP keyring instead of exporting the - keyring. gnupg stores the trust in the trust-DB so it is okay - to give a gpg keyring away (but we have a --export command too). - - - Q: What is the difference between options and commands? - A: If you do a "gpg --help", you will get two separate lists. The first is - a list of commands. The second is a list of options. Whenever you run GPG, - you *must* pick exactly one command (**with one exception, see below). You - *may* pick one or more options. The command should, just by convention, - come at the end of the argument list, after all the options. If the - command takes a file (all the basic ones do), the filename comes at the - very end. So the basic way to run gpg is: - - gpg [--option something] [--option2] [--option3 something] --command file - - Some options take arguments, for example the --output option (which can be - abbreviated -o) is an option that takes a filename. The option's argument - must follow immediately after the option itself, otherwise gpg doesn't know - which option the argument is supposed to go with. As an option, --output and - its filename must come before the command. The --recipient (-r) option takes - a name or keyid to encrypt the message to, which must come right after the -r - argument. The --encrypt (or -e) command comes after all the options followed - by the file you wish to encrypt. So use - - gpg -r alice -o secret.txt -e test.txt - - If you write the options out in full, it is easier to read - - gpg --recipient alice --output secret.txt --encrypt test.txt - - If you're saving it in a file called ".txt" then you'd probably expect to see - ASCII-armored text in there, so you need to add the --armor (-a) option, - which doesn't take any arguments. - - gpg --armor --recipient alice --output secret.txt --encrypt test.txt - - If you imagine square brackets around the optional parts, it becomes a bit - clearer: - - gpg [--armor] [--recipient alice] [--output secret.txt] --encrypt test.txt - - The optional parts can be rearranged any way you want. - - gpg --output secret.txt --recipient alice --armor --encrypt test.txt - - If your filename begins with a hyphen (e.g. "-a.txt"), gnupg assumes this is - an option and may complain. To avoid this you have either to use - "./-a.txt" or stop the option and command processing with two hyphens: - "-- -a.txt". - - ** the exception: signing and encrypting at the same time. Use - - gpg [--options] --sign --encrypt foo.txt - - - Q: What kind of output is this: "key C26EE891.298, uid 09FB: ...."? - A: This is the internal representation of an user id in the trustdb. - "C26EE891" is the keyid, "298" is the local id (a record number - in the trustdb) and "09FB" is the last two bytes of a ripe-md-160 - hash of the user id for this key. - - - Q: What is trust, validity and ownertrust? - A: "ownertrust" is used instead of "trust" to make clear that - this is the value you have assigned to a key to express how much you - trust the owner of this key to correctly sign (and so introduce) - other keys. "validity", or calculated trust, is a value which - says how much GnuPG thinks a key is valid (that it really belongs - to the one who claims to be the owner of the key). - For more see the chapter "The Web of Trust" in the Manual - - Q: How do I interpret some of the informational outputs? - A: While checking the validity of a key, GnuPG sometimes prints - some information which is prefixed with information about - the checked item. - "key 12345678.3456" - This is about the key with key ID 12345678 and the internal - number 3456, which is the record number of the so called - directory record in the trustdb. - "uid 12345678.3456/ACDE" - This is about the user ID for the same key. To identify the - user ID the last two bytes of a ripe-md-160 over the user ID - ring is printed. - "sig 12345678.3456/ACDE/9A8B7C6D" - This is about the signature with key ID 9A8B7C6D for the - above key and user ID, if it is a signature which is direct - on a key, the user ID part is empty (..//..). - - - Q: How do I sign a patch file? - A: Use "gpg --clearsign --not-dash-escaped ...". - The problem with --clearsign is that all lines starting with a dash are - quoted with "- "; obviously diff produces many of lines starting with a - dash and these are then quoted and that is not good for patch ;-). To - use a patch file without removing the cleartext signature, the special - option --not-dash-escaped may be used to suppress generation of these - escape sequences. You should not mail such a patch because spaces and - line endings are also subject to the signature and a mailer may not - preserve these. If you want to mail a file you can simply sign it - using your MUA. - - - Q: Where is the "encrypt-to-self" option? - A: Use "--encrypt-to your_keyid". You can use more than one - of these options. To temporary override the use of this additional - keys, you can use the option "--no-encrypt-to". - - - Q: How can I get rid of the Version and Comment headers in - armored messages? - A: Use "--no-version --comment ''". Note that the left over blank line - is required by the protocol. - - - Q: What does the "You are using the xxxx character set." mean? - A: This note is printed when UTF8 mapping has to be done. Make sure that - the displayed charset is the one you have activated on your system - "iso-8859-1" is the most used one, so this is the default. You can - change the charset with the option "--charset". It is important that - you active character set matches the one displayed - if not, restrict - yourself to plain 7 bit ASCII and no mapping has to be done. - - Q: How do I transfer owner trust values from PGP to GnuPG? - A: There is a script in the tools directory to help you: - After you have imported the PGP keyring you can give this command: - $ lspgpot pgpkeyring | gpg --import-ownertrust - where pgpkeyring is the original keyring and not the GnuPG one you - might have created in the first step. - - Q: Are the headerlines of a cleartext signater part of the signed - material? - A: No. For example you can add or remove "Comment:" lines. They - have a purpose like the mail header lines. However a "Hash:" - line is needed for modern signatures, to tell the parser which - hash algorithm to use. - - diff --git a/doc/HACKING b/doc/HACKING index 6f4c9ffd8..811179e53 100644 --- a/doc/HACKING +++ b/doc/HACKING @@ -10,12 +10,13 @@ CVS Access ========== Anonymous read-only CVS access is available: - cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs login + cvs -z3 -d :pserver:anoncvs@cvs.gnupg.org:/cvs/gnupg login -use the password "anonymous". To check out the the complete +use the password "anoncvs". To check out the the complete archive use: - cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs checkout gnupg + cvs -z3 -d :pserver:anoncvs@cvs.gnupg.org:/cvs/gnupg \ + checkout -R STABLE-BRANCH-1-0 gnupg This service is provided to help you in hunting bugs and not to deliver stable snapshots; it may happen that it even does not compile, so please @@ -112,6 +113,74 @@ Directory Layout ./gcrypt Stuff needed to build libgcrypt (under construction) +Detailed Roadmap +---------------- +g10/g10.c Main module with option parsing and all the stuff you have + to do on startup. Also has the exout handler and some + helper functions. +g10/sign.c Create signature and optionally encrypt + +g10/parse-packet.c +g10/build-packet.c +g10/free-packet.c + Parsing and creating of OpenPGP message packets. + +g10/getkey.c Key selection code +g10/pkclist.c Build a list of public keys +g10/skclist.c Build a list of secret keys +g10/ringedit.c Keyring I/O +g10/keydb.h + +g10/keyid.c Helper functions to get the keyid, fingerprint etc. + + +g10/trustdb.c +g10/trustdb.h +g10/tdbdump.c + Management of the trustdb.gpg + +g10/compress.c Filter to handle compression +g10/filter.h Declarations for all filter functions +g10/delkey.c Delete a key +g10/kbnode.c Helper for the KBNODE linked list +g10/main.h Prototypes and some constants +g10/mainproc.c Message processing +g10/armor.c Ascii armor filter +g10/mdfilter.c Filter to calculate hashs +g10/textfilter.c Filter to handle CR/LF and trailing white space +g10/cipher.c En-/Decryption filter +g10/misc.c Utlity functions +g10/options.h Structure with all the command line options + and related constants +g10/openfile.c Create/Open Files +g10/tdbio.c I/O handling for the trustdb.gpg +g10/tdbio.h +g10/hkp.h Keyserver access +g10/hkp.c +g10/packet.h Defintion of OpenPGP structures. +g10/passphrase.c Passphrase handling code +g10/pubkey-enc.c +g10/seckey-cert.c +g10/seskey.c +g10/import.c +g10/export.c +g10/comment.c +g10/status.c +g10/status.h +g10/sign.c +g10/plaintext.c +g10/encr-data.c +g10/encode.c +g10/revoke.c +g10/keylist.c +g10/sig-check.c +g10/signal.c +g10/helptext.c +g10/verify.c +g10/decrypt.c +g10/keyedit.c +g10/dearmor.c +g10/keygen.c diff --git a/doc/Makefile.am b/doc/Makefile.am index 209032141..ca4941411 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,42 +1,77 @@ +# Copyright (C) 1998, 1999, 2000, 2001 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 + ## Process this file with automake to create Makefile.in -BUILT_SOURCES = version.sgml +AUTOMAKE_OPTIONS = no-texinfo.tex + +EXTRA_DIST = DETAILS gpg.sgml gpg.1 gpgv.sgml gpgv.1 faq.raw FAQ faq.html \ + HACKING OpenPGP README.W32 samplekeys.asc + +man_MANS = gpg.1 gpgv.1 + +info_TEXINFOS = gpg.texi gpgv.texi + +# Need this to avoid building of dvis with automake 1.4 +DVIS = + +pkgdata_DATA = FAQ faq.html + +BUILT_SOURCES = FAQ faq.html +# we can't add gpg.texi gpgv.texi here because automake does not like them to +# be built files. + +CLEANFILES = faq.raw.xref gpg.xml gpgv.xml -#EXTRA_DIST = DETAILS gpg.sgml gpg.1 FAQ HACKING OpenPGP \ -# version.sgml.in $(BUILT_SOURCES) -EXTRA_DIST = DETAILS HACKING OpenPGP FAQ +%.texi : %.xml +if HAVE_DOCBOOK_TO_TEXI + docbook2texi $< | sed 's,--,---,' >$@ +else + : Warning: missing docbook to texinfo tools, cannot make $@ + touch $@ +endif -#man_MANS = gpg.1 - -### pkgdata_DATA = gcryptref.html gcryptref.ps +%.xml : %.sgml +if HAVE_DOCBOOK_TO_TEXI + sgml2xml -x lower $< >$@ +else + : Warning: missing docbook to texinfo tools, cannot make $@ + touch $@ +endif -# gcryptref.sgml : version.sgml - - -if HAVE_DB2MAN %.1 : %.sgml - $(DB2MAN) $< >$@ -endif - -if HAVE_DB2TEX -%.ps : %.dvi - dvips -o $@ $< - -%.tex : %.sgml - $(DB2TEX) -V generate-book-toc $< > $@ - -%.dvi : %.tex - $(JADETEX) $< -endif - -if HAVE_DB2HTML -%.html : %.sgml - $(DB2HTML) --nosplit $< +if HAVE_DOCBOOK_TO_MAN + docbook-to-man $< >$@ +else + : Warning: missing docbook-to-man, cannot make $@ + echo ".TH $< 1" >$@ + echo "No man page due to missing docbook-to-man" >>$@ endif +FAQ : faq.raw + $(FAQPROG) -f $< $@ || $(FAQPROG) -f $< $@ +faq.html : faq.raw + $(FAQPROG) -h -f $< $@ 2>&1 || $(FAQPROG) -h -f $< $@ - +dist-hook: + @if test "`wc -c < gpg.1`" -lt 200; then \ + echo 'ERROR: dummy man page'; false; fi diff --git a/doc/OpenPGP b/doc/OpenPGP index c73eee4f8..a511ad7fd 100644 --- a/doc/OpenPGP +++ b/doc/OpenPGP @@ -8,11 +8,7 @@ Compatibility Notes =================== - GnuPG (>0.4.5) is in compliance with RFC2440 despite these exceptions: - - * (9.1) states that RSA SHOULD be implemented. This is not done - (except with an extension, usable outside the U.S.) due to - patent problems. + GnuPG (>=1.0.3) is in compliance with RFC2440 despite these exceptions: * (9.2) states that IDEA SHOULD be implemented. This is not done due to patent problems. @@ -21,7 +17,7 @@ All MAY features are implemented with this exception: * multi-part armored messages are not supported. - MIME should be used instead. + MIME (rfc2015) should be used instead. Most of the OPTIONAL stuff is implemented. @@ -33,6 +29,15 @@ which can be considered to be in compliance with RFC1991; this format is only created if a special option is active. + GnuPG uses a S2K mode of 101 for GNU extensions to the secret key + protection algorithms. This number is not defined in OpenPGP, but + given the fact that this number is in a range which used at many + other places in OpenPGP for private/experimenat algorithm identifiers, + this should be not a so bad choice. The 3 bytes "GNU" are used + to identify this as a GNU extension - see the file DETAILS for a + definition of the used data formats. + + Some Notes on OpenPGP / PGP Compatibility: ========================================== diff --git a/doc/README.W32 b/doc/README.W32 new file mode 100644 index 000000000..05e41e3e2 --- /dev/null +++ b/doc/README.W32 @@ -0,0 +1,95 @@ +This is a binary version of GnuPG for MS-Windows 95, 98, WNT and W2000. + +A FAQ comes with this package and a probably more recent one can be +found online at http://www.gnupg.org/faq.html. See +http://www.gnupg.org/docs-mls.html for a list of mailing lists. In +particular the list gnupg-users@gnupg.org might be useful to answer +questions - but please read the FAQ first. + +Installation instructions: +-------------------------- + 1. Unpack the ZIP archive (alright, you already did this). + 2. Copy "gpg.exe" to some place where you usually store your + binaries. + 3. Create a directory "c:\gnupg" (or any other as you like) + 4. If you did not use the default directory "c:\gnupg", you + should enter a string with the directory into the Registry + under the key: + \\HKEY_CURRENT_USER\Software\GNU\GnuPG\HomeDir + Please use forward slashes and not the backslashes when + setting filenames for GnuPG into the Registry. + 5. Enter "gpg" and see what happens + 6. Read the file README and the online HOWTOs + + +Internationalization support: +----------------------------- + 1. Decide where to store the translation files for your language. + Here we assume the directory "c:/gnu/locale/fr" + 2. Set the directory with the translations into the Registry under the key: + \\HKEY_CURRENT_USER\Control Panel\Mingw32\NLS\MODir + (Example entry: "c:/gnu/locale/fr") + 3. Select which language to use and copy the currect translation file + under the name "gnupg.mo" into the directory set in step 2 + (Example: "copy fr.mo c:\gnu\locale\fr\gnupg.mo") + 4. Done. + +Currently we only support the Codepages 437, 850 und Latin1. If you have +problems, either delete the gnupg.mo file or don't set the environment +variable + + + +How to build it from the source: +-------------------------------- +This version has been build with the Mingw32/CPD kit using the latest +stable version of GnuPG. + +First get the source: It has to be available at the same location you +found this binary package - if not you should have received a written +offer to get the source delivered to you See the file COPYING (section +3) for details. + +If you got this package from its canonical place (ftp.gnupg.org), the +source is available at: + + ftp://ftp.gnupg.org/gcrypt/gnupg/gnupg-1.0.n.tar.gz + +or for snapshots (with a letter appended to the version number) + + ftp://ftp.gnupg.org/gcrypt/devel/gnupg-1.0.nx.tar.gz + +this is the same source as for the Unix version. If your binary +version of GnuPG is called something like gnupg-w32-1.0.4-1.zip, you +should find a patch file named gnupg-w32-1.0.4-1.0.4-1.diff.gz at the +same location, which has to be applied to the stock gpg source file. +Instructions are at the top of this file. + +To build it, you need the MingW32/CPD kit, which is available at + + ftp://ftp.gnupg.org/people/werner/cpd/mingw32-cpd-0.3.0.tar.gz + ftp://ftp.gnupg.org/people/werner/cpd/gcc-core-2.95.2.tar.gz + ftp://ftp.gnupg.org/people/werner/cpd/binutils-2.9.1.tar.gz + +gcc and binutils are stock GNU source which are available +at every GNU mirror. + +After you have installed this environment you should be able to do this: + + $ scripts/autogen.sh --build-w32 + $ make + $ mingw32 strip g10/gpg.exe + $ cp g10/gpg.exe /some_windows_drive/ + +And everything hopefully works. + + +Don't forget that MS-Windows ist just a temporary workaround until +you can switch to a GNU system ;-) + +Be the source always with you. + + Werner + + + diff --git a/doc/faq.raw b/doc/faq.raw new file mode 100644 index 000000000..eac856bd3 --- /dev/null +++ b/doc/faq.raw @@ -0,0 +1,932 @@ +[$htmltitle=GnuPG FAQ] +[$sfaqheader=The GnuPG FAQ says:] +[$sfaqfooter= +The most recent version of the FAQ is available from + +] +[$usenetheader= +] +[$maintainer=Douglas Calvert, ] +[$hGPG=http://www.gnupg.org] + +[H body bgcolor=#ffffff text=#000000 link=#1f00ff alink=#ff0000 vlink=#9900dd] +[H H1]GNUPG FREQUENTLY ASKED QUESTIONS[H /H1] + + +Version: 1.5.6[H p] +Last-Modified: Sep 14, 2001[H p] +Maintained-by: [$maintainer] + + +This is the GnuPG FAQ. The latest HTML version is available +[H a href=[$hGPG]/faq.html] here[H/a]. + +The index is generated automatically, so there may be errors here. Not +all questions may be in the section they belong to. Suggestions about +how to improve the structure of this FAQ are welcome. + +Please send additions and corrections to the maintainer. It would be +most convenient if you could provide the answer to be included +here. Your help is very much appreciated. + +Please, don't send message like "This should be a FAQ - what's the +answer?". If it hasn't been asked before, it isn't a FAQ. In that case +you could search in the mailing list archive. + + +[H HR] + + + +[H HR] + + GENERAL + + What is GnuPG? + + [H a href=[$hGPG]]GnuPG[H /a] stands for GNU Privacy Guard and + is GNU's tool for secure communication and data storage. + It can be used to encrypt data and to create digital signatures. + It includes an advanced key management facility and is compliant + with the proposed OpenPGP Internet standard as described in + [H a href=http://www.gnupg.org/rfc2440.html]RFC 2440[H/a]. As + such, it is aimed to be compatible with PGP from NAI Inc. + + Is GnuPG compatible with PGP? + + In general, yes. GnuPG and newer PGP releases should be implementing + the OpenPGP standard. But there are some interoperability + problems. See questions ff. for details. + + SOURCES of INFORMATION + + Where can I find more information? + + Here's a list of on-line resources: [H UL] + + [H LI] [H a href=[$hGPG]/docs.html]<[$hGPG]/docs.html>[H/a] is the + documentation page. Have a look at the HOWTOs and the GNU Privacy + Handbook (GPH, available in English, Spanish and Russian). The + latter provides a detailed user's guide to GnuPG. You'll also find a + document about how to convert from PGP 2.x to GnuPG. + + [H LI] On [H a href=http://lists.gnupg.org][H/a] + you'll find an online archive of the GnuPG mailing lists. Most + interesting should be gnupg-users for all user-related issues and + gnupg-devel if you want to get in touch with the developers. + + In addition, searchable archives can be found on MARC, e.g.: + GnuPG-users: [H a href=http://marc.theaimsgroup.com/?l=gnupg-users&r=1&w=2][H/a], + GnuPG-devel: [H a href=http://marc.theaimsgroup.com/?l=gnupg-devel&r=1&w=2][H/a]. + + [H B]PLEASE:[H/B] + Before posting to a list, read this FAQ and the available + documentation. In addition, search the list archive - maybe your + question has already been discussed. This way you help people focus + on topics that have not yet been resolved. + + [H LI] The GnuPG source distribution contains a subdirectory + [H PRE]./doc[H /PRE] where some additional documentation is located + (mainly interesting for hackers, not the casual user). + [H /UL] + + Where do I get GnuPG? + + You can download the GNU Privacy Guard from its primary FTP server + [H a href=ftp://ftp.gnupg.org/pub/gcrypt]ftp.gnupg.org[H /a] or from + one of the mirrors: [H a href=[$hGPG]/mirrors.html]<[$hGPG]/mirror.html>[H /a] + The current version is 1.0.4, please upgrade to this version as it + fixes a security bug regarding the verification of multiple signatures. + + + INSTALLATION + + Which OSes does GnuPG run on? + + It should run on most Unices as well as Windows 95 and Windows NT. A + list of OSes reported to be OK is presented at + [H a href=http://www.gnupg.org/backend.html#supsys] + http://www.gnupg.org/gnupg.html#supsys [H /a]. + + Which random gatherer should I use? + + "Good" random numbers are crucial for the security of your + encryption. Different operating systems provide a variety of more or + less quality random data. Linux and *BSD provide kernel generated + random data through /dev/random - this should be the preferred + choice on these systems. Also Solaris users with the SUNWski package + installed have a /dev/random. In these cases, use the configure + option [H pre]--enable-static-rnd=linux[H/pre]. In addition, there's + also the kernel random device by Andi Maier [H a href= http://www.cosy.sbg.ac.at/~andi] + [H /a], but it's still beta. Use at + own risk! + + On other systems, the Entropy Gathering Daemon (EGD) is a good + choice. It is a perl-daemon that monitors system activity and hashes + it into random data. See the download page [H a href=http://www.gnupg.org/download.html][H /a] + how to obtain egd. Use [H pre]--enable-static-rnd=egd[H/pre] here. + + If the above options do not work, you can use the random number + generator "unix". This is [H B]very[H /B] slow and should be + avoided. The random quality isn't very good so don't use it on + sensitive data. + + + How do I include support for RSA and IDEA? + + RSA is included as of GnuPG 1.0.3. + + The official GnuPG distribution does not contain IDEA due to a + patent restriction. The patent does not expire before 2007 so don't + expect official support before then. + + However, there is an unofficial module to include it even + in earlier version of GnuPG. It's available from [H a href=ftp://ftp.gnupg.org/pub/gcrypt/contrib/] + [H /a]. Look for [H pre]idea.c[H /pre]. + + Compilation directives are in the headers of these files. Then add + the following line to your ~/.gnupg/options: + [H pre] + load-extension idea + [H /pre] + + + USAGE + + What is the recommended key size? + + 1024 bit for DSA signatures; even for plain ElGamal + signatures this is sufficient as the size of the hash + is probably the weakest link if the key size is larger + than 1024 bits. Encryption keys may have greater sizes, + but you should then check the fingerprint of this key: + "gpg --fingerprint ". + + As for the key algorithms, you should stick with the default (i.e., + DSA signature and ElGamal encryption). A ElGamal signing key has the + following disadvantages: the signature is larger, it is hard to + create such a key useful for signatures which can withstand some + real world attacks, you don't get any extra security compared to + DSA, there might be compatibility problems with certain PGP + versions. It has only been introduced because at the time it was + not clear whether there was a patent on DSA. + + Why does it sometimes take so long to create keys? + + The problem here is that we need a lot of random bytes and for that + we (on Linux the /dev/random device) must collect some random data. + It is really not easy to fill the Linux internal entropy buffer; I + talked to Ted Ts'o and he commented that the best way to fill the + buffer is to play with your keyboard. Good security has its price. + What I do is to hit several times on the shift, control, alternate, + and caps lock keys, because these keys do not produce output to the + screen. This way you get your keys really fast (it's the same thing + PGP2 does). + + Another problem might be another program which eats up your random + bytes (a program (look at your daemons) that reads from + /dev/[u]random). + + And it really takes long when I work on a remote system. Why? + + Don't do this at all! You should never create keys or even use GnuPG + on a remote system because you normally have no physical control + over your secret key ring (which is in most cases vulnerable to + advanced dictionary attacks) - I strongly encourage everyone to only + create keys on a local computer (a disconnected laptop is probably + the best choice) and if you need it on your connected box (I know: + We all do this) be sure to have a strong password for your account + and for your secret key and that you can trust your system + administrator. + + When I check GnuPG on a remote system via ssh (I have no Alpha here + ;-) I have the same problem. It takes a *very* long time to create + the keys, so I use a special option, --quick-random, to generate + insecure keys which are only good for some tests. + + What is the difference between options and commands? + + If you do a 'gpg --help', you will get two separate lists. The first + is a list of commands. The second is a list of options. Whenever you + run GPG, you [H B]must[H /B] pick exactly one command (with one + exception, see below). You [H B]may[H /B] pick one or more options. + The command should, just by convention, come at the end of the + argument list, after all the options. If the command takes a file + (all the basic ones do), the filename comes at the very end. So the + basic way to run gpg is: + + [H pre] + gpg [--option something] [--option2] [--option3 something] --command file + [H/pre] + + Some options take arguments, for example the --output option (which + can be abbreviated -o) is an option that takes a filename. The + option's argument must follow immediately after the option itself, + otherwise gpg doesn't know which option the argument is supposed to + go with. As an option, --output and its filename must come before + the command. The --recipient (-r) option takes a name or keyid to + encrypt the message to, which must come right after the -r argument. + The --encrypt (or -e) command comes after all the options followed + by the file you wish to encrypt. So use + + [H pre] + gpg -r alice -o secret.txt -e test.txt + [H/pre] + + If you write the options out in full, it is easier to read + + [H pre] + gpg --recipient alice --output secret.txt --encrypt test.txt + [H/pre] + + If you're saving it in a file called ".txt" then you'd probably + expect to see ASCII-armored text in there, so you need to add the + --armor (-a) option, which doesn't take any arguments. + + [H pre] + gpg --armor --recipient alice --output secret.txt --encrypt test.txt + [H/pre] + + If you imagine square brackets around the optional parts, it becomes + a bit clearer: + + [H pre] + gpg [--armor] [--recipient alice] [--output secret.txt] --encrypt test.txt + [H/pre] + + The optional parts can be rearranged any way you want. + + [H pre] + gpg --output secret.txt --recipient alice --armor --encrypt test.txt + [H/pre] + + If your filename begins with a hyphen (e.g. "-a.txt"), gnupg assumes + this is an option and may complain. To avoid this you have either + to use "./-a.txt" or stop the option and command processing with two + hyphens: "-- -a.txt". + + [H B]The exception:[H /B] signing and encrypting at the same time. Use + [H pre] gpg [--options] --sign --encrypt foo.txt [H/pre] + + + I can't delete a user id because it is already deleted on my public +keyring? + + Because you can only select from the public key ring, there is no + direct way to do this. However it is not very complicated to do it + anyway. Create a new user id with exactly the same name and you + will see that there are now two identical user ids on the secret + ring. Now select this user id and delete it. Both user ids will be + removed from the secret ring. + + I can't delete the secret key because my public key disappeared? + + To select a key a search is always done on the public keyring, + therefore it is not possible to select an secret key without + having the public key. Normally it shoud never happen that the + public key got lost but the secret key is still available. The + reality is different, so we GnuPG implements a special way to do + deal with it: Simply use the long keyid which you can figure out + by using the --with-colons options (it is the fifth field in the + lines beginning with "sec"). + + What are trust, validity and ownertrust? + + "ownertrust" is used instead of "trust" to make clear that this is + the value you have assigned to a key to express how much you trust + the owner of this key to correctly sign (and so introduce) other + keys. "validity", or calculated trust, is a value which says how + much GnuPG thinks a key is valid (that it really belongs to the one + who claims to be the owner of the key). For more see the chapter + "The Web of Trust" in the Manual. + + How do I sign a patch file? + + Use "gpg --clearsign --not-dash-escaped ...". The problem with + --clearsign is that all lines starting with a dash are quoted with + "- "; obviously diff produces many of lines starting with a dash and + these are then quoted and that is not good for patch ;-). To use a + patch file without removing the cleartext signature, the special + option --not-dash-escaped may be used to suppress generation of + these escape sequences. You should not mail such a patch because + spaces and line endings are also subject to the signature and a + mailer may not preserve these. If you want to mail a file you can + simply sign it using your MUA. + + Where is the "encrypt-to-self" option? + + Use "--encrypt-to your_keyid". You can use more than one of these + options. To temporary override the use of this additional keys, you + can use the option "--no-encrypt-to". + + How can I get rid of the Version and Comment headers in armored +messages? + + Use "--no-version --comment ''". Note that the left over blank line + is required by the protocol. + + What does the "You are using the xxxx character set." mean? + + This note is printed when UTF8 mapping has to be done. Make sure + that the displayed charset is the one you have activated on your + system "iso-8859-1" is the most used one, so this is the default. + You can change the charset with the option "--charset". It is + important that you active character set matches the one displayed - + if not, restrict yourself to plain 7 bit ASCII and no mapping has to + be done. + + How can a get list of key IDs used to encrypt a message? + + [H pre] gpg --batch --decrypt --list-only --status-fd 1 2>/dev/null | \ + awk '/^\[GNUPG:\] ENC_TO / { print $3 }' [H /pre] + + I can't decrypt my symmetrical only (-c) encrypted message with + a new version of GnuPG. + + There used to be a bug in GnuPG < 1.0.1 which happens only if 3DES + or Twofish has been used for symmetric only encryption (this has + never been the default). The bug has been fixed but to enable you + to decrypt old messages, you should run gpg with the option + "--emulate-3des-s2k-bug", decrypt the message and encrypt it again + without this option. The option will be removed in 1.1, so better + re-encrypt your message now. + + How can I use GnuPG in an automated environment? + + You should use the option --batch and don't use pass phrases as + there is usually no way to store it more secure than the secret + keyring itself. The suggested way to create the keys for the + automated environment is: + + On a secure machine: + [H OL] [H LI] If you want to do automatic signing, create a signing + subkey for your key (edit menu, choose "addkey" and the DSA). [H + LI] Make sure that you use a passphrase (Needed by the current + implementation) [H LI] gpg --export-secret-subkeys --no-comment foo + >secring.auto [H LI] Copy secring.auto and the public keyring to a + test directory. [H LI] Cd to this directory. [H LI] gpg --homedir + . --edit foo and use "passwd" to remove the pass-phrase from the + subkeys. You may also want to remove all unused subkeys. [H LI] + copy secring.auto to a floppy and carry it to the target box [H /OL] + On the target machine: [H OL] [H LI] Install secring.auto as secret + keyring. [H LI] Now you can start your new service. It is a good + idea to install some intrusion detection system so that you + hopefully get a notice of an successful intrusion, so that you in + turn can revoke all the subkeys installed on that machine and + install new subkeys. [H /OL] + + Which email-client can I use with GnuPG? + + Using GnuPG to encrypt email is one of the most popular + uses. Several mail clients or mail user-agents (MUA) support GnuPG + at varying degrees. Simplifying a bit, there are two ways a mail can + be encrypted with GnuPG: the "old style" ASCII armor, i.e. plain + text encryption, and RFC2015 style (previously PGP/MIME, now + OpenPGP). The latter has full MIME support. Some MUAs support only + one of them, so whichever you actually use depends on your needs as + well as the capabilities of your addressee. + + The following list is probably not exhaustive: + + OpenPGP: Mutt (Unix), Emacs/Mew, Becky2 (Windows, with plugin), + TkRat (Unix). There is effort for a Mozilla plugin and + Emacs/GNUS has support in the current CVS. + + ASCII: Emacs/{VM,GNUS}/MailCrypt, Mutt(Unix), Pine(Unix), and + probably many more. + + Good overviews of OpenPGP-support can be found at + [H a href=http://cryptorights.org/pgp-users/pgp-mail-clients.html]http://cryptorights.org/pgp-users/pgp-mail-clients.html[H /a]. + and [H a href=http://www.geocities.com/openpgp/courrier_en.html]http://www.geocities.com/openpgp/courrier_en.html[H /a]. + + + Can't we have a gpg library? + + This has been frequently requested. However, the current viewpoint + of the GnuPG maintainers is that this would lead to several security + issues and will therefore not be implemented in the foreseeable + future. However, for some areas of areas of application gpgme could + do the trick. You'll find it at + [H a href=ftp://ftp.guug.de/pub/gcrypt/alpha/gpgme]ftp://ftp.guug.de/pub/gcrypt/alpha/gpgme[H /a] + + + I have successfully generated a revocation certificate, but I don't + understand how to send it to the key servers. + + Most keyservers don't accept a 'bare' revocation certificate. You + have to import the certificate into gpg first: + [H pre] + gpg --import my-revocation.asc + [H /pre] + then send the revoked key to the keyservers: + [H pre] + gpg --keyserver certserver.pgp.com --send-keys mykeyid + [H /pre] + (or use a keyserver web interface for this). + + + How do I put my keyring in a different directory? + + GnuPG keeps several files in a special homedir directory. These + include the options file, pubring.gpg, secring.gpg, the trustdb, and + others. Gnupg will always create and use these files. On unices, + the homedir is usually ~/.gnupg; on Windows "C:\gnupg\". + + If you want to put your keyrings somewhere else, use + [H pre]--homedir /my/path/[H /pre] to make gnupg create all its + files in that directory. Your keyring will be + "/my/path/pubring.gpg". This way you can store your secrets on a + floppy disk. Don't use "--keyring" as its purpose is to specify + additional keyring files. + + + COMPATIBILITY ISSUES + + + + How can I encrypt a message with GnuPG so that PGP is able to decrypt it? + + It depends on the PGP version.[H UL] + + [H LI] PGP 2.x + + You can't do that because PGP 2.x normally uses IDEA which is not + supported by GnuPG as it is patented (see ), but if you + have a modified version of PGP you can try this: + + [H pre] gpg --rfc1991 --cipher-algo 3des ... [H/pre] + + Please don't pipe the data to encrypt to gpg but provide it using a + filename; otherwise, PGP 2 will not be able to handle it. + + As for conventional encryption, you can't do this for PGP 2. + + + [H LI] PGP 5.x and higher + + You need to provide two additional options: + [H pre]--compress-algo 1 --cipher-algo cast5 [H/pre] + + You may also use "3des" instead of "cast5", "blowfish" does not + work with all versions of pgp5. You may also want to put [H pre] + compress-algo 1 [H/pre] into your ~/.gnupg/options file - this does + not affect normal gnupg operation. + + This applies to conventional encryption as well. + [H /UL] + + How do I migrate from PGP 2.x to GnuPG? + + PGP 2 uses the RSA and IDEA encryption algorithms. Whereas the RSA + patent has expired and RSA is included as of GnuPG 1.0.3, the IDEA + algorithm is still patented until 2007. Under certain conditions you + may use IDEA even today. In that case, you may refer to Question + about how to add IDEA support to GnuPG and read + [H a href=http://www.gnupg.org/gph/en/pgp2x.html]http://www.gnupg.org/gph/en/pgp2x.html[H /a] + to perform the migration. + + + (removed) + + (empty) + + Why is PGP 5.x not able to encrypt messages with some keys? + + PGP Inc refuses to accept ElGamal keys of type 20 even for + encryption. They only support type 16 (which is identical at least + for decryption). To be more inter-operable, GnuPG (starting with + version 0.3.3) now also uses type 16 for the ElGamal subkey which is + created if the default key algorithm is chosen. You may add an type + 16 ElGamal key to your public key which is easy as your key + signatures are still valid. + + Why is PGP 5.x not able to verify my messages? + + PGP 5.x does not accept V4 signatures for data material but OpenPGP + requests generation of V4 signatures for all kind of data, that's why + GnuPG defaults to them. Use the option "--force-v3-sigs" to generate + V3 signatures for data. + + How do I transfer owner trust values from PGP to GnuPG? + + There is a script in the tools directory to help you: After you have + imported the PGP keyring you can give this command: + + [H pre] + $ lspgpot pgpkeyring | gpg --import-ownertrust + [H /pre] + + where pgpkeyring is the original keyring and not the GnuPG one you + might have created in the first step. + + PGP does not like my secret key. + + Older PGPs probably bail out on some private comment packets used by + GnuPG. These packets are fully in compliance with OpenPGP; however + PGP is not really OpenPGP aware. A workaround is to export the + secret keys with this command: + [H pre] $ gpg --export-secret-keys --no-comment -a your-key-id [H /pre] + + Another possibility is this: by default, GnuPG encrypts your secret + key using the Blowfish symmetric algorithm. Older PGPs will only + understand 3DES, CAST5, or IDEA symmetric algorithms. Using the + following method you can re-encrypt your secret gpg key with a + different algo: + + [H pre] + $ gpg --s2k-cipher-algo=CAST5 --s2k-digest-algo=SHA1 \ + --compress-algo=1 --edit-key + [H /pre] + + Then use passwd to change the password (just change it to the same + thing, but it will encrypt the key with CAST5 this time). + + Now you can export it and PGP should be able to handle it. + + For PGP 6.x the following options work to export a key: + [H pre] + $ gpg --s2k-cipher-algo 3des --compress-algo 1 --rfc1991 \ + --export-secret-keys + [H /pre] + + PROBLEMS and ERROR MESSAGES + + Why do I get "gpg: Warning: using insecure memory!" + + On many systems this program should be installed as + setuid(root). This is necessary to lock memory pages. Locking + memory pages prevents the operating system from writing them + to disk and thereby keeping your secret keys really secret. If you + get no warning message about insecure memory your operating system + supports locking without being root. The program drops root + privileges as soon as locked memory is allocated. + + On UnixWare 2.x and 7.x you should install GnuPG with the + 'plock' privilege to get the same effect: + [H pre] + filepriv -f plock /path/to/gpg + [H /pre] + + If you can't or don't want to install GnuPG setuid(root), you can + use the option "--no-secmem-warning" or put [H pre] + no-secmem-warning [H /pre] in your ~/.gnupg/options file (this + disables the warning). + + On some systems (e.g., Windows) GnuPG does not lock memory pages + and older GnuPG versions (<=1.0.4) issue the warning + [H pre] + gpg: Please note that you don't have secure memory + [H /pre] + This warning can't be switched off by the above option because it + was thought to be a too serious issue. However, it confused users + too much so the warning was eventually removed. + + Large File Support doesn't work .. + + LFS is correctly working in post-1.0.4 CVS. If configure doesn't + detect it correctly, try a different (i.e., better) compiler. egcs + 1.1.2 works fine, other gccs sometimes don't. BTW, several + compilation problems of GnuPG 1.0.3 and 1.0.4 on HP-UX and Solaris + were due to broken LFS support. + + In the edit menu the trust values is not displayed correctly after +signing uids - why? + + This happens because the some informations are stored immediately in + the trustdb, but the actual trust calculation can be done after the + save command. This is a not easy to fix design bug which will be + addressed in some future release. + + What does "skipping pubkey 1: already loaded" mean? + + As of GnuPG 1.0.3, the RSA algorithm is included. If you still have + a "load-extension rsa" in your .options files, the above message + occurs. Just remove the load command from the .options file. + + GnuPG 1.0.4 doesn't create ~/.gnupg ... + + That's a known bug, already fixed in newer versions. + + An ElGamal signature does not verify anymore since version 1.0.2 ... + + Use the option --emulate-md-encode-bug. + + Old versions of GnuPG can't verify ElGamal signatures + + Update to GnuPG 1.0.2 or newer. + + + When I use --clearsign, the plain text has sometimes extra dashes +in it - why? + + This is called dash-escaped text and required by OpenPGP. + It always happens when a line starts with a dash ("-") and is needed + to make the lines that structure signature and text + (i.e., "-----BEGIN PGP SIGNATURE-----") to be the only lines that + start with two dashes. + + If you use GnuPG to process those messages, the extra dashes are removed. + Good mail clients remove those extra dashes when displaying such a + message. + + What is the thing with "can't handle multiple signatures"? + + Due to different message formats GnuPG is not always able to split a + file with multiple signatures unambiguously into its parts. This + error message informs you that there is something wrong with the input. + + The only way to have multiple signatures in a file is by using the + OpenPGP format with one-pass-signature packets (which is GnuPG's + default) or the cleartext signed format. + + If I submit a key to a keyserver, nothing happens ... + + You are most likely using GnuPG on Windows 1.0.2 or older. That's + feature isn't yet implemented, but it's a bug not to say it. Newer + versions issue a warning. Upgrade to 1.0.4 or newer. + + I get "gpg: waiting for lock ..." + + A previous gpg has most likely exited abnormally and left a lock + file. Go to ~/.gnupg and look for .*.lock files and remove them. + + Older gpg's (e.g., 1.0) have problems with keys from newer gpgs ... + + As of 1.0.3, keys generated with gpg are created with preferences to + TWOFISH (and AES since 1.0.4) and that also means that they have the + capability to use the new MDC encryption method. This will go into + OpenPGP soon and is also suppoted by PGP 7. This new method avoids + a (not so new) attack on all email encryption systems. + + This in turn means that pre-1.0.3 gpg's have problems with newer + key. Because of security fixes, you should keep your gpg + installation in a recent state anyway. As a workaround, you can + force gpg to use a previous default cipher algo by putting + [H pre]cipher-algo cast5[H /pre] into your options file. + + With 1.0.4, I get "this cipher algorithm is deprecated ..." + + If you just generated a new key and get this message while + encrypting, you've witnessed a bug in 1.0.4. It uses the new AES + cipher Rijndael that is incorrectly being referred as + "deprecated". Ignore this warning, more recent versions of gpg are + corrected. + + Some dates are displayed as ????-??-??, why? + + Due to constraints in most libc implementations, dates beyond + 2038-01-19 can't be displayed correctly. 64 bit OSes are not + affected by this problem. To avoid printing wrong dates, GnuPG + instead prints some question marks. To see the correct value, you + can use the options --with-colons and --fixed-list-mode. + + I still have a problem. How do I report a bug? + + Are you sure that it's not been mentioned somewhere on the mailing + lists? Did you have a look at the bug list (You'll find a link to + the list of reported bugs on the documentation page). If you're not + sure about it being a bug, you can send mail to the gnupg-devel + list. Otherwise, use the GUUG bug tracking system + [H a href=http://bugs.guug.de/Reporting.html] + http://bugs.guug.de/Reporting.html[H /a]. + + Why doesn't GnuPG support X509 certificates? + + GnuPG, first and foremost, is an implementation of the OpenPGP + standard (RFC 2440), which is a competing infrastructure, different + from X509. + + They are both public-key cryptosystems, but how the public keys are + actually handled is different. + + + Why do national characters in my user ID look funny? + + According to OpenPGP, GnuPG encodes user id strings (and other + things) using UTF-8. In this encoding of Unicode, most national + characters get encoded as two- or three-byte sequences. For + example, å (0xE5 in ISO-8859-1) becomes Ã¥ (0xC3, + 0xA5). This might also be the reason why keyservers can't find + your key. + + I get 'sed' errors when running ./configure on Mac OS X ... + + This will be fixed after GnuPG has been upgraded to + autoconf-2.50. Until then, find the line setting CDPATH in the + configure script and place a [H pre]unset CDPATH[H /pre] statement + below it. + + Why does GnuPG 1.0.6 bail out on keyrings used with 1.0.7? + + There is a small bug in 1.0.6 which didn't parse trust packets + currectly. You may want to apply this patch if you can't upgrade: + http://www.gnupg.org/developer/gpg-woody-fix.txt + + + + ADVANCED TOPICS + + How does this whole thing work? + + To generate a secret/public keypair, run [H pre] gpg --gen-key + [H/pre] and choose the default values. + + Data that is encrypted with a public key can only be decrypted by + the matching secret key. The secret key is protected by a password, + the public key is not. + + So to send your friend a message, you would encrypt your message + with his public key, and he would only be able to decrypt it by + having the secret key and putting in the password to use his secret + key. + + GnuPG is also useful for signing things. Things that are encrypted + with the secret key can be decrypted with the public key. To sign + something, a hash is taken of the data, and then the hash is in some + form encoded with the secret key. If someone has your public key, they + can verify that it is from you and that it hasn't changed by checking + the encoded form of the hash with the public key. + + A keyring is just a large file that stores keys. You have a public + keyring where you store yours and your friend's public keys. You have + a secret keyring that you keep your secret key on, and be very careful + with this secret keyring: Never ever give anyone else access to it and + use a *good* passphrase to protect the data in it. + + You can 'conventionally' encrypt something by using the option 'gpg + -c'. It is encrypted using a passphrase, and does not use public and + secret keys. If the person you send the data to knows that + passphrase, they can decrypt it. This is usually most useful for + encrypting things to yourself, although you can encrypt things to your + own public key in the same way. It should be used for communication + with partners you know and where it is easy to exchange the + passphrases (e.g. with your boy friend or your wife). The advantage + is that you can change the passphrase from time to time and decrease + the risk, that many old messages may be decrypted by people who + accidently got your passphrase. + + You can add and copy keys to and from your keyring with the 'gpg + --import' and 'gpg --export' option. 'gpg --export-secret-keys' will + export secret keys. This is normally not useful, but you can generate + the key on one machine then move it to another machine. + + Keys can be signed under the 'gpg --edit-key' option. When you sign a + key, you are saying that you are certain that the key belongs to the + person it says it comes from. You should be very sure that is really + that person: You should verify the key fingerprint + [H pre] + gpg --fingerprint user-id + [H/pre] + over phone (if you really know the voice of the other person) or at a + key signing party (which are often held at computer conferences) or at + a meeting of your local GNU/Linux User Group. + + Hmm, what else. You may use the option "-o filename" to force output + to this filename (use "-" to force output to stdout). "-r" just lets + you specify the recipient (which public key you encrypt with) on the + command line instead of typing it interactively. + + Oh yeah, this is important. By default all data is encrypted in some + weird binary format. If you want to have things appear in ASCII text + that is readable, just add the '-a' option. But the preferred method + is to use a MIME aware mail reader (Mutt, Pine and many more). + + There is a small security glitch in the OpenPGP (and therefore GnuPG) + system; to avoid this you should always sign and encrypt a message + instead of only encrypting it. + + + Why are some signatures with an ELG-E key valid? + + These are ElGamal Key generated by GnuPG in v3 (rfc1991) packets. + The OpenPGP draft later changed the algorithm identifier for ElGamal + keys which are usable for signatures and encryption from 16 to 20. + GnuPG now uses 20 when it generates new ElGamal keys but still + accept 16 (which is according to OpenPGP "encryption only") if this + key is in a v3 packet. GnuPG is the only program which had used + these v3 ElGamal keys - so this assumption is quite safe. + + + How does the whole trust thing work? + + It works more or less like PGP. The difference is that the trust is + computed at the time it is needed. This is one of the reasons for + the trustdb which holds a list of valid key signatures. If you are + not running in batch mode you will be asked to assign a trust + parameter (ownertrust) to a key. + + + + You can see the validity (calculated trust value) using this + command. + [H pre] gpg --list-keys --with-colons [H/pre] + + If the first field is "pub" or "uid", the second field shows you the + trust: + + [H pre] + o = Unknown (this key is new to the system) + e = The key has expired + q = Undefined (no value assigned) + n = Don't trust this key at all + m = There is marginal trust in this key + f = The key is full trusted + u = The key is ultimately trusted; this is only used + for keys for which the secret key is also available. + r = The key has been revoked + d = The key has been disabled + [H/pre] + + The value in the "pub" record is the best one of all "uid" records. + + You can get a list of the assigned trust values (how much you trust + the owner to correctly sign another person's key) + + [H pre] gpg --list-ownertrust [H/pre] The first field is the + fingerprint of the primary key, the second field is the assigned + value: + + [H pre] + - = No Ownertrust value yet assigned. + n = Never trust this keyholder to correctly verify others signatures. + m = Have marginal trust in the keyholders capability to sign other + keys. + f = Assume that the key holder really knows how to sign keys. + u = No need to trust ourself because we have the secret key. + [H/pre] + + Keep these values confidential because they express your opinions + about others. PGP stores this information with the keyring thus it + is not a good idea to publish a PGP keyring instead of exporting the + keyring. gnupg stores the trust in the trust-DB so it is okay to + give a gpg keyring away (but we have a --export command too). + + What kind of output is this: "key C26EE891.298, uid 09FB: ...."? + + This is the internal representation of a user id in the trustdb. + "C26EE891" is the keyid, "298" is the local id (a record number in + the trustdb) and "09FB" is the last two bytes of a ripe-md-160 hash + of the user id for this key. + + How do I interpret some of the informational outputs? + + While checking the validity of a key, GnuPG sometimes prints some + information which is prefixed with information about the checked + item. [H pre] "key 12345678.3456" [H/pre] This is about the key + with key ID 12345678 and the internal number 3456, which is the + record number of the so called directory record in the trustdb. + [H pre] "uid 12345678.3456/ACDE" [H/pre] This is about the user ID for + the same key. To identify the user ID the last two bytes of a + ripe-md-160 over the user ID ring is printed. [H pre] "sig + 12345678.3456/ACDE/9A8B7C6D" [H/pre] This is about the signature + with key ID 9A8B7C6D for the above key and user ID, if it is a + signature which is direct on a key, the user ID part is empty + (..//..). + + Are the header lines of a cleartext signature part of the signed +material? + + No. For example you can add or remove "Comment:" lines. They have + a purpose like the mail header lines. However a "Hash:" line is + needed for OpenPGP signatures to tell the parser which hash + algorithm to use. + + + What is the list of preferred algorithms? + + The list of preferred algorithms is a list of cipher, hash and + compression algorithms stored in the self-signature of a key during + key generation. When you encrypt a document, GnuPG uses this list + (which is then part of a public key) to determine which algorithms + to use. Basically it tells other people what algorithms the + recipient is able to handle and provides an order of preference. + + How do I change the list of preferred algorithms? + + Use the edit menu and set the new list of preference using the + command "setpref"; the format of this command resembles the output + of the command "pref". The preference are not changes immediately + but the set preference will be used when a new user ID is + created. If you want to update the preferences for existing user + IDs, select those user IDs (or select none to update all) and + enter the command "updpref". Note that the timestamp of the + self-signatures is increaded by one second when running this + command. + + + ACKNOWLEDGEMENTS + + Many thanks to Nils Ellmenreich for maintaining this FAQ file for + a long time and to all posters to gnupg-users and gnupg-devel. They + all provided most of the answers. + + Also thanks to Casper Dik for providing me with a script to generate + this FAQ (he uses it for the excellent Solaris2 FAQ). + +[H HR] + +Copyright (C) 2000, 2002 Free Software Foundation, Inc. , +59 Temple Place - Suite 330, Boston, MA 02111, USA + +Verbatim copying and distribution of this entire article is permitted in +any medium, provided this notice is preserved. diff --git a/doc/fr/ChangeLog b/doc/fr/ChangeLog new file mode 100644 index 000000000..167093dcc --- /dev/null +++ b/doc/fr/ChangeLog @@ -0,0 +1,17 @@ +2001-09-10 Gilbert Fernandes + + * Traduction en français des documents doc/* + + +Copyright 2001 Free Software Foundation, Inc. + +Ce fichier est un logiciel libre ; l'auteur vous donne une autorisation +spéciale de copies illimitées et/ou distribution illimitée avec ou sans +modifications attendu que cette notice de copyright et note associée +se trouve conservée dans le document. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/doc/fr/DETAILS b/doc/fr/DETAILS new file mode 100644 index 000000000..5c7246c9d --- /dev/null +++ b/doc/fr/DETAILS @@ -0,0 +1,945 @@ + +Format des listings "---with-colons" +==================================== + +sec::1024:17:6C7EE1B8621CC013:1998-07-07:0:::Werner Koch : +ssb::1536:20:5CE086B5B5A18FF4:1998-07-07:0::: + + 1. Champ: Type d'enregistrement + pub = clef publique + sub = sous-clef (clef secondaire) + sec = clef secrète + ssb = sous-clef secrète (clef secondaire) + uid = id d'utilisateur (seul le champ 10 est utilisé) + sig = signature + fpr = fingerprint: (le champ 10 est le fingerprint) + pkd = données publiques de la clef + (champ au format spécial, voir ci-dessous) + + 2. Champ: Une lettre décrivant la confiance calculée. Ce n'est qu'une + seule lettre, mais elle fera peut-être l'objet d'une information + supplémentaire pour les versions futures, comme décrit ici + (ceci ne sera pas utilisé pour les clefs privées) + o = Inconnu (cette clef est nouvelle au système) + i = La clef est invalide (eg. il manque sa propre signature) + d = La clef a été désactivée + r = La clef a été révoquée + e = La clef a expiré + q = Non-défini (pas de valeur attribuée) + n = Ne jamais faire confiance à cette clef + m = Cette clef dispose d'une confiance marginale + f = Cette clef dispose d'une confiance totale + u = Cette clef dispose d'une confiance ultime. Cette valeur + n'est utilisée que pour les clefs où la clef secrète est + également disponibles. + 3. Champ: taille de la clef en bits. + 4. Champ: Algorithme utilisé: 1 = RSA + 16 = ElGamal (chiffrement uniquement) + 17 = DSA (parfois appellé DH, signature seulement) + 20 = ElGamal (signe et chiffre) + (pour d'autres is, consultez include/cipher.h) + 5. Champ: ID de clef (KeyID) + 6. Champ: Date de création (en UTC) + 7. Champ: Date d'expiration de la clef, vide si aucune. + 8. Champ: ID local : numéro d'enregistrement du répertoire dans la + trustdb. Cette valeur n'est valide que tant que la + trustdb n'est pas effacée. Vous pouvez utiliser + "#" comme id d'utilisateur lorsque vous spécifiez + la clef. Ceci est requis puisque les id de clef ne sont pas + toujours uniques - un programme peut donc utiliser ce numéro + pour accéder aux clefs ultérieurement. + 9. Champ: Confiance propre (clef publiques primaires uniquement) + C'est une simple lettre, mais une information supplémentaire pourrait + se voir ajoutée dans les versions futures. +10. Champ: ID utilisateur. La valeur est placée entre guillemets comme une + chaîne en C, par exemple : "\x3a". +11. Champ: Classe de signature. C'est un nombre hexadécimal à deux chiffres + suivi par la lettre "x" si la signature peut être exportée ou la + lettre "l" si la signature est uniquement locale. +12. Champ: Capacités de la clef : + e = chiffrement + s = signature + c = certification + Une clef peut disposer de toute combinaison de ces caractéristiques. + La clef primaire dispose, en plus de ces lettres, une version en + majuscule des lettres pour marquer les capacités "d'utilisation" + de la totalité de la clef. + +Toutes les dates sont affichées dans le format : + +yyyy-mm-dd + +Sauf si vous utilisez l'option --fixed-list-mode où dans ce cas précis les +dates sont affichées en secondes depuis Epoch. Plus de champs feront l'objet +d'additions dans les futures versions et les parsers doivent y être préparés. +Lorsque le parser traitera ces données, il devra s'arrêter au premier +caractère non-numérique afin que des informations supplémentaires soient +ajoutées à l'avenir. + +Le champ 1 dispose d'un tag "pkd" dont le listing ressemble à ceci : + +pkd:0:1024:B665B1435F4C2 .... FF26ABB: + ! ! !-- la valeur + ! !------ indicateur du nombre de bits de la valeur + !--------- index (eg. DSA va de 0 à 3 : p,q,g,y) + + + +Format de la sortie "--status-fd" +================================= + +Chaque ligne dispose d'un préfixe : + +"[GNUPG:] " + +Suivie par un mot clef indiquant le type de la ligne de statut, +et quelques arguments selon le type (probablement aucun) ; une application +devrait toujours assumer que des arguments supplémentaires seront +présents dans les versions futures. + + GOODSIG + La signature keyid est valide. + Pour chaque signature seul l'un des trois codes GOODSIG, BADSIG ou + ERRSIG seront produits et ils pourront être utilisés comme + marqueurs pour les nouvelles signatures. + + BADSIG + La signature keyid n'a pas été vérifiée correctement. + + ERRSIG \ + + Il n'a pas été possible de vérifier la signature. Ceci peut provenir + d'une clef publique manquante, ou bien à cause d'un algorithme non- + supporté. Un RC de 4 indique un algorithme inconnu, un 9 indique + une clef publique manquante. Les autres champs donnent plus d'information + sur la signature. sig_class est une valeur hexadécimale de 2 octets. + + VALIDSIG + La signature keyid est valide. C'est ici la même chose que GOODSIG + mais avec le fingerprint comme argument. Les lignes de statut seront + émises pour une bonne signature. + sig-timestamp est la date de création de la signature en secondes + depuis Epoch. + + SIG_ID + N'est émis que pour les signatures de classe 0 ou 1 qui ont été + vérifiées comme valides. Le chaîne est un identifiant d'utilisateur + et peut être utilisée dans les applications pour détecter les + attaques par rejeu de messages signés. Notez que seuls les + algorithmes DLP offrent des identifiants uniques ; les autres peuvent + produire des id dupliqués lorsqu'ils furent créés à la même seconde. + + ENC_TO + Le message est chiffré avec ce keyid. + keytype est une valeur numérique de l'algorithme à clef publique, + keylength est la taille de la clef ou 0 si elle n'est pas connue + (ce qui est toujours le cas). + + NODATA + Aucune donnée n'a été trouvée. Les codes suivants sont utilisés : + 1 - Pas de données sous ARMOR. + 2 - Un paquet attendu n'a pas été trouvé. + 3 - Paquet invalide trouvé ; ceci peut indiquer un message + non-OpenPGP. Vous devez vous attendre à une extension + de ces lignes de statu à l'avenir. + + UNEXPECTED + Des données innatendues ont été rencontrées + 0 - pas de détail supplémentaire + + TRUST_UNDEFINED + TRUST_NEVER + TRUST_MARGINAL + TRUST_FULLY + TRUST_ULTIMATE + Pour les signatures valides, l'une de ces lignes de statut sera produite + pour indiquer le niveau de confiance attribué à la clef. Pas d'arguments + pour l'instant. + + SIGEXPIRED + La clef de signature a expiré. Pas d'arguments pour l'instant. + + KEYREVOKED + L'utilisateur a révoqué sa clef. Pas d'arguments pour l'instant. + + BADARMOR + L'ARMOR ASCII est corrompu. Pas d'arguments pour l'instant. + + RSA_OR_IDEA + Les algorithmes IDEA ont été utilisés sur les données. Un programme + pourra basculer sur un autre programme de traitement si GnuPG échoue. + Ce message de statut sera affiché pour le RSA aussi, mais ceci a été + abandonné puisque le brevêt sur le RSA a expiré. + Toutefois, nous ne pouvons modifier le nom du message. + + SHM_INFO + SHM_GET + SHM_GET_BOOL + SHM_GET_HIDDEN + + GET_BOOL + GET_LINE + GET_HIDDEN + GOT_IT + + NEED_PASSPHRASE + Sera affiché à chaque fois qu'une phrase passe sera requise. + keytype est la valeur numérique de l'algorithme à clef publique + ou bien 0 si cela n'est pas applicable. keylength est la taille de la + clef ou 0 si la taille n'est pas connue (ceci est actuellement + toujours le cas). + + NEED_PASSPHRASE_SYM + Affiché à chaque fois qu'une phrase passe pour un chiffrement + symétrique sera requise. + + MISSING_PASSPHRASE + Aucune phrase passe n'a été fournie. Une application qui rencontre + ce message devrait stopper immédiatement le parsing car le prochain + message sera probablement BAD_PASSPHRASE. Toutefois, si l'application + n'est qu'un wrapper autour de la fonctionnalité d'édition de clefs, + ceci pourrait avoir un autre sens et stopper le parsing pourrait + être incorrect, et il faudra ignorer le BAD_PASSPHRASE. + + BAD_PASSPHRASE + La phrase passe fournie est soit invalide, soit n'a pas été fournie. + Dans le seconde cas vous devriez voir un MISSING_PASSPHRASE. + + GOOD_PASSPHRASE + La phrase passe fournie est valide et le matériel de clefs secrète + est utilisable. + + DECRYPTION_FAILED + La déchiffrement symétrique a échoué. Il s'agit généralement d'une + mauvaise phrase passe ne correspondant pas au message chiffré. + + DECRYPTION_OKAY + Succès du déchiffrement. Ceci signifie que soit la clef secrète + adaptée a été utilisée avec succès, soit que la phrase passe + valide pour un chiffrement symétrique aura conduit au déchiffrement. + Le programme pourait toutefois renvoyer un message d'erreur s'il + n'a pas été possible de vérifier la signature. + + NO_PUBKEY + NO_SECKEY + La clef n'est pas utilisable. + + IMPORTED + Le keyid et la signature ont été importés. + + IMPORTED_RES + + Statistiques finales sur le processus d'importation (cette ligne est longue!) + + FILE_START + Début de traitement du fichier . indique l'opération + réalisée : + 1 - vérifier + + FILE_DONE + Marque la fin de traitement d'un fichier, ayant débuté avec FILE_START. + + BEGIN_DECRYPTION + END_DECRYPTION + Marque le début et la fin du processus de déchiffrement. Ces messages + seront également produits lors de l'utilisation du mode --list-only. + + BEGIN_ENCRYPTION + END_ENCRYPTION + Marque le début et la fin du processus de chiffrement. + + DELETE_PROBLEM reason_code + L'effacement d'une clef a échoué. Un code indique la raison de l'erreur : + 1 - La clef spécifiée n'existe pas + 2 - La clef privée doit être détruite avant ! + + PROGRESS what char cur total + Utilisé par les fonctions primegen et de clef publique pour indiquer + la progression de l'opération. "char" est le caractère affiché sans + --status-fd avec les retours à la ligne marqués par "X". "cur" indique + la quantitité de traitement terminée et "total" indique la valeur + finale à atteindre. Un total de 0 indique que le total n'est pas + connu. 100/100 peut être utilisé pour détecter la fin de l'opération. + + SIG_CREATED + Une signature a été créée à l'aide de ces paramètres. + type: 'D' = détachée + 'C' = en texte clair + 'S' = standard + (seul le premier caractère doit être vérifié) + class: 2 chiffres hexadécimaux avec la classe de signature + + KEY_CREATED + Une clef a été créée + type: 'B' = primaire et sous-clef + 'P' = primaire + 'S' = sous-clef + + SESSION_KEY : + La clef de session utilisée pour déchiffrer le message. Ce message + sera seulement affiché si l'option --show-session est utilisée. + Le format est utilisable pour un passage direct à la fonction + --override-session-key. + + NOTATION_NAME + NOTATION_DATA + Le nom et la chaîne sont "escaped" à l'aide de %XX et les données + peuvent être découpées sur plusieurs lignes notation_data. + + USERID_HINT + Donne un indice sur l'ID utilisateur pour un keyID donné. + + POLICY_URL + La chaîne est "escaped" en %XX + + BEGIN_STREAM + END_STREAM + Produit par pipemode. + + +Génération de clef +================== + +La génération de clef marque sa progression à l'aide de différents caractères, dont +voici la signification : + +"." : les 10 derniers tests Miller-Rabin ont échoué. +"+" : réussite du test Miller-Rabin. +"!" : Rechargement du pool avec des nombres premiers frais. +"^" : Vérification d'une nouvelle valeur pour le générateur. +"<" : La taille d'un facteur a été réduite. +">" : La taille d'un facteur a été augmentée. + +Le nombre premier pour l'ElGamal est généré de la manière suivante : + +1. On crée un nombre premier q de 160, 200 ou 240 bits (selon la taille + de la clef). +2. On sélectionne la taille de l'autre facteur premier, afin qu'elle soit + au moins de la taille de q et on calcule le nombre de facteurs premiers + requis. +3. On crée un pool de nombres premiers, chacun dont la longueur fut déterminée + à l'étape 2. +4. On obtient une nouvelle permutation du pool et nous continuons avec + l'étape 3 une fois toutes les permutations testées. +5. Le premier cancidat est calculé par p = 2 * q * p[1] * ... * p[n] + 1 +6. On vérifie que ce premier dispose de la taille désirée (ceci peut changer + q s'il ne semble pas possible de produire un premier de la taille voulue) +7. On vérifie si ce nombre est premier à l'aide de divisions d'essai et par + le test de Miller-Rabin. +8. On continue à l'étape 4 si on n'a pas trouvé de premier à l'étape 7. +9. On trouve un générateur pour ce premier. + +Cet algorithme se base sur la suggestion de Lim et Lee du Crypto' 97 (p. 260). + +Génération de clef innatendue +============================= + +Cette fonction est actuellement expérimentale et permet la production de +clefs innatendues avec un contrôle depuis un fichier de paramètres. +Cette fonctionnalité n'a pas fait l'objet de tests poussés ! Veuillez ne +PAS vous plaindre si nous décidons d'apporter des modifications importantes +à cette commande. + +Pour utiliser cette fonctionnalité, vous devez utiliser --gen-key en +combinaison avec --batch et fournir les paramètres soit depuis stdin, +soit depuis un fichier dont le nom est fourni en ligne de commande. + +Ce fichier devra utiliser le format suivant : + + o En texte uniquement, chaque ligne étant limitée à environ 1000 caractères. + o Vous devez utiliser un codage UTF-8 pour marquer les caractères non ASCII. + o Les lignes vides seront ignorées. + o Les espaces en début et fin de ligne seront ignorés. + o Un signe "-" en tant que premier caractère "non white space" marque + une ligne de commentaire. + o Les commandes sont marquées par un signe "%" en début de ligne, + suivi par la commande et ses arguments sont séparés par des espaces. + o Les paramètres sont indiqués par un mot clef, suivi par un ":". Les + arguments sont séparés par des espaces. + o Le premier paramètre doit être "Key-Type" et ses contrôles peuvent + être placés à votre discrétion. + o La génération de clef aura lieu soit à la fin du fichier de paramètres, + soit lorsque le premier "Key-Type" est rencontré au sein du fichier, + dans un ensenble de contrôle "%commit". + o Les ensembles de contrôle sont : + %echo + Affiche + + %dry-run + Ne réalise pas la production de clef (pratique pour vérifier la + syntaxe). + + %commit + Réalise la production de clef. Un commit implicite est produit + à chaque rencontre de "Key-Type". + + %pubring + %secring + Ne renvoie pas la clef vers le sortie par défaut ou dans le keyring + indiqué en ligne de commande, mais vers le fichier . Ce + contrôle doit être utilisé avant que le commit ne soit rencontré. + Toute double mention sera ignorée et le dernier nom de fichier + rencontré sera celui utilisé. Le fichier sera utilisé jusqu'à ce + qu'un nouveau fichier soit spécifié (au points de commit) sinon + toutes les clefs seront placées dans le même fichier. Si un nouveau + nom de fichier est indiqué, le fichier sera créé (et tout ancien + fichier sera alors écrasé). Les deux indications doivent être + fournies au contrôle. + + o L'ordre des paramètres n'a pas d'importance, sauf pour "Key-Type" qui + doit être le premier paramètre rencontré. Les paramètres ne sont + destinés qu'au bloc keybloc généré et les paramètres des productions + précédentes de clefs ne seront pas pris en compte. Certaines + vérifications syntaxiques seront mises en place et peuvent être + ou non actives. Les paramètres actuellement définis sont : + + Key-Type: | + Débute un nouveau bloc de paramètres indiquant le type de la clef + primaire à produire. L'algorithme doit être capable de produire + des signatures. Ce paramètre est indispensable ! + + Key-Length: + Indique la taille de la clef, en bits. La valeur par défaut est + 1024. + + Subkey-Type: | + Permet de produire une clef secondaire. Actuellement, seule une + sous-clef peut être gérée. + + Subkey-Length: + Taille de la sous-clef en bits. La valeur par défaut est + 1024. + + Passphrase: + Si vous souhaitez spécifier une phrase passe pour la clef + secrète vous pouvez utiliser cette commande. Par défaut, + aucune phrase passe ne sera associée aux clefs privées. + + Name-Real: + Name-Comment: + Name-Email: + Voici les trois composantes d'une clef. Vous devez ici + n'utiliser que de l'UTF-8. Si vous ne fournissez aucune + de ces indications, aucun ID d'utilisateur ne sera créé. + + Expire-Date: |([d|w|m|y]) + Spécifie la date d'expiration de la clef (et de sa sous-clef) + La date doit être entrée sous la forme d'une date au format + ISO (année-mois-jour) ou bien sous forme d'un nombre de + jours, de semaines, de mois ou d'années. Si vous n'utilisez + pas de lettre pour indiquer la durée, des "jours" sont + assumés par défaut. + +Voici un exemple : +$ cat >foo < +ssb 1024g/8F70E2C0 2000-03-09 + + + +Composition de la TrustDB +========================= + +La TrustDB est construire à partir d'enregistrements à taille fixe, où le premier +octet décrit le type d'enregistrement. Toutes les valeurs numériques sont +conservées dans un réseau d'ordre d'octets. La longueur de chaque enregistrement +est de 40 octets. Le premier enregistrement de la TrustDB est toujours de type 1 +et c'est le seul enregistrement de ce type. + + Record type 0: + -------------- + + Cet enregistrement n'est pas utilisé. Il peut être utilisé + à votre discrétion. + + Record type 1: + -------------- + + Indique la version de la TrustDB. Cet enregistrement doit toujours être + le premier enregistrement de la base de données et c'est le seul + enregistrement de type 1. + + 1 octet valeur : 1 + 3 octets 'gpg' valeur "magic" + 1 octet Version de la TrustDB (2) + 1 octet marginales requises + 1 octet complètes requises + 1 octet max_cert_depth + + Ces trois éléments sont utilisés pour vérifier si la valeur de validité + mise en cache dans l'enregistrement du répertoire peut être utilisée : + + 1 u32 locked flags + 1 u32 datation de la création de la trustdb + 1 u32 datation de la dernière modification + + Cette datation pourrait affecter la validité des clefs dans la base de + données. Cette valeur sera comparée à celle de la datation de validité + des enregistrements dir : + + 1 u32 datation de la dernière validation + + Cette valeur sera utilisée pour stocker le passage du temps, lorsque + cette TrustDB sera comparée au trousseau de clefs publiques : + + 1 u32 numéro de l'enregistrement du keyhashtable + 1 u32 premier enregistrement libre + 1 u32 numéro de l'enregistrement répertoire shadow de la table de hachage + + Cette table ne devrait pas être combinée avec la table de clefs car le + keyid n'est pas dans chaque cas un élément du fingerprint. + + 4 bytes réservés pour l'enregistrement d'extension de version + + + Record type 2: (enregistrement répertoire) + -------------- + + Regroupe les informations sur un certificat de clef publique. + Ces valeur sont statiques et ne sont jamais modifiées sans une + interaction avec l'utilisateur : + + 1 octet valeur : 2 + 1 octet réservé + 1 u32 LID . (numéro d'enregistrement de cet enregistrement) + 1 u32 Liste de key-records (le premier est la clef primaire) + 1 u32 Liste de uid-records + 1 u32 cache record + 1 octet ownertrust + 1 octet dirflag + 1 octet validité maximale de tous les id utilisateurs + 1 u32 datation de la dernière vérification de validité + 1 u32 Vérification requise lorsque cette datation sera atteinte + (0 = pas de vérification requise) + + + Record type 3: (enregistrement de clef) + -------------- + + Regroupe les informations sur une clef publique primaire. + (ces informations sont principalement utilisées pour réaliser les lookup + dans l'enregistrement trust) + + 1 octet valeur : 3 + 1 octet réservé + 1 u32 LID + 1 u32 next - prochain enregistrement + 7 octets réservés + 1 octet keyflags + 1 octet algorithme de la clef publique + 1 octet taille du fingerprint (en octets) + 20 octets fingerprint de la clef publique + (Cette valeur est utilisée pour identifier toute clef) + + Record type 4: (enregistrement uid) + -------------- + + Regroupe les informations sur un id utilisateur (un "uid"). + Nous ne stockons par l'uid mais un hachage de l'uid : cela semble suffire. + + 1 octet valeur : 4 + 1 octet réservé + 1 u32 LID pointe vers l'enregistrement directory + 1 u32 next le userid suivant + 1 u32 pointeur vers l'enregistrement preference + 1 u32 siglist liste de signatures valides + 1 octet uidflags + 1 octet validité de la clef calculée pour cet userid + 20 bytes ripemd160 hachage du nom de l'utilisateur + + + Record type 5: (enregistrement pref) + -------------- + + Regroupe les informations formant les préférences. + + 1 octet valeur : 5 + 1 octet réservé + 1 u32 LID; pointe vers l'enregistrement directory (et PAS vers le uid !!!) + (égal à 0 pour un enregistrement de préférences standard) + 1 u32 suivant + 30 byte données de préférences + + Record type 6 (sigrec) + ------------- + + Cet enregistrement est utilisé pour traquer les signatures de clefs. Les + auto-signatures ne sont pas conservées. Si une clef publique ne se trouve + pas dans la TrustDB, la signature pointe vers un enregistrement dir fantôme, + lequel contient une liste des enregistrements qui seraient intéressés + par cette clef (et l'enregistrement signature en fait partie). + + 1 octet valeur : 6 + 1 octet réservé + 1 u32 LID pointe en retour vers l'enregistrment dir + 1 u32 next prochain sigrec de cet uid ou bien 0 pour indiquer que ce + sigrec est le dernier. + 6 times + 1 u32 Local_id des dir signatures ou de l'enregistrement dir fantôme + 1 octet Flag: Bit 0 = vérifié: Bit 1 est valide (nous avons un + véritable enregistrement directory) + 1 = valide est vrai (mais pourrait être révoqué) + + + + Record type 8: (enregistrement répertoire (dir) fantôme) + -------------- + + Cet enregistrement est utilisé pour réserver un LID pour une clef publique. + Nous avons besoin de cet enregistrement pour créer les enregistrements sigs + des autres clefs, même si nous ne disposons pas d'une signature de la clef + publique. + Cet enregistrement (le numéro d'enregistrement pour être plus précis) + sera réutilisé dans l'enregistrement dir lorsque nous importerons la + véritable clef publique. + + 1 octet valeur : 8 + 1 octet réservé + 1 u32 LID (Ceci est simplement le numéro d'enregistrement de ce record.) + 2 u32 keyid + 1 octet algorithme de la clef publique + 3 octets réservé + 1 u32 hintlist + + hintlist contient la liste des enregistrements qui ont des références qui pointent + vers cette clef. Nous utilisons cet élément pour augmenter la vitesse d'accès + des enregistrements de signature qui ne sont pas encore vérifiés. Notez que ces + données ne sont qu'un indice, une indication ("hint") mais les enregistrements actuels + pourraient ne pas détenir d'enregistrement de signature pour la clef, mais le + code du programme saura prendre soin de tout cela. + + 18 octets réservés + + + + Record Type 10 (table de hachage) + -------------- + + Comme nous utilisons les fingerprint pour accéder aux clefs, nous devons + implémenter un accès rapide en utilisant des méthodes de hachages simples, + afin d'éviter une surcharge de gdbm. La propriété des fingerprint + est qu'ils permettent un usage direct en tant que valeurs hachées (ils + peuvent être considérés comme des nombres aléatoires cryptographiquement + forts). + Nous utilisons une architecture à multiples niveaux dynamique, qui combine + les tables de hachage, les listes d'enregistrements et les listes + chaînées. + + Cet enregistrement est une table de hachages de 256 entrées ; une propriété + spéciale est que tous les enregistrements sont stockés consécutivement + pour produire une grande table. La valeur hachée est simplement le 1er, + 2nd.. octet du fingerprint (selon le niveau d'indirection). + + Lorsque nous les utilisons pour hacher les enregistrements de répertoires + shadow, une différente table est utilisée, et elle se trouve indexée + par le keyid. + + 1 octet valeur : 10 + 1 octet réservé + n u32 recnum; n dépend de la taille de l'enregistrement : + n = (reclen-2)/4 ce qui donne 9 pour la taille actuelle + d'enregistrement de 40 octets. + + Le nombre total de ces enregistrements constituant la table est : + + m = (256+n-1) / n + + ce qui donne 29 pour une taille d'enregistrement de 40. + + Pour rechercher une clef, nous utilisons le premier octet du fingerprint + pour obtenir le recnum de la table de hachage et nous étudions l'enregistrement + adressé : + + o Si cet enregistrement est une autre table de hachage, nous pouvons + utiliser le second octet pour indexer cette table de hachage et continuer. + + o Si cet enregistrement est une liste de hachages, nous pouvons parcourir + toutes les entrées jusqu'à trouver la bonne. + + o Si cet enregistrement est un enregistrement de clef, nous comparons + le fingerprint avec celui recherché et nous déterminons s'il s'agit + de la clef recherchée. + + + + Record type 11 (liste hachée) + -------------- + + Consultez la table hachée pour une explication. + Ceci sera également utilisé à d'autres fins. + + 1 octet valeur : 11 + 1 octet réservé + 1 u32 next enregistrement de liste hachée suivant + n times n = (reclen-5)/5 + 1 u32 recnum + + Pour la taille actuelle utilisée par les enregistrements (taille 40) nous avons n = 7. + + + + + Record type 254 (enregistrement libre) + --------------- + +Tous ces enregistrements forment une liste chaînée d'enregistrements non-utilisés. + + 1 octet valeur 254 + 1 octet réservé (0) + 1 u32 next_free + + + +En-têtes de paquets +=================== + +GnuPG utilise des en-têtes PGP 2 et il est aussi capable de comprendre +les en-têtes de type OpenPGP. C'est une amélioration utilisée sur les anciens +en-têtes de paquets : + +Les CTB bits 10, les "packet-length length bits" ont leurs valeurs listées +dans la table suivante : + + 00 - 1-octet champ packet-length + 01 - 2-octets champ packet-length + 10 - 4-octets champ packet-length + 11 - pas de taille de paquet fournie, taille inconnue + +Comme indiqué dans cette table, selon la taille du packet-length les +octets restants (1, 2, 4 ou 0) du champ de structure de paquets sont +un "champ packet-length". Ce champ est une valeur numérique à part entière. +La valeur du champ packet-length est définie par la valeur de la +totalité du champ numérique. + +La valeur 11 est actuellement utilisée dans un cas : les données +compressées. C''est à dire qu'un bloc de données compressées +ressemble à : où A3 est le binaire "10 1000 11" et +produit ici un paquet de taille non-définie. L'interprétation +correcte en est : "jusqu'à la fin de la structure englobante" +bien qu'en fait la structure englobante soit généralement +le fichier. + ++ Ceci sera modifié dans une future version, où la signification de la ++ valeur 11 (voir ci-dessous) aura aussi sa place. ++ ++ Une valeur de 11 pour d'autres paquets active un codage spécial ++ de la taille, où la taille du paquet suivant ne pourra pas être ++ déterminée avant l'écriture du paquet, en particulier ceci sera ++ utilisé si de grande quantités de données sont à traiter dans ++ un mode filtre. ++ ++ Ceci fonctionne de la manière suivante : après le CTB (qui est un ++ champ de longueur de 11) un champ marqueur sera utilisé, il indiquera ++ alors la taille du bloc de données suivant. C'est un simple champ ++ de deux octets (MSB en premier) contenant la quantité de données qui ++ suivent le champ, sans inclure le champ de taille toutefois. Après ++ ce bloc de données un autre champ de taille suivra, qui donnera la taille ++ du bloc de données suivant. Une valeur de 0 indique une fin de paquet. ++ La taille maximale d'un bloc de données est limitée à 65534, ce qui ++ réserve la valeur 0xffff pour des extensions futures. Ces marqueurs de ++ taille devront être insérés dans le flux de données avant que les ++ données ne soient envoyées en sortie. ++ ++ Ce champ de deux octets est largement suffisant, car l'application ++ doit placer en tampon cette quantité de données pour précéder le ++ marqueur de taille avant de produire une sortie. Les blocs de données ++ d'une taille supérieure à 32 Ko n'ont aucun sens. Notez que ceci pourra ++ également être utilisé pour les flux de données compressées, mais ++ nous devrons alors utiliser une autre version de paquet afin de dire à ++ l'application qu'elle ne peut assumer qu'il s'agit du dernier paquet. + + +Extensions GNU à l'algorithme S2K +================================= + +Le S2K mode 101 est utilisé pour identifier ces extensions. +Après l'algorithme de hachage les trois octets "GNU" sont utilisés +pour indiquer clairement qu'il s'agit d'extensions GNU et les octets +qui suivent donnent le mode de protection GNU utilisé : 1000. Les +modes définis sont : + + 1001 - ne pas conserver du tout de partie secrète + + + +Usage des fichiers gdbm pour les trousseaux de clefs +==================================================== + +La clef utilisé pour stocker le keyblock est son propre fingerprint, +les autres enregistrements sont utilisés pour les clefs secondaires. +Les fingerprint font toujours 20 octets où 16 bits de fingerprint +sont suivis par 0. Le premier octet de chaque clef indique une +information sur le type de clef : + + 1 = la clef est un fingerprint de 20 octets (16 octets fpr "paddés" de 0) + les données sont le keyblock + 2 = la clef est un keyid complet de 8 octets + les données sont une liste de 20 octets fingerprints + 3 = la clef est un keyid court de 4 octets + les données sont une liste de 20 octets fingerprints + 4 = la clef est une adresse email + les données sont une liste de 20 octets fingerprints + + Les données sont pre-appended (précédées) par un octet de type : + + 1 = keyblock + 2 = liste de 20 octets fingerprints "paddés" + 3 = liste de liste de fingerprints ("but how to we key them?") + + + +Pipemode +======== + +Ce mode est utilisé pour réaliser des opérations multiples avec un +unique appel à gpg. C'est assez pratique lorsqu'il faut pouvoir vérifier +un grand nombre de signatures. Actuellement nous n'avons qu'un support +des signatures détachées. Ce mode est une astuce qui permet d'éviter +de faire fonctionner gpg n en daemon mode et d'utiliser les Unix Domain +Sockets pour lui faire passer les données. Il n'existe aucun moyen +pratique de portabilité de ce concept sous Windows, alors nous utilisons +des pipes simples pour faire fonctionner ce mode sous Windows. Comme nous +n'avons aucun moyen de signaler des EOF multiples dans un pipe nous +devons laisser le contrôle s'insérer dans le flux de données lui-même. +Nous réalisons alors une distinction entre les données du flux et un +état de contrôle. A son lancement, le système se trouve dans un état +de données mais n'acceptera aucune donnée. Il attend en fait une +transition vers un mode de contrôle qui s'obtient en envoyant un simple +caractère '@'. Une fois dans le mode de contrôle, des commandes sont +attendues et ces commandes sont à un octet après lequel le système +revient au mode de données (mais cela n'implique pas qu'il acceptera +des données immédiatement). La commande de contrôle la plus simple +est '@' qui permet d'insérer ce caractère dans le flux de données. + +Voici le format que nous utilisons pour les signatures détachées : + +"@<" - Début d'un nouveau flux +"@B" - La signature détachée suit. + Ceci émet le paquet de contrôle (1,'B') + +"@t" - Le texte signé suit. + Ceci émet le paquet de contrôle (2, 'B') + +"@." - Fin de l'opération. Le paquet de contrôle final force la + vérification de la signature. +"@>" - Fin du flux. + + + +Autres notes +============ + +Dans la version* 3 de version de paquet nous calculons les keyid de cette manière : + +RSA : les 64 bits de poids faible de n +ELGAMAL : nous construisons un paquet de clef publique v3 (avec CTB 0x99) + et nous calculons une valeur hachée rmd160 à partir de ce paquet. + Il est utilisé comme fingerprint avec les 64 bits de poids faible + qui produisent le keyid. + +* Les certificats de révocation ne comportent qu'un paquet de signature ; +"import" sait comment traiter ces paquets. L'idée derrière ce principe +est de conserver une petite taille de paquet. + + + +Format des messages Keyserver +============================= + +Le serveur de clef peut être contacté par un Unix Domain Socket ou via TCP. + +Le format des requêtes est : + +==== +command-tag +"Content-length:" digits +CRLF +======= + +Où le command-tag est : + +NOOP +GET +PUT +DELETE + + +Le format de réponse utilisé est : + +====== +"GNUPG/1.0" status-code status-text +"Content-length:" digits +CRLF +============ + +suivi par octets de données. + + +Les codes de statut utilisés sont : + + o 1xx: Information: requête reçue, traitement en cours. + + o 2xx: Succès - L'action a été reçue, comprise et acceptée. + + o 4xx: Erreur client : la requête contient une erreur, mauvaise syntaxe + ou demande irréalisable. + + o 5xx: Erreur serveur - Le serveur n'a pu traiter une demande + qui semble valide. + + +Documentation sur HKP (le protocol de serveurs de clefs http) +============================================================= + +Un serveur HTTP minimal sur port 11371 reconnaît les requêtes GET +pour /pks/lookup. Les paramètres standard encodés URL de la requête +sont toujours ceux-ci : (toujours key=valeur) + +- op=index (comme pgp -kv), op=vindex (comme pgp -kvv) and op=get (comme + pgp -kxa) + +- search=. Nous avons ici une liste de mots qui doivent + apparaître dans la clef. Ces mots sont séparés par des espaces, + points, @, etc. Les délimiteurs ne feront pas partie de la + recherche et l'ordre des mots n'a aucune importance (mais consultez + l'option suivante). + +- exact=on. Ce switch permet d'indiquer au serveur hkp qu'il ne doit + rechercher que les correspondances exactes. Dans ce cas, les + délimiteurs et l'ordre des mots sera considéré. + +- fingerprint=on. Renvoie également les fingerprint, lorsque utilisé + avec 'index' ou 'vindex' + +Les serveurs de clefs savent aussi reconnaître le format http-POST vers /pks/add. +Vous utilisez ceci pour envoyer des clefs au serveur. + +Le mieux pour produire une requête reste : + + /pks/lookup/?op= + +Ceci peut être implémenté en utilisant le mécanisme de traduction Hurd. +Toutefois, nous pensons que les traitements du serveur de clef doivent +faire l'objet d'une refonte. diff --git a/doc/fr/FAQ b/doc/fr/FAQ new file mode 100644 index 000000000..48c28ae76 --- /dev/null +++ b/doc/fr/FAQ @@ -0,0 +1,1111 @@ + +GNUPG : FOIRE AUX QUESTIONS + +Version : 1.2 +Dernière modification : 10 septembre 2001 +Maintenu par : Nils Ellmenreich +Traduction : Gilbert Fernandes + +Ce document est la FAQ de GnuPG. La dernière version HTML est +disponble ici : + +L'index est produit automatiquement. Des erreurs peuvent donc +s'y trouver. Toutes les questions ne seront pas situées dans leurs +sections afférentes. Les suggestions quand à l'amélioration de cette +FAQ seront les bienvenues. + +Veuilez envoyer vos additions et corrections au mainteneur de la FAQ. +Il serait plus pratique si vous pouviez fournir une réponse à inclure +directement dans la FAQ. Toute aide sera fortement appréciée. + +Veuillez ne pas nous envoyer de message du type : "Ceci devrait +être une FAQ, quelle est la réponse ?". Si la réponse ne se trouve +pas dans la FAQ c'est que la question n'a pas été considérée. +Dans ce cas, recherchez dans les archives de la liste de +distribution par email. + + + + + 1. GENERAL + 1.1) Qu'est-ce que GnuPG ? + 1.2) GnuPG est-il compatible avec PGP ? + + 2. SOURCES D'INFORMATION + 2.1) Où puis-je trouver plus d'informations ? + 2.2) Où puis-je obtenir GnuPG ? + + 3. INSTALLATION + 3.1) Sur quels systèmes fonctionne GnuPG ? + 3.2) Quel collecteur d'entropie dois-je utiliser ? + 3.3) Comment puis-je inclure le support du RSA et de l'IDEA ? + + 4. UTILISATION + 4.1) Quelle est la taille de clef recommandée ? + 4.2) Pourquoi la création de clefs est-elle aussi longue ? + 4.3) Pourquoi tout est si lent quand je travaille sur un système distant ? + 4.4) Quelle est la différence entre options et commandes ? + 4.5) Je ne peux pas effacer un userid car il a déjà été effacé dans mon + trousseau de clefs publiques ? + 4.6) Que sont la confiance, la validité et l'ownertrust ? + 4.7) Comment puis-je signer un fichier de patch ? + 4.8) Où se trouve l'option "encrypt-to-self" ? + 4.9) Comment puis-je me débarasser de la version et du champ de commentaire + dans la version "armor" des messages ? + 4.10) Que signifie le message "You are using the xxxx character set" ? + 4.11) Comment puis-je obtenir la liste des keyid ayant servi à + chiffrer un message ? + 4.12) Je ne peux plus déchiffrer mon message chiffré symétriquement (-c) avec la nouvelle +version de GnuPG ? + 4.13) Comment puis-je utiliser GnuPG en environnement automatisé ? + 4.14) Quel client email puis-je utiliser avec GnuPG ? + 4.15) On ne peut pas avoir une librairie gpg ? + 4.16) J'ai produit avec succès un certificat de révocation, mais comment dois-je + le transmettre aux serveurs de clefs ? + + 5. QUESTIONS SUR LA COMPATIBILITE + 5.1) Comment puis-je chiffrer un message avec GnuPG pour que PGP soit capable de le déchiffrer ? + 5.2) Comment migrer de PGP 2.x vers GnuPG ? + 5.3) (supprimé) + 5.4) Pourquoi PGP 5.x n'est pas capable de déchiffrer les messages pour certaines clefs ? + 5.5) Pourquoi PGP 5.x ne peut vérifier mes messages ? + 5.6) Comment puis-je transférer mes valeurs de confiance de PGP vers GnuPG ? + 5.7) PGP n'aime pas ma clef privée. + + 6. PROBLEMES ET MESSAGES D'ERREUR + 6.1) Pourquoi GnupG me dit sans cesse "Warning : using insecure memory!" ? + 6.2) Le support des fichiers de grande taille ne fonctionne pas .. + 6.3) Dans le menu d'édition les valeurs de confiance ne sont pas affichées + correctement après la signature des uid : pourquoi ? + 6.4) Que signifie "skipping pubkey 1: already loaded" ? + 6.5) GnuPG 1.0.4 ne tient pas compte de ~/.gnupg ... + 6.6) Une signature ElGamal ne vérifie plus rien depuis la 1.0.2 .. + 6.7) Les anciennes versions de GnuPG ne vérifient pas les anciennes + signatures ElGamal + 6.8) Lorsque j'utilise --clearsign le texte en clair comporte parfois des + tirets supplémentaires : pourquoi ? + 6.9) Que signifie "can't handle multiple signatures" ? + 6.10) Si je soumet une clef au serveur de clefs, rien ne survient ! + 6.11) J'obtiens un "gpg: waiting for lock ..." + 6.12) Les anciennes versions de GnuPG (e.g. 1.0) ont des problèmes + avec les clefs de GnuPG récents .. + 6.13) Avec GnuPG 1.0.4 j'obtiens un "this cipher algorithm is deprecated ..." + 6.14) Les dates sont affichées par ????-??-??, pourquoi ? + 6.15) J'ai encore un problème, dois-je produire un message de bogue ? + 6.16) Pourquoi GnuPG ne supporte pas les certificats X.509 ? + + 7. SUJETS AVANCES + 7.1) Comment tout cela fonctionne-t-il ? + 7.2) Pourquoi certaines signatures avec une clef ELG-E sont valides ? + 7.3) Comment tout le système de confiance fonctionne au juste ? + 7.4) Quel est ce genre de sortie : "key C26EE891.298, uid 09FB: ...."? + 7.5) Comment interpréter certaines sorties informatives ? + 7.6) Les lignes d'en-tête des messages font-elles parties des éléments signés ? + 7.7) Quelle est la liste des algorithmes préférés ? + 7.8) Comment puis-je changer la liste des algorithmes préférés ? + + 8. REMERCIEMENTS + + + +1. GENERAL + +1.1) Qu'est-ce que GnuPG ? + +GnuPG signifie GNU Privacy Guard et est +l'outil GNU destiné aux communications protégées par chiffrement, +ainsi que le stockage protégé d'informations. Ce programme peut +être utilisé pour chiffrer des données et produire des signatures +numériques. Il comprend une gestion avancée des clefs et respecte +le standard Internet proposé OpenPGP comme décrit dans le +RFC 2440 : et il se destine +à une parfaite compatibilité avec le PGP produit par NAI Inc. + +1.2) GnuPG est-il compatible avec PGP ? + +En règle générale, oui. GnuPG et les distributions récentes de PGP +devraient respecter le standard OpenPGP et fonctionner de concert. +Il existe toutefois quelques problèmes d'interopérabilité. Consultez +les questions 5.1ff pour plus de détails. + +2. SOURCES D'INFORMATION + +2.1) Où puis-je trouver plus d'informations ? + +Voici une liste de ressources en ligne : + + + +Cette page regroupe la page de documentation GnuPG. Vous pouvez consulter +les HOWTO ainsi que le manuel de GnuPG : le GNU Privacy Handbook +actuellement disponible en anglais, espagnol et russe. Ce dernier offre par +ailleurs une présentation étendue de GnuPG. Vous trouverez aussi des +documentations expliquant la conversion de PGP 2.x vers GnuPG. + + + +Vous trouverez ici une archive en ligne des listes de distribution par +courrier électronique de GnuPG. La liste la plus intéressante sera +probablement gnupg-users où toutes les questions en rapport avec +l'utilisation de GnuPG se trouvent rassemblées. Si le développement +vous intéresse vous consulterez avec joie la liste gnupg-devel et +vous pourrez également prendre contact avec les développeurs. + +S'IL-VOUS-PLAIT ! + +Avant de poster sur une liste, veuillez lire avec attention la FAQ et +toutes les documentations disponibles. D'autre part, vous devez ensuite +consulter les archives afin de découvrir si votre question n'a pas été +déjà posée et résolue. Vous épargnerez des pertes de temps et la +liste pourra se concentrer sur les problèmes qui n'ont pas encore +été résolus. + +La distribution des sources de GnuPG comprend également un +sous-répertoire /doc qui contient des documentations supplémentaires +et ces informations seront précieuses aux hackers (pas beaucoup aux +utilisateurs habituels, sauf les plus curieux). + +2.2) Où puis-je obtenir GnuPG ? + +Vous pouvez télécharger GNU Privacy Guard depuis son FTP primaire : + + + +Ou depuis l'un des mirroirs : + + + +La version actuelle est la version 1.0.6 et nous vous encourageons à migrer +vers cette version rapidement : elle corrige des bogues et améliore le +fonctionnement du programme, ainsi que votre sécurité de fait. + + +3. INSTALLATION + +3.1) Sur quels systèmes fonctionne GnuPG ? + +GnuPG devrait fonctionner sur tous les Unices ainsi que Windows (95, 98..) et les variantes +NT. Une liste de systèmes d'exploitation fonctionnels se trouve à : + + + +3.2) Quel collecteur d'entropie dois-je utiliser ? + +Les "bons" générateurs de nombres aléatoires sont cruciaux pour la sécurité de vos +chiffrements. Les différents systèmes d'exploitation proposent des valeurs +aléatoires de qualité variable. Linux et les systèmes *BSD produisent généralement +de bonnes valeurs grâce au /dev/random et cette méthode devrait rester la +méthode de choix pour ces systèmes. Les utilisateurs de Solaris devraient opter +pour pe paquetage SUNWski afin de disposer d'un /dev/random. Dans ces cas, +vous devriez utiliser l'option --enable-static-rnd=linux. D'autre part, il existe également +un dispositif au niveau kernel pour la production de valeurs aléatoires développé +par Andi Maier : + +< http://www.cosy.sbg.ac.at/~andi> + +Ce logiciel est au stade de beta : vous ne l'utilisez que sous votre seule +responsabilité ! + +Sur les autres systèmes, l'utilisation de l'EGC ou "Entropy Gathering Daemon" +se montre un bon choix. C'est un daemon écrit en Perl qui surveille l'activité du +système et produit des hachages permettant d'obtenir des valeurs aléatoires. +Vous devriez en consulter la page de téléchargement depuis : + + + +Pour l'utiliser vous devrez utiliser l'option --enable-static-rnd=egd + +Si les options ci-dessus ne fonctionne pas, vous pourrez utiliser le producteur +d'entropie "unix". Il est *TRES* lent et il devrait être évité lorsque possible. +Sa qualité d'entropie laisse vraiment à désirer et vous ne devrez jamais +l'utiliser dans la protection de données sensibles. + +3.3) Comment puis-je inclure le support du RSA et de l'IDEA ? + +RSA se trouve inclus dans GnuPG depuis la version 1.0.3 et supérieures. + +La distribution officielle de GnuPG ne comprend pas l'IDEA à cause +d'une restriction par brevêt. Le brevêt devrait expirer en 2007 et nous +attendons cette date pour l'inclure dans GnuPG. + +Toutefois, il existe des modules officieux qui permettent de l'inclure +même dans les versions de GnuPG avant cette date. Ces modules +sont disponibles depuis : + + + +Recherchez 'idea.c' + +Les directives de compilation se trouvent dans les fichiers "headers" de +ces fichiers. Vous pourrez ensuite ajouter la ligne suivante à votre +fichier ~/.gnupg/options : + + load-extension idea + +4. USAGE + +4.1) Quelle est la taille de clef recommandée ? + +Nous vous recommandons un minimum de 1024 bits pour les clefs de type +DSA et également pour les signatures simples de type ElGamal. La taille +du hachage est probablement le lien le plus faible si la taille de la clef +augmente à plus de 1024 bits. Les clefs de chiffrement peuvent avoir +des tailles supérieures, mais vous devriez alors vérifier le fingerprint +de la clef de cette manière : + +gpg --fingerprint --fingerprint + +Comme pour les algorithmes de clef, vous devriez vous en tenir aux +valeurs par défaut (i.e. les chiffrements ElGamal avec signature +DSA). Une clef de signature ElGamal comporte les désavantages +suivants : si la signature est grosse, il est difficile de créer une +clef correspondante utile pour les signatures et capable de résister +aux attaques réelles, et vous n'obtiendrez pas de sécurité +supplémentaire face au DSA. Il pourrait y avoir des problèmes +de compatibilité avec certaines versions de PGP. Il n'aura été +introduit que parce à l'époque, il n'était pas clair de savoir si +un brevêt s'appliquait ou non au DSA. + +4.2) Pourquoi la création de clefs est-elle aussi longue ? + +Le problème est ici que nous avons besoin d'une grande quantité d'octets aléatoires et que +nous devons pour ce faire collecter une certaine quantité d'entropie depuis, sous Linux, +le /dev/random. Il n'est pas vraiment facile de remplir l'entropie de Linux ; nous en avons +discuté avec Ted Ts'o et il a expliqué que la meilleure méthode pour remplir le buffer +n'est autre que de jouer avec votre clavier. Une bonne sécurité implique un coût. +Vous pouvez utiliser les touches Shift, Control, Alt en appuyant dessus de manière aléatoire, +d'autant que ces touches ne produisent aucune sortie à l'écran et vous pourrez accélérer +la production des clefs. + +Un autre programme pourrait également consommer une partie de l'entropie du système +dont vous avez besoin (jettez un oeil à vos daemons actifs). + +4.3) Pourquoi tout est si lent quand je travaille sur un système distant ? + +Vous ne devez SURTOUT pas faire cela ! Vous ne devez jamais créer de +clef GnuPG sur un système distant car vous n'aurez alors aucun contrôle +physique sur votre clef privée, ni même votre trousseau de clefs privées. +Ces clefs seront alors suspectibles de subir une attaque par dictionnaire. +Nous vous encourageons vivement à ne produire vos clefs que sur une +machine personnelle (un portable déconnecté de toute alimentation +et connexion réseau est le meilleur choix) et si vous devez conserver +votre clef privée sur une machine fixe, assurez-vous qu'une phrase +passe solide en protège le contenu et que vous pouvez faire confiance +à votre administrateur système. + +Lorsque nous devons utiliser GnuPG à distance c'est au-travers de SSH +et nous rencontrons le même problème. Il faut *beaucoup* de temps +pour produire des clefs de toute manière. Il ne faut pas créer de clefs +à distance. Si vous avez juste besoin de clefs à fins de tests, vous +pouvez utiliser l'optoin --quick-random pour produire rapidement des +clefs *faibles* qui permettent de vérifier quelques tests. + +4.4) Quelle est la différence entre options et commandes ? + +Si vous tapez 'gpg --help' vous obtiendrez deux listes séparées. La première +liste vous répertorie les commandes. La seconde liste regroupe elle les +options. A chaque fois que vous utiliserez GnuPG vous devrez utiliser +*UNE* commande (avec une exception, voir ci-dessous) et vous pourrez +utiliser une ou *plusieurs* options en combinaison avec la commande. + +Par convention, la commande doit se trouver à la fin de la liste d'arguments +après toutes les options. Si la commande requiert un nom de fichier, +ce dernier sera donné à GnuPG en *dernier* sur la ligne de commande. + +L'usage basique de GnuPG est donc : + + gpg [--option something] [--option2] [--option3 something] --command file + +Certaines options demandent des arguments. Par exemple, l'option +--output (que l'on peut raccourcir par -o) requiert un nom de fichier +en argument. L'argument de l'option doit suivre celle-ci immédiatement ! +GnuPG ne sera sinon pas capable de différencier le nom de fichier comme +option. Comme option, --output et son nom de fichier doivent se trouver +avant la commande donnée à GnuPG. L'option --recipient (ou -r) demande +un nom ou un keyID pour chiffrer le message et ces informations devront +imméditamenet suivre l'option --recipient/-r. La commande --encrypt ou +-e sera fournie après ces options, avec en final le nom du fichier à +chiffrer. En voici un exemple : + + gpg -r alice -o secret.txt -e test.txt + +Mais l'utilisation des options sous leur forme longue permet de simplifier +la compréhension des lignes de commande : + + gpg --recipient alice --output secret.txt --encrypt test.txt + +Si vous sauvez dans un fichier nommé ".txt" alors vous devriez probablement +utiliser l'option ARMOR en ajoutant l'option --armor ou -a qui ne prend aucun +argument : + + gpg --armor --recipient alice --output secret.txt --encrypt test.txt + +Si nous plaçons des crochets autour des parties optionnelles, les choses +deviennent plus claires : + + gpg [--armor] [--recipient alice] [--output secret.txt] --encrypt test.txt + +Les parties entre crochets peuvent être placées dans l'ordre de votre +choix : + + gpg --output secret.txt --recipient alice --armor --encrypt test.txt + +Si votre nom de fichier commence par un tiret, GnuPG risque de penser +qu'il s'agit d'un paramètre et pour éviter cette situation vous pouvez +soit utiliser un "./-a.txt" soit utiliser un double-tiret comme ceci : + +-- -a.txt + +* L'exception concerne le chiffrement ET la signature au même moment. +On utilise alors gpg [--options] --sign --encrypt foo.txt + +4.5) Je ne peux pas effacer un userid car il a déjà été effacé dans mon + trousseau de clefs publiques ? + +Comme vous ne pouvez sélectionner que depuis le trousseau de clefs +publiques, vous ne pouvez pas directement effacer le userid. Toutefois, +ce n'est pas très compliqué à faire. Vous devez créer un nouvel +utilisateur, disposant du même userid ce qui vous permet d'obtenir deux +utilisateurs identiques avec un seul disposant d'une correspondance +dans la clef privée. Vous pouvez désormais sélectionner cet utilisateur +et l'effacer. Les deux identifiants seront affacés du trousseau de clefs +privées. + +4.6) Que sont la confiance, la validité et l'ownertrust ? + +Le terme "ownertrust" est utilisé en remplacement de "trust" lorsqu'il +s'agit de la valeur que vous avez attribuée à une clef en fonction +du degré de confiance que vous accordez à son propriétaire, et si +vous l'autorisez à introduire de nouvelles clefs avec votre signature +jointe. La "validité" est un terme de confiance calculée, une valeur +numérique calculée par GnuPG en fonction des paramètres de +confiance des clefs et vous donne une idée de la confiance que +GnuPG attribue ou n'attribue pas à une clef et s'il estime que la clef +est valide pour un usage de chiffrement. Pour plus de détails consultez +le chapître "The web of trust" + +4.7) Comment puis-je signer un fichier de patch ? + +Vous pouvez utiliser : + +gpg --clearsign --not-dash-espaced ... + +Le problème avec --clearsign c'est que toutes les lignes qui +commençent par un tiret sont "quotées" avec "- " et comme diff +produit beaucoup de lignes de ce type, le patch risque d'être +détruit par la signature. Pour utiliser un fichier patch en le signant +et sans perdre la signature claire, l'option spéciale : + +--not-dash-escaped + +Permet de supprimer la production de ces séquences d'échappement. +Vous ne devriez pas transmettre par courrier électronique un patch +de ce type car les espaces et les fins de ligne font également +partie de la signature et un logiciel de messagerie risque de modifier +l'espacement et/ou les tailles de lignes, invalidant la signature. Si vous +souhaitez transmettre le fichier, le plus simple reste de le signer à l'aide +de votre MUA. + +4.8) Où se trouve l'option "encrypt-to-self" ? + +Utilisez l'option : + +--encrypt-to + +Vous pouvez utiliser une combinaison de cette option pour spécifier +plus d'un keyID. Pour désactiver temporairement l'utilisation de clefs +additionnelles, vous pouvez utiliser l'option : --no-encrypt-to. + +4.9) Comment puis-je me débarasser de la version et du champ de commentaire + dans la version "armor" des messages ? + +Utilisez l'option --no-version --comment "" + +Veuillez noter que la ligne vide laissée en place est *requise* par le format +et le protocole. + +4.10) Que signifie le message "You are using the xxxx character set" ? + +Cette note est affichée lorsque une conversion UTF-8 a été réalisée. +Veuillez vous assurer que le jeu de caractères utilisé pour l'affichage +correspond bien à celui du système. Le plus utilisé reste "iso-8859-1" et +c'est le jeu de caractères par défaut. Vous pouvez modifier ce jeu +de caractères à l'aide de l'option "--charset". Il faut que le jeu de +caractères utilisé corresponde à celui de votre affichage ou des +caractères pourraient ne plus correspondre dans le message une +fois transmis. Sinon, n'utilisez que de l'ASCII 7 bits pour qu'aucune +conversion ne puisse survenir. + +4.11) Comment puis-je obtenir la liste des keyid ayant servi à + chiffrer un message ? + + gpg --batch --decrypt --list-only --status-fd 1 2>/dev/null | \ + awk '/^\[GNUPG:\] ENC_TO / { print $3 }' + +4.12) Je ne peux plus déchiffrer mon message chiffré symétriquement + (-c) avec la nouvelle version de GnuPG ? + +Il existait un bogue dans les versions 1.0.1 et antérieures de GnuPG +qui surveniait lorsque 3DES ou Twofish avaient été utilisé pour des +chiffrements symétriques (ce qui n'a jamais été le cas par défaut). +Ce bogue a été corrigé afin de permettre le déchiffrement des anciens +messages, en utilisant l'option : + +---emulate-3des-s2k-bug + +Vous devriez déchiffrer puis rechiffrer (correctement) le ou les +messages concernés. Cette option sera retirée dans la version 1.1 +de GnuPG : n'attendez pas pour convertir vos messages ! + +4.13) Comment puis-je utiliser GnuPG en environnement automatisé ? + +Vous devriez utiliser l'option --batch et ne pas utiliser de phrase +passe car il n'existe alors aucun moyen de conserver cette +information de manière plus secrète que le trousseau de clefs +lui-même. Nous vous suggérons de créer vos clefs, en environnement +automatisé, de la manière suivante : + +Sur une machine protégée : + +Créez une sous-clef de signature pour votre clef, en utilisant le menu +edit et en utilisant l'option "addkeu" puis DSA. Vous devez ensuite +vous assurer que vous utilisez une phrase passe (requise par +l'implémentation actuelle) puis utiliser : + +gpg --export-secret-subkeys --no-comment foo + >secring.auto + +Copiez secring.auto et le trousseau de clefs publiques dans un +répertoire test. Entrez dans le répertoire, puis : + +gpg --homedir . --edit foo + +Et utilisez "passwd" pour retirer la phrase passe des sous-clefs. +Vous devriez également retirer toutes les sous-clefs qui ne sont +pas utilisées et copier secring.auto sur une disquette et la +porter jusqu'à la machine cible. + +Sur celle-ci, installez secring.auto comme trousseau de clefs +secrètes. Vous pouvez maintenant faire démarrer votre +nouveau service. C'est aussi une bonne idée que d'installer +un système de détection d'intrusions afin de pouvoir repérer +les intrusions ce qui vous permettra alors de révoquer toutes +les sous-clefs installées sur cette machine et de procéder à une +nouvelle installation de sous-clefs. + +4.14) Quel client email puis-je utiliser avec GnuPG ? + +Utiliser GnuPG pour le chiffrement de courrier électronique est +probablement l'usage le plus répandu. De nombreux logiciels de +messagerie (les "MUA") supportent GnuPG à divers degrés. Pour simplifier, +il existe deux moyens de chiffrer les emails avec GnuPG : l'ancien style +qui repose sur l'utilisation de l'ASCII Armor (un chiffrement classique +suivi par une conversion selon le RFC2015) ce qu'on appellait le +PGP/MIME et qui s'appelle désormais l'OpenPGP. Ce dernier supporte +d'autre part le MIME. Certains MUA ne supportent qu'un seul de ces +formats et vous devrez utiliser ce qui correspond aux capacités +de votre client de messagerie. + +La liste suivante n'est probablement pas exhaustive : + + OpenPGP: Mutt (Unix), Emacs/Mew, Becky2 (Windows avec plugin), + TkRat (Unix). Il y a un effort pour disposer d'un plug-in + Mozilla et Emacs/GNUS dispose d'un support en CVS. + + ASCII: Emacs/{VM,GNUS}/MailCrypt, Mutt(Unix), Pine(Unix), et + probablement beaucoup d'autres. + +Un bon aperçu du support de PGP se trouve à l'adresse : + +http://cryptorights.org/pgp-users/pgp-mail-clients.html + +Le support direct de GnuPG n'est pas indiqué, toutefois dans certains +cas il doit être possible d'utiliser un "wrapper". + +4.15) On ne peut pas avoir une librairie gpg ? + +Cette question aura souvent été posée. Toutefois, le point de vue +actuel est que GnuPG en tant que librairie risque de conduire à des +problèmes de sécurité. Dans un futur proche, GnuPG ne sera pas +implémenté sous forme de librairie. Toutefois, pour quelques domaines +d'application le programme gpgme doit pouvoir assurer ces questions. +Vous pouvez obtenir ce programme depuis : + +ftp://ftp.guug.de/pub/gcrypt/alpha/gpgme + + +4.16) J'ai produit avec succès un certificat de révocation, mais comment + dois-je le transmettre aux serveurs de clefs ? + +La plupart des serveurs de clefs n'accepteront pas une simple et "dure" +révocation. Vous devez d'abord importer le certificat dans GnuPG : + + gpg --import my-revocation.asc + +Puis transmettre la révocation au serveurs de clefs : + + gpg --keyserver certserver.pgp.com --send-keys mykeyid + +5. COMPATIBILITY ISSUES + +5.1) Comment puis-je chiffrer un message avec GnuPG pour que PGP + soit capable de le déchiffrer ? + +Tout ceci dépend de la version de PGP. + + PGP 2.x + +Vous ne pourrez pas dans ce cas, car PGP 2.x utilise l'IDEA qui n'est +pas un algorithme supporté par GnuPG à cause de son brevêt (voir +la section 3.3) mais si vous disposez d'une version modifiée de PGP +vous pouvez essayer ceci : + + gpg --rfc1991 --cipher-algo 3des ... + +Attention ! N'utlisez pas de pipe des données à chiffrer vers gpg, +mais donnez à gpg un nom de fichier sinon PGP 2 ne sera pas +capable de le prendre en charge. + +Quand à ce qui concerne le chiffrement conventionnel, vous ne +pouvez l'obtenir avec PGP 2. + + + PGP 5.x et ultérieurs + +Vous devrez utiliser deux options additionnelles : + + --compress-algo 1 --cipher-algo cast5 + +Vous devrez parfois utiliser "3des" au lieu de "cast5". PGP 5 ne +supporte pas l'algorithme "blowfish". Vous devrez aussi insérer +un "compress-algo 1" au sein de votre fichier ~/.gnupg/options +et ceci n'affectera pas le fonctionnement général de GnuPG. + +Ceci s'applique également au chiffrement conventionnel. + +5.2) Comment migrer de PGP 2.x vers GnuPG ? + +PGP 2 utilise les algorithmes RSA et IDEA pour le chiffrement. Depuis que le +brevêt sur le RSA a expiré GnuPG incorpore ce dernier, depuis la version +1.0.3 et ultérieures. L'algorithme IDEA reste sous brevêt jusqu'en 2007. +Sous certaines conditions vous pouvez utiliser l'IDEA, même aujourd'hui. +Dans ce cas, vous devriez consulter la réponse à la question 3.3 qui +explique l'ajout du support de l'IDEA à GnuPG et également lire ce +document : + +http://www.gnupg.org/gph/en/pgp2x.html + +Pour procéder à la migration. + +5.3) (supprimé) + + (vide) + +5.4) Pourquoi PGP 5.x n'est pas capable de déchiffrer les messages + pour certaines clefs ? + +PGP Inc refuse d'accepter les clefs ElGamal de type 20 même pour +le chiffrement. Ils ne supportent que le type 16 (qui est identifique en tout +cas en ce qui concerne le déchiffrement). Pour être plus inter-opérable, +GnuPG (depuis la version 0.3.3) utilise également le type 16 pour la sous- +clef ElGamal qui est créée par l'algorithme par défaut. Vous pouvez +aussi ajouter une clef de type 16 à votre trousseau de clefs publiques +tout en assurant que vos signatures sont valides. + +5.5) Pourquoi PGP 5.x ne peut vérifier mes messages ? + +PGP 5.x n'accepte pas les signatures en version 4 pour les données +mais OpenPGP demande la production de clefs V4 pour tous les types +de données et c'est pourquoi GnuPG les utilise... Vous devrez utiliser +l'option --force-v3-sigs pour produir'e des signatures V3 sur les +données. + +5.6) Comment puis-je transférer mes valeurs de confiance de + PGP vers GnuPG ? + +Il existe un script au sein du répertoire tools qui pourra vous aider. Après +avoir importé le trousseau de clefs publiques PGP vous pouvez utiliser +cette commande : + + $ lspgpot pgpkeyring | gpg --import-ownertrust + +où "pgpkeyring" est le trousseau de clefs originels et NON celui de GnuPG +que vous avez produit à la première étape. + +5.7) PGP n'aime pas ma clef privée. + +Les anciens PGP échouent parfois au traitement des commentaires privés +sur les paquets utilisés par GnuPG. Ces paquets sont en *totale* conformité +avec OpenPGP mais vous l'aurez compris, PGP n'est pas vraiment soucieux +d'OpenPGP. Pour contourner ce problème il faut exporter les clefs privées +à l'aide de cette commande : + + $ gpg --export-secret-keys --no-comment -a your-key-id + +Une autre possibilité : par défaut, GnuPG chiffre votre clef privée à l'aide +de l'algorithme symétrique Blowfish. Les anciennes versions de PGP +ne peuvent comprendre que le 3DES, CAST5 ou l'IDEA sous leurs formes +symétriques. L'utilisation de la méthode suivante permet de rechiffrer +vos clefs privées à l'aide d'un algorithme différent : + + $ gpg --s2k-cipher-algo=CAST5 --s2k-digest-algo=SHA1 \ + --compress-algo=1 --edit-key + +Vous utiliserez alors l'option passwd pour modifier le mot de passe ; il suffit +de choisir la même phrase passe mais cette fois la clef sera chiffrée +symétriquement par du CAST5. + +Vous pouvez maintenant exporter la clef et PGP devrait pouvoir la gérer. + +Pour PGP 6.x les options suivantes permettent d'exporter une clef : + + $ gpg --s2k-cipher-algo 3des --compress-algo 1 --rfc1991 \ + --export-secret-keys + +6. PROBLEMS and ERROR MESSAGES + +6.1) Pourquoi GnupG me dit sans cesse "Warning : using insecure memory!" ? + +Sur beaucoup de systèmes, ce programme doit être installé en tant que +setuid(root). Ceci est requis afin de pouvoir produire un blocage en mémoire +des pages utilisées (et d'éviter tout transfert en swap ou sur disque). Ce "lock" +permet de verrouiller dans la pratique les informations sensibles en RAM +afin de conserver ces données comme secrètes. Si vous n'obtenez aucun +message d'erreur c'est que votre système supporte le verrouillage de pages +mémoire depuis l'accès root (le programme s'exécute en tant que root grâce +à son setuid). Le programme quitte le mode d'exécution "root" dès que les +pages sont verrouillées en mémoire qui plus est. + +Sur Unixware 2.x et 7.x vous devriez installer GnuPG avec le privilège +"plock" pour obtenir le même effet : + + filepriv -f plock /path/to/gpg + +Si vous ne pouvez pas installer GnuPG en tant que setuid(root) ou si vous +ne voulez pas, vous pouvez utiliser l'option : + +--no-secmem-warning + +Ou bien le placer en tant qu'option (sans les deux tirets) dans votre +fichier ~/.gnupg/options ce qui permet de désactiver le warning. + +Sur quelques systèmes (e.g; Windows) GnuPG ne verrouille pas les +pages en mémoire (ce n'est pas toujours possible selon les systèmes) +et les anciennes versions de GnuPG (1.0.4 et antérieures) produisent +sur ces systèmes le message d'erreur suivant : + + gpg: Please note that you don't have secure memory + +Cet avertissement ne peut être désactivé en utilisant l'option décrite +ci-dessus car nous considérons que cet avertissement forme une +faille de sécurité importante. Toutefois, comme il provoquait une trop +forte confusion auprès des utilisateurs de ces systèmes, le message +d'avertissement a été retiré. + +6.2) Le support des fichiers de grande taille ne fonctionne pas .. + +Le LFS fonctionne correctement depuis les versions 1.0.4 et ultérieures. +Si le configure ne le détecte pas correctement, essayez un autre +compilateur : egcs 1.1.2 fonctionne parfaitement mais d'autres +versions semblent poser problème. D'autre part, certains problèmes +de compilation rencontrés dans GnuPG 1.0.3 et 1.0.4 sur HP-UX et +Solaris étaient provoqués par un support "cassé" du LFS dans les +sources ... + +6.3) Dans le menu d'édition les valeurs de confiance ne sont pas affichées + correctement après la signature des uid : pourquoi ? + +Ceci survient car certaines informations sont stockées immédiatement +dans la TrustDB, mais le calcul ne se réalisé qu'au moment de la +sauvegarde effective. Ce n'est pas un bogue vraiment facile à corriger +mais nous pensons régler ce problème dans une future version. + +6.4) Que signifie "skipping pubkey 1: already loaded" ? + +Depuis la version 1.0.3 de GnuPG l'algorithme RSA est inclus. Si vous +avez toujours l'option : + +load-extension rsa + +Dans votre fichier .options le message en question apparaîtra. +Il vous suffira de retirer la commande qui n'est plus requise +du fichier .options pour que le message cesse. + +6.5) GnuPG 1.0.4 ne tient pas compte de ~/.gnupg ... + +Ce bogue est connu et il a été corrigé dans les versions ultérieures. + +6.6) Une signature ElGamal ne vérifie plus rien depuis la 1.0.2 .. + +Utilisez l'option : + +--emulate-md-encode-bug + + Use the option --emulate-md-encode-bug. + +6.7) Les anciennes versions de GnuPG ne vérifient pas les anciennes + signatures ElGamal + +Veuillez migrer vers la version 1.0.2 au minimum, et de préférence +une version ultérieure (1.0.6 par exemple). + +6.8) Lorsque j'utilise --clearsign le texte en clair comporte parfois des + tirets supplémentaires : pourquoi ? + +Ceci s'appelle le "dash-escaped" et il est requis par le format +OpenPGP. A chaque fois qu'une ligne commence par un tiret, ceci +risque de survenir. Cela permet aux programmes de retrouver +sans difficulté les lignes de marquage du format, comme : + +-----BEGIN PGP SIGNATURE----- + +Seules ces lignes doivent pouvoir commencer par deux tirets. Si vous +utilisez GnuPG pour traiter ces messages, les tirets supplémentaires +seront retirés et les clients de messagerie "corrects" devraient +également retirer ces tirets lorsqu'ils affichent le message. + +6.9) Que signifie "can't handle multiple signatures" ? + +A cause des différents formats de messages, GnuPG n'est pas toujours +capable de découper un fichier contenant des signatures multiples. +Ce message d'erreur vous informe que les données en entrée +comportent un problème. Le seul moyen pour disposer correctement +de signatures multiples revient à utiliser le standard : le format +OpenPGP avec les paquets "one-pass-signature" qui sont utilisés +par défaut par GnuPG ou bien de recourir au format de texte en clair. + +6.10) Si je soumet une clef au serveur de clefs, rien ne survient ! + +Vous utilisez probablement GnuPG sur Windows en version 1.0.2 ou +antérieure. Cette fonctionnalité n'était alors pas encore disponible, +et il ne s'agit pas d'un bogue. Vous devriez adopter une version +plus récente, qui dispose de toutes les fonctionnalités :-) + +6.11) J'obtiens un "gpg: waiting for lock ..." + +Les anciennes versions de GnuPG ne quittaient pas correctement +et laissaient un fichier "lock". Allez dans le répertoire ~/.gnupg et +effacez les fichiers *.lock qui s'y trouvent pour continuer. + +6.12) Les anciennes versions de GnuPG (e.g. 1.0) ont des problèmes + avec les clefs de GnuPG récents .. + +Depuis la version 1.0.3 les clefs produites par GnuPG sont créées avec +une préférence pour Twofish (et l'AES depuis la version 1.0.4 à savoir, +l'algorithme Rijndael) et ceci signifie également qu'elles disposent de la +capacité d'utilisation de la nouvelle méthode de chiffrement MDC. Ceci +sera disponible dans OpenPGP très rapidement et sera supporté en +tout logique par PGP 7. Cette nouvelle méthode de chiffrement permet +de se protéger votre des attaques (des anciennes attaques en fait) +contre les systèmes de chiffrement du courrier électronique. + +Ceci signifie également que les versions 1.0.3 et antérieures de GnuPG +auront des problèmes avec les clefs plus récentes. A cause des +correctifs de sécurité, vous devriez conserver votre installation +de GnuPG à jour de toute manière. Comme manière de régler le +problème vous devriez demander à GnuPG de n'utiliser que l'ancien +algorithme de chiffrement en utilisant la ligne : + +cipher-algo cast5 + +dans votre fichiers d'options. + +6.13) Avec GnuPG 1.0.4 j'obtiens un "this cipher algorithm is deprecated ..." + +Si vous venez de produire une nouvelle clef et que vous obtenez ce message +pendant un chiffrement, il s'agit d'un bogue de la version 1.0.4 ; le nouvel +algorithme AES Rijndael est utilisé mais il n'est pas enregistré sous le bon +numéro d'algorithme ce qui produit ce message d'erreur "deprecated". +Vous pouvez ignorer cet avertissement et les versions plus récentes +de GnuPG sont corrigées sur ce point. + +6.14) Les dates sont affichées par ????-??-??, pourquoi ? + +A cause de contraintes dans la plupart des implémentations de la libc, +les dates au-delà de 2038-01-19 ne seront pas affichées correctement. +Les systèmes 64-bit ne sont pas affectés par ce problème. Pour éviter +d'afficher les dates de manière incorrecte, GnuPG utilise des signes +"?" au lieu des chiffres. Pour obtenir la valeur correcte vous devrez +utiliser l'option : + +--with-colons --fixed-list-mode + +6.15) J'ai encore un problème, dois-je produire un message de bogue ? + +Si vous êtes sûr(e) que le problème n'est mentionné nulle part, ni dans +cette FAQ ni dans aucune liste de distribution GnuPG, commencez +par consulter la liste de bogues qui sont en cours de traitement (la page +de documentation dispose d'un lien vers la page de bogues). Si vous +ne savez pas trop s'il s'agit d'un bogue, envoyez un courrier +électronique à la liste : gnupg-devel. Sinon, vous pouvez utiliser +le système de suivi de bogues GUUG à l'adresse : + +http://bugs.guug.de/Reporting.html. + +6.16) Pourquoi GnuPG ne supporte pas les certificats X.509 ? + +GnuPG est avant tout une implémentation du standard OpenPGP, +défini dans le RFC 2440. Ce standard propose une infrastructure +complète et différente du X.509 + +Ces deux systèmes sont des cryptosystèmes à clef publique, mais +la manière dont les clefs sont traitées diffèrent. + +7. SUJETS AVANCES + +7.1) Comment tout cela fonctionne-t-il ? + +Pour produire une paire de clefs publique/privée, utilisez la commande + +gpg --gen-key + +Puis répondez aux questions en adoptant de préférence les valeurs +par défaut. + +Les données qui sont chiffrées par une clef publique ne peuvent être +déchiffrées que par la clef privée correspondante. La clef secrète +est d'autre part protégée par une phrase-passe ce qui n'est pas le cas +de la clef publique, librement distribuable. + +Pour transmettre à vos amis un message, il vous suffit de le chiffrer +à l'aide de leurs clefs publiques. Seules leurs clefs privées seront +capables de déchiffrer le message. + +GnuPG est pratique pour signer de manière numérique les choses. +Les éléments qui sont chiffrés à l'aide de la clef publique ne peuvent +être déchiffrés que par la clef publique, ce qui permet de signer +des documents. On commence par produire un hachage, une sorte +d'empreinte à taille fixe d'un document (de taille variable). Ensuite, +votre clef privée est utilisée pour chiffrer ce hachage. Par la suite, +toute personne disposant de votre clef publique et du document +peut vérifier si le hachage du document correspond bien au +déchiffrement du hachage, obtenu par votre clef publique dont +disposent vos destinataires. + +Un trousseau de clefs n'est qu'un gros fichier (selon le nombre de +clefs qu'il contient). Vous avez un trousseau de clefs publiques +qui contient vos clefs publiques et celles de vos amis. Vous avez +également un trousseau de clefs privées qui ne contient que vos +clefs privées (chiffrées et protégées par votre phrase-passe). Vous +devez faire très *attention* à ce fichier. Personne ne devra jamais +y avoir accès et la phrase-passe qui le protège devra être +complexe, et longue afin de bien protéger le secret. + +Vous pouvez aussi chiffrer des données de manière conventionnelle, +en utilisant l'option "-c" de GnuPG. Dans ce cas, la phrase-passe +utilisée servira de clef pour protéger le message. Aucun usage +de clef publique ou de clef privée ici : il s'agit d'un chiffrement +classique où il n'existe qu'une seule clef, utilisée pour chiffrer et +déchiffrer les données. Généralement, on utilise cette méthode +pour chiffrer ses propres documents à l'aide d'une phrase-passe +secrète qui vous est propre. Cette méthode de chiffrement ne +doit être utilisée pour des communications que si vous avez +physiquement rencontré vos destinataires et que vous partagez +dans le plus grand secret la phrase-passe (votre propre époux ou +épouse, ou un ami de confiance). L'avantage est que vous pouvez +changer de temps en temps la phrase-passe et en réduire le +risque afin qu'en cas de découverte de la phrase-passe toutes +vos données ne soient pas lisibles ;-) + +Vous pouvez ajouter et copier des clefs depuis votre trousseau +de clefs publiques à l'aide des commandes "gpg --import" et +"gpg --export". Vous pouvez également (ATTENTION !!) exporter +vos clefs privées à l'aide de la commande : "gpg --export-secret-keys" +mais ce n'est généralement pas utile sauf si vous devez déplacer +vos clefs privées d'une machine à l'autre. + +Les clefs peuvent être signées à l'aide de l'option "gpg --edit-key". Lorsque +vous signez une clef, vous certifiez que la clef appartient selon vous +à la personne dont l'identité se trouve mentionnée dans la clef. Vous +devez absolument être sûr(e) que la clef appartient bien à cette +personne, sans le moindre doute. Vous devez vérifier son fingerprint +à l'aide de la commande : + +gpg --fingerprint userid + +Et recevoir le même finger par téléphone ou de visu par la personne +concernée. Généralement, on procède à des "fêtes" où chaque personne +amène sa pièce d'identité, une carte de visite comprenant le fingerprint +et l'on procède à un échange des fingerprint, ou directement des clefs. + +Vous pouvez également utiliser l'option "-o filename" pour forcer +la sortie vers le fichier "filename". Pour forcer une sortie en console +par défaut on utilise un tiret. La commande "-r" permet de spécifier +le destinataire (avec quelle clef publique vous allez chiffrer) en ligne +de commande au lieu d'avoir à taper le nom du destinataire dans +le mode interactif. + +Autre chose d'importance. Par défaut, TOUTES les données sont chiffrées +dans un format binaire particulier; Si vous souhaitez transmettre les données +par courrier électronique (par exemple) vous devez les protéger dans +un format d'amure qu'on appelle ASCII ARMOR. Ce format sera obtenu +en utilisant l'option "-a" mais la méthode préférée reste d'utiliser +un client de messagerie respectueux du format MIME comme Mutt, Pine +et bien d'autres. + +Enfin, il existe une petite faille de sécurité dans OpenPGP (et donc dans PGP) +et vous devriez TOUJOURS chiffrer PUIS signer un message. Il ne faut +pas seulement chiffrer afin d'être totalement protégé. N'oubliez jamais. + +7.2) Pourquoi certaines signatures avec une clef ELG-E sont valides ? + +Ces clefs ElGamal furent produites par GnuPG en version 3 de paquets +(selon le RFC 1991). Le brouillon OpenPGP a été modifié par la suite +afin de modifier l'identifiant d'algorithme pour les clefs ElGamal qui est +utilisable pour les signatures et le chiffrement des modes 16 à 20. +GnuPG utilise le mode 20 quand il produit ses nouvelles clefs ElGamal +mais il accepte toujours les clefs de type 16 qui selon le standard +OpenPGP ne peuvent servir qu'au chiffrement, si la clef se trouve +dans un paquet en version 3 du format. GnuPG est le seul programme +ayant jamais utilisé les clefs au sein de paquets v3 - vous ne risquez +donc pas grand chose. + +7.3) Comment tout le système de confiance fonctionne au juste ? + +Il fonctionne d'une manière proche de PGP. La différence c'est que +la confiance est calculée uniquement lorsqu'elle est requise. C'est +pourquoi la TrustDB contient une liste des signatures de clefs +valides. Si vous ne fonctionnez pas en mode batch, vous devrez +assigner un paramètre de confiance aux clefs (un ownertrust). + +Vous pouvez consulter la validité (la valeur de confiance +calculée) en utilisant cette commande : + + gpg --list-keys --with-colons + +Si le premier champ est "pub" ou "uid" le second champ vous +indiquera le niveau de confiance : + +o = Inconnu (cette clef est nouvelle au système) +i = La clef est invalide (eg. il manque sa propre signature) +d = La clef a été désactivée +r = La clef a été révoquée +e = La clef a expiré +q = Non-défini (pas de valeur attribuée) +n = Ne jamais faire confiance à cette clef +m = Cette clef dispose d'une confiance marginale +f = Cette clef dispose d'une confiance totale +u = Cette clef dispose d'une confiance ultime. Cette valeur + n'est utilisée que pour les clefs où la clef secrète est + également disponibles. + +La valeur dans l'enregistrement "pub" est la meilleure valeur +obtenue depuis les enregistrements "uid". + +Vous pouvez obtenir la liste des valeurs de confiance attribuées ; +i.e. la confiance que vous accordez aux autres lorsqu'il s'agit +de signer la clef d'un autre individu) : + + gpg --list-ownertrust + +Le premier champ est le fingerprint de la clef primaire, le second +champ est la valeur assignée : + +_ = Aucune valeur d'ownertrust assignée +n = Ne jamais faire confiance au propriétaire de cette clef + lorsqu'il s'agit de vérifier d'autres signatures. +m = Une confiance marginale est accordée au détenteur de cette clef + lorsqu'il s'agit de signer d'autres clefs. +f = Assumer que le détenteur de cette clef est une personne de confiance + lorsqu'il s'agit de signer des clefs. +u = Nous n'avons pas besoin de nous faire confiance à nous-même puisque + nous détenons notre propre clef privée. + +Vous devez conserver ces valeurs confidentielles, car elles représentent +la confiance que vous accordez ou non à d'autres individus. PGP stocke +cette information au sein de trousseau de clefs et le publier n'est PAS +une bonne idée. Vous devez utiliser la commande d'exportation pour +transmettre des clefs. Quoi qu'il en soit, GnuPG +évite ces problèmes en ne conservant ces valeurs qu'aun sein de sa +TrustDB donc vous pouvez copier un trousseau de clefs publiques +si vous utilisez GnuPG (et nous disposons aussi de la commande +d'exportation). + +7.4) Quel est ce genre de sortie : "key C26EE891.298, uid 09FB: ...."? + +Cette sortie est la représentation interne d'un userid au sein +de la TrustDB. Le keyid est "C26EE891" et le "298" est le keyid local, +un simple numéro d'enregistrement dans la TrustDB. Enfin, le "09FB" +sont les deux derniers octets d'un ripe-md-160 de l'identifiant de +l'utilisateur pour cette clef. + +7.5) Comment interpréter certaines sorties informatives ? + +Lorsque vous vérifiez la validité d'une clef, GnuPG affiche +parfois une information préfixée par l'information en rapport +avec le sujet vérifié. Par exemple : "key 12345678.3456" indique +que la clef disposant de l'ID 12345678, et du numéro interne 3456 +est considérée au sein de la TrustDB au sein de ce qu'on +appelle un enregistrement "directory". Un "uid 12345678.3456/ACDE" +indique quel est l'identifiant d'utilisateur qui correspond +à cette clef. Il s'agit d'une information sur la signature de la +clef 9A8B7C6D disposant de cet ID et s'il s'agit d'une signature +directe sur la clef, la partie User ID sera vide : + +(..//..) + +7.6) Les lignes d'en-tête des messages font-elles parties des + éléments signés ? + +Non. Par exemple, vous pouvez retirer les lignes "Comment:" +Elles n'ont pas vraiment d'objet comme les lignes "header" des +courriers électroniques. Toutefois, une ligne qui débute par +"Hash: ..." est requise par les signatures OpenPGP afin de permettre +au parser de déterminer quel algorithme de hachage utiliser. + +7.7) Quelle est la liste des algorithmes préférés ? + +La liste des algorithmes préférés est une liste d'algorithmes +de chiffrement, de hachage et de compression stockés dans +la signature propre de la clef durant sa production. Lorsque +vous chiffrez un document, GnuPG utilise cette liste (elle fait +partie de la clef publique) pour déterminer quels algorithmes +doivent être utilisés. De manière basique, ces indications +expliquent aux autres utilisateurs quels algorithmes vous +acceptez en entrée avec un ordre de préférence. + +7.8) Comment puis-je changer la liste des algorithmes préférés ? + +Actuellement la liste et les préférences sont directement intégrées +dans les codes sources de GnuPG. Vous devrez modifier le fichier +g10/keygen afin de modifier cette liste et procéder à une +nouvelle compilation. La fonction que vous devrez modifier est +keygen_add_std_prefs. Le code est d'ailleurs assez simple à +comprendre. Les constantes utilisées pour différencier les +algorithmes sont définies au sein du fichier include/cipher.h + +Après avoir modifié ces fichiers, générez une nouvelle paire +de clefs (ou une nouvelle sous-clef de chiffrement) avec +la version modifiée de l'exécutable. La nouvelle clef disposera +des nouvelles préférences et pourra être utilisée depuis des +exécutables non modifiés. + +Pour modifier les préférénces d'une clef existante, vous devrez +utiliser un exécutable modifié (voir ci-dessus) afin de modifier +la date d'expiration puis sauvegardez les changements. Les +préférences seront automatiquement modifiées lors de la +sauvegarde et vous pouvez désormais utiliser la clef modifiée +avec tout exécutable, modifié ou non. + +La modification de la liste de préférences à l'aide d'une +version non-modifiée de GnuPG (probablement depuis le menu +d'édition) fait partie de la liste TODO (A FAIRE) prévue +pour les prochaines versions de GnuPG. + + +8. REMERCIEMENTS + +Nous souhaitons remercier Werker Kosh pour la rédaction de la +première FAQ originelle et pour tous les participants aux listes +de discussion gnupg-users et gnupg-devel. La quasi-totalité +des réponses de ce document proviennent de leurs efforts. + +Nous souhaitons également remercier Casper Dik pour nous +avoir fourni le script permettant de générer cette FAQ, +qu'il utilise d'autre part pour son excellente FAQ Solaris2 ;-) + +Copyright (C) 2000 Free Software Foundation, Inc. , +59 Temple Place - Suite 330, Boston, MA 02111, USA + +Verbatim copying and distribution of this entire article is permitted in +any medium, provided this notice is preserved. diff --git a/doc/fr/README.fr b/doc/fr/README.fr new file mode 100644 index 000000000..3a5d8485e --- /dev/null +++ b/doc/fr/README.fr @@ -0,0 +1,10 @@ +You find here translations to French of some of the documents in +../doc. Those translations are not necessary up-to-date and should +not be used as reference without checking the original English +versions. + +Gilbert Fernandes kindly contributed thses translatons. + + + + diff --git a/doc/gnupg-w32.reg b/doc/gnupg-w32.reg new file mode 100644 index 000000000..7a6e346a8 --- /dev/null +++ b/doc/gnupg-w32.reg @@ -0,0 +1,8 @@ +REGEDIT4 + +[HKEY_CURRENT_USER\Software\GNU\GNUPG] +"HomeDir"="C:\\GnuPG" +"gpgProgram"="C:\\GnuPG\\gpg.exe" + +[HKEY_CURRENT_USER\Control Panel\Mingw32\NLS] +"MODir"="C:\\GnuPG\\Locale" diff --git a/doc/gpg.sgml b/doc/gpg.sgml index 44220a16e..145ad7c52 100644 --- a/doc/gpg.sgml +++ b/doc/gpg.sgml @@ -1,5 +1,5 @@ -directory"> file"> &ParmFile;"> @@ -71,6 +71,16 @@ + +This man page only lists the commands and options available. +For more verbose documentation get the GNU Privacy Handbook (GPH) or +one of the other documents at http://www.gnupg.org/docs.html . + + +Please remember that option parsing stops as soon as a non option is +encountered, you can explicitly stop option parsing by using the +special option "--". + @@ -113,7 +123,7 @@ Encrypt data. This option may be combined with --sign. -c, --symmetric -Encrypt with symmetric cipher only +Encrypt with symmetric cipher only. This command asks for a passphrase. @@ -144,16 +154,42 @@ message. Assume that - as the second filename. +For security reasons a detached signature cannot read the signed +material from stdin without denoting it in the above way. + + + +--verify-files + +This is a special version of the --verify command which does not work with +detached signatures. The command expects the files to be verified either +on the command line or reads the filenames from stdin; each name must be on +separate line. The command is intended for quick checking of many files. + + + +--encrypt-files + +This is a special version of the --encrypt command. The command expects +the files to be encrypted either on the command line or reads the filenames +from stdin; each name must be on separate line. The command is intended +for a quick encryption of multiple files. + + + +--decrypt-files + +The same as --encrypt-files with the difference that files will be +decrypted. The syntax or the filenames is the same. + + + +directory"> +file"> +&ParmFile;"> +files"> +&ParmFiles;"> +names"> +&ParmNames;"> +name"> +&ParmName;"> +key IDs"> +n"> +flags"> +string"> +value"> +name=value"> +]> + + + + gpgv + 1 + GNU Tools + + + signature verification tool + + + +gpgv + + + + + + + DESCRIPTION + + + +This program is a stripped down version of + + + + + +OPTIONS + + + + + + + +-v, --verbose + +Give more information during processing. If used +twice, the input data is listed in detail. + + + + +-q, --quiet + +Try to be as quiet as possible. + + + + +--keyring &ParmFile; + +Add &ParmFile to the list of keyrings. +If &ParmFile begins with a tilde and a slash, these +are replaced by the HOME directory. If the filename +does not contain a slash, it is assumed to be in the +home-directory ("~/.gnupg" if --homedir is not used). +The filename may be prefixed with a scheme: +"gnupg-ring:" is the default one. +It might make sense to use it together with --no-default-keyring. + + + + +--homedir &ParmDir; + +Set the name of the home directory to &ParmDir; If this +option is not used it defaults to "~/.gnupg". It does +not make sense to use this in a options file. This +also overrides the environment variable "GNUPGHOME". + + + + +--status-fd &ParmN; + +Write special status strings to the file descriptor &ParmN;. +See the file DETAILS in the documentation for a listing of them. + + + + +--logger-fd &ParmN; + +Write log output to file descriptor &ParmN; and not to stderr. + + + + +--ignore-time-conflict + +GnuPG normally checks that the timestamps associated with keys and +signatures have plausible values. However, sometimes a signature seems to +be older than the key due to clock problems. This option makes these +checks just a warning. + + + + + + + + + RETURN VALUE + +The program returns 0 if everything was fine, 1 if at least +one signature was bad, and other error codes for fatal errors. + + + + + EXAMPLES + + + +gpgv +gpgv + +Verify the signature of the file. The second form +is used for detached signatures, where + + + + + + + ENVIRONMENT + + + +HOME +Used to locate the default home directory. + + +GNUPGHOME +If set directory used instead of "~/.gnupg". + + + + + + + + FILES + + + +~/.gnupg/trustedkeys.gpg +The default keyring with the allowed keys + + + + + + + + + diff --git a/doc/gpgv.texi b/doc/gpgv.texi new file mode 100644 index 000000000..cc83e6a2d --- /dev/null +++ b/doc/gpgv.texi @@ -0,0 +1,115 @@ +\input texinfo +@c This Texinfo document has been automatically generated by +@c docbook2texi from a DocBook documentation. The tool used +@c can be found at: +@c +@c Please send any bug reports, improvements, comments, +@c patches, etc. to Steve Cheng . + +@setfilename gpgv.info + +@node top +@top gpgv +@menu +@end menu + +@majorheading Name +gpgv ---- signature verification tool + +@majorheading Synopsis + +@majorheading DESCRIPTION +@code{gpgv} is the OpenPGP signature checking tool. + +This program is a stripped down version of @code{gpg} which is only +able +to check signatures. It is somewhat smaller than the full blown +@code{gpg} and uses a different (and more simple way) to check that +the public keys used to made the signature are trustworth. There is +no options files and only very few options are implemented. + +@code{gpgv} assumes that all keys in the keyring are trustworty. +It uses by default a keyring named @file{trustedkeys.gpg} which is +assumed to be in the home directory as defined by GnuPG or set by an +option or an environment variable. An option may be used to specify +another keyring or even multiple keyrings. + +@majorheading OPTIONS +@code{gpgv} recognizes these options: + +@table @asis +@item -v, ---verbose +Give more information during processing. If used +twice, the input data is listed in detail. + +@item -q, ---quiet +Try to be as quiet as possible. + +@item ---keyring @code{file} +Add @code{file} to the list of keyrings. +If @code{file} begins with a tilde and a slash, these +are replaced by the HOME directory. If the filename +does not contain a slash, it is assumed to be in the +home-directory ("~/.gnupg" if ---homedir is not used). +The filename may be prefixed with a scheme: + +"gnupg-ring:" is the default one. + +It might make sense to use it together with ---no-default-keyring. + +@item ---homedir @code{directory} +Set the name of the home directory to @code{directory} If this +option is not used it defaults to "~/.gnupg". It does +not make sense to use this in a options file. This +also overrides the environment variable "GNUPGHOME". + +@item ---status-fd @code{n} +Write special status strings to the file descriptor @code{n}. +See the file DETAILS in the documentation for a listing of them. + +@item ---logger-fd @code{n} +Write log output to file descriptor @code{n} and not to stderr. + +@item ---ignore-time-conflict +GnuPG normally checks that the timestamps associated with keys and +signatures have plausible values. However, sometimes a signature seems to +be older than the key due to clock problems. This option makes these +checks just a warning. + +@end table + +@majorheading RETURN VALUE +The program returns 0 if everything was fine, 1 if at least +one signature was bad, and other error codes for fatal errors. + +@majorheading EXAMPLES +@table @asis +@item gpgv @code{pgpfile} +@itemx gpgv @code{sigfile} @code{files} +Verify the signature of the file. The second form +is used for detached signatures, where @code{sigfile} is the detached +signature (either ASCII armored or binary) and @code{files} are the signed +data; if this is not given the name of the file holding the signed data is +constructed by cutting off the extension (".asc", ".sig" or ".sign") from +@code{sigfile}. + +@end table + +@majorheading ENVIRONMENT +@table @asis +@item HOME +Used to locate the default home directory. + +@item GNUPGHOME +If set directory used instead of "~/.gnupg". + +@end table + +@majorheading FILES +@table @asis +@item ~/.gnupg/trustedkeys.gpg +The default keyring with the allowed keys + +@end table + +@bye diff --git a/doc/gph/Makefile.am b/doc/gph/Makefile.am index 732c3e3e6..d36b0013a 100644 --- a/doc/gph/Makefile.am +++ b/doc/gph/Makefile.am @@ -11,7 +11,7 @@ all-local: ./signatures.jpg ./signatures.jpg: $(srcdir)/signatures.jpg.asc ../../g10/gpg --yes --dearmor \ -o ./signatures.jpg $(srcdir)/signatures.jpg.asc - test -d manual && cp ./signatures.jpg ./manual/signatures.jpg + -test -d manual && cp ./signatures.jpg ./manual/signatures.jpg index.html: $(PARTS) @@ -27,7 +27,7 @@ index.html: $(PARTS) echo '' >>index.html -rm -r manual.junk -rm manual/signatures.jpg - (cd manual; rm -r stylesheet-images; ls | grep -v distfiles >distfiles) +## (cd manual; rm -r stylesheet-images; ls | grep -v distfiles >distfiles) dist-hook: index.html diff --git a/doc/gph/signatures.jpg.asc b/doc/gph/signatures.jpg.asc new file mode 100644 index 000000000..99f04e394 --- /dev/null +++ b/doc/gph/signatures.jpg.asc @@ -0,0 +1,232 @@ +-----BEGIN PGP ARMORED FILE----- +Version: GnuPG v0.9.11 (GNU/Linux) +Comment: For info see http://www.gnupg.org +Comment: Use "gpg --dearmor" for unpacking + +/9j/4AAQSkZJRgABAQEAUABQAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkS +Ew8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJ +CQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy +MjIyMjIyMjIyMjIyMjL/wAARCACxAogDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEA +AAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIh +MUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6 +Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZ +mqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx +8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREA +AgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV +YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hp +anN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPE +xcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3 ++iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiub8Z+MrbwRpaan +f6bqV1Zl9kktlGjiEnG3fudSAScA8jPBwSM5+i/Emx1bxBa6LcaH4g0i7vEka1/t +Sx8lZig3MqnceQvPpx1yQCAdpRXH6V4y1G7+Id74U1HQPsHk2kl7b3X2xZftEIlE +atsC/Lu5OCcjGMV0Gp67o+ieV/a2q2Nh52fL+13CRb8YzjcRnGR09RQBoUVyfi7x +NfWfgO78Q+EhpuqmBDN5jT7ovKQnzGUqcOQFPG4dDySNpuaF4x0fW7XTF/tCxh1O ++tIrn+zvtaNMm+ISbdvDHCnOcDjmgDoKKy9S8S6Do1wtvqmt6bYzsgdY7q6SJiuS +MgMQcZBGfY1qUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF +FFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF +FFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF +FFABRRRQAVz/AIk8ceGvCPljXNXgtJJMFYcNJIQc4bYgLbflI3YxkYzmjxZ400Lw +Vpy3mtXflebuEEKKXkmZRkhVH4DJwoJGSMivnTxl4Z8X/EB5/Htr4TktLS6SDZbw +ytNPOu3YJQnUj5V6KvylSAw3PQB29/8AHy+1zVLPSfAnh2S5vLhwoOoDlj82VCI2 +AAMNvL4ADZAAzXsmh2+o2mh2UGr3v23UliX7TOAoDyHltoVVG0HIHAOAM85Ncn8M +/hnY+ANLLuY7nWrhALq7A4A6+XHnkID36sRk9AF7ygDzf41zXlx4EuNDsNF1XUbr +Utux7G1MyReXLG58wjlcjOODnBrj/B2j6jL8XNI1a1s/GUlnFaTR3lx4qtlLxLtb +b5Up9WYDaoDD5uSrNj3iigDxf/hMLz/haf8AwlH/AAg/jL7D/Yn9n+X/AGSfM8zz +/MzjdjbjvnOe1SfFZtc1PWdHNrpF3Popsmljnh8ORalOJmYZR45sGIbQh6Kc5BBx +8vslFAHgfhNtS0n4UeNtKufDfiD7Xe3E4tUXRmiM32iLYpEacIF2EsB8qgqASSBR +4A0G58I+ILCDxD4Ru9bfUreyuLbVhYPLJpr4VRDJv4iEeOqkEBVyDwE98ooA+ZNZ +8JeKbbVNYg16DWdQnvLiVhfWvhi21EzxH5FcSl90JwvEYI2DGMZr2/4aWs1j8PNI +tJ21IvCkiD+0rcwThRIwUNGWbaAuAoyflA6dB1lFAGXrniPSPDVvbXGs30dnBcXC +20ckgO3zGBIBIGFGFJ3HAGOSK0IJ4bq3iuLeWOaCVA8ckbBldSMggjggjnNU9Z0P +S/EOnPYavYQXtq2TsmTO0kEblPVWwThhgjPBryufwV43+G1vLd+BdZk1bSYULtou +oqZGAA/5Z7cZO5nchPLJwB854oA9korh/B3xS0Lxdef2UVn0zXU3LLpt4hVwyAbw +p6Ng7hg4b5WJUAV3FABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFF +FABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFF +FABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUVz/izx +poXgrTlvNau/K83cIIUUvJMyjJCqPwGThQSMkZFAHQV5P4i+LFxq2oyeGvhxZ/2z +q7xSFr1SBDalTgsC4Cv3wxITJTBfO2stNN8afGZEm1dpPDfg6ZIporOMrJLd4bOS +2AcHkgsNv+rIRvvV6xoHhzSPC2lrpui2MdpaBy+xSWLMepZmJLHoMkngAdAKAOL8 +J/Ce307WG8S+Kbz+3fEskq3H2iQERwOFxhFzhsHoSBgKm1UxXpFFFABRRRQAUUUU +AFFFFABRRRQAUUUUAFFFFAHJ+M/hz4c8dIjavbSLdxJsivLd9kqLuBxnBDDrwwON +zYwTmuHGpeP/AIWXDrrC3fi/wuqKft0Y/wBItuS0jMCWYgAN94lcbPnTla9kooAw +/C/i7RfGOlpf6PexzAorSwFgJYCcjbImcqcq3scZBI5rcrzPxR8G9IvnfVfC0knh +3Xo0YwTWMhhiLbQuGVfuAqCMpj7xJDdDn2fxQ1rwdqkGi/EzTo7QSI/kazaAvFOE +wMlFBOSQScYI3plFBzQB65RXPt458LLqOmWA16xkuNT3fYxFKHWXBK/eXKjLAqMk +ZYEDJGK6CgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA +KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA +KKKKACiiigAqnqt+2maXcXyWN3fGBN/2e0VWlcd9oYgE45xnJxgZOAblcf8AE7Vd +Y0vwNe/2BYX15qd1/osP2KF5Hh3A7pPkIZcKGww6MVoAj8D/ABP0Hx9cXlvpcd3B +PaortHdhFZ1JIyoV2JAIAJ7bl9aku/GWo2PxH07wxc6BssdS837JqX2xT5nlw+Y/ +7oLkYJ28kZ6ivLLHTPEfw88S+FdYtLfWdetH0z7Pc2dtoP2d7W1Y71Rtu5TLvZnI +yGymGbDZro/FfiW8k+Jnh3UYfB3iua10CW+iuJItMLCbzEEatEQcMuRnJxwRQB6Z +4h1y28PaNPf3E1ojqjCCO6ukt1nl2krGHc4BbHXtye1WNJvW1LRrG/eKOJ7m3jma +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 +zwt4F1O3WWMzpqbO8YYblVoowpI6gEqwB77T6V7BPBDdW8tvcRRzQSoUkjkUMrqR +ggg8EEcYrzf4deCz4E8a+KbCJJDp9+kF1YusMmxIw0oMTOcjeu5RgsSwIb1AAPTK +KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK +KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK +KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAr +31hZ6nZyWd/aQXdrJjfDPGJEbBBGVPBwQD+FeZ3nwaXSXnvvAniDUvD94zpILfz2 +ktZCinarg/MQW5JYuACw2kHFeqUUAeP/APCxPHPgj/kffDH2nTE/d/2rpWG+78u9 +1ztG9imM+V1OAfuiSP8AaC8LnxZNp0qSLo4TMWrLvYM20HDRbA6jO5cjPIHGDkeu +V88az+zjrEu+6s/FMF/fTSl5jfQPFuzksxcM5LZx1HOSc+oB9BwTw3VvFcW8sc0E +qB45I2DK6kZBBHBBHOakrw/wj4S+KPw22/ZvsPiHTGzG2lR37J5edzB0aVVVPmPO +M7t3I6MvsF9Zf25oclrM99p7XMQyYJ/KngY4PDoSAwPoSpxjkHkA0KK+YPAq+JPG +9wNLi8WeK7O/fTxeLdT6jIIDtuvLkKJ1kXyyMfMv7xGBODx6n408W+OtA8Z2OlaP +pWjalb6qkw0+Eu6T7o4gzGRmYIAGbOB1UYyCc0AemUVwer+I/EvhbwHe6l4kvvDF +pqwuFS1dRcNaspK8MoBkZ8eYcKDwAegNY/w2+J2oeLfFV3ot7Jo12iWX2uO60tLi +NVIcIUZZgCT8wORgDHfPAB6pRXibfEn4g2Wia1r15Z+GJdP0PUzp97DD9oSWVldE +byySQAd4wT7/AC9j2ninxT4gj8W2XhTwpY2MupyWhv7i51JmEEUAYoOEO4sXAHHT +I4OSVAO4org9Kv8A4lXNv4gtb2x8Pw6haPAmn3AWcWs5YBpc5O8hVIAIAG7I5wcS +fCC4iu/hbo08NlBZRt5+IIC5RMTyDguzNz15J6+nFAHcUV4f4q+LnivRvEOo2EVr +odj5V2YLK01OG5Sa5j37BMJPlhEbHccllAAPJxk+4UAFFFFABRRRQAUUUUAFFFFA +BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA +BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFA +BRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVn63pX9t6PPp32++sPO2/6TYTe +VMmGDfK2DjOMH2JrQooA5PwZ4CtvA6PBp+tazc2bJtWzvZ0kijO4tuQBAVOS2cHB +zyCQCKfiH4ZWfiPxGNcm8R+I7S6j/wCPdLO+EaW2UCN5QKEpuA+bB5ya7iigDl9V +8D2et+F7LRNR1TVZmsZY57fUftAW7SRCdr7woBYAkZKk9/vfNWXpfwuttK8QLrie +KfE9xqCW72yy3d6k3yMDwd0fIVjvAORuAJBrvKKAPN/+FM6O2h6hpEniDxHJa6hd +peXO+8QmSRd2SfkwdxYFsgklEOflrY1r4c6XrkWkyS3+q22p6ZEIYdWtbnZeOm0q +Q8mDuzkk8dScY3MD2FFAHDp8M7ePTprdfFPisXU0sbyah/aZ+0siBwsW7bjywZHb +GOp68CpPCXw4tvBlxE2neIfEEtpGjILC6uke3wxycJsG07ucrg5z2JB7SigDzf8A +4UtoXkfYf7b8R/2N5vmf2R/aJ+ybd+/Zt2525993fOea9IoooAKKKKACiiigAooo +oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo +oAKKKKACiiigAooooAKKKKACiiigAooooA//2Q== +=ao7I +-----END PGP ARMORED FILE----- diff --git a/doc/samplekeys.asc b/doc/samplekeys.asc new file mode 100644 index 000000000..04599e895 --- /dev/null +++ b/doc/samplekeys.asc @@ -0,0 +1,624 @@ + + pub 1024D/621CC013 1998-07-07 Werner Koch + uid Werner Koch + sub 1536g/ADF6A6E1 1999-02-20 [expires: 2002-11-01] + + pub 1024D/5B0358A2 1999-03-15 Werner Koch + + pub 4096R/99242560 2002-01-28 David M. Shaw + sub 2048g/1643B926 2002-01-28 [expires: 2012-01-26] + + pub 1024D/B2D7795E 2001-01-04 + uid Philip R. Zimmermann + uid Philip R. Zimmermann + uid [image of size 3457] + sub 3072g/A8E92834 2001-01-04 + + pub 1024D/57548DCD 1998-07-07 Werner Koch (gnupg sig) + + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.6e-cvs (GNU/Linux) + +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 +bS5vcmc+iEYEEBECAAYFAjpU6LcACgkQx0Y2ObLXeV4TyQCg5ii9gHqOjlsHGSsq +kliw+Ha0MX4AoLie5O1xLkK/rS9J3aIp9EUkE5AhiEYEEBECAAYFAjpU6WkACgkQ +Y8tpHfrr1fykfgCeLP0tqVZ8D9lU2EVrKZkdauwst50AoIQsSo6PBhfNwwb5zDLK +O/PGftGhiEYEEBECAAYFAjpXKUkACgkQ14y85WanSzGqnQCePrJJrLngH0MDYrDU +qrK1ju2/BHUAnieEItKJUoN9FXzacVsEFW1D0UwQiD8DBRA6WP4q8CBzV/QUlSsR +Ap0RAJwPSxTAIb6M1TM8LSNgnvYigYZXwwCfZzVNckHKo7WtpZ1lWN+4W80eKJyI +RgQQEQIABgUCOlrmuwAKCRBnkE+tCnkWEOpjAKDeibXDKCIMiNZafH0nzDD/CRU+ +pACglr+BhEKX68HeW4QnooPxoFwlviKIRgQQEQIABgUCOleFogAKCRCsuxZLz3Ps +TDo9AJ97srZSNDeiQUHoiGsETRMKG6Uf+ACgwsiJIzN2rVgvAgCfq89g/efv8hTR +zNf/AAANkgEQAAEBAAAAAAAAAAAAAAAA/9j/4AAQSkZJRgABAQAAAQABAAD/2wBD +AAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEEx +NDk7Pj4+JS5ESUM8SDc9Pjv/2wBDAQoLCw4NDhwQEBw7KCIoOzs7Ozs7Ozs7Ozs7 +Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/wAARCACPAHUD +ASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA +AgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAk +M2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlq +c3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXG +x8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEB +AQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx +BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5 +OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaX +mJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq +8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD2aiiigAooooAKyNb8S6boUZN1Lulx8sS/ +eP8Ah+NZXjbxcdCt/sdjh7+UdcjES+p968fvLyW6leaa4mmlY5kkL4AP1qXLsaQh +fVnc6l8TdSncrYRRW6Zx03t/L+lYsvjjXnA8zUZY8nI2kr/QVzlu0b8+S2R/HvJN +WFgAYuwDFuvJ/lzms2/M2UbdDrLPxlrETK51CRxn7sm1gfzrs9F8b2d8ix3v+jyn ++Ij5T/hXkQj8gZX5hnlCMZq9YShm8vzDt7HuDQm0KUUz3ZHWRQ6MGU9CDkGnV5VZ +6xf6FJ5qTlY8/Mh5Vh9K77QNfi1uEkJskUZI7EeorRSuYyjY16KKKogKKKKACiii +gArO17VU0XR575sFkXCKf4mPQVo1wHxXvfJ0yztw+N8hdh3IHA/nSew4q7PNdT1G +a9vpLi4kaaaRyWY8KDRYWCXkuG5Qc+gzWe8mWAUYz19TW9pbGJAScZ6msJuyO2nG +7NOPTrcxhAMdOmOKp3eg36OWsw0qY4x2rVgkynIyfrite0bKDBrBNo3aOOtvDWr3 +dwPPjEKDOS1dJbeFJYY/3UqKxGC5TJ/Wt+Fdx4HNaMUSlM9yK1TbMJ2RwWo+GtXe +MiaZLlByCo2mpvCOpTaDrKpdEmA/KxIwVz612rR4PPWue13T4RcwXBUBWYI5A6Z6 +GmpNMmyasejghgCDkHkGlrD8J3ck+lfZ5m3SWreXu/vL/Cfy/lW5XQnc5GrMKKKK +YgooooAK8j+LF4ZNchtmACQQjGDySefy6V6jqeowaVp099cnEcK7j7+grwXxjq1x +r2ovqYRUV8DaCTtA7VMmtjWnBv3jMgjM0wAUnFbcCtHGFHOevtUek2RisUmkwS3O +4HIqeWTaP3e0HPzMemfwrmk7s7oWSuatk7BQG71v28OFUpjHt2rj7XWreH91NLGW +PQ7W/qK6bTdYs5IgFuI8njGajlsPmubtrmMGVuAo5q7GxWMcZBH51nmVDaIqMpEr +DJB7VcWf98Y+wXg9jVowlqTtIpGP6Vj+KNv/AAj1y4xuUAr9cjFajHnHWsvxG6DS +ij8h3H6c0yUW/Aju/n7xg7Rn6gkV2Fc14Lg22MszD53IBPf1rpa6I7HNLcKKKKok +KKKKAOQ+JchHhuOIMR5twufoATXkjOkjqqAHLYAzxXq3xLikl0uzKAkCYg49SvFe +YR2htbqKJyN3JODnNc837zO6l/DSNOLeijyuy7cEZzVG50jUbsmWKTamTny1GRzV +4TAPtUZ+la2nyJbBWmZogScBhgfnWN7G9jmrfR7/AM7ZJdq8GDw8Suf6VRtXubfU +FjMZR8jATjP0r0jfbMM7ULHvgVyl3BFPreICruTglTwvPr60+buKK1NeKe5S3W5l +iaNmHBTgKfU//WpJ/E13bYVJxM+MnEYyK25LKNtPtkPCK4U/TNYF94IinuWfcUVj +uDxnBBpITa7GppvitLnalxZzRseN6pkE/TtUviOVbmC0jhdSGk+b26VlGz1PSpkE +Vz9sthgGN/vr7hq6PT7Qajq9os4ZI0BfYB1AOcH/AD3rSOrsYzVlc6bQrZrXR4Ed +drldzD3P+RWjRRXUcQUUUUAFFFFAGN4r06bU9Blhtl3TIQ6qOrY7D8K8fvraW31J +VmR0ZQPlYYI/Cvea8q+IVi0PiFrgnImjBUY/P+VZTj1OijP7JyP2n/SMnPB9eldX +pV/5kIRsbfQ9K4yTMbhmyMnvUg1FoGYyI4THAXoPT+dYONztckkb2v69ZwSJa29q +gLf6ybYPlHt7+9Q6JdWA1NWgYBMdBXOzTf2id0aFg3anW+l3Fkv2tmcL1A/wo5VY +Sl9x6+ghnswgcEOOcdvemWs7zQHgSMjFGK+oNcZpd/Kl5Ct1JMIVAOA+M/WtGzu1 +0nXHWObdbXZ8xCT3PVTSuRyHTymN1QeUSwYcba1dHt1W5Z2xvVOg9z/9YVmC583G +OM9BWtoTectzN/CZNi+4H/661p2uc9S6ia1FFFdBzBRRRQAUUVi6x4v0HQwft2ox +K4/5ZodzfkOn40AbVcX8SrHdo6akg+e2ba2P7p/+v/OsDVvjhYws0elaZLO3Z5m2 +g/gM/wA6525+I+t+IQ+n3ywQ290rDy0jwQMZHJOetS9jSKdzm7i+USAlhkZ56Dr1 +rd0vy5o9r4cuvzcg54rjLzNvcFMY55xW3od8FKx4GR8zMemazlG6N4zfMap02KC6 +bEcTJ6Nx+tbumPYyRrb/AL+Jc/dBEig+wYcU20FtqSguuMcZ7mtCx8PrDMZGkJVG +yB/Kuf1Oly7Ej6XcyebgQ3IZTtdl2OD26cViw2lxeSrayYTyzklTnbg9veun1LUU +021IDb5Dwi+vvXOaVfIJZJN4LF8YHuadmTzHTqZEt/3eTIFwg7lu1dnpdn9g06K3 +7gZb6nrXn0mvWujeVqOoI8ltG6/LHyS3b/Gu20TxRo3iCMNp16kj4yYm+Vx/wE10 +U1ZHJWd3oa9FFFamAUUUUAeF+KPijqurI0Fq32K3PaJvmP1avPbi5kuZCWJOTyfW +mzOzNinwxBRuPXtSNCe3hSIBiMv/ACp1vcbdThkbp5gz9KYzEL9agcE7vXND1Hex +s6raecSVA3jkZ71nWdy1qWjkG3sQRWlBdi8tQ+cuvyuPcVFMsc3yyrz2P/16yi2t +GdE4p+8jWsfEMNsU3H7vf+92rdt/FyiI4Zcnt6GvPmsyv3HB46k4zUiQTRKF3gAH +Od3ehwi9SVOSVrHT6nrjzSYMgJUjknOKgsZnS4MrMVRerY/zk1mafAly2W3SAclg +NoNWPNaW+kUDbFF8qovQHufr/hVqFkTzXNG+v3v5T5oxGq4WM9AKxlMlheCS1leN +kO5CrYI59a0XOPvAfX1rN1OPPIB5TB+lUSekeF/ipNEqWutKbhBwJ1Hzj6jv/nrX +pWnaxp2rRCSxu4pwRnCtyPqOor5ht5G3Dca2bW+mtXEkEzxsDkMuQaCeVM+kqK8W +sPiPr1rB5bXImx0MqbiPxoouTyM80jh8xyxHyg1KVx1qxEEeNfK5FI6euKZViq5I +FJDGZA+Occ0sik9BVaYMqZUkFecjjFIksQtJZT7+iEjcPSt63W1mUNIRjFc9ZXhu +D5FwQSwwre/oa3raW3+xlGwWPr1FRUj1RtSl0GmW1jdlWCNz2Y/40yCBNQZijq0a +NtKp/X/P51nXk4RJdqYBPJJHJq74a2x6XM4I3NJyM46f5NaQgkyZVG9DRv7hNPsW +8pQP4VA7k/8A66g06Hy7dcnJbkk9yetU9TZpr+KHnKfO2fXoK0LYqYh1x6ZqpPUm +JKy45z+XaqV8AUQ89x06VeccHA6896rXSbrZj3Ug1JRjYKsQfXrVxX+Xg+4qCVQQ +D0NOhJYcdTSEtGWVkIyFU/gtFJGEywbA568c0UFmUomil/dAtk9B3q/nzBjHTqKW +BVjIPU45NMPDn3pkLQY6jBwRxTIoxJIE7HjmpW4/OmQcXC+maBdTG2FHdckFDxWp +p7yyyu+eMcD/AGj3qpdLsvpAMdTWxpkQjsVfpn5j+NVFXZCIL6N5YhG5GeWA6laT +w/c+TJLYy4Al5TI/iHb8v5VYlwblAW6qMZ9c1mztgSleCzAKR26c1T0dwL1sDNPN +Oed7HafYcCr8MnlSAZwrdSfWobSLZCij0xRLlXHHDVBojSLZGSTz29KYFDK6nncM +VHbTCSMqx+739RUJvWz+5A4/jbp+VIZSnGFOAOKbC3zZzjr0pbjvnkk9qihyZAB3 +4oFfU0IEO05BH9f0oq1hIkXIySKKBn//2YhGBBARAgAGBQI8ZiQyAAoJEMdGNjmy +13leJSIAoIx0Ql/m4Gf4ZZeFQ1Of+zq6499DAKCHBzmIEtE740kuUl5HGNvCJ4Qb +MIhGBBARAgAGBQI8ZiXuAAoJEGPLaR3669X8OzwAoKHGtOZfI1nc4NEGzRLorYzu +HN2YAKC6koYnTdhlsiEOJxiaUxTGi+Vv4rkDDQQ6VOgnEAwAzB13VyQ4SuLE8OiO +E2eXTpITYfbb6yUOF/32mPfIfHmwch04dfv2wXPEgxEmK0Ngw+Po1gr9oSgmC66p +rrNlD6IAUwGgfNaroxIe+g8qzh90hE/K8xfzpEDp19J3tkItAjbBJstoXp18mAkK +jX4t7eRdefXUkk+bGI78KqdLfDL2Qle3CH8IF3KiutapQvMF6PlTETlPtvFuuUs4 +INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2Uk89PY3b +zpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVyOtQa8L9G +AFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsYjY67 +VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM +2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpTDJvAAICDACNUV4K2PS6 +h574Z3NaBsIQe5jkVO48MSohjC6s29CjPhlU79cQIYWmBpuNfwroZ6zltyz6Y2Fm +65V0IfvVicR7zvFFCOhahMuk1cr+Qp936OMEq9sLZGxTjClgwrHGS7YpMSZrEC7b +pOmERjo4F/n5YmCHJCH8QzCOc9+80gjVEsHiJVABrC8yykjKL5x1V/PSArE4QtML +bkBPGmQYOw8bx6jCHoO43QjUzbqRfBMHZqWVJyoIIZCp+n13XM4+NO/cDVsZ8bjc +h0LIOyMrT85n24yfXRlP0s7BFjLm59Jjhf4djuJWikJawWETlypAy86OYRRuwCbI +yNauBeTKy+avZvF2oLvpwH4UnudpC06/O0jkj2lQpn9EEUw11RwO6sq9zYTwAUyK +erN00cbCfyiZl01CIo0btcTO6hQK3c67PaloJ9lVH8/mH7LuqkMLDH5ugkpzmed/ +8SorfqVkakne6b4mRySFCBXaVZoKmDHzcH2oSSMhM9exyh6dzi1bGu6ITAQYEQIA +DAUCOlToJwUbDAAAAAAKCRDHRjY5std5XuVtAKD4358jdvOoX358HnQnmwUdUczu +FgCfT70B8OXmdyevgPtF4wOVighnBFGZAaIENaIeHhEEAP6XSuDmn2tbgzewq+Z7 +LOGzaYPGFEoNNVVSdPCkwhHaQgD2lPjc2j9yg9qMO+FlNoMz+9LPbkhkNlYnuAS7 +zpGmgR22v94rwa4NyCxa8Wzn5ikIPBYbZ3Hf0wTsM35JG8QTXFSbgT0bY2d3ZQ20 +uCDzbCCL9krgiH0JgPKjRr1rAKCKyfdG9n8xEQmZCrX5KMmAPH5zawQA4SfEZiKy +ogpw5N085NOJ7ujvH6d6ba5pzu45brw37BFbGEY8jGw5254whrtT3haD9h2fh/Za +eAmkG8o1odiZbyPVDnO9ldekhZFdK/JNHrjUFx4Yc11iJH8+IMEmwZDdpzufunCF +Xip7HchWJEMlbPkPOvzzH46O7rcq3Fi6tQgEAKLt3WtSUeviiTuIFGVYdhdTaGlQ +hDwL5Q4TVddP4cHuZktJE41CdYzJeepsABb4RRRfbGlvngJ68CDh46KW3R6zwZky +ZTpzTB1SycxZao4ocEUWUMi/Ijbtpn2q5/TK9vLreQUJqdApzRCeoZdArO5dsWoF +hbZRCtiCNeOLyt3xtCdXZXJuZXIgS29jaCAoZ251cGcgc2lnKSA8ZGQ5am5AZ251 +Lm9yZz6IXQQTEQIAHQUCNlWgpgUJCG0MiAMLBAMFFQMCBgEDFgIBAheAAAoJEGi3 +q4lXVI3NLj4AoId15gcyYpBX2YLtEQTlXPp3mtEGAJ9UxzJE/t3EHCHK2bAIOkBw +IW8ItIkBXwMFEDWiHkMDbxG4/z6qCxADYzIFHR6I9Si9gzPQNRcFs2znrTp5pV5M +k6f1aqRgZxL3E4qUZ3xePQhwAo3fSy3kCwLmFGqvzautSMHn8K5V1u+T5CSHqLFY +Kqj5FGtuB/xwoKDXH6UOP0+l5IP8H1RTjme3Fhqahec+zPG3NT57vc2Ru2t6PmuA +wry2BMuSFMBs7wzXkyC3DbI54MV+IKPjHMORivK8uI8jmna9hdNVyBifCk1GcxkH +BSCFvU8xJePsA/Q//zCelvrnrIiMfY4CQTmKzke9MSzbAZQIRddgrGAsiX1tE8Z3 +YMd8lDpuujHLVEdWZo6s54OJuynHrtFFObdapu0uIrT+dEXSASMUbEuNCLL3aCnr +EtGJCwxB2TPQvCCvR2BKzol6MGWxA+nmddeQib2r+GXoKXLdnHcpsAjA7lkXk3IF +yJ7MLFK6uDrjGbGJs2FKSduUjS/Ib4hGBBARAgAGBQI1oic8AAoJEGx+4bhiHMAT +ftYAn1fOaKDUOt+dS38rB+CJ2Q+iElWJAKDRPpp8q5GylbM8DPlMpClWN3TYqYhG +BBARAgAGBQI27U5sAAoJEF3iSZZbA1iiarYAn35qU3ZOlVECELE/3V6q98Q30eAa +AKCtO+lacH0Qq1E6v4BP/9y6MoLIhohGBBARAgAGBQI5TM2WAAoJEAJx6COq/B+4 +jTYAnjOMlKc5tuqspHgAUgAVmBda5XNGAKCIqZ3Fu33suLyRABGZ+tN3tJ1QZ4hG +BBARAgAGBQI1pysWAAoJEAQ1xdJF3KZpeMoAmwZEvOS95jEKj/HnbFBDDp5C4dw0 +AJ4nsZgDnGDAG7FCEJI6+LoIIUit44hGBBARAgAGBQI26PrdAAoJEAcDKpaJBMji +EpgAoM3IisrN7XXdhnP9lmx0UJKE7SsFAJwMWIBnGK93ojuWXh9YgDRySZKZqIhG +BBARAgAGBQI7JUB0AAoJEB3TgN9DaBQASVsAn28snlWv8ljqxPsS2e7xqJxzND3G +AKCsObLMGdGyED2YKlu0sSa4E7cE+4hGBBARAgAGBQI6xKZNAAoJECAsPjFYbhLl +DsgAn0tfgJSaxWUd5s0ZGmKob7b84onEAKC15V+DRTrE1tArKxy/itSNiMtQG4hG +BDARAgAGBQI4no7wAAoJECShvswraT6/w8oAn0XLPn0F4s9wQ4pGXNPCm7MJ6E5z +AJ9CbanRlaKAXoD1LP5bmADGkRBqfYhGBBARAgAGBQI4vt9pAAoJEC5ArMtkcKsm +HDkAoL3TIizomIuEKO6vwHMFcFndsaAaAKCJAkq+I2mjYimFE7ajlaL0jyecGohM +BBARAgAMBQI6IYGCBQMD7eiAAAoJEDJKcxqmfO/9aXgAoOumahVFuBTuZsv5ma2x +G3dVPZczAKC1viEIhAakthEb+Pi0SRyeK7cqqYhGBBARAgAGBQI5zA88AAoJEDLD +W4BHupNX9vwAn1ZRUYyIWV5XoRUIq7Epz1id+hDVAKDMZSo15h9vfGAjrytpxOs5 +clW+G4hGBBARAgAGBQI5bedgAAoJEDLGkzuo7SAfxjMAn2I7CSRyEz8mkaD3emaM +1WYxvbb5AKCFOlNjoxNmu3SSWfgrW1EESYPQY4hGBBARAgAGBQI4q/0WAAoJEDW6 +YX9GCEVakzQAmgNaF00/D/eOgHmtLEjE0IH1H2yUAJ9EKs47I9s8U7IYJOGoQRy7 +LD1JRYhGBBARAgAGBQI7ScU3AAoJEDeckqFodBLoiG0AoItVFw4742i3VVL75rHp +S/iRTyXXAJ46OJxgMvJ9knQ0l4so5JiBotS/8IkAdQMFMDifLTk7IqtjPG8o8QEB +gOEDAJEaFnJ11GJlMpSIkxT4kU1DpXJGc+w5vhX8xjqjTlkbCS1AeryM2FGz/wPK +DjHtG97Ybptmeigrx5ZZ9O/wp96sTYpKiKk93YRyzPOtJ4GhahMR48LBu6YnHppJ +nxCyg4hGBBARAgAGBQI4XUq+AAoJEEPM0G/dqdt2qekAoN1HvYZQ6AxvNVLx3M06 +s/ytk21NAKDNn0RgGyCBiyQeLuV3Gkuqxke7kIhGBBARAgAGBQI5Zs0MAAoJEEcW +KRmClXtmuPEAoJe7siEXNYVflP+Glf71M2xvkSa3AKCerd0dwvhmi4Ao4ujBnuZI +4YUIhIkBFQMFEDfZA2RNwxExOP7mwwEByhEH/2zbTPiXuaff02Xj7QqSIwjo0O47 +sgxNHbuUMJB7pvD0q8g/T+jX0ux6Ci16m42aOUjp254G33RN679BdjiHG47DOric +TvdLq9uWtqg+irQosJen+e0pIsFTfmj1zA1G8rrbADqVCEz4SpibDLB5wXDhVdqa +R3sAteIAZti1xoTiFc12KrarkLn+BaWUtvBbi93bsD+ySTE/kIeeCGLW9IEHok8d +id1QMWXNM2VuzSdKSoxaiuJOkuZ2Aui0HAdEycY5fhOqIo4B/rtxGpdBXBBCxNi+ +VRaq0CWn13BiII2BvNOmCn879R89qMxuj10X3RnRQIHgj4mg/X7zni684FOIRgQQ +EQIABgUCOQ0ojwAKCRBS/u9nIH5xmceVAJ9VIlMfbC6Gni3jLXZs7VEX5NWQCQCg +id47hulygTIy5ePkpgjOO1ZDP/aIRgQQEQIABgUCO1X9UgAKCRBW05T8JNULxIz6 +AJ9tUSb17Etq+1C6V7YiiHCt//vY2ACgt6hl1q6z2ZhSgJLBV6N6wss0GWGIRgQQ +EQIABgUCOJj9UAAKCRBl3EK31OWAJovMAJ4oWYv+ThvQp8zMdVCnbQQL77eLdgCf +ZV/ownqDt0xfEMpHTF0hSHQxy96IRgQQEQIABgUCOpP0TgAKCRBpwYMr+Tra7NWk +AKDQEafW/9gKnUNFINJqEkYUXsYlLgCZAcGWOePrrM7PEOz/h03kqllYt86IRgQQ +EQIABgUCOFjPGgAKCRBxLQsX0D2KT22cAJ0a+519NvXqtRND7/RcEK4LN2bvpwCe +LNuUSotPPf2r7FVap5vO3oAMwdmIRgQQEQIABgUCOGDD6AAKCRBxRvDjMHApSKW9 +AJ9R/bMcCRef9myi9B2bC1zuN2qtbACfc+1NHDhmDSK0TaR5Seu2TyV9LceIRgQQ +EQIABgUCOUbNKQAKCRB/4u1e9RQ7Ki5KAJ4r4dNSN7kLq1nOW52+309RiDpn8gCc +DhPygqyVfPUZKOtVwvttHZcysxqIRgQQEQIABgUCOPN6JwAKCRCEP1fXrLWNT4SW +AJ9IRICEmPNdhoYWUc7hP7HOUVhHfgCfUsR4bR9KCTaynBmKvAKA/ciTBh6IRgQQ +EQIABgUCNacrcQAKCRCE5PiUAeWZaBjoAJ41XKqKVxMjGBGXxffEkyprrSj4igCf +cR5sWVtyrVUk0X/yE0jUrP9IApSIRgQQEQIABgUCOnNH4AAKCRCI98SPIjWV9R3S +AJwLoPyJ8dzW1f2ubzYBEkkHN41p9QCeKbvAZQNRcsMKTJCAuhlwFnh7KGqJARUD +BRA21moYjl8DByup3WkBAZ0tB/9v5kOKdh7rwDaPHFLxvG7flsD8XOvMM/LH0uAx +smUebXYwIRWDziZqDmFHpnzTt5LM7nyaPJjggfSCmlLKtx5ZgIgXM9D7WrwPRgcX +g3SHbuKbXTeiSQRP8goMeADlQFd+sX8l40mwKF9klQXR7/02CT+LM5A/KnXM4mqQ +1cjFLiCwhx2G+Rsx4PEDTDoBL3W6ME/pxIzn0NJuhp9oDVvKuWmKtwKPWSHRj8CR +56OBxeZG+sPK3UySM/ZEdEL0iEZvgYRwpf/t8vnS8/Li/M6pem6FnwLalQwv/vMF +FQvBiHJqRJ1VxsdHVDMbap1LO7A2QGghPkeDnAN4jyCsqXVtiEYEEBECAAYFAjt4 +2yAACgkQj8C3jQmzMQbrmgCfeBACKTFlOsTcbhhlvIjZJ9ZUT10An0NHUHnoktA4 +GMdxW5vR+t1uhGcWiEYEEBECAAYFAjbWagEACgkQkrJ6leQEE6q4FwCg2WMRtIdc +wsfnj8ngeK0CyIjXxqYAoOsMufELOYL7yb85M27iZlqZ48/eiEYEEBECAAYFAjnK +lgsACgkQnznd8F4pxsIVuACfc+MHLblJgJcI5Z42D4d5ufs+LsYAoMq1/GdeKCtx +028BGZm1Yc0zO8cwiEYEEBECAAYFAjnPNIIACgkQpll1bT9NtmnSywCfWpns8kIg +d/oStQbXXVzltaMJtbcAoL/cJ/9k1kraYpk6Z8IJGf2wEGVFiEYEEBECAAYFAjqW +fQEACgkQq79czSEmG4giGACg/qNL4huhd12Jyya3qTJeFYFgMm0AoOWNXs1CepYM +GZ1HNhbcJiH+G8/IiEYEEBECAAYFAjoZ9rYACgkQvhpT6zI73uZHuQCeNJfhA/uB +HrHUFhMILz27aBJcBC0An2dF4AKA1T8P5MuqKaUxL1OqdPJkiEYEEBECAAYFAjmS +plwACgkQx+D2lKJNi05V5QCgxOAE1SMP4BhATMhTXNiSJbU2BmEAoNbcbOwM+rOz +ecX6aQyeCBg8WcSeiEYEEBECAAYFAjfZA0MACgkQzTbgIX48jquOOQCgqjyYGNri +U4Zb6aKW4GHcuJNoM0kAoNCupziSR9pBxWVeMNVhVp6XvigmiEYEEBECAAYFAjm0 +32EACgkQ0Y4PDnuqkPpwSQCgubij+epzZINnZ4qvmFgNNR9YGUIAn2Dwom8wzr7/ +W0Q9qiUz+FVYoHHqiEYEEBECAAYFAjgmg+4ACgkQ1eiHQ5R2ErMIAwCdF+TWZ/T7 +KJR0y5IQ2EoxfLKxnawAoK8xJ0QSYaiZYKCxB8tYzMItHv7liEYEEBECAAYFAjfX +jLIACgkQ1rb6S4yOnyPYrACgr35M5uneN/5PCc9Uh9caSYdJtwwAoOjzOz6KwrKd +c4wXaDnRJNnBpZMdiEYEEBECAAYFAjpCNWEACgkQ30kDp8mywsCuGACgw405ZqhW +MrgNewU0gPllz+S9V68AoLer9gdEcr3aHhxZxmZpjsRy4w/tiEYEEBECAAYFAjrO +IywACgkQ4HkONspwutzZoQCdHVZOvgnh2kW4229FOwRdtVybZGUAoOhlsIEL0j5W +4YJCGQrhd7vxuo0viEYEEBECAAYFAjnzJCIACgkQ5jU8OLhSiwGGrwCg304/n0hg +n41Bgmal2jI8WAmK098Ani2W7uoOHSWlBQEkoisKMbSh3jIhiEYEEBECAAYFAjqQ +EYkACgkQ86QzvnxWxe/4rwCfSXD8N6MhMzfKqZ6b6X/kag/dS/QAn2QM9U4dCrUl +8kOTdZbP+NC+Hcx0iEYEEBECAAYFAjnND5cACgkQ93111w6M5IHPxgCfZrmMKTTn +ZT5+uv6wVFDUyoqavEoAn0nvU51E1kt5+QPuKEnZiZyjwayniEYEEBECAAYFAjqe +VPUACgkQ+qVJWkKzL8lzvACfXa4hgEv1Z+GZLZKHQ76Yg7aPnzQAn2cm8G7PirTu +WSANQVUlCWu4PUh8 +=9VIS +-----END PGP PUBLIC KEY BLOCK----- diff --git a/doc/version.sgml.in b/doc/version.sgml.in deleted file mode 100644 index d78bda934..000000000 --- a/doc/version.sgml.in +++ /dev/null @@ -1 +0,0 @@ -@VERSION@ diff --git a/include/ChangeLog b/include/ChangeLog index 91515d4a1..464e339c7 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,48 +1,171 @@ -Fri Aug 18 14:27:14 CEST 2000 Werner Koch +2002-06-21 Stefan Bellon - * gpga-prot.h: New. + * util.h [__riscos__]: Further moving away of RISC OS specific + stuff from general code. -Fri Jul 14 19:38:23 CEST 2000 Werner Koch +2002-06-20 Stefan Bellon - * http.h (HTTP_FLAG_TRY_PROXY): new. + * util.h [__riscos__]: Added riscos_set_filetype(). - * error.h (G10ERR_NOT_PROCESSED): New. +2002-06-14 David Shaw - * iobuf.h (IOBUFCTRL_CANCEL): New. + * util.h: Add pop_strlist() from strgutil.c. - * types.h (HAVE_U64_TYPEDEF): Defined depending on configure test. +2002-06-07 Stefan Bellon -Thu Jan 27 18:00:44 CET 2000 Werner Koch + * util.h [__riscos__]: RISC OS needs strings.h for strcasecmp() + and strncasecmp(). - * Changed all "g10_"/"GPG_" prefixes to "gpg_"/"GPG_". +2002-05-22 Werner Koch -Mon Jan 24 13:04:28 CET 2000 Werner Koch + * util.h: Add strncasecmp. Removed stricmp and memicmp. - * memory.h: Removed. +2002-05-10 Stefan Bellon -Wed Dec 8 21:58:32 CET 1999 Werner Koch + * mpi.h: New function mpi_debug_alloc_like for M_DEBUG. - * util.h: Moved argparse stuff to the argparse header. Move some - of the string stuff to the stringhelp header. + * util.h [__riscos__]: Make use of __func__ that later + Norcroft compiler provides. - * mpi.h: Moved to ../gcrypt - * cipher.h: Moved to ../gcrypt - * g10lib.h: Moved to ../gcrypt + * memory.h: Fixed wrong definition of m_alloc_secure_clear. -Tue Oct 26 14:10:21 CEST 1999 Werner Koch +2002-04-23 David Shaw - * g10lib.h: Moved from ../gcrypt to here. + * util.h: New function answer_is_yes_no_default() to give a + default answer. + +2002-04-22 Stefan Bellon + + * util.h [__riscos__]: Removed riscos_open, riscos_fopen and + riscos_fstat as those special versions aren't needed anymore. + +2002-02-19 David Shaw + + * keyserver.h: Add KEYSERVER_NOT_SUPPORTED for unsupported actions + (say, a keyserver that has no way to search, or a readonly + keyserver that has no way to add). + +2002-01-02 Stefan Bellon + + * util.h [__riscos__]: Updated prototype list. + + * types.h [__riscos__]: Changed comment wording. + +2001-12-27 David Shaw + + * KEYSERVER_SCHEME_NOT_FOUND should be 127 to match the POSIX + system() (via /bin/sh) way of signaling this. + + * Added G10ERR_KEYSERVER + +2001-12-27 Werner Koch + + * util.h [MINGW32]: Fixed name of include file. + +2001-12-22 Timo Schulz + + * util.h (is_file_compressed): New. + +2001-12-19 Werner Koch + + * util.h [CYGWIN32]: Allow this as an alias for MINGW32. Include + stdarg.h becuase we use the va_list type. By Disastry. + +2001-09-28 Werner Koch + + * cipher.h (PUBKEY_USAGE_CERT): New. + +2001-09-07 Werner Koch + + * util.h: Add strsep(). + +2001-08-30 Werner Koch + + * cipher.h (DEK): Added use_mdc. + +2001-08-24 Werner Koch + + * cipher.h (md_write): Made buf arg const. + +2001-08-20 Werner Koch + + * cipher.h (DEK): Added algo_info_printed; + + * util.h [__riscos__]: Added prototypes and made sure that we + never use __attribute__. + * cipher.h, iobuf.h, memory.h, mpi.h [__riscos__]: extern hack. + * i18n.h [__riscos__]: Use another include file + +2001-05-30 Werner Koch + + * ttyio.h (tty_printf): Add missing parenthesis for non gcc. + * http.h: Removed trailing comma to make old ccs happy. Both are + by Albert Chin. + +2001-05-25 Werner Koch + + * ttyio.h (tty_printf): Add printf attribute. + +2001-04-23 Werner Koch + + * http.h: New flag HTTP_FLAG_NO_SHUTDOWN. + +2001-04-13 Werner Koch + + * iobuf.h: Removed iobuf_fopen. + +2001-03-01 Werner Koch + + * errors.h (G10ERR_UNU_SECKEY,G10ERR_UNU_PUBKEY): New + +2000-11-30 Werner Koch + + * iobuf.h (iobuf_translate_file_handle): Add prototype. + +2000-11-11 Paul Eggert + + * iobuf.h (iobuf_get_filelength): Now returns off_t, not u32. + (struct iobuf_struct, iobuf_set_limit, + iobuf_tell, iobuf_seek): Use off_t, not ulong, for file offsets. + +2000-10-12 Werner Koch + + * mpi.h: Changed the way mpi_limb_t is defined. + +Wed Sep 6 17:55:47 CEST 2000 Werner Koch + + * iobuf.c (IOBUF_FILELENGTH_LIMIT): New. + +2000-03-14 14:03:43 Werner Koch (wk@habibti.openit.de) + + * types.h (HAVE_U64_TYPEDEF): Defined depending on configure test. + +Thu Jan 13 19:31:58 CET 2000 Werner Koch + + * types.h (HAVE_U64_TYPEDEF): Add a test for _LONGLONG which fixes + this long living SGI bug. Reported by Alec Habig. + +Sat Dec 4 12:30:28 CET 1999 Werner Koch + + * iobuf.h (IOBUFCTRL_CANCEL): Nww. + +Mon Oct 4 21:23:04 CEST 1999 Werner Koch + + * errors.h (G10ERR_NOT_PROCESSED): New. Wed Sep 15 16:22:17 CEST 1999 Werner Koch + * i18n.h: Add support for simple-gettext. Tue Jun 29 21:44:25 CEST 1999 Werner Koch + * util.h (stricmp): Use strcasecmp as replacement. Sat Jun 26 12:15:59 CEST 1999 Werner Koch + * cipher.h (MD_HANDLE): Assigned a structure name. Fri Apr 9 12:26:25 CEST 1999 Werner Koch @@ -53,6 +176,7 @@ Tue Apr 6 19:58:12 CEST 1999 Werner Koch * cipher.h (DEK): increased max. key length to 32 bytes + Sat Feb 20 21:40:49 CET 1999 Werner Koch * g10lib.h: Removed file and changed all files that includes this. @@ -137,3 +261,15 @@ Tue Mar 3 15:11:21 1998 Werner Koch (wk@isil.d.shuttle.de) * cipher.h (random.h): Add new header and move all relevalt functions to this header. + + Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + diff --git a/include/cipher.h b/include/cipher.h new file mode 100644 index 000000000..634569199 --- /dev/null +++ b/include/cipher.h @@ -0,0 +1,194 @@ +/* cipher.h + * Copyright (C) 1998, 1999, 2000, 2001 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_CIPHER_H +#define G10_CIPHER_H + +#define DBG_CIPHER g10c_debug_mode + +#include "mpi.h" +#include "../cipher/random.h" + + +#define CIPHER_ALGO_NONE 0 +#define CIPHER_ALGO_IDEA 1 +#define CIPHER_ALGO_3DES 2 +#define CIPHER_ALGO_CAST5 3 +#define CIPHER_ALGO_BLOWFISH 4 /* blowfish 128 bit key */ +#define CIPHER_ALGO_SAFER_SK128 5 +#define CIPHER_ALGO_DES_SK 6 +#define CIPHER_ALGO_RIJNDAEL 7 +#define CIPHER_ALGO_RIJNDAEL192 8 +#define CIPHER_ALGO_RIJNDAEL256 9 +#define CIPHER_ALGO_TWOFISH 10 /* twofish 256 bit */ +#define CIPHER_ALGO_SKIPJACK 101 /* experimental: skipjack */ +#define CIPHER_ALGO_TWOFISH_OLD 102 /* experimental: twofish 128 bit */ +#define CIPHER_ALGO_DUMMY 110 /* no encryption at all */ + +#define PUBKEY_ALGO_RSA 1 +#define PUBKEY_ALGO_RSA_E 2 /* RSA encrypt only */ +#define PUBKEY_ALGO_RSA_S 3 /* RSA sign only */ +#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/ +#define PUBKEY_ALGO_DSA 17 +#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */ + +#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */ +#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */ +#define PUBKEY_USAGE_CERT 4 /* key is also good to certify other keys*/ + +#define DIGEST_ALGO_MD5 1 +#define DIGEST_ALGO_SHA1 2 +#define DIGEST_ALGO_RMD160 3 +#define DIGEST_ALGO_TIGER 6 + +#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \ + || (a)==PUBKEY_ALGO_RSA_S ) +#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E) + +typedef struct { + int algo; + int keylen; + int algo_info_printed; + int use_mdc; + byte key[32]; /* this is the largest used keylen (256 bit) */ +} DEK; + +struct cipher_handle_s; +typedef struct cipher_handle_s *CIPHER_HANDLE; + + +#define CIPHER_MODE_ECB 1 +#define CIPHER_MODE_CFB 2 +#define CIPHER_MODE_PHILS_CFB 3 +#define CIPHER_MODE_AUTO_CFB 4 +#define CIPHER_MODE_DUMMY 5 /* used with algo DUMMY for no encryption */ +#define CIPHER_MODE_CBC 6 + +struct md_digest_list_s; + +struct gcry_md_context { + int secure; + FILE *debug; + int finalized; + struct md_digest_list_s *list; + int bufcount; + int bufsize; + byte buffer[1]; +}; + +typedef struct gcry_md_context *MD_HANDLE; + +#ifndef EXTERN_UNLESS_MAIN_MODULE + #if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE) + #define EXTERN_UNLESS_MAIN_MODULE extern + #else + #define EXTERN_UNLESS_MAIN_MODULE + #endif +#endif +EXTERN_UNLESS_MAIN_MODULE int g10c_debug_mode; +EXTERN_UNLESS_MAIN_MODULE int g10_opt_verbose; +EXTERN_UNLESS_MAIN_MODULE const char *g10_opt_homedir; + + +/*-- dynload.c --*/ +void register_cipher_extension( const char *mainpgm, const char *fname ); + +/*-- md.c --*/ +int string_to_digest_algo( const char *string ); +const char * digest_algo_to_string( int algo ); +int check_digest_algo( int algo ); +MD_HANDLE md_open( int algo, int secure ); +void md_enable( MD_HANDLE hd, int algo ); +MD_HANDLE md_copy( MD_HANDLE a ); +void md_reset( MD_HANDLE a ); +void md_close(MD_HANDLE a); +void md_write( MD_HANDLE a, const byte *inbuf, size_t inlen); +void md_final(MD_HANDLE a); +byte *md_read( MD_HANDLE a, int algo ); +int md_digest( MD_HANDLE a, int algo, byte *buffer, int buflen ); +int md_get_algo( MD_HANDLE a ); +int md_digest_length( int algo ); +const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); +void md_start_debug( MD_HANDLE a, const char *suffix ); +void md_stop_debug( MD_HANDLE a ); +#define md_is_secure(a) ((a)->secure) +#define md_putc(h,c) \ + do { \ + if( (h)->bufcount == (h)->bufsize ) \ + md_write( (h), NULL, 0 ); \ + (h)->buffer[(h)->bufcount++] = (c) & 0xff; \ + } while(0) +/*-- rmd160.c --*/ +void rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length ); + + +/*-- cipher.c --*/ +int string_to_cipher_algo( const char *string ); +const char * cipher_algo_to_string( int algo ); +void disable_cipher_algo( int algo ); +int check_cipher_algo( int algo ); +unsigned cipher_get_keylen( int algo ); +unsigned cipher_get_blocksize( int algo ); +CIPHER_HANDLE cipher_open( int algo, int mode, int secure ); +void cipher_close( CIPHER_HANDLE c ); +int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ); +void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ); +void cipher_encrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes ); +void cipher_decrypt( CIPHER_HANDLE c, byte *out, byte *in, unsigned nbytes ); +void cipher_sync( CIPHER_HANDLE c ); + +/*-- pubkey.c --*/ +#define PUBKEY_MAX_NPKEY 4 +#define PUBKEY_MAX_NSKEY 6 +#define PUBKEY_MAX_NSIG 2 +#define PUBKEY_MAX_NENC 2 + +int string_to_pubkey_algo( const char *string ); +const char * pubkey_algo_to_string( int algo ); +void disable_pubkey_algo( int algo ); +int check_pubkey_algo( int algo ); +int check_pubkey_algo2( int algo, unsigned use ); +int pubkey_get_npkey( int algo ); +int pubkey_get_nskey( int algo ); +int pubkey_get_nsig( int algo ); +int pubkey_get_nenc( int algo ); +unsigned pubkey_nbits( int algo, MPI *pkey ); +int pubkey_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors ); +int pubkey_check_secret_key( int algo, MPI *skey ); +int pubkey_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ); +int pubkey_decrypt( int algo, MPI *result, MPI *data, MPI *skey ); +int pubkey_sign( int algo, MPI *resarr, MPI hash, MPI *skey ); +int pubkey_verify( int algo, MPI hash, MPI *data, MPI *pkey, + int (*cmp)(void *, MPI), void *opaque ); + +/*-- smallprime.c --*/ +extern ushort small_prime_numbers[]; + +/*-- primegen.c --*/ +void register_primegen_progress ( void (*cb)( void *, int), void *cb_data ); +MPI generate_secret_prime( unsigned nbits ); +MPI generate_public_prime( unsigned nbits ); +MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits, + MPI g, MPI **factors ); + +/*-- elsewhere --*/ +void register_pk_dsa_progress ( void (*cb)( void *, int), void *cb_data ); +void register_pk_elg_progress ( void (*cb)( void *, int), void *cb_data ); + +#endif /*G10_CIPHER_H*/ diff --git a/include/distfiles b/include/distfiles index 7e066ad44..fe9c41c7f 100644 --- a/include/distfiles +++ b/include/distfiles @@ -1,11 +1,14 @@ +cipher.h errors.h iobuf.h +memory.h +mpi.h ttyio.h types.h util.h i18n.h host2net.h http.h -gpga-prot.h +keyserver.h ChangeLog diff --git a/include/errors.h b/include/errors.h index 9fbf9320e..0dde0f9b5 100644 --- a/include/errors.h +++ b/include/errors.h @@ -1,5 +1,5 @@ -/* errors.h - error codes fro GnuPG - * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc. +/* errors.h - erro code + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -17,67 +17,68 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_ERRORS_H -#define GPG_ERRORS_H +#ifndef G10_ERRORS_H +#define G10_ERRORS_H +#define G10ERR_GENERAL 1 +#define G10ERR_UNKNOWN_PACKET 2 +#define G10ERR_UNKNOWN_VERSION 3 /* Unknown version (in packet) */ +#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */ +#define G10ERR_DIGEST_ALGO 5 /* Unknown digest algorithm */ +#define G10ERR_BAD_PUBKEY 6 /* Bad public key */ +#define G10ERR_BAD_SECKEY 7 /* Bad secret key */ +#define G10ERR_BAD_SIGN 8 /* Bad signature */ +#define G10ERR_NO_PUBKEY 9 /* public key not found */ +#define G10ERR_CHECKSUM 10 /* checksum error */ +#define G10ERR_BAD_PASS 11 /* Bad passphrase */ +#define G10ERR_CIPHER_ALGO 12 /* Unknown cipher algorithm */ +#define G10ERR_KEYRING_OPEN 13 +#define G10ERR_INVALID_PACKET 14 +#define G10ERR_INVALID_ARMOR 15 +#define G10ERR_NO_USER_ID 16 +#define G10ERR_NO_SECKEY 17 /* secret key not available */ +#define G10ERR_WRONG_SECKEY 18 /* wrong seckey used */ +#define G10ERR_UNSUPPORTED 19 +#define G10ERR_BAD_KEY 20 /* bad (session) key */ +#define G10ERR_READ_FILE 21 +#define G10ERR_WRITE_FILE 22 +#define G10ERR_COMPR_ALGO 23 /* Unknown compress algorithm */ +#define G10ERR_OPEN_FILE 24 +#define G10ERR_CREATE_FILE 25 +#define G10ERR_PASSPHRASE 26 /* invalid passphrase */ +#define G10ERR_NI_PUBKEY 27 +#define G10ERR_NI_CIPHER 28 +#define G10ERR_SIG_CLASS 29 +#define G10ERR_BAD_MPI 30 +#define G10ERR_RESOURCE_LIMIT 31 +#define G10ERR_INV_KEYRING 32 +#define G10ERR_TRUSTDB 33 /* a problem with the trustdb */ +#define G10ERR_BAD_CERT 34 /* bad certicate */ +#define G10ERR_INV_USER_ID 35 +#define G10ERR_CLOSE_FILE 36 +#define G10ERR_RENAME_FILE 37 +#define G10ERR_DELETE_FILE 38 +#define G10ERR_UNEXPECTED 39 +#define G10ERR_TIME_CONFLICT 40 +#define G10ERR_WR_PUBKEY_ALGO 41 /* unusabe pubkey algo */ +#define G10ERR_FILE_EXISTS 42 +#define G10ERR_WEAK_KEY 43 /* NOTE: hardcoded into the cipher modules */ +#define G10ERR_WRONG_KEYLEN 44 /* NOTE: hardcoded into the cipher modules */ +#define G10ERR_INV_ARG 45 +#define G10ERR_BAD_URI 46 /* syntax error in URI */ +#define G10ERR_INVALID_URI 47 /* e.g. unsupported scheme */ +#define G10ERR_NETWORK 48 /* general network error */ +#define G10ERR_UNKNOWN_HOST 49 +#define G10ERR_SELFTEST_FAILED 50 +#define G10ERR_NOT_ENCRYPTED 51 +#define G10ERR_NOT_PROCESSED 52 +#define G10ERR_UNU_PUBKEY 53 +#define G10ERR_UNU_SECKEY 54 +#define G10ERR_KEYSERVER 55 -/* FIXME: some constants have to be the same as the ones from - * libgcrypt - include gcrypt.h and use those constants */ -#define GPGERR_GENERAL 101 -#define GPGERR_UNKNOWN_PACKET 102 -#define GPGERR_UNKNOWN_VERSION 103 /* Unknown version (in packet) */ -#define GPGERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */ -#define GPGERR_DIGEST_ALGO 5 /* Unknown digest algorithm */ -#define GPGERR_BAD_PUBKEY 6 /* Bad public key */ -#define GPGERR_BAD_SECKEY 7 /* Bad secret key */ -#define GPGERR_BAD_SIGN 8 /* Bad signature */ -#define GPGERR_NO_PUBKEY 109 /* public key not found */ -#define GPGERR_CHECKSUM 110 /* checksum error */ -#define GPGERR_BAD_PASS 111 /* Bad passphrase */ -#define GPGERR_CIPHER_ALGO 12 /* Unknown cipher algorithm */ -#define GPGERR_KEYRING_OPEN 113 -#define GPGERR_INVALID_PACKET 114 -#define GPGERR_INVALID_ARMOR 115 -#define GPGERR_NO_USER_ID 116 -#define GPGERR_NO_SECKEY 117 /* secret key not available */ -#define GPGERR_WRONG_SECKEY 118 /* wrong seckey used */ -#define GPGERR_UNSUPPORTED 119 -#define GPGERR_BAD_KEY 120 /* bad (session) key */ -#define GPGERR_READ_FILE 121 -#define GPGERR_WRITE_FILE 122 -#define GPGERR_COMPR_ALGO 123 /* Unknown compress algorithm */ -#define GPGERR_OPEN_FILE 124 -#define GPGERR_CREATE_FILE 125 -#define GPGERR_PASSPHRASE 126 /* invalid passphrase */ -#define GPGERR_NI_PUBKEY 127 -#define GPGERR_NI_CIPHER 128 -#define GPGERR_SIG_CLASS 129 -#define GPGERR_BAD_MPI 30 -#define GPGERR_RESOURCE_LIMIT 131 -#define GPGERR_INV_KEYRING 132 -#define GPGERR_TRUSTDB 133 /* a problem with the trustdb */ -#define GPGERR_BAD_CERT 134 /* bad certicate */ -#define GPGERR_INV_USER_ID 135 -#define GPGERR_CLOSE_FILE 136 -#define GPGERR_RENAME_FILE 137 -#define GPGERR_DELETE_FILE 138 -#define GPGERR_UNEXPECTED 139 -#define GPGERR_TIME_CONFLICT 140 -#define GPGERR_WR_PUBKEY_ALGO 41 /* unusabe pubkey algo */ -#define GPGERR_FILE_EXISTS 142 -#define GPGERR_WEAK_KEY 43 /* NOTE: hardcoded into the cipher modules */ -#define GPGERR_WRONG_KEYLEN 44 /* NOTE: hardcoded into the cipher modules */ -#define GPGERR_INV_ARG 145 -#define GPGERR_BAD_URI 146 /* syntax error in URI */ -#define GPGERR_INVALID_URI 147 /* e.g. unsupported scheme */ -#define GPGERR_NETWORK 148 /* general network error */ -#define GPGERR_UNKNOWN_HOST 149 -#define GPGERR_SELFTEST_FAILED 50 -#define GPGERR_NOT_ENCRYPTED 151 -#define GPGERR_NOT_PROCESSED 152 #ifndef HAVE_STRERROR char *strerror( int n ); #endif -#endif /*GPG_ERRORS_H*/ +#endif /*G10_ERRORS_H*/ diff --git a/include/gpga-prot.h b/include/gpga-prot.h deleted file mode 100644 index 0e408c4b8..000000000 --- a/include/gpga-prot.h +++ /dev/null @@ -1,127 +0,0 @@ -/* gpga-prot.h - GnuPG Agent protocol definition - * 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 - */ - -/* - * The gpg-agent protocol: - * The protocol is connection based and runs over a Unix Domain socket. - * The client requests a service from the server and waits for the result. - * A connection request starts with a magic string to transfer the - * version number the followed by the regular traffic. All numbers - * are transfered in network-byte-order, strings are prefixed with a - * 32 bit length and NOT 0 terminated. - * The magic string is: - * 0x47, 0x50, 0x47, 0x41, 0x00, 0x00, 0x00, 0x01 - * which nicely fits into 2 32 bit words. - * The server does not respond to this magic string if the protocol - is supported; otherwise it will return an error packet and close - the connection. - Standard request and reply packets are composed like this - u32 Length of following packet ( 4 <= n < 2048 ) - u32 Request/Reply type or error code - n-bytes Data specific to the request/reply - - Request codes are just the given number, - Reply codes are all to be ORed with 0x00010000, - Error codes are all to be ORer with 0x00020000. - - Requests: - ========= - GET_VERSION - - GET_PASSPHRASE, expected data: - 20 Bytes fingerprint of the key - (use all zeroes to get a passphrase not associated with a key) - n Bytes with the text to be displayed in case the - passphrase is not cached or the fingerprint was all zero. - - CLEAR_PASSPHRASE, expected data: - 20 Bytes fingerprint of the key - - Returns either OKAY or NO_PASSPHRASE - - HAVE_PASSPHRASE, expected data: - 20 Bytes fingerprint of the key - - Returns either OKAY or NO_PASSPHRASE - - - Replies: - ======== - OKAY (reply code 1) - Data may be interpreted as the version string - - GOT_PASSPHRASE (reply code 2) - u32 Length of passphrase - n bytes passphrase - m bytes padding so that the packets have some standard length - - - Error Replies: - ============== - PROTOCOL_ERROR - no data yes specified - - CANCELED - User canceled the input - - NO_PASSPHRASE - No user intercation possible and passphrase not available. - Also return as answer on HAVE_PASSPHRASE etc. - - BAD_PASSPHRASE - Returned when the user does not repeat the passphrase correctly - - INVALID_DATA - - */ - - - -#ifndef GPG_GPGA_PROT_H -#define GPG_GPGA_PROT_H 1 - -enum gpga_protocol_codes { - /* Request codes */ - GPGA_PROT_GET_VERSION = 1, - GPGA_PROT_GET_PASSPHRASE = 2, - GPGA_PROT_CLEAR_PASSPHRASE= 3, - GPGA_PROT_SHUTDOWN = 4, - GPGA_PROT_FLUSH = 5, - - /* Reply codes */ - GPGA_PROT_REPLY_BASE = 0x10000, - GPGA_PROT_OKAY = 0x10001, - GPGA_PROT_GOT_PASSPHRASE = 0x10002, - - /* Error codes */ - GPGA_PROT_ERROR_BASE = 0x20000, - GPGA_PROT_PROTOCOL_ERROR = 0x20001, - GPGA_PROT_INVALID_REQUEST= 0x20002, - GPGA_PROT_CANCELED = 0x20003, - GPGA_PROT_NO_PASSPHRASE = 0x20004, - GPGA_PROT_BAD_PASSPHRASE = 0x20005, - GPGA_PROT_INVALID_DATA = 0x20006, - GPGA_PROT_NOT_IMPLEMENTED= 0x20007, - GPGA_PROT_UI_PROBLEM = 0x20008, -}; - - - -#endif /*GPG_GPGA_PROT_H*/ diff --git a/include/host2net.h b/include/host2net.h index 784737a0d..0f12a8e1d 100644 --- a/include/host2net.h +++ b/include/host2net.h @@ -1,5 +1,5 @@ /* host2net.h - Some macros - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -18,8 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_HOST2NET_H -#define GPG_HOST2NET_H +#ifndef G10_HOST2NET_H +#define G10_HOST2NET_H #include "types.h" @@ -40,4 +40,4 @@ #define u32tobuf( p, a) ulongtobuf( (p), (a) ) -#endif /*GPG_HOST2NET_H*/ +#endif /*G10_HOST2NET_H*/ diff --git a/include/http.h b/include/http.h index a1d70406f..7e79ed2c1 100644 --- a/include/http.h +++ b/include/http.h @@ -1,5 +1,5 @@ /* http.h - HTTP protocol handler - * Copyright (C) 1999 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -17,8 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_HTTP_H -#define GPG_HTTP_H 1 +#ifndef G10_HTTP_H +#define G10_HTTP_H 1 #include "iobuf.h" @@ -50,7 +50,8 @@ typedef enum { } HTTP_REQ_TYPE; enum { /* put flag values into an enum, so that gdb can display them */ - HTTP_FLAG_TRY_PROXY = 1 + HTTP_FLAG_TRY_PROXY = 1, + HTTP_FLAG_NO_SHUTDOWN = 2 }; struct http_context { @@ -64,7 +65,7 @@ struct http_context { PARSED_URI uri; HTTP_REQ_TYPE req_type; byte *buffer; /* line buffer */ - unsigned int buffer_size; + unsigned buffer_size; unsigned int flags; }; typedef struct http_context *HTTP_HD; @@ -77,4 +78,4 @@ void http_close( HTTP_HD hd ); int http_open_document( HTTP_HD hd, const char *document, unsigned int flags ); -#endif /*GPG_HTTP_H*/ +#endif /*G10_HTTP_H*/ diff --git a/include/i18n.h b/include/i18n.h index db22940a3..0b270687a 100644 --- a/include/i18n.h +++ b/include/i18n.h @@ -1,5 +1,5 @@ /* i18n.h - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -18,8 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_I18N_H -#define GPG_I18N_H +#ifndef G10_I18N_H +#define G10_I18N_H #ifdef USE_SIMPLE_GETTEXT int set_gettext_file( const char *filename ); @@ -34,7 +34,11 @@ #endif #ifdef ENABLE_NLS +#ifndef __riscos__ #include +#else + #include "libgettext.h" +#endif /* __riscos__ */ #define _(a) gettext (a) #ifdef gettext_noop #define N_(a) gettext_noop (a) @@ -47,4 +51,4 @@ #endif #endif /* !USE_SIMPLE_GETTEXT */ -#endif /*GPG_I18N_H*/ +#endif /*G10_I18N_H*/ diff --git a/include/iobuf.h b/include/iobuf.h index 2f35f9af9..f94cf4d28 100644 --- a/include/iobuf.h +++ b/include/iobuf.h @@ -1,5 +1,5 @@ /* iobuf.h - I/O buffer - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -18,8 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_IOBUF_H -#define GPG_IOBUF_H +#ifndef G10_IOBUF_H +#define G10_IOBUF_H #include "types.h" @@ -40,9 +40,9 @@ typedef struct iobuf_struct *IOBUF; /* fixme: we should hide most of this stuff */ struct iobuf_struct { int use; /* 1 input , 2 output, 3 temp */ - unsigned long nlimit; - unsigned long nbytes; /* used together with nlimit */ - unsigned long ntotal; /* total bytes read (position of stream) */ + off_t nlimit; + off_t nbytes; /* used together with nlimit */ + off_t ntotal; /* total bytes read (position of stream) */ int nofast; /* used by the iobuf_get() */ void *directfp; struct { @@ -71,17 +71,26 @@ struct iobuf_struct { } unget; }; -int iobuf_debug_mode; +#ifndef EXTERN_UNLESS_MAIN_MODULE + #if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE) + #define EXTERN_UNLESS_MAIN_MODULE extern + #else + #define EXTERN_UNLESS_MAIN_MODULE + #endif +#endif +EXTERN_UNLESS_MAIN_MODULE int iobuf_debug_mode; +void iobuf_enable_special_filenames ( int yes ); IOBUF iobuf_alloc(int use, size_t bufsize); IOBUF iobuf_temp(void); IOBUF iobuf_temp_with_content( const char *buffer, size_t length ); IOBUF iobuf_open( const char *fname ); IOBUF iobuf_fdopen( int fd, const char *mode ); -IOBUF iobuf_fopen( const char *fname, const char *mode ); +IOBUF iobuf_sockopen( int fd, const char *mode ); IOBUF iobuf_create( const char *fname ); IOBUF iobuf_append( const char *fname ); IOBUF iobuf_openrw( const char *fname ); +int iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval ); int iobuf_close( IOBUF iobuf ); int iobuf_cancel( IOBUF iobuf ); @@ -96,10 +105,10 @@ void iobuf_clear_eof(IOBUF a); #define iobuf_set_error(a) do { (a)->error = 1; } while(0) #define iobuf_error(a) ((a)->error) -void iobuf_set_limit( IOBUF a, unsigned long nlimit ); +void iobuf_set_limit( IOBUF a, off_t nlimit ); -ulong iobuf_tell( IOBUF a ); -int iobuf_seek( IOBUF a, ulong newpos ); +off_t iobuf_tell( IOBUF a ); +int iobuf_seek( IOBUF a, off_t newpos ); int iobuf_readbyte(IOBUF a); int iobuf_read(IOBUF a, byte *buf, unsigned buflen ); @@ -115,7 +124,7 @@ int iobuf_write_temp( IOBUF a, IOBUF temp ); size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen ); void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp ); -u32 iobuf_get_filelength( IOBUF a ); +off_t iobuf_get_filelength( IOBUF a ); #define IOBUF_FILELENGTH_LIMIT 0xffffffff const char *iobuf_get_real_fname( IOBUF a ); const char *iobuf_get_fname( IOBUF a ); @@ -124,6 +133,9 @@ void iobuf_set_block_mode( IOBUF a, size_t n ); void iobuf_set_partial_block_mode( IOBUF a, size_t len ); int iobuf_in_block_mode( IOBUF a ); +int iobuf_translate_file_handle ( int fd, int for_write ); + + /* get a byte form the iobuf; must check for eof prior to this function * this function returns values in the range 0 .. 255 or -1 to indicate EOF * iobuf_get_noeof() does not return -1 to indicate EOF, but masks the @@ -146,4 +158,4 @@ int iobuf_in_block_mode( IOBUF a ); #define iobuf_get_temp_length(a) ( (a)->d.len ) #define iobuf_is_temp(a) ( (a)->use == 3 ) -#endif /*GPG_IOBUF_H*/ +#endif /*G10_IOBUF_H*/ diff --git a/include/keyserver.h b/include/keyserver.h new file mode 100644 index 000000000..017711a76 --- /dev/null +++ b/include/keyserver.h @@ -0,0 +1,31 @@ +/* keyserver.h + * Copyright (C) 2001 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 _KEYSERVER_H_ +#define _KEYSERVER_H_ + +/* Return codes */ +#define KEYSERVER_OK 0 +#define KEYSERVER_INTERNAL_ERROR 1 +#define KEYSERVER_NOT_SUPPORTED 2 +#define KEYSERVER_VERSION_ERROR 3 +#define KEYSERVER_SCHEME_NOT_FOUND 127 + +#endif /* !_KEYSERVER_H_ */ diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 000000000..6a364795b --- /dev/null +++ b/include/memory.h @@ -0,0 +1,95 @@ +/* memory.h - memory allocation + * Copyright (C) 1998, 1999, 2000, 2001 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_MEMORY_H +#define G10_MEMORY_H + +#ifdef M_DEBUG +#ifndef STR + #define STR(v) #v +#endif +#ifndef __riscos__ + #define M_DBGINFO(a) __FUNCTION__ "["__FILE__ ":" STR(a) "]" +#else /* __riscos__ */ + #define M_DBGINFO(a) "["__FILE__ ":" STR(a) "]" +#endif /* __riscos__ */ +#define m_alloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) ) +#define m_alloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) ) +#define m_alloc_secure(n) m_debug_alloc((n), M_DBGINFO(__LINE__) ) +#define m_alloc_secure_clear(n) m_debug_alloc_secure_clear((n), M_DBGINFO(__LINE__) ) +#define m_realloc(n,m) m_debug_realloc((n),(m), M_DBGINFO(__LINE__) ) +#define m_free(n) m_debug_free((n), M_DBGINFO(__LINE__) ) +#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) ) +/*#define m_copy(a) m_debug_copy((a), M_DBGINFO(__LINE__) )*/ +#define m_strdup(a) m_debug_strdup((a), M_DBGINFO(__LINE__) ) + +void *m_debug_alloc( size_t n, const char *info ); +void *m_debug_alloc_clear( size_t n, const char *info ); +void *m_debug_alloc_secure( size_t n, const char *info ); +void *m_debug_alloc_secure_clear( size_t n, const char *info ); +void *m_debug_realloc( void *a, size_t n, const char *info ); +void m_debug_free( void *p, const char *info ); +void m_debug_check( const void *a, const char *info ); +/*void *m_debug_copy( const void *a, const char *info );*/ +char *m_debug_strdup( const char *a, const char *info ); + +#else +void *m_alloc( size_t n ); +void *m_alloc_clear( size_t n ); +void *m_alloc_secure( size_t n ); +void *m_alloc_secure_clear( size_t n ); +void *m_realloc( void *a, size_t n ); +void m_free( void *p ); +void m_check( const void *a ); +/*void *m_copy( const void *a );*/ +char *m_strdup( const char * a); +#endif + +size_t m_size( const void *a ); +void m_print_stats(const char *prefix); + +/*-- secmem.c --*/ +void secmem_init( size_t npool ); +void secmem_term( void ); +void *secmem_malloc( size_t size ); +void *secmem_realloc( void *a, size_t newsize ); +void secmem_free( void *a ); +int m_is_secure( const void *p ); +void secmem_dump_stats(void); +void secmem_set_flags( unsigned flags ); +unsigned secmem_get_flags(void); + + + +#define DBG_MEMORY memory_debug_mode +#define DBG_MEMSTAT memory_stat_debug_mode + +#ifndef EXTERN_UNLESS_MAIN_MODULE + #if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE) + #define EXTERN_UNLESS_MAIN_MODULE extern + #else + #define EXTERN_UNLESS_MAIN_MODULE + #endif +#endif +EXTERN_UNLESS_MAIN_MODULE int memory_debug_mode; +EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode; + + +#endif /*G10_MEMORY_H*/ diff --git a/include/mpi.h b/include/mpi.h new file mode 100644 index 000000000..80d617b1d --- /dev/null +++ b/include/mpi.h @@ -0,0 +1,202 @@ +/* mpi.h - Multi Precision Integers + * Copyright (C) 1994, 1996, 1998, 1999, + * 2000, 2001 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 + * + * Note: This code is heavily based on the GNU MP Library. + * Actually it's the same code with only minor changes in the + * way the data is stored; this is to support the abstraction + * of an optional secure memory allocation which may be used + * to avoid revealing of sensitive data due to paging etc. + * The GNU MP Library itself is published under the LGPL; + * however I decided to publish this code under the plain GPL. + */ + +#ifndef G10_MPI_H +#define G10_MPI_H + +#include +#include +#include "iobuf.h" +#include "types.h" +#include "memory.h" + +#if BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_INT + typedef unsigned int mpi_limb_t; + typedef signed int mpi_limb_signed_t; +#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG + typedef unsigned long int mpi_limb_t; + typedef signed long int mpi_limb_signed_t; +#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_LONG_LONG + typedef unsigned long long int mpi_limb_t; + typedef signed long long int mpi_limb_signed_t; +#elif BYTES_PER_MPI_LIMB == SIZEOF_UNSIGNED_SHORT + typedef unsigned short int mpi_limb_t; + typedef signed short int mpi_limb_signed_t; +#else + #error BYTES_PER_MPI_LIMB does not match any C type +#endif +#define BITS_PER_MPI_LIMB (8*BYTES_PER_MPI_LIMB) + +#ifndef EXTERN_UNLESS_MAIN_MODULE + #if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE) + #define EXTERN_UNLESS_MAIN_MODULE extern + #else + #define EXTERN_UNLESS_MAIN_MODULE + #endif +#endif + +#define DBG_MPI mpi_debug_mode +EXTERN_UNLESS_MAIN_MODULE int mpi_debug_mode; + + +struct gcry_mpi { + int alloced; /* array size (# of allocated limbs) */ + int nlimbs; /* number of valid limbs */ + int nbits; /* the real number of valid bits (info only) */ + int sign; /* indicates a negative number */ + unsigned flags; /* bit 0: array must be allocated in secure memory space */ + /* bit 1: the mpi is encrypted */ + /* bit 2: the limb is a pointer to some m_alloced data */ + mpi_limb_t *d; /* array with the limbs */ +}; + +typedef struct gcry_mpi *MPI; + +#define MPI_NULL NULL + +#define mpi_get_nlimbs(a) ((a)->nlimbs) +#define mpi_get_nbit_info(a) ((a)->nbits) +#define mpi_set_nbit_info(a,b) ((a)->nbits = (b)) +#define mpi_is_neg(a) ((a)->sign) + +/*-- mpiutil.c --*/ + +#ifdef M_DEBUG + #define mpi_alloc(n) mpi_debug_alloc((n), M_DBGINFO( __LINE__ ) ) + #define mpi_alloc_secure(n) mpi_debug_alloc_secure((n), M_DBGINFO( __LINE__ ) ) + #define mpi_alloc_like(n) mpi_debug_alloc_like((n), M_DBGINFO( __LINE__ ) ) + #define mpi_free(a) mpi_debug_free((a), M_DBGINFO(__LINE__) ) + #define mpi_resize(a,b) mpi_debug_resize((a),(b), M_DBGINFO(__LINE__) ) + #define mpi_copy(a) mpi_debug_copy((a), M_DBGINFO(__LINE__) ) + MPI mpi_debug_alloc( unsigned nlimbs, const char *info ); + MPI mpi_debug_alloc_secure( unsigned nlimbs, const char *info ); + MPI mpi_debug_alloc_like( MPI a, const char *info ); + void mpi_debug_free( MPI a, const char *info ); + void mpi_debug_resize( MPI a, unsigned nlimbs, const char *info ); + MPI mpi_debug_copy( MPI a, const char *info ); +#else + MPI mpi_alloc( unsigned nlimbs ); + MPI mpi_alloc_secure( unsigned nlimbs ); + MPI mpi_alloc_like( MPI a ); + void mpi_free( MPI a ); + void mpi_resize( MPI a, unsigned nlimbs ); + MPI mpi_copy( MPI a ); +#endif +#define mpi_is_opaque(a) ((a) && ((a)->flags&4)) +MPI mpi_set_opaque( MPI a, void *p, int len ); +void *mpi_get_opaque( MPI a, int *len ); +#define mpi_is_protected(a) ((a) && ((a)->flags&2)) +#define mpi_set_protect_flag(a) ((a)->flags |= 2) +#define mpi_clear_protect_flag(a) ((a)->flags &= ~2) +#define mpi_is_secure(a) ((a) && ((a)->flags&1)) +void mpi_set_secure( MPI a ); +void mpi_clear( MPI a ); +void mpi_set( MPI w, MPI u); +void mpi_set_ui( MPI w, ulong u); +MPI mpi_alloc_set_ui( unsigned long u); +void mpi_m_check( MPI a ); +void mpi_swap( MPI a, MPI b); + +/*-- mpicoder.c --*/ +int mpi_write( IOBUF out, MPI a ); +#ifdef M_DEBUG + #define mpi_read(a,b,c) mpi_debug_read((a),(b),(c), M_DBGINFO( __LINE__ ) ) + MPI mpi_debug_read(IOBUF inp, unsigned *nread, int secure, const char *info); +#else + MPI mpi_read(IOBUF inp, unsigned *nread, int secure); +#endif +MPI mpi_read_from_buffer(byte *buffer, unsigned *ret_nread, int secure); +int mpi_fromstr(MPI val, const char *str); +int mpi_print( FILE *fp, MPI a, int mode ); +void g10_log_mpidump( const char *text, MPI a ); +u32 mpi_get_keyid( MPI a, u32 *keyid ); +byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign ); +byte *mpi_get_secure_buffer( MPI a, unsigned *nbytes, int *sign ); +void mpi_set_buffer( MPI a, const byte *buffer, unsigned nbytes, int sign ); + +#define log_mpidump g10_log_mpidump + +/*-- mpi-add.c --*/ +void mpi_add_ui(MPI w, MPI u, ulong v ); +void mpi_add(MPI w, MPI u, MPI v); +void mpi_addm(MPI w, MPI u, MPI v, MPI m); +void mpi_sub_ui(MPI w, MPI u, ulong v ); +void mpi_sub( MPI w, MPI u, MPI v); +void mpi_subm( MPI w, MPI u, MPI v, MPI m); + +/*-- mpi-mul.c --*/ +void mpi_mul_ui(MPI w, MPI u, ulong v ); +void mpi_mul_2exp( MPI w, MPI u, ulong cnt); +void mpi_mul( MPI w, MPI u, MPI v); +void mpi_mulm( MPI w, MPI u, MPI v, MPI m); + +/*-- mpi-div.c --*/ +ulong mpi_fdiv_r_ui( MPI rem, MPI dividend, ulong divisor ); +void mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor ); +void mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor ); +void mpi_fdiv_qr( MPI quot, MPI rem, MPI dividend, MPI divisor ); +void mpi_tdiv_r( MPI rem, MPI num, MPI den); +void mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den); +void mpi_tdiv_q_2exp( MPI w, MPI u, unsigned count ); +int mpi_divisible_ui(MPI dividend, ulong divisor ); + +/*-- mpi-gcd.c --*/ +int mpi_gcd( MPI g, MPI a, MPI b ); + +/*-- mpi-pow.c --*/ +void mpi_pow( MPI w, MPI u, MPI v); +void mpi_powm( MPI res, MPI base, MPI exp, MPI mod); + +/*-- mpi-mpow.c --*/ +void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod); + +/*-- mpi-cmp.c --*/ +int mpi_cmp_ui( MPI u, ulong v ); +int mpi_cmp( MPI u, MPI v ); + +/*-- mpi-scan.c --*/ +int mpi_getbyte( MPI a, unsigned idx ); +void mpi_putbyte( MPI a, unsigned idx, int value ); +unsigned mpi_trailing_zeros( MPI a ); + +/*-- mpi-bit.c --*/ +void mpi_normalize( MPI a ); +unsigned mpi_get_nbits( MPI a ); +int mpi_test_bit( MPI a, unsigned n ); +void mpi_set_bit( MPI a, unsigned n ); +void mpi_set_highbit( MPI a, unsigned n ); +void mpi_clear_highbit( MPI a, unsigned n ); +void mpi_clear_bit( MPI a, unsigned n ); +void mpi_rshift( MPI x, MPI a, unsigned n ); + +/*-- mpi-inv.c --*/ +void mpi_invm( MPI x, MPI u, MPI v ); + + +#endif /*G10_MPI_H*/ diff --git a/include/ttyio.h b/include/ttyio.h index e81c659c4..08ca994c9 100644 --- a/include/ttyio.h +++ b/include/ttyio.h @@ -1,5 +1,5 @@ /* ttyio.h - * Copyright (C) 1998, 1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -17,11 +17,15 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_TTYIO_H -#define GPG_TTYIO_H +#ifndef G10_TTYIO_H +#define G10_TTYIO_H int tty_batchmode( int onoff ); -void tty_printf( const char *fmt, ... ); +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) + void tty_printf (const char *fmt, ... ) __attribute__ ((format (printf,1,2))); +#else + void tty_printf (const char *fmt, ... ); +#endif void tty_print_string( byte *p, size_t n ); void tty_print_utf8_string( byte *p, size_t n ); void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ); @@ -32,4 +36,4 @@ int tty_get_answer_is_yes( const char *prompt ); int tty_no_terminal(int onoff); -#endif /*GPG_TTYIO_H*/ +#endif /*G10_TTYIO_H*/ diff --git a/include/types.h b/include/types.h index baece0bca..b41109ee5 100644 --- a/include/types.h +++ b/include/types.h @@ -1,5 +1,5 @@ /* types.h - some common typedefs - * Copyright (C) 1998 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -18,8 +18,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_TYPES_H -#define GPG_TYPES_H +#ifndef G10_TYPES_H +#define G10_TYPES_H /* The AC_CHECK_SIZEOF() in configure fails for some machines. @@ -43,7 +43,14 @@ #ifndef HAVE_BYTE_TYPEDEF #undef byte /* maybe there is a macro with this name */ - typedef unsigned char byte; + #ifndef __riscos__ + typedef unsigned char byte; + #else + /* Norcroft treats char = unsigned char as legal assignment + but char* = unsigned char* as illegal assignment + and the same applies to the signed variants as well */ + typedef char byte; + #endif #define HAVE_BYTE_TYPEDEF #endif @@ -121,4 +128,4 @@ typedef struct string_list { } *STRLIST; -#endif /*GPG_TYPES_H*/ +#endif /*G10_TYPES_H*/ diff --git a/include/util.h b/include/util.h index 375204e78..1d0e4edd5 100644 --- a/include/util.h +++ b/include/util.h @@ -1,5 +1,5 @@ /* util.h - * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. * * This file is part of GNUPG. * @@ -17,82 +17,135 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifndef GPG_UTIL_H -#define GPG_UTIL_H +#ifndef G10_UTIL_H +#define G10_UTIL_H -#ifdef _GCRYPT_IN_LIBGCRYPT - #error This header should not be used internally by libgcrypt +#if defined (__MINGW32__) || defined (__CYGWIN32__) +# include #endif -#include #include "types.h" #include "errors.h" -#include "../jnlib/mischelp.h" -#include "../jnlib/stringhelp.h" -#include "../jnlib/argparse.h" -#include "../jnlib/dotlock.h" +#include "types.h" +#include "mpi.h" +typedef struct { + int *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; + int inarg; + int stopped; + const char *last; + void *aliases; + const void *cur_alias; + } internal; /* DO NOT CHANGE */ +} ARGPARSE_ARGS; + +typedef struct { + int short_opt; + const char *long_opt; + unsigned flags; + const char *description; /* optional option description */ +} ARGPARSE_OPTS; + /*-- logger.c --*/ void log_set_logfile( const char *name, int fd ); FILE *log_stream(void); -void gpg_log_print_prefix(const char *text); +void g10_log_print_prefix(const char *text); void log_set_name( const char *name ); const char *log_get_name(void); void log_set_pid( int pid ); -void log_inc_errorcount(void); int log_get_errorcount( int clear ); -void gpg_log_hexdump( const char *text, const char *buf, size_t len ); +void log_inc_errorcount(void); +void g10_log_hexdump( const char *text, const char *buf, size_t len ); -#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) - void gpg_log_bug( const char *fmt, ... ) +#if defined (__riscos__) \ + || (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )) + void g10_log_bug( const char *fmt, ... ) __attribute__ ((noreturn, format (printf,1,2))); - void gpg_log_bug0( const char *, int, const char * ) __attribute__ ((noreturn)); - void gpg_log_fatal( const char *fmt, ... ) + void g10_log_bug0( const char *, int, const char * ) __attribute__ ((noreturn)); + void g10_log_fatal( const char *fmt, ... ) __attribute__ ((noreturn, format (printf,1,2))); - void gpg_log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); - void gpg_log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); - void gpg_log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); - void gpg_log_fatal_f( const char *fname, const char *fmt, ... ) + void g10_log_error( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); + void g10_log_info( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); + void g10_log_debug( const char *fmt, ... ) __attribute__ ((format (printf,1,2))); + void g10_log_fatal_f( const char *fname, const char *fmt, ... ) __attribute__ ((noreturn, format (printf,2,3))); - void gpg_log_error_f( const char *fname, const char *fmt, ... ) + void g10_log_error_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); - void gpg_log_info_f( const char *fname, const char *fmt, ... ) + void g10_log_info_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); - void gpg_log_debug_f( const char *fname, const char *fmt, ... ) + void g10_log_debug_f( const char *fname, const char *fmt, ... ) __attribute__ ((format (printf,2,3))); - #define BUG() gpg_log_bug0( __FILE__ , __LINE__, __FUNCTION__ ) +#ifndef __riscos__ + #define BUG() g10_log_bug0( __FILE__ , __LINE__, __FUNCTION__ ) #else - void gpg_log_bug( const char *fmt, ... ); - void gpg_log_bug0( const char *, int ); - void gpg_log_fatal( const char *fmt, ... ); - void gpg_log_error( const char *fmt, ... ); - void gpg_log_info( const char *fmt, ... ); - void gpg_log_debug( const char *fmt, ... ); - void gpg_log_fatal_f( const char *fname, const char *fmt, ... ); - void gpg_log_error_f( const char *fname, const char *fmt, ... ); - void gpg_log_info_f( const char *fname, const char *fmt, ... ); - void gpg_log_debug_f( const char *fname, const char *fmt, ... ); - #define BUG() gpg_log_bug0( __FILE__ , __LINE__ ) + #define BUG() g10_log_bug0( __FILE__ , __LINE__, __func__ ) +#endif +#else + void g10_log_bug( const char *fmt, ... ); + void g10_log_bug0( const char *, int ); + void g10_log_fatal( const char *fmt, ... ); + void g10_log_error( const char *fmt, ... ); + void g10_log_info( const char *fmt, ... ); + void g10_log_debug( const char *fmt, ... ); + void g10_log_fatal_f( const char *fname, const char *fmt, ... ); + void g10_log_error_f( const char *fname, const char *fmt, ... ); + void g10_log_info_f( const char *fname, const char *fmt, ... ); + void g10_log_debug_f( const char *fname, const char *fmt, ... ); + #define BUG() g10_log_bug0( __FILE__ , __LINE__ ) #endif -#define log_hexdump gpg_log_hexdump -#define log_bug gpg_log_bug -#define log_bug0 gpg_log_bug0 -#define log_fatal gpg_log_fatal -#define log_error gpg_log_error -#define log_info gpg_log_info -#define log_debug gpg_log_debug -#define log_fatal_f gpg_log_fatal_f -#define log_error_f gpg_log_error_f -#define log_info_f gpg_log_info_f -#define log_debug_f gpg_log_debug_f +#define log_hexdump g10_log_hexdump +#define log_bug g10_log_bug +#define log_bug0 g10_log_bug0 +#define log_fatal g10_log_fatal +#define log_error g10_log_error +#define log_info g10_log_info +#define log_debug g10_log_debug +#define log_fatal_f g10_log_fatal_f +#define log_error_f g10_log_error_f +#define log_info_f g10_log_info_f +#define log_debug_f g10_log_debug_f /*-- errors.c --*/ -const char * gpg_errstr( int no ); +const char * g10_errstr( int no ); + +/*-- argparse.c --*/ +int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +int optfile_parse( FILE *fp, const char *filename, unsigned *lineno, + ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts); +void usage( int level ); +const char *default_strusage( int level ); +/*-- (main program) --*/ +const char *strusage( int level ); + + +/*-- dotlock.c --*/ +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 ); +void remove_lockfiles (void); /*-- fileutil.c --*/ char * make_basename(const char *filepath); @@ -101,6 +154,7 @@ char *make_filename( const char *first_part, ... ); int compare_filenames( const char *a, const char *b ); const char *print_fname_stdin( const char *s ); const char *print_fname_stdout( const char *s ); +int is_file_compressed(const char *s, int *r_status); /*-- miscutil.c --*/ @@ -112,7 +166,9 @@ const char *strtimestamp( u32 stamp ); /* GMT */ const char *asctimestamp( u32 stamp ); /* localized */ void print_string( FILE *fp, const byte *p, size_t n, int delim ); void print_utf8_string( FILE *fp, const byte *p, size_t n ); +void print_utf8_string2( FILE *fp, const byte *p, size_t n, int delim); char *make_printable_string( const byte *p, size_t n, int delim ); +int answer_is_yes_no_default( const char *s, int def_answer ); int answer_is_yes( const char *s ); int answer_is_yes_no_quit( const char *s ); @@ -125,13 +181,63 @@ STRLIST append_to_strlist( STRLIST *list, const char *string ); STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 ); STRLIST strlist_prev( STRLIST head, STRLIST node ); STRLIST strlist_last( STRLIST node ); +char *pop_strlist( STRLIST *list ); +const char *memistr( const char *buf, size_t buflen, const char *sub ); +const char *ascii_memistr( const char *buf, size_t buflen, const char *sub ); +char *mem2str( char *, const void *, size_t); +char *trim_spaces( char *string ); +unsigned int trim_trailing_chars( byte *line, unsigned int len, + const char *trimchars); +unsigned int trim_trailing_ws( byte *line, unsigned len ); +unsigned int check_trailing_chars( const byte *line, unsigned int len, + const char *trimchars ); +unsigned int check_trailing_ws( const byte *line, unsigned int len ); int string_count_chr( const char *string, int c ); int set_native_charset( const char *newset ); const char* get_native_charset(void); char *native_to_utf8( const char *string ); -char *utf8_to_native( const char *string, size_t length ); +char *utf8_to_native( const char *string, size_t length, int delim); int check_utf8_string( const char *string ); +int ascii_isupper (int c); +int ascii_islower (int c); +int ascii_toupper (int c); +int ascii_tolower (int c); +int ascii_strcasecmp( const char *a, const char *b ); +int ascii_memcasecmp( const char *a, const char *b, size_t n ); + +#ifndef HAVE_STPCPY +char *stpcpy(char *a,const char *b); +#endif +#ifndef HAVE_STRLWR +char *strlwr(char *a); +#endif +#ifndef HAVE_STRSEP +char *strsep (char **stringp, const char *delim); +#endif +#ifndef HAVE_STRCASECMP +int strcasecmp( const char *, const char *b); +#endif +#ifndef HAVE_STRNCASECMP +int strncasecmp (const char *, const char *b, size_t n); +#endif +#ifndef HAVE_STRTOUL + #define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c))) +#endif +#ifndef HAVE_MEMMOVE + #define memmove(d, s, n) bcopy((s), (d), (n)) +#endif + +#if defined (__MINGW32__) || defined (__CYGWIN32__) +/*-- w32reg.c --*/ +char *read_w32_registry_string( const char *root, + const char *dir, const char *name ); +int write_w32_registry_string(const char *root, const char *dir, + const char *name, const char *value); + +/*-- strgutil.c --*/ +int vasprintf ( char **result, const char *format, va_list args); +#endif /**** other missing stuff ****/ #ifndef HAVE_ATEXIT /* For SunOS */ @@ -143,7 +249,42 @@ int check_utf8_string( const char *string ); #endif /******** some macros ************/ +#ifndef STR + #define STR(v) #v +#endif +#define STR2(v) STR(v) #define DIM(v) (sizeof(v)/sizeof((v)[0])) #define DIMof(type,member) DIM(((type *)0)->member) -#endif /*GPG_UTIL_H*/ +/******* RISC OS stuff ***********/ +#ifdef __riscos__ +/* needed for strcasecmp() */ +#include +/* needed for filename munging */ +#include +/* needed for image file system feature */ +#include +void riscos_global_defaults(); +#define RISCOS_GLOBAL_STATICS(a) const char *__dynamic_da_name = (a); +void riscos_set_filetype(const char *filename, const char *mimetype); +pid_t riscos_getpid(void); +int riscos_kill(pid_t pid, int sig); +int riscos_access(const char *path, int amode); +int fdopenfile(const char *filename, const int allow_write); +void close_fds(void); +int renamefile(const char *old, const char *new); +char *gstrans(const char *old); +void not_implemented(const char *feature); +#ifdef DEBUG +void dump_fdlist(void); +void list_openfiles(void); +#endif +#ifndef __RISCOS__C__ + #define getpid riscos_getpid + #define kill(a,b) riscos_kill((a),(b)) + #define access(a,b) riscos_access((a),(b)) +#endif /* !__RISCOS__C__ */ +#endif /* __riscos__ */ + +#endif /*G10_UTIL_H*/ + diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog new file mode 100644 index 000000000..0831eebb8 --- /dev/null +++ b/keyserver/ChangeLog @@ -0,0 +1,116 @@ +2002-06-11 David Shaw + + * Makefile.am: Don't hard-code the LDAP libraries - get them from + LDAPLIBS via configure. Also, gpgkeys_hkp is a program, not a + script. + +2002-06-10 David Shaw + + * gpgkeys_ldap.c (include_subkeys): Default "include-subkeys" to + off, since GnuPG now defaults it to on. + +2002-06-06 David Shaw + + * gpgkeys_hkp.c (parse_hkp_index): Type tweaks. + + * gpgkeys_hkp.c (main): Add experimental code warning. + +2002-06-05 David Shaw + + * Makefile.am, gpgkeys_hkp.c (new): Experimental HKP keyserver + interface. + +2002-05-08 David Shaw + + * gpgkeys_ldap.c: Include if we absolutely must. This + helps when compiling against a very old OpenLDAP. + +2002-04-29 David Shaw + + * gpgkeys_mailto.in: Properly handle key requests in full + fingerprint form. + +2002-03-29 David Shaw + + * gpgkeys_ldap.c (printquoted): Quote backslashes within keyserver + search responses. + +2002-02-25 David Shaw + + * gpgkeys_ldap (get_key): LDAP keyservers do not support v3 + fingerprints, so error out if someone tries. Actually, they don't + support any fingerprints, but at least we can calculate a keyid + from a v4 fingerprint. + +2002-02-23 David Shaw + + * gpgkeys_ldap: Clarify the notion of a partial failure. This is + possible if more than one key is being handled in a batch, and one + fails while the other succeeds. Note that a search that comes up + with no results is not a failure - that is a valid response of "no + answer". + + * gpgkeys_ldap.c (get_key): Allow GnuPG to send us full v4 + fingerprints, long key ids, or short key ids while fetching. + Since the LDAP server doesn't actually handle fingerprints, chop + them down to long key ids for actual use. + + * gpgkeys_ldap.c (main, get_key): When searching for a keyid, + search for subkeys as well as primary keys. This is mostly + significant when automatically fetching the key based on the id in + a header (i.e. "signature made by...."). "no-include-subkeys" + disables. + +2002-02-14 David Shaw + + * gpgkeys_ldap.c: Fix compiler warning. + + * gpgkeys_ldap.c: Be much more robust with mangled input files. + +2001-12-28 David Shaw + + * gpgkeys_mailto.in: Use the new OUTOFBAND indicator so gpg knows + not to try and import anything. Also turn on perl -w for + warnings. + + * gpgkeys_ldap.c (main): If we're using temp files (rather than + stdin/stdout), make sure the file is closed when we're done. + +2001-12-20 David Shaw + + * Properly free the LDAP response when we're done with it. + + * Now that we handle multiple keys, we must remove duplicates as + the LDAP keyserver returns keys with multiple user IDs multiple + times. + + * Properly handle multiple keys with the same key ID (it's really + rare, so fetch "0xDEADBEEF" to test this). + +2001-12-17 David Shaw + + * gpgkeys_ldap.c, gpgkeys_mailto.in: Fix GNU capitalization + issues. Prefix log messages with "gpgkeys" to clarify which + program is generating them. + +2001-12-14 David Shaw + + * gpgkeys_ldap.c (search_key): Use unsigned int rather than uint + for portability. + +2001-12-04 David Shaw + + * Initial version of gpgkeys_ldap (LDAP keyserver helper) and + gpgkeys_mailto (email keyserver helper) + + + Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + \ No newline at end of file diff --git a/keyserver/Makefile.am b/keyserver/Makefile.am new file mode 100644 index 000000000..343fb4bd2 --- /dev/null +++ b/keyserver/Makefile.am @@ -0,0 +1,36 @@ +# Copyright (C) 2001, 2002 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 + +## Process this file with automake to produce Makefile.in + +INCLUDES = -I$(top_srcdir)/include +EXTRA_PROGRAMS = gpgkeys_ldap gpgkeys_hkp +EXTRA_SCRIPTS = gpgkeys_mailto + +# We don't need the libs the regular GPG binaries do +LIBS= + +bin_PROGRAMS = @GPGKEYS_LDAP@ @GPGKEYS_HKP@ +bin_SCRIPTS = @GPGKEYS_MAILTO@ +noinst_SCRIPTS = gpgkeys_test + +# don't distribute hkp for now +nodist_gpgkeys_hkp_SOURCES = gpgkeys_hkp.c + +gpgkeys_ldap_LDADD = @LDAPLIBS@ @NETLIBS@ +gpgkeys_hkp_LDADD = @NETLIBS@ diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c new file mode 100644 index 000000000..24bc9cb0d --- /dev/null +++ b/keyserver/gpgkeys_hkp.c @@ -0,0 +1,981 @@ +/* gpgkeys_hkp.c - talk to an HKP keyserver + * Copyright (C) 2001, 2002 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "keyserver.h" + +#define GET 0 +#define SEND 1 +#define SEARCH 2 +#define MAX_LINE 80 + +int verbose=0,include_disabled=0,include_revoked=0; +char *basekeyspacedn=NULL; +char host[80]; +FILE *input=NULL,*output=NULL,*console=NULL,*server=NULL; + +struct keylist +{ + char str[MAX_LINE]; + struct keylist *next; +}; + +int http_connect(const char *host,unsigned short port) +{ + int sock=-1; + struct hostent *ent; + struct sockaddr_in addr; + + sock=socket(AF_INET,SOCK_STREAM,0); + if(sock==-1) + { + fprintf(console,"gpgkeys: internal socket error: %s\n",strerror(errno)); + goto fail; + } + + ent=gethostbyname(host); + if(ent==NULL) + { + fprintf(console,"gpgkeys: DNS error: %s\n",hstrerror(h_errno)); + goto fail; + } + + addr.sin_family=AF_INET; + addr.sin_addr.s_addr=*(int *)ent->h_addr_list[0]; + addr.sin_port=htons(port?port:11371); + + if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==-1) + { + fprintf(console,"gpgkeys: unable to contact keyserver: %s\n", + strerror(errno)); + goto fail; + } + + server=fdopen(sock,"r+"); + if(server==NULL) + { + fprintf(console,"gpgkeys: unable to fdopen socket: %s\n", + strerror(errno)); + goto fail; + } + + if(verbose>3) + fprintf(console,"gpgkeys: HKP connect to %s:%d\n",host,port?port:11371); + + return 0; + + fail: + if(sock>-1) + close(sock); + + return -1; +} + +void http_disconnect(void) +{ + if(verbose>3) + fprintf(console,"gpgkeys: HKP disconnect from %s\n",host); + + fclose(server); +} + +int http_get(const char *op,const char *search) +{ + fprintf(server,"GET /pks/lookup?op=%s&search=%s HTTP/1.0\n\n",op,search); + + if(verbose>2) + fprintf(console,"gpgkeys: HTTP GET /pks/lookup?op=%s&search=%s HTTP/1.0\n", + op,search); + + return 0; +} + +int http_post(const char *data) +{ + char line[MAX_LINE]; + int result; + + fprintf(server, + "POST /pks/add HTTP/1.0\n" + "Content-type: application/x-www-form-urlencoded\n" + "Content-Length: %d\n\n%s",strlen(data),data); + + if(verbose>2) + fprintf(console, + "gpgkeys: HTTP POST /pks/add HTTP/1.0\n" + "gpgkeys: Content-type: application/x-www-form-urlencoded\n" + "gpgkeys: Content-Length: %d\n\n",strlen(data)); + + /* Now wait for a response */ + + while(fgets(line,MAX_LINE,server)!=NULL) + if(sscanf(line,"HTTP/%*f %d OK",&result)==1) + return result; + + return -1; +} + +/* Returns 0 on success, -1 on failure, and 1 on eof */ +int send_key(void) +{ + int err,gotit=0,keylen,maxlen,ret=-1; + char keyid[17],line[MAX_LINE],*key; + + key=strdup("keytext="); + if(key==NULL) + { + fprintf(console,"gpgkeys: unable to allocate for key\n"); + goto fail; + } + + maxlen=keylen=strlen(key); + + /* Read and throw away stdin until we see the BEGIN */ + + while(fgets(line,MAX_LINE,input)!=NULL) + if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1) + { + gotit=1; + break; + } + + if(!gotit) + { + /* i.e. eof before the KEY BEGIN was found */ + ret=1; + goto fail; + } + + gotit=0; + + /* Now slurp up everything until we see the END */ + + while(fgets(line,MAX_LINE,input)!=NULL) + if(sscanf(line,"KEY %16s END\n",keyid)==1) + { + gotit=1; + break; + } + else + { + char *c=line; + + while(*c!='\0') + { + if(maxlen-keylen<4) + { + maxlen+=1024; + key=realloc(key,maxlen); + if(key==NULL) + { + fprintf(console,"gpgkeys: unable to reallocate for key\n"); + goto fail; + } + } + + if(isalnum(*c) || *c=='-') + { + key[keylen++]=*c; + key[keylen]='\0'; + } + else if(*c==' ') + { + key[keylen++]='+'; + key[keylen]='\0'; + } + else + { + sprintf(&key[keylen],"%%%02X",*c); + keylen+=3; + } + + c++; + } + } + + if(!gotit) + { + fprintf(console,"gpgkeys: no KEY %s END found\n",keyid); + goto fail; + } + + err=http_post(key); + if(err!=200) + { + fprintf(console,"gpgkeys: remote server returned error %d\n",err); + goto fail; + } + + ret=0; + + fail: + + free(key); + + if(ret!=0) + fprintf(output,"KEY %s FAILED\n",keyid); + + return ret; +} + +int get_key(char *getkey) +{ + int err,gotit=0; + char search[29],line[MAX_LINE]; + + /* Build the search string. HKP only uses the short key IDs. */ + + if(strncmp(getkey,"0x",2)==0) + getkey+=2; + + if(strlen(getkey)==32) + { + fprintf(console, + "gpgkeys: HKP keyservers do not support v3 fingerprints\n"); + fprintf(output,"KEY 0x%s BEGIN\n",getkey); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + return -1; + } + + if(strlen(getkey)>8) + { + char *offset=&getkey[strlen(getkey)-8]; + + /* fingerprint or long key id. Take the last 8 characters and + treat it like a short key id */ + + sprintf(search,"0x%.8s",offset); + } + else + { + /* short key id */ + + sprintf(search,"0x%.8s",getkey); + } + + fprintf(output,"KEY 0x%s BEGIN\n",getkey); + + if(verbose>2) + fprintf(console,"gpgkeys: HKP fetch for: %s\n",search); + + fprintf(console,"gpgkeys: requesting key 0x%s from HKP keyserver %s\n", + getkey,host); + + err=http_get("get",search); + if(err!=0) + { + fprintf(console,"gpgkeys: HKP fetch error: %s\n",strerror(errno)); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + return -1; + } + + while(fgets(line,MAX_LINE,server)) + { + if(gotit) + { + fprintf(output,line); + if(strcmp(line,"-----END PGP PUBLIC KEY BLOCK-----\n")==0) + { + gotit=0; + fprintf(output,"KEY 0x%s END\n",getkey); + break; + } + } + else + if(strcmp(line,"-----BEGIN PGP PUBLIC KEY BLOCK-----\n")==0) + { + fprintf(output,line); + gotit=1; + } + } + + return 0; +} + +void print_quoted(FILE *stream,char *string,char delim) +{ + while(*string) + { + if(*string==delim) + fprintf(stream,"\\x%02X",*string); + else + fputc(*string,stream); + + string++; + } +} + +void append_quoted(char *buffer,char *string,char delim) +{ + while(*buffer) + buffer++; + + while(*string) + { + if(*string==delim) + { + sprintf(buffer,"\\x%02X",*string); + buffer+=4; + } + else + *buffer=*string; + + buffer++; + string++; + } + + *buffer='\0'; +} + +unsigned int scan_isodatestr( const char *string ) +{ + int year, month, day; + struct tm tmbuf; + time_t stamp; + int i; + + if( strlen(string) != 10 || string[4] != '-' || string[7] != '-' ) + return 0; + for( i=0; i < 4; i++ ) + if( !isdigit(string[i]) ) + return 0; + if( !isdigit(string[5]) || !isdigit(string[6]) ) + return 0; + if( !isdigit(string[8]) || !isdigit(string[9]) ) + return 0; + year = atoi(string); + month = atoi(string+5); + day = atoi(string+8); + /* some basic checks */ + if( year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ) + return 0; + memset( &tmbuf, 0, sizeof tmbuf ); + tmbuf.tm_mday = day; + tmbuf.tm_mon = month-1; + tmbuf.tm_year = year - 1900; + tmbuf.tm_isdst = -1; + stamp = mktime( &tmbuf ); + if( stamp == (time_t)-1 ) + return 0; + return stamp; +} + +/* pub 2048/3CB3B415 1998/04/03 David M. Shaw <dshaw@jabberwocky.com> */ + +/* Luckily enough, both the HKP server and NAI HKP interface to their + LDAP server are close enough in output so the same function can + parse them both. */ + +int parse_hkp_index(char *line,char **buffer) +{ + static int open=0,revoked=0; + static char *key,*uid; + static unsigned int bits,createtime; + int ret=0; + + /* printf("Open %d, LINE: %s\n",open,line); */ + + /* For multiple UIDs */ + if(open && uid!=NULL) + { + ret=0; + + if(!(revoked && !include_revoked)) + { + char intstr[11],*buf; + + buf=realloc(*buffer, + (*buffer?strlen(*buffer):0)+ + (strlen(key)*4)+ + 1+ + (strlen(uid)*4) + +1 + +2 + +10 + +4 + +10 + +1 + +1); + + if(buf) + *buffer=buf; + else + return -1; + + append_quoted(*buffer,key,':'); + append_quoted(*buffer,":",0); + append_quoted(*buffer,uid,':'); + append_quoted(*buffer,":",0); + append_quoted(*buffer,revoked?"1:":":",0); + sprintf(intstr,"%u",createtime); + append_quoted(*buffer,intstr,':'); + append_quoted(*buffer,"::::",0); + sprintf(intstr,"%u",bits); + append_quoted(*buffer,intstr,':'); + append_quoted(*buffer,"\n",0); + + ret=1; + } + + if(strncmp(line," ",5)!=0) + { + revoked=0; + free(key); + free(uid); + uid=NULL; + open=0; + } + } + + if(strncasecmp(line,"pub ",5)==0) + { + char *tok,*temp; + + open=1; + + line+=4; + + tok=strsep(&line,"/"); + if(tok==NULL) + return ret; + + bits=atoi(tok); + + tok=strsep(&line,">"); + if(tok==NULL) + return ret; + + tok=strsep(&line,"<"); + if(tok==NULL) + { + key=strdup("00000000"); + return ret; + } + + key=strdup(tok); + + tok=strsep(&line," "); + if(tok==NULL) + return ret; + + tok=strsep(&line," "); + if(tok==NULL) + return ret; + + /* The date parser wants '-' instead of '/', so... */ + temp=tok; + while(*temp!='\0') + { + if(*temp=='/') + *temp='-'; + + temp++; + } + + createtime=scan_isodatestr(tok); + } + + if(open) + { + int uidindex=0; + + if(line==NULL) + { + uid=strdup("Key index corrupted"); + return ret; + } + + /* All that's left is the user name. Strip off anything + and de-urlencode it. */ + + while(*line==' ' && *line!='\0') + line++; + + if(strncmp(line,"*** KEY REVOKED ***",19)==0) + { + revoked=1; + return ret; + } + + uid=malloc(strlen(line)+1); + + while(*line!='\0') + { + switch(*line) + { + case '<': + while(*line!='>' && *line!='\0') + line++; + + if(*line!='\0') + line++; + break; + + case '&': + if((*(line+1)!='\0' && tolower(*(line+1))=='l') && + (*(line+2)!='\0' && tolower(*(line+2))=='t') && + (*(line+3)!='\0' && *(line+3)==';')) + { + uid[uidindex++]='<'; + line+=4; + break; + } + + if((*(line+1)!='\0' && tolower(*(line+1))=='g') && + (*(line+2)!='\0' && tolower(*(line+2))=='t') && + (*(line+3)!='\0' && *(line+3)==';')) + { + uid[uidindex++]='>'; + line+=4; + break; + } + + default: + uid[uidindex++]=*line; + line++; + break; + } + } + + uid[uidindex]='\0'; + + /* Chop off the trailing \r, \n, or both. This is fussy as the + true HKP servers have \r\n, and the NAI HKP servers have just + \n. */ + + if(isspace(uid[uidindex-1])) + uid[uidindex-1]='\0'; + + if(isspace(uid[uidindex-2])) + uid[uidindex-2]='\0'; + } + + return ret; +} + +int search_key(char *searchkey) +{ + int ret=-1,err,count=0; + char *search,*request,*buffer=NULL; + char line[1024]; + int max,len; + + fprintf(output,"SEARCH %s BEGIN\n",searchkey); + + /* Build the search string. It's going to need url-encoding. */ + + max=0; + len=0; + search=NULL; + request=searchkey; + + while(*request!='\0') + { + if(max-len<3) + { + max+=100; + search=realloc(search,max+1); /* Note +1 for \0 */ + } + + if(isalnum(*request) || *request=='-') + search[len++]=*request; + else if(*request==' ') + search[len++]='+'; + else + { + sprintf(&search[len],"%%%02X",*request); + len+=3; + } + + request++; + } + + search[len]='\0'; + + if(verbose>2) + fprintf(console,"gpgkeys: HKP search for: %s\n",search); + + fprintf(console,("gpgkeys: searching for \"%s\" from HKP server %s\n"), + searchkey,host); + + http_get("index",search); + + free(search); + + while(fgets(line,1024,server)) + { + err=parse_hkp_index(line,&buffer); + if(err==-1) + goto fail; + + count+=err; + } + + fprintf(output,"COUNT %d\n%s",count,buffer); + // fprintf(output,"COUNT -1\n%s",buffer); + + fprintf(output,"SEARCH %s END\n",searchkey); + + ret=0; + + fail: + free(buffer); + + return ret; +} + +int main(int argc,char *argv[]) +{ + int port=0,arg,action=-1,ret=KEYSERVER_INTERNAL_ERROR; + char line[MAX_LINE]; + int version,failed=0; + struct keylist *keylist=NULL,*keyptr=NULL; + + console=stderr; + + fprintf(console, + "gpgkeys: Warning: this is an *experimental* HKP interface!\n"); + + while((arg=getopt(argc,argv,"ho:"))!=-1) + switch(arg) + { + default: + case 'h': + fprintf(console,"-h\thelp\n"); + fprintf(console,"-o\toutput to this file\n"); + return KEYSERVER_OK; + + case 'o': + output=fopen(optarg,"w"); + if(output==NULL) + { + fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n", + optarg,strerror(errno)); + return KEYSERVER_INTERNAL_ERROR; + } + + break; + } + + if(argc>optind) + { + input=fopen(argv[optind],"r"); + if(input==NULL) + { + fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n", + argv[optind],strerror(errno)); + return KEYSERVER_INTERNAL_ERROR; + } + } + + if(input==NULL) + input=stdin; + + if(output==NULL) + output=stdout; + + /* Get the command and info block */ + + while(fgets(line,MAX_LINE,input)!=NULL) + { + char commandstr[7]; + char portstr[10]; + char optionstr[30]; + char hash; + + if(line[0]=='\n') + break; + + if(sscanf(line,"%c",&hash)==1 && hash=='#') + continue; + + if(sscanf(line,"COMMAND %6s\n",commandstr)==1) + { + commandstr[6]='\0'; + + if(strcasecmp(commandstr,"get")==0) + action=GET; + else if(strcasecmp(commandstr,"send")==0) + action=SEND; + else if(strcasecmp(commandstr,"search")==0) + action=SEARCH; + + continue; + } + + if(sscanf(line,"HOST %79s\n",host)==1) + { + host[79]='\0'; + continue; + } + + if(sscanf(line,"PORT %9s\n",portstr)==1) + { + portstr[9]='\0'; + port=atoi(portstr); + continue; + } + + if(sscanf(line,"VERSION %d\n",&version)==1) + { + if(version!=0) + { + ret=KEYSERVER_VERSION_ERROR; + goto fail; + } + + continue; + } + + if(sscanf(line,"OPTION %29s\n",optionstr)==1) + { + int no=0; + char *start=&optionstr[0]; + + optionstr[29]='\0'; + + if(strncasecmp(optionstr,"no-",3)==0) + { + no=1; + start=&optionstr[3]; + } + + if(strcasecmp(start,"verbose")==0) + { + if(no) + verbose--; + else + verbose++; + } + else if(strcasecmp(start,"include-disabled")==0) + { + if(no) + include_disabled=0; + else + include_disabled=1; + } + else if(strcasecmp(start,"include-revoked")==0) + { + if(no) + include_revoked=0; + else + include_revoked=1; + } + + continue; + } + } + + /* If it's a GET or a SEARCH, the next thing to come in is the + keyids. If it's a SEND, then there are no keyids. */ + + if(action==SEND) + while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n'); + else if(action==GET || action==SEARCH) + { + for(;;) + { + struct keylist *work; + + if(fgets(line,MAX_LINE,input)==NULL) + break; + else + { + if(line[0]=='\n') + break; + + work=malloc(sizeof(struct keylist)); + if(work==NULL) + { + fprintf(console,"gpgkeys: out of memory while " + "building key list\n"); + goto fail; + } + + strcpy(work->str,line); + + /* Trim the trailing \n */ + work->str[strlen(line)-1]='\0'; + + work->next=NULL; + + /* Always attach at the end to keep the list in proper + order for searching */ + if(keylist==NULL) + keylist=work; + else + keyptr->next=work; + + keyptr=work; + } + } + } + else + { + fprintf(console,"gpgkeys: no keyserver command specified\n"); + goto fail; + } + + /* Send the response */ + + fprintf(output,"VERSION 0\n"); + fprintf(output,"PROGRAM %s\n\n",VERSION); + + if(verbose>1) + { + fprintf(console,"Host:\t\t%s\n",host); + if(port) + fprintf(console,"Port:\t\t%d\n",port); + fprintf(console,"Command:\t%s\n",action==GET?"GET": + action==SEND?"SEND":"SEARCH"); + } + +#if 0 + if(verbose>1) + { + vals=ldap_get_values(ldap,res,"software"); + if(vals!=NULL) + { + fprintf(console,"Server: \t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,res,"version"); + if(vals!=NULL) + { + fprintf(console,"Version:\t%s\n",vals[0]); + ldap_value_free(vals); + } + } +#endif + + switch(action) + { + case GET: + keyptr=keylist; + + while(keyptr!=NULL) + { + http_connect(host,port); + + if(get_key(keyptr->str)==-1) + failed++; + + http_disconnect(); + + keyptr=keyptr->next; + } + break; + + case SEND: + { + int ret; + + do + { + http_connect(host,port); + ret=send_key(); + if(ret==-1) + failed++; + http_disconnect(); + } + while(ret!=1); + } + break; + + case SEARCH: + { + char *searchkey=NULL; + int len=0; + + /* To search, we stick a space in between each key to search + for. */ + + keyptr=keylist; + while(keyptr!=NULL) + { + len+=strlen(keyptr->str)+1; + keyptr=keyptr->next; + } + + searchkey=malloc(len+1); + if(searchkey==NULL) + goto fail; + + searchkey[0]='\0'; + + keyptr=keylist; + while(keyptr!=NULL) + { + strcat(searchkey,keyptr->str); + strcat(searchkey," "); + keyptr=keyptr->next; + } + + /* Nail that last space */ + searchkey[strlen(searchkey)-1]='\0'; + + http_connect(host,port); + + if(search_key(searchkey)==-1) + { + fprintf(output,"SEARCH %s FAILED\n",searchkey); + failed++; + } + + http_disconnect(); + + free(searchkey); + } + + break; + } + + if(!failed) + ret=KEYSERVER_OK; + + fail: + + while(keylist!=NULL) + { + struct keylist *current=keylist; + keylist=keylist->next; + free(current); + } + + if(input!=stdin) + fclose(input); + + if(output!=stdout) + fclose(output); + + return ret; +} diff --git a/keyserver/gpgkeys_ldap.c b/keyserver/gpgkeys_ldap.c new file mode 100644 index 000000000..fa9edab8d --- /dev/null +++ b/keyserver/gpgkeys_ldap.c @@ -0,0 +1,986 @@ +/* gpgkeys_ldap.c - talk to a LDAP keyserver + * Copyright (C) 2001, 2002 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 +#include +#include +#include +#include +#include +#include +#ifdef NEED_LBER_H +#include +#endif +#include +#include "keyserver.h" + +#ifdef __riscos__ +#include +#endif + +#define GET 0 +#define SEND 1 +#define SEARCH 2 +#define MAX_LINE 80 + +int verbose=0,include_disabled=0,include_revoked=0,include_subkeys=0; +char *basekeyspacedn=NULL; +char host[80]; +FILE *input=NULL,*output=NULL,*console=NULL; +LDAP *ldap=NULL; + +struct keylist +{ + char str[MAX_LINE]; + struct keylist *next; +}; + +/* Returns 0 on success, -1 on failure, and 1 on eof */ +int send_key(void) +{ + int err,gotit=0,keysize=1,ret=-1; + char *dn=NULL; + char line[MAX_LINE]; + char *key[2]={0,0}; + char keyid[17]; +#ifndef __riscos__ + LDAPMod mod={LDAP_MOD_ADD,"pgpKeyV2",{key}},*attrs[2]={&mod,NULL}; +#else + LDAPMod mod, *attrs[2]; + + mod.mod_op = LDAP_MOD_ADD; + mod.mod_type = "pgpKeyV2"; + mod.mod_values = 0; + mod.mod_bvalues = 0; + + attrs[0] = &mod; + attrs[1] = NULL; +#endif + + dn=malloc(strlen("pgpCertid=virtual,")+strlen(basekeyspacedn)+1); + if(dn==NULL) + { + fprintf(console,"gpgkeys: can't allocate memory for keyserver record\n"); + goto fail; + } + + strcpy(dn,"pgpCertid=virtual,"); + strcat(dn,basekeyspacedn); + + key[0]=malloc(1); + if(key[0]==NULL) + { + fprintf(console,"gpgkeys: unable to allocate memory for key\n"); + goto fail; + } + + key[0][0]='\0'; + + /* Read and throw away stdin until we see the BEGIN */ + + while(fgets(line,MAX_LINE,input)!=NULL) + if(sscanf(line,"KEY %16s BEGIN\n",keyid)==1) + { + gotit=1; + break; + } + + if(!gotit) + { + /* i.e. eof before the KEY BEGIN was found */ + ret=1; + goto fail; + } + + gotit=0; + + /* Now slurp up everything until we see the END */ + + while(fgets(line,MAX_LINE,input)!=NULL) + if(sscanf(line,"KEY %16s END\n",keyid)==1) + { + gotit=1; + break; + } + else + { + keysize+=strlen(line); + key[0]=realloc(key[0],keysize); + if(key[0]==NULL) + { + fprintf(console,"gpgkeys: unable to reallocate for key\n"); + goto fail; + } + + strcat(key[0],line); + } + + if(!gotit) + { + fprintf(console,"gpgkeys: no KEY %s END found\n",keyid); + goto fail; + } + + err=ldap_add_s(ldap,dn,attrs); + if(err!=LDAP_SUCCESS) + { + fprintf(console,"gpgkeys: error adding key %s to keyserver: %s\n", + keyid,ldap_err2string(err)); + goto fail; + } + + ret=0; + + fail: + + free(key[0]); + free(dn); + + if(ret!=0) + fprintf(output,"KEY %s FAILED\n",keyid); + + return ret; +} + +/* Returns 0 on success and -1 on failure. Note that key-not-found is + not an error! */ +int get_key(char *getkey) +{ + char **vals; + LDAPMessage *res,*each; + int ret=-1,err,count; + struct keylist *dupelist=NULL; + char search[62]; + char *attrs[]={"pgpKeyV2","pgpuserid","pgpkeyid","pgpcertid","pgprevoked", + "pgpdisabled","pgpkeycreatetime","modifytimestamp", + "pgpkeysize","pgpkeytype",NULL}; + + /* Build the search string */ + + /* GPG can send us a v4 fingerprint, a v3 or v4 long key id, or a v3 + or v4 short key id */ + + if(strncmp(getkey,"0x",2)==0) + getkey+=2; + + if(strlen(getkey)==32) + { + fprintf(console, + "gpgkeys: LDAP keyservers do not support v3 fingerprints\n"); + fprintf(output,"KEY 0x%s BEGIN\n",getkey); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + return -1; + } + + if(strlen(getkey)>16) + { + char *offset=&getkey[strlen(getkey)-16]; + + /* fingerprint. Take the last 16 characters and treat it like a + long key id */ + + if(include_subkeys) + sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))", + offset,offset); + else + sprintf(search,"(pgpcertid=%.16s)",offset); + } + else if(strlen(getkey)>8) + { + /* long key id */ + + if(include_subkeys) + sprintf(search,"(|(pgpcertid=%.16s)(pgpsubkeyid=%.16s))", + getkey,getkey); + else + sprintf(search,"(pgpcertid=%.16s)",getkey); + } + else + { + /* short key id */ + + sprintf(search,"(pgpkeyid=%.8s)",getkey); + } + + fprintf(output,"KEY 0x%s BEGIN\n",getkey); + + if(verbose>2) + fprintf(console,"gpgkeys: LDAP fetch for: %s\n",search); + + if(!verbose) + attrs[1]=NULL; + + fprintf(console,"gpgkeys: requesting key 0x%s from LDAP keyserver %s\n", + getkey,host); + + err=ldap_search_s(ldap,basekeyspacedn, + LDAP_SCOPE_SUBTREE,search,attrs,0,&res); + if(err!=0) + { + fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err)); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + return -1; + } + + count=ldap_count_entries(ldap,res); + if(count<1) + { + fprintf(console,"gpgkeys: key %s not found on keyserver\n",getkey); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + } + else + { + /* There may be more than one unique result for a given keyID, + so we should fetch them all (test this by fetching short key + id 0xDEADBEEF). */ + + each=ldap_first_entry(ldap,res); + while(each!=NULL) + { + struct keylist *keyptr=dupelist; + + /* Use the long keyid to remove duplicates. The LDAP server + returns the same keyid more than once if there are + multiple user IDs on the key. Note that this does NOT + mean that a keyid that exists multiple times on the + keyserver will not be fetched. It means that each KEY, + no matter how many user IDs share it's keyid, will be + fetched only once. If a keyid that belongs to more than + one key is fetched, the server quite properly responds + with all matching keys. -ds */ + + vals=ldap_get_values(ldap,each,"pgpcertid"); + if(vals!=NULL) + { + while(keyptr!=NULL) + { + if(strcasecmp(keyptr->str,vals[0])==0) + break; + + keyptr=keyptr->next; + } + + if(!keyptr) + { + /* it's not a duplicate, so add it */ + + keyptr=malloc(sizeof(struct keylist)); + if(keyptr==NULL) + { + fprintf(console,"gpgkeys: out of memory when deduping " + "key list\n"); + goto fail; + } + + strncpy(keyptr->str,vals[0],MAX_LINE); + keyptr->str[MAX_LINE-1]='\0'; + + keyptr->next=dupelist; + dupelist=keyptr; + keyptr=NULL; + } + + ldap_value_free(vals); + } + + if(!keyptr) /* it's not a duplicate */ + { + if(verbose) + { + vals=ldap_get_values(ldap,each,"pgpuserid"); + if(vals!=NULL) + { + /* This is wrong, as the user ID is UTF8. A + better way to handle this would be to send it + over to gpg and display it on that side of + the pipe. */ + fprintf(console,"\nUser ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgprevoked"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + fprintf(console,"\t\t** KEY REVOKED **\n"); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpdisabled"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + fprintf(console,"\t\t** KEY DISABLED **\n"); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeyid"); + if(vals!=NULL) + { + fprintf(console,"Short key ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpcertid"); + if(vals!=NULL) + { + fprintf(console,"Long key ID:\t%s\n",vals[0]); + ldap_value_free(vals); + } + + /* YYYYMMDDHHmmssZ */ + + vals=ldap_get_values(ldap,each,"pgpkeycreatetime"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(console,"Key created:\t%.2s/%.2s/%.4s\n", + &vals[0][4],&vals[0][6],vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"modifytimestamp"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(console,"Key modified:\t%.2s/%.2s/%.4s\n", + &vals[0][4],&vals[0][6],vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeysize"); + if(vals!=NULL) + { + fprintf(console,"Key size:\t%d\n",atoi(vals[0])); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpkeytype"); + if(vals!=NULL) + { + fprintf(console,"Key type:\t%s\n",vals[0]); + ldap_value_free(vals); + } + } + + vals=ldap_get_values(ldap,each,"pgpKeyV2"); + if(vals==NULL) + { + fprintf(console,"gpgkeys: unable to retrieve key %s " + "from keyserver\n",getkey); + fprintf(output,"KEY 0x%s FAILED\n",getkey); + } + else + { + fprintf(output,"%sKEY 0x%s END\n",vals[0],getkey); + + ldap_value_free(vals); + } + } + + each=ldap_next_entry(ldap,each); + } + } + + ret=0; + + fail: + ldap_msgfree(res); + + /* free up the dupe checker */ + while(dupelist!=NULL) + { + struct keylist *keyptr=dupelist; + + dupelist=keyptr->next; + free(keyptr); + } + + return ret; +} + +time_t ldap2epochtime(const char *timestr) +{ + struct tm pgptime; + + memset(&pgptime,0,sizeof(pgptime)); + + /* YYYYMMDDHHmmssZ */ + + sscanf(timestr,"%4d%2d%2d%2d%2d%2d", + &pgptime.tm_year, + &pgptime.tm_mon, + &pgptime.tm_mday, + &pgptime.tm_hour, + &pgptime.tm_min, + &pgptime.tm_sec); + + pgptime.tm_year-=1900; + pgptime.tm_isdst=-1; + pgptime.tm_mon--; + + return mktime(&pgptime); +} + +void printquoted(FILE *stream,char *string,char delim) +{ + while(*string) + { + if(*string==delim || *string=='\\') + fprintf(stream,"\\x%02x",*string); + else + fputc(*string,stream); + + string++; + } +} + +/* Returns 0 on success and -1 on error. Note that key-not-found is + not an error! */ +int search_key(char *searchkey) +{ + char **vals; + LDAPMessage *res,*each; + int err,count; + /* The maxium size of the search, including the optional stuff and + the trailing \0 */ + char search[2+12+MAX_LINE+2+15+14+1+1]; + char *attrs[]={"pgpcertid","pgpuserid","pgprevoked","pgpdisabled", + "pgpkeycreatetime","pgpkeyexpiretime","modifytimestamp", + "pgpkeysize","pgpkeytype",NULL}; + + fprintf(output,"SEARCH %s BEGIN\n",searchkey); + + /* Build the search string */ + + sprintf(search,"%s(pgpuserid=*%s*)%s%s%s", + (!(include_disabled&&include_revoked))?"(&":"", + searchkey, + include_disabled?"":"(pgpdisabled=0)", + include_revoked?"":"(pgprevoked=0)", + !(include_disabled&&include_revoked)?")":""); + + if(verbose>2) + fprintf(console,"gpgkeys: LDAP search for: %s\n",search); + + fprintf(console,("gpgkeys: searching for \"%s\" from LDAP server %s\n"), + searchkey,host); + + err=ldap_search_s(ldap,basekeyspacedn, + LDAP_SCOPE_SUBTREE,search,attrs,0,&res); + if(err!=0) + { + fprintf(console,"gpgkeys: LDAP search error: %s\n",ldap_err2string(err)); + return -1; + } + + count=ldap_count_entries(ldap,res); + + if(count<1) + fprintf(output,"COUNT 0\n"); + else + { + fprintf(output,"COUNT %d\n",count); + + each=ldap_first_entry(ldap,res); + while(each!=NULL) + { + int flags=0; + + vals=ldap_get_values(ldap,each,"pgpcertid"); + if(vals!=NULL) + { + fprintf(output,"%s:",vals[0]); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"pgpuserid"); + if(vals!=NULL) + { + /* Need to escape any colons */ + printquoted(output,vals[0],':'); + fputc(':',output); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"pgprevoked"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + flags|=1; + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,each,"pgpdisabled"); + if(vals!=NULL) + { + if(atoi(vals[0])==1) + flags|=2; + ldap_value_free(vals); + } + + fprintf(output,"%d:",flags); + + /* YYYYMMDDHHmmssZ */ + + vals=ldap_get_values(ldap,each,"pgpkeycreatetime"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0])); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"pgpkeyexpiretime"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0])); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"modifytimestamp"); + if(vals!=NULL && strlen(vals[0])==15) + { + fprintf(output,"%u:",(unsigned int)ldap2epochtime(vals[0])); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"pgpkeytype"); + if(vals!=NULL) + { + fprintf(output,"%s:",vals[0]); + ldap_value_free(vals); + } + else + fputc(':',output); + + vals=ldap_get_values(ldap,each,"pgpkeysize"); + if(vals!=NULL) + { + /* Not sure why, but some keys are listed with a key size of + 0. Treat that like an unknown. */ + if(atoi(vals[0])>0) + fprintf(output,"%d",atoi(vals[0])); + ldap_value_free(vals); + } + + fputc('\n',output); + + each=ldap_next_entry(ldap,each); + } + } + + ldap_msgfree(res); + + fprintf(output,"SEARCH %s END\n",searchkey); + + return 0; +} + +int main(int argc,char *argv[]) +{ + int port=0,arg,err,action=-1,ret=KEYSERVER_INTERNAL_ERROR; + char line[MAX_LINE],**vals; + int version,failed=0; + char *attrs[]={"basekeyspacedn","version","software",NULL}; + LDAPMessage *res; + struct keylist *keylist=NULL,*keyptr=NULL; + +#ifdef __riscos__ + __riscosify_control = __RISCOSIFY_NO_PROCESS; +#endif + + console=stderr; + + while((arg=getopt(argc,argv,"ho:"))!=-1) + switch(arg) + { + default: + case 'h': + fprintf(console,"-h\thelp\n"); + fprintf(console,"-o\toutput to this file\n"); + return KEYSERVER_OK; + + case 'o': + output=fopen(optarg,"w"); + if(output==NULL) + { + fprintf(console,"gpgkeys: Cannot open output file \"%s\": %s\n", + optarg,strerror(errno)); + return KEYSERVER_INTERNAL_ERROR; + } + + break; + } + + if(argc>optind) + { + input=fopen(argv[optind],"r"); + if(input==NULL) + { + fprintf(console,"gpgkeys: Cannot open input file \"%s\": %s\n", + argv[optind],strerror(errno)); + return KEYSERVER_INTERNAL_ERROR; + } + } + + if(input==NULL) + input=stdin; + + if(output==NULL) + output=stdout; + + /* Get the command and info block */ + + while(fgets(line,MAX_LINE,input)!=NULL) + { + char commandstr[7]; + char portstr[10]; + char optionstr[30]; + char hash; + + if(line[0]=='\n') + break; + + if(sscanf(line,"%c",&hash)==1 && hash=='#') + continue; + + if(sscanf(line,"COMMAND %6s\n",commandstr)==1) + { + commandstr[6]='\0'; + + if(strcasecmp(commandstr,"get")==0) + action=GET; + else if(strcasecmp(commandstr,"send")==0) + action=SEND; + else if(strcasecmp(commandstr,"search")==0) + action=SEARCH; + + continue; + } + + if(sscanf(line,"HOST %79s\n",host)==1) + { + host[79]='\0'; + continue; + } + + if(sscanf(line,"PORT %9s\n",portstr)==1) + { + portstr[9]='\0'; + port=atoi(portstr); + continue; + } + + if(sscanf(line,"VERSION %d\n",&version)==1) + { + if(version!=0) + { + ret=KEYSERVER_VERSION_ERROR; + goto fail; + } + + continue; + } + + if(sscanf(line,"OPTION %29s\n",optionstr)==1) + { + int no=0; + char *start=&optionstr[0]; + + optionstr[29]='\0'; + + if(strncasecmp(optionstr,"no-",3)==0) + { + no=1; + start=&optionstr[3]; + } + + if(strcasecmp(start,"verbose")==0) + { + if(no) + verbose--; + else + verbose++; + } + else if(strcasecmp(start,"include-disabled")==0) + { + if(no) + include_disabled=0; + else + include_disabled=1; + } + else if(strcasecmp(start,"include-revoked")==0) + { + if(no) + include_revoked=0; + else + include_revoked=1; + } + else if(strcasecmp(start,"include-subkeys")==0) + { + if(no) + include_subkeys=0; + else + include_subkeys=1; + } + + continue; + } + } + + /* If it's a GET or a SEARCH, the next thing to come in is the + keyids. If it's a SEND, then there are no keyids. */ + + if(action==SEND) + while(fgets(line,MAX_LINE,input)!=NULL && line[0]!='\n'); + else if(action==GET || action==SEARCH) + { + for(;;) + { + struct keylist *work; + + if(fgets(line,MAX_LINE,input)==NULL) + break; + else + { + if(line[0]=='\n') + break; + + work=malloc(sizeof(struct keylist)); + if(work==NULL) + { + fprintf(console,"gpgkeys: out of memory while " + "building key list\n"); + goto fail; + } + + strcpy(work->str,line); + + /* Trim the trailing \n */ + work->str[strlen(line)-1]='\0'; + + work->next=NULL; + + /* Always attach at the end to keep the list in proper + order for searching */ + if(keylist==NULL) + keylist=work; + else + keyptr->next=work; + + keyptr=work; + } + } + } + else + { + fprintf(console,"gpgkeys: no keyserver command specified\n"); + goto fail; + } + + /* Send the response */ + + fprintf(output,"VERSION 0\n"); + fprintf(output,"PROGRAM %s\n\n",VERSION); + + if(verbose>1) + { + fprintf(console,"Host:\t\t%s\n",host); + if(port) + fprintf(console,"Port:\t\t%d\n",port); + fprintf(console,"Command:\t%s\n",action==GET?"GET": + action==SEND?"SEND":"SEARCH"); + } + + ldap=ldap_init(host,port); + if(ldap==NULL) + { + fprintf(console,"gpgkeys: internal LDAP init error: %s\n",strerror(errno)); + goto fail; + } + + err=ldap_simple_bind_s(ldap,NULL,NULL); + if(err!=0) + { + fprintf(console,"gpgkeys: internal LDAP bind error: %s\n", + ldap_err2string(err)); + goto fail; + } + + /* Get the magic info record */ + + err=ldap_search_s(ldap,"cn=PGPServerInfo",LDAP_SCOPE_BASE, + "(objectclass=*)",attrs,0,&res); + if(err==-1) + { + fprintf(console,"gpgkeys: error retrieving LDAP server info: %s\n", + ldap_err2string(err)); + goto fail; + } + + if(ldap_count_entries(ldap,res)!=1) + { + fprintf(console,"gpgkeys: more than one serverinfo record\n"); + goto fail; + } + + if(verbose>1) + { + vals=ldap_get_values(ldap,res,"software"); + if(vals!=NULL) + { + fprintf(console,"Server: \t%s\n",vals[0]); + ldap_value_free(vals); + } + + vals=ldap_get_values(ldap,res,"version"); + if(vals!=NULL) + { + fprintf(console,"Version:\t%s\n",vals[0]); + ldap_value_free(vals); + } + } + + /* This is always "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not + be in the future. */ + + vals=ldap_get_values(ldap,res,"basekeyspacedn"); + if(vals!=NULL) + { + basekeyspacedn=strdup(vals[0]); + if(basekeyspacedn==NULL) + { + fprintf(console,"gpgkeys: can't allocate string space " + "for LDAP base\n"); + goto fail; + } + + ldap_value_free(vals); + } + + ldap_msgfree(res); + + switch(action) + { + case GET: + keyptr=keylist; + + while(keyptr!=NULL) + { + if(get_key(keyptr->str)==-1) + failed++; + + keyptr=keyptr->next; + } + break; + + case SEND: + { + int ret; + + do + { + ret=send_key(); + if(ret==-1) + failed++; + } + while(ret!=1); + } + break; + + case SEARCH: + { + char *searchkey=NULL; + int len=0; + + /* To search, we stick a * in between each key to search for. + This means that if the user enters words, they'll get + "enters*words". If the user "enters words", they'll get + "enters words" */ + + keyptr=keylist; + while(keyptr!=NULL) + { + len+=strlen(keyptr->str)+1; + keyptr=keyptr->next; + } + + searchkey=malloc(len+1); + if(searchkey==NULL) + goto fail; + + searchkey[0]='\0'; + + keyptr=keylist; + while(keyptr!=NULL) + { + strcat(searchkey,keyptr->str); + strcat(searchkey,"*"); + keyptr=keyptr->next; + } + + /* Nail that last "*" */ + searchkey[strlen(searchkey)-1]='\0'; + + if(search_key(searchkey)==-1) + { + fprintf(output,"SEARCH %s FAILED\n",searchkey); + failed++; + } + + free(searchkey); + } + + break; + } + + if(!failed) + ret=KEYSERVER_OK; + + fail: + + while(keylist!=NULL) + { + struct keylist *current=keylist; + keylist=keylist->next; + free(current); + } + + if(input!=stdin) + fclose(input); + + if(output!=stdout) + fclose(output); + + if(ldap!=NULL) + ldap_unbind_s(ldap); + + free(basekeyspacedn); + + return ret; +} diff --git a/keyserver/gpgkeys_mailto.in b/keyserver/gpgkeys_mailto.in new file mode 100755 index 000000000..c31048360 --- /dev/null +++ b/keyserver/gpgkeys_mailto.in @@ -0,0 +1,164 @@ +#!@PERL@ -w + +# gpgkeys_mailto - talk to a email keyserver +# Copyright (C) 2001, 2002 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 + +use Getopt::Std; +$sendmail="@SENDMAIL@ -t"; + +### + +getopts('o:'); + +if(defined($opt_o)) +{ + open(STDOUT,">$opt_o") || die "Can't open output file $opt_o\n"; +} + +if(@ARGV) +{ + open(STDIN,$ARGV[0]) || die "Can't open input file $ARGV[0]\n"; +} + +($login,$name)=(getpwuid($<))[0,6]; + +while() +{ + last if($_ eq "\n"); + + if(/^COMMAND (\w+)/) + { + $command=$1; + } + + if(/^HOST (\S+)/) + { + $host=$1; + } + + if(/^OPTION (\w+)/) + { + if($1=~/^verbose$/i) + { + $verbose++; + } + elsif($1=~/^no-verbose$/i) + { + $verbose--; + } + } +} + +while() +{ + last if($_ eq "\n"); + + chomp; + + push(@keys,$_); +} + +# Send response + +print "VERSION 0\n"; +print "OPTION OUTOFBAND\n\n"; + +# Email keyservers get and search the same way + +if($command=~/get/i || $command=~/search/i) +{ + if($command=~/search/i) + { + print "COUNT 0\n"; + } + + foreach $key (@keys) + { + open(MAIL,"|$sendmail") || die "ERROR: Can't open $sendmail\n"; + print MAIL "From: $name <$login>\n"; + print MAIL "To: $host\n"; + if($command=~/get/i) + { + # mail keyservers don't like long-form keyids + + if(substr($key,0,2) eq "0x") + { + $key=substr($key,2); + } + + if(length($key)>8) + { + $key=substr($key,-8); + } + + print MAIL "Subject: GET 0x$key\n\n"; + } + else + { + print MAIL "Subject: GET $key\n\n"; + } + print MAIL "GnuPG keyserver request\n"; + close(MAIL); + + # Tell GnuPG not to expect a key + print "KEY $key OUTOFBAND\n"; + + if($verbose) + { + print STDERR "gpgkeys: key $key requested from $host\n"; + } + } +} + +if($command=~/send/i) +{ + while(!eof(STDIN)) + { + open(MAIL,"|$sendmail") || die "ERROR: Can't open $sendmail\n"; + print MAIL "From: $name <$login>\n"; + print MAIL "To: $host\n"; + print MAIL "Subject: ADD\n\n"; + + while() + { + if(/^KEY (\w+) BEGIN$/) + { + $key=$1; + last; + } + } + + while() + { + if(/^KEY \w+ END$/) + { + last; + } + + print MAIL; + } + + close(MAIL); + + if($verbose) + { + print STDERR "gpgkeys: key $key sent to $host\n"; + } + } +} diff --git a/keyserver/gpgkeys_test.in b/keyserver/gpgkeys_test.in new file mode 100755 index 000000000..09c14bfd4 --- /dev/null +++ b/keyserver/gpgkeys_test.in @@ -0,0 +1,79 @@ +#!@PERL@ + +# gpgkeys_test - keyserver code tester +# Copyright (C) 2001 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 + +use Getopt::Std; + +$|=1; + +print STDERR "gpgkeys_test starting\n"; + +getopts('o:'); + +if(defined($opt_o)) +{ + print STDERR "Using output file $opt_o\n"; + open(STDOUT,">$opt_o") || die "Can't open output file $opt_o\n"; +} + +if(@ARGV) +{ + print STDERR "Using input file $ARGV[0]\n"; + open(STDIN,$ARGV[0]) || die "Can't open input file $ARGV[0]\n"; +} + +# Get the command block + +print STDERR "Command block:\n"; + +while() +{ + last if($_ eq "\n"); + print STDERR "--command-> $_"; + + if(/^COMMAND (\w+)/) + { + $command=$1; + } +} + +# Get the keylist block + +print STDERR "Keylist block:\n"; + +while() +{ + last if($_ eq "\n"); + print STDERR "--keylist-> $_"; +} + +# If it's a SEND, then get the key material + +if($command eq "SEND") +{ + print STDERR "Key material to send:\n"; + + while() + { + print STDERR "$_"; + } +} + +printf STDERR "gpgkeys_test finished\n"; diff --git a/zlib/ChangeLog b/zlib/ChangeLog index 69965ba90..5f06bcc7b 100644 --- a/zlib/ChangeLog +++ b/zlib/ChangeLog @@ -1,3 +1,7 @@ +2002-03-12 Werner Koch + + Merged changes from zlib 1.1.4. + Sat Feb 13 12:04:43 CET 1999 Werner Koch * Makefile.am: Removed -Wall @@ -8,19 +12,27 @@ Wed Jan 20 21:40:21 CET 1999 Werner Koch Wed Jan 13 14:10:15 CET 1999 Werner Koch - - * Merged version 1.1.13 with the previousy used 1.0.4 + Merged version 1.1.3 with the previousy used 1.0.4 Thu Feb 12 12:20:45 1998 Werner Koch (wk@frodo) -- removed a couple of files, as this is only used if zlib is - missing on a system. -- added automake stuff + Removed a couple of files, as this is only used if zlib is + missing on a system. Added automake stuff ChangeLog file for zlib +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + Changes in 1.1.3 (9 July 1998) - fix "an inflate input buffer bug that shows up on rare but persistent occasions" (Mark) @@ -489,3 +501,5 @@ Changes in 0.3: - use Z_FINISH instead of deflateEnd to finish compression. - added Z_HUFFMAN_ONLY - added gzerror() + + diff --git a/zlib/adler32.c b/zlib/adler32.c index 16cf9a703..fae88b655 100644 --- a/zlib/adler32.c +++ b/zlib/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/compress.c b/zlib/compress.c index 1cee47091..814bd9d60 100644 --- a/zlib/compress.c +++ b/zlib/compress.c @@ -1,5 +1,5 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/crc32.c b/zlib/crc32.c index a91101a81..60deca2dd 100644 --- a/zlib/crc32.c +++ b/zlib/crc32.c @@ -1,5 +1,5 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/deflate.c b/zlib/deflate.c index 25d5818e2..16ebdade3 100644 --- a/zlib/deflate.c +++ b/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.1.3 Copyright 1995-1998 Jean-loup Gailly "; + " deflate 1.1.4 Copyright 1995-2002 Jean-loup Gailly "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -242,7 +242,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { return Z_STREAM_ERROR; } diff --git a/zlib/deflate.h b/zlib/deflate.h index 962676da8..b99a48a52 100644 --- a/zlib/deflate.h +++ b/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-1998 Jean-loup Gailly + * Copyright (C) 1995-2002 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/example.c b/zlib/example.c index 8307c841e..e7e367333 100644 --- a/zlib/example.c +++ b/zlib/example.c @@ -1,5 +1,5 @@ /* example.c -- usage example of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/infblock.c b/zlib/infblock.c index f4920faa5..dd7a6d40a 100644 --- a/zlib/infblock.c +++ b/zlib/infblock.c @@ -1,5 +1,5 @@ /* infblock.c -- interpret and process block types to last block - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -249,10 +249,12 @@ int r; &s->sub.trees.tb, s->hufts, z); if (t != Z_OK) { - ZFREE(z, s->sub.trees.blens); r = t; if (r == Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BAD; + } LEAVE } s->sub.trees.index = 0; @@ -313,11 +315,13 @@ int r; t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), s->sub.trees.blens, &bl, &bd, &tl, &td, s->hufts, z); - ZFREE(z, s->sub.trees.blens); if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) + { + ZFREE(z, s->sub.trees.blens); s->mode = BAD; + } r = t; LEAVE } @@ -329,6 +333,7 @@ int r; } s->sub.decode.codes = c; } + ZFREE(z, s->sub.trees.blens); s->mode = CODES; case CODES: UPDATE diff --git a/zlib/infblock.h b/zlib/infblock.h index bd25c8075..173b2267a 100644 --- a/zlib/infblock.h +++ b/zlib/infblock.h @@ -1,5 +1,5 @@ /* infblock.h -- header to use infblock.c - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/infcodes.c b/zlib/infcodes.c index d4e5ee9a5..9abe5412b 100644 --- a/zlib/infcodes.c +++ b/zlib/infcodes.c @@ -1,5 +1,5 @@ /* infcodes.c -- process literals and length/distance pairs - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -196,15 +196,9 @@ int r; Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif + while (f < s->window) /* modulo window size-"while" instead */ + f += s->end - s->window; /* of "if" handles invalid distances */ while (c->len) { NEEDOUT diff --git a/zlib/infcodes.h b/zlib/infcodes.h index 6c750d896..46821a02b 100644 --- a/zlib/infcodes.h +++ b/zlib/infcodes.h @@ -1,5 +1,5 @@ /* infcodes.h -- header to use infcodes.c - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/inffast.c b/zlib/inffast.c index 61a78ee93..aa7f1d4d2 100644 --- a/zlib/inffast.c +++ b/zlib/inffast.c @@ -1,5 +1,5 @@ /* inffast.c -- process literals and length/distance pairs fast - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -93,28 +93,41 @@ z_streamp z; /* do the copy */ m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ + r = q - d; + if (r < s->window) /* wrap if needed */ { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ + do { + r += s->end - s->window; /* force pointer in window */ + } while (r < s->window); /* covers invalid distances */ + e = s->end - r; + if (c > e) { - c -= e; /* copy to end of window */ + c -= e; /* wrapped copy */ do { - *q++ = *r++; + *q++ = *r++; } while (--e); - r = s->window; /* copy rest from start of window */ + r = s->window; + do { + *q++ = *r++; + } while (--c); + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); } } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } break; } else if ((e & 64) == 0) diff --git a/zlib/inffast.h b/zlib/inffast.h index 8facec553..a31a4bbb0 100644 --- a/zlib/inffast.h +++ b/zlib/inffast.h @@ -1,5 +1,5 @@ /* inffast.h -- header to use inffast.c - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/inflate.c b/zlib/inflate.c index 32e9b8de6..dfb2e867d 100644 --- a/zlib/inflate.c +++ b/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib interface to inflate modules - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/inftrees.c b/zlib/inftrees.c index ef1e0b6b8..4c32ca30d 100644 --- a/zlib/inftrees.c +++ b/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -11,7 +11,7 @@ #endif const char inflate_copyright[] = - " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; + " inflate 1.1.4 Copyright 1995-2002 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -104,8 +104,7 @@ uIntf *v; /* working area: values in order of bit length */ /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this - case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of - lengths), or Z_MEM_ERROR if not enough memory. */ + case), or Z_DATA_ERROR if the input is invalid. */ { uInt a; /* counter for codes of length k */ @@ -231,7 +230,7 @@ uIntf *v; /* working area: values in order of bit length */ /* allocate new table */ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_MEM_ERROR; /* not enough memory */ + return Z_DATA_ERROR; /* overflow of MANY */ u[h] = q = hp + *hn; *hn += z; diff --git a/zlib/inftrees.h b/zlib/inftrees.h index 85853e097..04b73b729 100644 --- a/zlib/inftrees.h +++ b/zlib/inftrees.h @@ -1,5 +1,5 @@ /* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/infutil.c b/zlib/infutil.c index 824dab571..9a076221f 100644 --- a/zlib/infutil.c +++ b/zlib/infutil.c @@ -1,5 +1,5 @@ /* inflate_util.c -- data and routines common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/infutil.h b/zlib/infutil.h index 99d1135d0..4401df82f 100644 --- a/zlib/infutil.h +++ b/zlib/infutil.h @@ -1,5 +1,5 @@ /* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler + * Copyright (C) 1995-2002 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/trees.c b/zlib/trees.c index f01fb30d8..0a9840567 100644 --- a/zlib/trees.c +++ b/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1998 Jean-loup Gailly + * Copyright (C) 1995-2002 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/uncompr.c b/zlib/uncompr.c index d10332137..a287714f5 100644 --- a/zlib/uncompr.c +++ b/zlib/uncompr.c @@ -1,5 +1,5 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/zconf.h b/zlib/zconf.h index 6d450fc79..eb0ae2e1a 100644 --- a/zlib/zconf.h +++ b/zlib/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/zlib.h b/zlib/zlib.h index 49f56b43b..52cb529f6 100644 --- a/zlib/zlib.h +++ b/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.1.3, July 9th, 1998 + version 1.1.4, March 11th, 2002 - Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,7 +37,7 @@ extern "C" { #endif -#define ZLIB_VERSION "1.1.3" +#define ZLIB_VERSION "1.1.4" /* The 'zlib' compression library provides in-memory compression and diff --git a/zlib/zutil.c b/zlib/zutil.c index b3de4e883..dfc38ec14 100644 --- a/zlib/zutil.c +++ b/zlib/zutil.c @@ -1,5 +1,5 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/zutil.h b/zlib/zutil.h index 6f2cb97ca..718ebc15b 100644 --- a/zlib/zutil.h +++ b/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. + * Copyright (C) 1995-2002 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */