summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore4
-rw-r--r--ChangeLog112
-rw-r--r--Cipher/__init__.py6
-rw-r--r--Demo/README29
-rwxr-xr-xDemo/cipher150
-rw-r--r--Demo/secimp/README24
-rw-r--r--Demo/secimp/secimp.py84
-rwxr-xr-xDemo/secimp/sign.py46
-rw-r--r--Demo/secimp/testkey.py36
-rw-r--r--Doc/pycrypt.tex1458
-rw-r--r--Doc/pycrypt.txt1400
-rw-r--r--Hash/HAVAL.c398
-rw-r--r--Hash/HMAC.py141
-rw-r--r--Hash/MD2.c120
-rw-r--r--Hash/MD4.c203
-rw-r--r--Hash/MD5.c289
-rw-r--r--Hash/RIPEMD.c519
-rw-r--r--Hash/SHA.c436
-rw-r--r--Hash/__init__.py3
-rw-r--r--Makefile47
-rw-r--r--Makefile.pre.in369
-rw-r--r--Protocol/AllOrNothing.py306
-rw-r--r--Protocol/Chaffing.py220
-rw-r--r--Protocol/PGP/Info/draft-ietf-openpgp-formats2356
-rw-r--r--Protocol/PGP/Info/penguin1.tgzbin0 -> 7453 bytes
-rw-r--r--Protocol/PGP/Info/pgformat.doc343
-rw-r--r--Protocol/PGP/Info/pgpdoc1.txt0
-rw-r--r--Protocol/PGP/Info/pgpdoc2.txt0
-rw-r--r--Protocol/PGP/Info/rfc1991.txt1179
-rw-r--r--Protocol/PGP/Info/scaleweb.txt719
-rw-r--r--Protocol/PGP/Info/stealth173
-rw-r--r--Protocol/PGP/Makefile7
-rw-r--r--Protocol/PGP/README26
-rw-r--r--Protocol/PGP/TODO24
-rw-r--r--Protocol/PGP/config.txt3
-rw-r--r--Protocol/PGP/doc/bugreport89
-rw-r--r--Protocol/PGP/doc/pgp.texi298
-rw-r--r--Protocol/PGP/docerrors.txt5
-rw-r--r--Protocol/PGP/dump.py17
-rw-r--r--Protocol/PGP/excludefiles33
-rwxr-xr-xProtocol/PGP/filepgp61
-rw-r--r--Protocol/PGP/format.doc841
-rw-r--r--Protocol/PGP/keyring.shelvebin0 -> 32768 bytes
-rwxr-xr-xProtocol/PGP/parsepgp39
-rw-r--r--Protocol/PGP/pgp-api.txt74
-rw-r--r--Protocol/PGP/pgp.py1061
-rw-r--r--Protocol/PGP/pgpapi.html191
-rw-r--r--Protocol/PGP/pgpconst.py81
-rw-r--r--Protocol/PGP/pgpdoc1.txt0
-rw-r--r--Protocol/PGP/pgpdoc2.txt0
-rw-r--r--Protocol/PGP/pgpops.py350
-rwxr-xr-xProtocol/PGP/pgpsort.py51
-rw-r--r--Protocol/PGP/prof.py3
-rw-r--r--Protocol/PGP/pubkey.py39
-rw-r--r--Protocol/PGP/pubring.pgpbin0 -> 428 bytes
-rw-r--r--Protocol/PGP/secring.pgpbin0 -> 640 bytes
-rwxr-xr-xProtocol/PGP/shelvepgp35
-rw-r--r--Protocol/PGP/test.pgpbin0 -> 939 bytes
-rw-r--r--Protocol/PGP/test.py79
-rw-r--r--Protocol/PGP/testpub.pgpbin0 -> 423 bytes
-rw-r--r--Protocol/PGP/testsec.pgpbin0 -> 464 bytes
-rw-r--r--Protocol/__init__.py2
-rw-r--r--PublicKey/DSA.py132
-rw-r--r--PublicKey/ElGamal.py103
-rw-r--r--PublicKey/RSA.py85
-rw-r--r--PublicKey/__init__.py3
-rw-r--r--PublicKey/pubkey.py103
-rw-r--r--PublicKey/qNEW.py146
-rw-r--r--README86
-rw-r--r--Setup.in30
-rw-r--r--Setup.in-export15
-rw-r--r--TODO23
-rw-r--r--Util/RFC1751.py340
-rw-r--r--Util/__init__.py3
-rw-r--r--Util/number.py156
-rw-r--r--Util/randpool.py223
-rw-r--r--Util/test.py803
-rw-r--r--Util/testdata.py860
-rw-r--r--__init__.py3
-rw-r--r--_checkversion.py16
-rw-r--r--block/ARC2.c186
-rw-r--r--block/Blowfish.c506
-rw-r--r--block/CAST.c466
-rw-r--r--block/DES.c678
-rw-r--r--block/DES3.c690
-rw-r--r--block/Diamond.c415
-rw-r--r--block/IDEA.c214
-rw-r--r--block/RC5.c233
-rw-r--r--block/Skipjack.c139
-rw-r--r--block/cast5.c437
-rwxr-xr-xbuildkit144
-rw-r--r--curiosa/README161
-rw-r--r--curiosa/arc4.py7
-rw-r--r--curiosa/gentest.py8
-rw-r--r--curiosa/otp.py3
-rw-r--r--curiosa/rsa.py5
-rw-r--r--excludefiles6
-rw-r--r--framewks/block.in561
-rw-r--r--framewks/hash.in285
-rw-r--r--framewks/simple.in3
-rw-r--r--framewks/stream.in279
-rw-r--r--info/architecture.txt647
-rw-r--r--info/connect.txt1001
-rw-r--r--info/digisign.py340
-rw-r--r--info/libdsign.tex146
-rw-r--r--info/mail1867
-rw-r--r--info/rfc2104.html625
-rw-r--r--info/rfc2104.txt619
-rw-r--r--info/transport.txt1178
-rw-r--r--info/userauth.txt647
-rw-r--r--not-for-export10
-rw-r--r--stream/ARC4.c72
-rw-r--r--stream/Sapphire.c125
-rw-r--r--stream/XOR.c51
-rw-r--r--test.py41
115 files changed, 30504 insertions, 0 deletions
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 0000000..f945743
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1,4 @@
+project.log
+tailor.state
+tailor.state.old
+tailor.state.journal \ No newline at end of file
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..81f21a6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,112 @@
+
+Changes since 1.1a1
+===================
+ * Most importantly, the distribution has been broken into two
+parts: exportable, and export-controlled. The exportable part
+contains all the hashing algorithms, signature-only public key
+algorithms, chaffing & winnowing, random number generation, various
+utility modules, and the documentation.
+
+ The export-controlled part contains public-key encryption
+algorithms such as RSA and ElGamal, and bulk encryption algorithms
+like DES, IDEA, or Skipjack. Getting this code still requires that
+you go through an access control CGI script, and denies you access if
+you're outside the US or Canada.
+
+ * Added the RIPEMD hashing algorithm. (Contributed by
+Hirendra Hindocha.)
+
+ * Implemented the recently declassified Skipjack block
+encryption algorithm. My implementation runs at 864 K/sec on a
+PII/266, which isn't particularly fast, but you're probably better off
+using another algorithm anyway. :)
+
+ * A simple XOR cipher has been added, mostly for use by the
+chaffing/winnowing code. (Contributed by Barry Warsaw.)
+
+ * Added Protocol.Chaffing and Hash.HMAC.py. (Contributed by
+Barry Warsaw.)
+
+ Protocol.Chaffing implements chaffing and winnowing, recently
+proposed by R. Rivest, which hides a message (the wheat) by adding
+many noise messages to it (the chaff). The chaff can be discarded by
+the receiver through a message authentication code. The neat thing
+about this is that it allows secret communication without actually
+having an encryption algorithm, and therefore this falls within the
+exportable subset.
+
+ * Tidied up randpool.py, and removed its use of a block
+cipher; this makes it work with only the export-controlled subset
+available.
+
+ * Various renamings and reorganizations, mostly internal.
+
+Changes since 1.0.2
+===================
+
+ * Changed files to work with Python 1.5; everything has been
+re-arranged into a hierarchical package. (Not backward compatible.)
+The package organization is:
+Crypto.
+ Hash.
+ MD2, MD4, MD5, SHA, HAVAL
+ Cipher.
+ ARC2, ARC4, Blowfish, CAST, DES, DES3, Diamond,
+ IDEA, RC5, Sapphire
+ PublicKey.
+ DSA, ElGamal, qNEW, RSA
+ Util.
+ number, randpool, RFC1751
+
+ Since this is backward-incompatible anyway, I also changed
+module names from all lower-case to mixed-case: diamond -> Diamond,
+rc5 -> RC5, etc. That had been an annoying inconsistency for a while.
+
+ * Added CAST5 module contributed by <wiml@hhhh.org>.
+
+ * Added qNEW digital signature algorithm (from the digisign.py
+I advertised a while back). (If anyone would like to suggest new
+algorithms that should be implemented, please do; I think I've got
+everything that's really useful at the moment, but...)
+
+ * Support for keyword arguments has been added. This allowed
+removing the obnoxious key handling for Diamond and RC5, where the
+first few bytes of the key indicated the number of rounds to use, and
+various other parameters. Now you need only do something like:
+
+from Crypto.Cipher import RC5
+obj = RC5.new(key, RC5.ECB, rounds=8)
+
+(Not backward compatible.)
+
+ * Various function names have been changed, and parameter
+names altered. None of these were part of the public interface, so it
+shouldn't really matter much.
+
+ * Various bugs fixed, the test suite has been expanded, and
+the build process simplified.
+
+ * Updated the documentation accordingly.
+
+Changes since 1.0.1:
+====================
+
+ * Changed files to work with Python 1.4 .
+
+ * The DES and DES3 modules now automatically correct the
+parity of their keys.
+
+ * Added R. Rivest's DES test (see http://theory.lcs.mit.edu/~rivest/destest.txt)
+
+ Changes since 1.0.0:
+
+ * REDOC III succumbed to differential cryptanalysis, and has
+been removed.
+
+ * The crypt and rotor modules have been dropped; they're still
+available in the standard Python distribution.
+
+ * The Ultra-Fast crypt() module has been placed in a separate
+distribution; see <http://starship.skyport.net/crew/amk/maintained/crypto.html>.
+
+ * Various bugs fixed.
diff --git a/Cipher/__init__.py b/Cipher/__init__.py
new file mode 100644
index 0000000..dffec17
--- /dev/null
+++ b/Cipher/__init__.py
@@ -0,0 +1,6 @@
+
+__all__ = ['ARC2', 'Blowfish', 'DES', 'DES3', 'IDEA', 'RC5', 'Diamond', 'CAST',
+ 'Skipjack', 'ARC4', 'Sapphire', 'XOR' ]
+
+
+
diff --git a/Demo/README b/Demo/README
new file mode 100644
index 0000000..0e48d7c
--- /dev/null
+++ b/Demo/README
@@ -0,0 +1,29 @@
+This directory contains demonstration files that use the modules
+included in the Python Cryptography Toolkit.
+
+Note: These programs have version numbers of their own, which are not
+necessarily the same as the version number of the Toolkit package.
+
+cipher Encrypt and decrypt sensitive files; type 'cipher -h'
+ for a usage message.
+
+voice Allows secure voice communication over a TCP/IP link.
+ Currently this is Linux-specific; changes to make it
+ run on other systems would be greatly appreciated.
+
+RSAgen.py Generates a new RSA key. Demonstrates using
+ randpool.py, and maintains a file of random data in
+ "randseed". Requires that the IDEA and MD5 modules
+ are installed.
+
+testkey.py RSA public/private key pair used by example programs.
+
+Secure importing of Python modules:
+
+ sign.py Sign all *.pyc files in a directory, using the
+ key defined in testkey.py.
+
+ secimp.py Implementation of the secure 'import' command.
+
+
+
diff --git a/Demo/cipher b/Demo/cipher
new file mode 100755
index 0000000..79c92da
--- /dev/null
+++ b/Demo/cipher
@@ -0,0 +1,150 @@
+#!/usr/bin/env python
+# -*-Python-*-
+# Cipher 1.00
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# 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.
+#
+
+import sys, getopt, os
+
+# Determine the name of this executable
+executable = os.path.basename(sys.argv[0])
+if executable=='': executable='cipher'
+cipher = '' # Unknown ciphering algorithm
+key = (0, '') # Empty key
+magic = 'ctx\001' # Magic string prefixed to the data
+NoInputFile = '' # Exceptions raised on file errors
+NoOutputFile = ''
+
+def PrintUsage():
+ print 'Usage: cipher [OPTIONS] file1 file2 ...'
+ print '\n -c ciphername Force use of ciphername to encrypt/decrypt'
+ print ' -k key Key to use for encryption/decryption'
+ print '\nThe default cipher algorithm is IDEA; if no key is set on the command'
+ print 'line, you will be prompted to enter a key.'
+ print 'Files are read completely into memory, so do not try to encrypt'
+ print 'very large files.'
+
+def GenerateIV(length):
+ import whrandom
+ IV=''
+ for i in range(0, length):
+ IV=IV + chr(int(256*whrandom.random()))
+ return IV
+
+def Encipher(filename, cipher, key):
+ if (cipher==''): cipher='IDEA'
+ try:
+ exec ('from Crypto.Cipher import '+cipher)
+ module=eval(cipher)
+ except ImportError:
+ print executable+ ':', cipher, ': Cipher does not exist.'
+ sys.exit(1)
+ import Crypto.Hash.MD5
+ try:
+ input=open(filename, 'r')
+ except IOError:
+ raise NoInputFile
+ try:
+ output=open(filename+'.cip', 'w')
+ except IOError:
+ raise NoOutputFile, filename+'.cip'
+
+ if (key[0]==0):
+ key=raw_input('Enter encryption key for '+ filename+ ':')
+ else: key=key[1]
+ key=Crypto.Hash.MD5.new(key).digest()
+ IV=''
+ for i in range(0, module.blocksize): IV=IV+'A'
+ if (module.keysize==0):
+ cipherobj=module.new(key, module.CBC, IV)
+ else:
+ cipherobj=module.new(key[0:module.keysize], module.CBC, IV)
+ output.write(magic+cipher+'\0')
+ data = GenerateIV(module.blocksize)
+ filedata=input.read()
+ data = data + magic + str(len(filedata))+'\0'+filename+'\0'
+ data = data + filedata
+ input.close()
+ padding=module.blocksize - (len(data) % module.blocksize)
+ for i in range(0, padding):
+ data = data + chr(i)
+ ciphertext=cipherobj.encrypt(data)
+ output.write(ciphertext)
+ output.close()
+
+def Decipher(filename, cipher, key):
+ import Crypto.Hash.MD5, string
+ try:
+ input=open(filename, 'r')
+ except IOError:
+ raise NoInputFile
+ if (input.read(len(magic))!=magic):
+ print executable+':', filename+': Does not seem to be a ciphered file'
+ return
+ t=''
+ while (1):
+ c=input.read(1)
+ if (ord(c)==0): break
+ t=t+c
+ if (cipher==''): cipher=t
+ try:
+ from Crypto.Cipher import *
+ module=eval(cipher)
+ except ImportError:
+ print executable+ ':', cipher, ': Cipher does not exist.'
+ sys.exit(1)
+ if (key[0]==0):
+ key=raw_input('Enter encryption key for '+ filename+ ':')
+ else: key=key[1]
+ key=Crypto.Hash.MD5.new(key).digest()
+ IV = ''
+ for i in range(0, module.blocksize): IV=IV+'A'
+ data=input.read()
+ if (module.keysize==0):
+ cipherobj=module.new(key, module.CBC, IV)
+ else:
+ cipherobj=module.new(key[0:module.keysize], module.CBC, IV)
+ plain=cipherobj.decrypt(data) # Decrypt the data
+ plain=plain[module.blocksize:] # Discard first block of random data
+ if (plain[0:len(magic)]!=magic):
+ print executable+':', filename+': Incorrect key or cipher algorithm'
+ return
+ else: plain=plain[len(magic):]
+ i=string.find(plain, '\0')
+ length=string.atoi(plain[0:i])
+ j=string.find(plain, '\0', i+1)
+ newfilename=plain[i+1:j]
+ try:
+ output=open(newfilename, 'w')
+ except IOError:
+ raise NoOutputFile, newfilename
+ output.write(plain[j+1:j+1+length])
+ output.close()
+
+if len(sys.argv)==1: PrintUsage() ; sys.exit(0)
+
+options, args=getopt.getopt(sys.argv[1:], 'c:k:hH')
+for opt in options:
+ letter, param = opt
+ if (letter=='-c'): cipher = param
+ if (letter=='-k'): key = (1, param)
+ if (letter=='-h' or letter=='-H'):
+ PrintUsage()
+ sys.exit(0)
+
+for file in args:
+ try:
+ if (file[-4:]=='.cip'):
+ Decipher(file, cipher, key)
+ else:
+ Encipher(file, cipher, key)
+ except NoInputFile:
+ print executable+ ':', file+ ': No such file.'
+ except NoOutputFile, filename:
+ print executable+ ':', filename+ ': Cannot open file'
+
diff --git a/Demo/secimp/README b/Demo/secimp/README
new file mode 100644
index 0000000..94a6e30
--- /dev/null
+++ b/Demo/secimp/README
@@ -0,0 +1,24 @@
+
+This is a simple demonstration of adding an import hook that verifies
+a digital signature on a Python code object before allowing it to be
+imported. There are three files:
+
+ * sign.py, which signs all the *.pyc files in the directories
+listed on the command line. The contents of the .pyc file is stored
+along with the signature in a file whose name ends with .pys .
+
+ * secimp.py, which implements a secimport() function which
+will use *.pys files.
+
+ * testkey.py is the key used to sign and verify *.pys files.
+
+To try it out:
+ 1. Run "sign.py ." to compile and sign all the *.py files in
+the current directory.
+
+ 2. Run secimp.py from the command-line; it will try to
+securely import testkey.pys, which should succeed.
+
+ 3. Fire up your favorite editor, and change a single byte in a
+string somewhere in testkey.pys. Run secimp.py again; it should raise
+an exception when the signature can't be verified.
diff --git a/Demo/secimp/secimp.py b/Demo/secimp/secimp.py
new file mode 100644
index 0000000..a1ecb1d
--- /dev/null
+++ b/Demo/secimp/secimp.py
@@ -0,0 +1,84 @@
+#!/usr/local/bin/python
+
+import sys ; sys.path = ['../../../'] + sys.path
+
+import imp, os
+from sys import modules
+
+# Secure import:
+def secimport(name, globals=None, locals=None, fromlist=None):
+ # Fast path: let's see if it's already in sys.modules.
+ # Two speed optimizations are worth mentioning:
+ # - We use 'modules' instead of 'sys.modules'; this saves a
+ # dictionary look-up per call.
+ # - It's also faster to use a try-except statement than
+ # to use modules.has_key(name) to check if it's there.
+ try:
+ return modules[name]
+ except KeyError:
+ pass
+
+ # See if it's a built-in module
+ m = imp.init_builtin(name)
+ if m:
+ return m
+
+ # See if it's a frozen module
+ m = imp.init_frozen(name)
+ if m:
+ return m
+
+ # Search the default path (i.e. sys.path).
+ # If this raises an exception, the module is not found --
+ # let the caller handle the exception.
+ fp, pathname, (suffix, mode, type) = imp.find_module(name)
+
+ # See what we got...
+ # Note that fp will be closed automatically when we return.
+
+ # Extensions are written in C, and can just be loaded.
+ if type == imp.C_EXTENSION:
+ return imp.load_dynamic(name, pathname)
+
+ # For a compiled or source file, we'll check if there is a *.pys file
+ # present in the same directory.
+ if type == imp.PY_COMPILED or type == imp.PY_SOURCE:
+ root, ext = os.path.splitext(pathname)
+ testfile = root + '.pys'
+ try:
+ print testfile
+ secfile=open(testfile, 'rb')
+ except IOError, tuple:
+ if (tuple[0]==2): pass # Ignore 'file not found' error
+ else: raise IOError, tuple
+ else:
+ # Check the signature (a signed hash of the code object).
+ # We could sign the whole code object, but that would
+ # require a huge key and would double the size of the
+ # *.pys file.
+ import marshal
+ from Crypto.Hash import MD5
+ fp.close() # Close the original *.pyc file
+ from testkey import * # Get the key for verification
+ signature=marshal.load(secfile) # Read signature
+ position=secfile.tell() # Save position
+ data=secfile.read() # Read code object
+ hash=MD5.new(data).digest() # Compute its hash value
+ ##print 'sigcheck:', key.verify(hash, signature)
+ if (not key.verify(hash, signature)):
+ raise ImportError, 'Signature check of '+ testfile + ' failed'
+ secfile.seek(position) # Rewind pointer to the
+ # beginning of the code object
+ fp=secfile
+ del secfile
+ # Now we can happily import the compiled code object.
+ return imp.load_compiled(name, pathname, fp)
+
+ # Shouldn't get here at all.
+ raise ImportError, '%s: unknown module type (%d)' % (name, type)
+
+if __name__=='__main__':
+ # A sample invocation of the secure import looks like this:
+ print 'Attempting secure import'
+ r=secimport('testkey')
+ print 'Secure import succeeded'
diff --git a/Demo/secimp/sign.py b/Demo/secimp/sign.py
new file mode 100755
index 0000000..727bef6
--- /dev/null
+++ b/Demo/secimp/sign.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Using the public key defined in testkey.py, sign all *.pyc files in
+# the listed directories.
+
+from testkey import *
+from Crypto.Hash import MD5
+import os, glob, sys
+import marshal, compileall
+
+filelist = []
+if (len(sys.argv)>1):
+ for dir in sys.argv[1:]:
+ dir=os.path.join(dir, '')
+ compileall.compile_dir(dir)
+ filelist=filelist + glob.glob(dir + '*.pyc')
+else:
+ print "Usage: sign.py dir1 dir2 dir3 ..."
+ print " All *.pyc files in the listed directories will be signed,"
+ print "leaving the signatures in *.pys files."
+ sys.exit(0)
+
+if len(filelist)==0:
+ print "No *.pyc files found"
+ sys.exit(0)
+
+for file in filelist:
+ input=open(file, 'rb')
+ try:
+ os.unlink(file[:-4]+'.pys') # Delete any existing signed file
+ except os.error, tuple:
+ if (tuple[0]==2): pass # Ignore 'file not found' error
+ else: raise os.error, tuple
+ output=open(file[:-4]+'.pys', 'wb')
+ data=input.read()
+ hash=MD5.new(data).digest() # Compute hash of the code object
+ K = "random bytes"
+ signature=key.sign(hash, K) # Sign the hash value
+ marshal.dump(signature, output) # Save signature to the file
+ output.write(data) # Copy code object to signed file
+ input.close()
+ output.close()
+ print os.path.basename(file)+ ' processed.'
+
+
+
diff --git a/Demo/secimp/testkey.py b/Demo/secimp/testkey.py
new file mode 100644
index 0000000..d32d284
--- /dev/null
+++ b/Demo/secimp/testkey.py
@@ -0,0 +1,36 @@
+
+import sys
+#sys.path = ['../../..', sys.path]
+
+import Crypto.PublicKey.DSA
+
+key = Crypto.PublicKey.DSA.construct((
+ # y
+ 0x43E9162E224CBD1B66D7C27EB7E795392310B5E7AC6E0B1F60021F5E03F90E851CB7F76603FAE73907154371AE04EDBF0D9D557DF03488F34C18324B8DFEF5D2L,
+ # g
+ 0x4D6DB63479E55D0BE31CF1BEA58AB9365FC5EA267FFCD8424B56390E6EE7DD9BF788F696EED8475516353E61F37B8441137FA4F8DC82A9F84FA52BCD37517C32L,
+ # p
+ 0x8000011124427A59DC0AF8AC982B490C75B1B3E94042F50F500E0636391C6FCC8C13E628528B4B75E158618A34592D5A68CA684371F9678BBA54DD40C0020F25L,
+ # q
+ 0x9B128544B02353FF961E1774D2FA94E52E078F5DL,
+ # x
+ 0x991386B7B92C221E42B1386D61255F5C58FD79A7L,
+))
+
+if __name__ == '__main__':
+ # Running this script directly will generate a new key and print it out
+ from Crypto.PublicKey import DSA
+ from Crypto.Util.randpool import KeyboardRandomPool
+
+ pool = KeyboardRandomPool(numbytes = 64)
+ pool.Randomize()
+
+ key = DSA.generate(512, pool.getBytes, sys.stdout.write)
+ print "key = Crypto.PublicKey.DSA.construct(("
+ for field in key.keydata:
+ print " #", field
+ print " " + hex(getattr(key, field)) + ","
+ print '))'
+
+
+
diff --git a/Doc/pycrypt.tex b/Doc/pycrypt.tex
new file mode 100644
index 0000000..365ed70
--- /dev/null
+++ b/Doc/pycrypt.tex
@@ -0,0 +1,1458 @@
+\documentclass{howto}
+
+\title{The Python Cryptography Modules}
+
+\release{1.1.0}
+
+\author{A.M. Kuchling}
+\authoraddress{\email{akuchling@acm.org}}
+
+\begin{document}
+\maketitle
+
+\begin{abstract}
+\noindent
+This document describes a package containing various cryptographic
+modules available for the Python programming language. It assumes you
+have some basic knowledge about the Python language and about
+cryptography in general.
+\end{abstract}
+
+\tableofcontents
+
+\section{Introduction}
+
+\subsection{Design Goals}
+The Python cryptography modules are intended to provide a reliable and
+stable base for writing Python programs that require
+cryptographic functions.
+
+A central goal of the author's has been to provide a
+simple, consistent interface for similar classes of algorithms. For
+example, all block cipher objects have the same methods and return
+values, and support the same feedback modes; hash functions have a
+different interface, but it too is consistent over all the
+hash functions available. Individual modules also define variables to
+help you write Python code that doesn't depend on the algorithms used;
+for example, each block cipher module defines a variable that gives
+the algorithm's block size. This is intended to make it easy to
+replace old algorithms with newer, more secure ones. If you're given
+a bit of portably-written Python code that uses the DES encryption
+algorithm, you should be able to use IDEA instead by simply changing
+\code{from Crypto.Cipher import DES} to \code{from Crypto.Cipher import
+idea}, and changing all references to
+\code{DES.new()} to \code{IDEA.new()}. It's also fairly simple to write
+your own modules that mimic this interface, thus letting you use
+combinations or permutations of algorithms.
+
+\index{C language}
+\index{language, C}
+\index{Intel}
+Some modules are implemented in C for performance; others are written in
+Python for ease of modification. Generally, low-level functions like
+ciphers and hash functions are written in C, while less speed-critical
+functions have been written in Python. This division may change in
+future releases. When speeds are quoted in this document, they were
+measured on a 266 MHz Pentium II running Linux. The exact speeds will obviously
+vary with different machines and different compilers, but they provide a
+basis for comparing algorithms. Currently the cryptographic
+implementations are acceptably fast, but not spectacularly good. I
+welcome any suggestions or patches for faster code.
+
+% You may be surprised that I'm distributing the code worldwide. Aren't
+% North Americans prohibited from exporting cryptographic software? Well,
+% yes and no. American citizens have to get permission from the US
+% government before exporting \emph{any} such software, even if it's
+% publicly available or originated outside the US; there are no exceptions
+% whatsoever.
+
+% The laws in Canada are slightly less restrictive, though, and I'm a
+% Canadian citizen. In particular, free software is specifically exempted
+% from export restrictions, so I'm acting within the law. However, if
+% you're a US citizen, you \emph{still} can't export these programs
+% without government permission.
+
+\index{ITAR, regulations}
+\index{regulations, ITAR}
+If you live outside of Canada or the US, please do not attempt to
+download it from a North American FTP site; you may get the site's
+maintainer in trouble. Documentation is not covered by the ITAR
+regulations, and can be freely sent anywhere in the world.
+
+\index{licensing terms}
+I have placed the code under no restrictions; you can redistribute the
+code freely or commercially, in its original form or with any
+modifications you make, subject to whatever local laws may apply in your
+jurisdiction. Note that you still have to come to some agreement with
+the holders of any patented algorithms you're using. If you're
+intensively using these modules, please tell me about it; there's little
+incentive for me to work on this package if I don't know of anyone using
+it.
+
+I also make no guarantees as to the usefulness, correctness, or legality
+of these modules, nor does their inclusion constitute an endorsement of
+their effectiveness. Many cryptographic algorithms are patented;
+inclusion in this package does not necessarily mean you are allowed to
+incorporate them in a product and sell it. Some of these algorithms may
+have been cryptanalyzed, and may no longer be secure. While I will
+include commentary on the relative security of the algorithms in the
+sections entitled "Security Notes", there may be more recent analyses
+I'm not aware of. (Or maybe I'm just clueless.) If you're implementing
+an important system, don't just grab things out of a toolbox and put
+them together; do some research first. On the other hand, if you're
+just interested in keeping your co-workers or your relatives out of your
+files, any of the components here could be used.
+
+This document is very much a work in progress. If you have any
+questions, comments, complaints, or suggestions, please send them to me
+at \email{akuchling@acm.org}.
+
+\subsection{Acknowledgements}
+\index{Schneier, Bruce}
+Much of the code that actually implements the various cryptographic
+algorithms was not written by me. I'd like to thank all the people who
+implemented them, and released their work under terms which allowed me
+to use their code. The individuals are credited in the relevant
+chapters of this documentation. Bruce Schneier's book \emph{Applied
+Cryptography} was also very useful in writing this toolkit; I highly
+recommend it if you're interested in learning more about cryptography.
+Mr. Schneier also has a Web site at \url{http://www.counterpane.com}.
+
+Good luck with your cryptography hacking!
+
+A.M.K.
+
+\email{akuchling@acm.org}
+
+Washington, DC, USA
+
+January 1998
+
+\section{Crypto.Hash: Hash Functions}
+
+\index{MD2 (hash function)}
+\index{MD5 (hash function)}
+\index{SHA (hash function)}
+\index{HAVAL (hash function)}
+Hash functions take arbitrary strings as input, and produce an output
+of fixed size that is dependent on the input; it should never be
+possible to derive the input data given only the hash function's
+output. One simple hash function consists of simply adding together
+all the bytes of the input, and taking the result modulo 256. For a
+hash function to be cryptographically secure, it must be very
+difficult to find two messages with the same hash value, or to find a
+message with a given hash value. The simple additive hash function
+fails this criterion miserably; the hash functions described below do
+not. Examples of cryptographically secure hash functions include MD2,
+MD5, SHA, and HAVAL.
+
+Hash functions can be used simply as a checksum, or, in association with a
+public-key algorithm, can be used to implement digital signatures.
+
+The hashing algorithms currently implemented are listed in the following table:
+
+\begin{tableii}{c|l}{}{Hash function}{Digest length}
+\lineii{HAVAL}{Variable size: 128, 160, 192, 224, or 256 bits}
+\lineii{MD2}{128 bits}
+\lineii{MD4}{128 bits}
+\lineii{MD5}{128 bits}
+\lineii{RIPEMD}{160 bits}
+\lineii{SHA}{160 bits}
+\end{tableii}
+
+All hashing modules share the same interface. After importing a given
+hashing module, call the \code{new()} function to create a new hashing
+object. (In older versions of the Python interpreter, the \code{md5()}
+function was used to perform this task. If you're modifying an old script, you
+should change any calls to \code{md5()} to use \code{new()} instead.) You
+can now feed arbitrary strings into the object, and can ask for the
+hash value at any time. The \code{new()} function can also be passed an
+optional string parameter, which will be hashed immediately.
+
+Hash function modules define one variable:
+
+\begin{datadesc}{digestsize}
+An integer value; the size of the digest
+produced by the hashing objects. You could also obtain this value by
+creating a sample object, and taking the length of the digest string
+it returns, but using \code{digestsize} is faster.
+\end{datadesc}
+
+The methods for hashing objects are always the following:
+
+\begin{funcdesc}{copy}{}
+Return a separate copy of this hashing object. An \code{update} to this
+ copy won't affect the original object.
+\end{funcdesc}
+
+\begin{funcdesc}{digest}{}
+Return the hash value of this hashing object, as a string containing 8-bit data. The object is not
+altered in any way by this function; you can continue updating the
+object after calling this function.
+\end{funcdesc}
+
+\begin{funcdesc}{digest}{}
+Return the hash value of this hashing object, as a string containing the
+digest data as hexadecimal digits. The resulting string will be twice
+as long as that returned by \code{digest()}. The object is not altered
+in any way by this function; you can continue updating the object after
+calling this function.
+\end{funcdesc}
+
+\begin{funcdesc}{update}{arg}
+Update this hashing object with the string \var{arg}.
+\end{funcdesc}
+
+\index{RSA Data Security, Inc.}
+\index{MD5 (hash function)}
+Here's an example, using RSA Data Security's MD5 algorithm:
+
+\begin{verbatim}
+>>> from Crypto.Hash import MD5
+>>> m = MD5.new()
+>>> m.update('abc')
+>>> m.digest()
+'\220\001P\230<\322O\260\326\226?@}(\341\177r'
+\end{verbatim}
+
+
+Or, more compactly:
+\begin{verbatim}
+>>> MD5.new('abc').digest()
+'\220\001P\230<\322O\260\326\226?@}(\341\177r'
+\end{verbatim}
+
+\subsection{Algorithm-specific Notes for Hash Functions}
+
+HAVAL provides a variable-size digest, and allows for a variable number
+of rounds. It's believed that increasing the number of rounds increases
+the security; at least, I don't know of any results to the contrary.
+The \code{HAVAL.new()} accordingly has two keyword arguments,
+\code{rounds} and \code{digestsize}. \code{rounds} can be 3, 4, or 5,
+and has a default value of 5. \code{digestsize} can be 128, 160, 192,
+224, or 256 bits, and has a default value of 256.
+
+\subsection{Security Notes}
+Hashing algorithms are broken when it's easy to compute a
+string that produces a given hash value, or to find two
+messages that produce the same hash value. Consider an example where
+Alice and Bob are using digital signatures to sign a contract. Alice
+computes the hash value of the text of the contract and signs it. Bob
+could then compute a different contract that has the same hash value,
+and it would appear that Alice has signed that bogus contract; she'd
+have no way to prove otherwise. Finding such a message by brute force
+takes \code{pow(2, b-1)} operations, where the hash function produces
+\emph{b}-bit hashes.
+
+If Bob can only find two messages with the same hash value but can't
+choose the resulting hash value, he can look for two messages with
+different meanings, such as "I will mow Bob's lawn for $10" and "I owe
+Bob $1,000,000", and ask Alice to sign the first, innocuous contract.
+This attack is easier for Bob, since finding two such messages by brute
+force will take \code{pow(2, b/2)} operations on average. However,
+Alice can protect herself by changing the protocol; she can simply
+append a random string to the contract before hashing and signing it;
+the random string can then be kept with the signature.
+
+None of the algorithms implemented here have been completely broken.
+There are no attacks on MD2, but it's rather slow at 376 K/sec. MD4 is
+faster at 11946 K/sec but there have been some partial attacks on it. MD4
+operates in three iterations of a basic mixing operation; two of the
+three rounds have been cryptanalyzed, but the attack can't be extended
+to the full algorithm. MD5 is a strengthened version of MD4 with four
+rounds; an attack against one round has been found. XXX Dobbertin's
+attack. Because MD5 is more
+commonly used, the implementation is better optimized and thus faster on
+x86 processors (27193 K/sec). MD4 may be faster than MD5 when other
+processors and compilers are used.
+
+All the MD algorithms produce 128-bit hashes; SHA produces a larger 160-bit
+hash, and there are no known attacks against it. The first version of
+SHA had a weakness which was later corrected; the code used here
+implements the second, corrected, version. It operates at 13157 K/sec.
+RIPEMD also has a 160-bit output, and operates at 5869 K/sec.
+HAVAL is a variable-size hash function; it can generate hash values that
+are 128, 160, 192, 224, or 256 bits in size, and can use 3, 4, or 5
+rounds. 5-round HAVAL runs at 5371 K/sec.
+
+\subsection{Credits}
+\index{Plumb, Colin}
+\index{Kuchling, Andrew}
+\index{Gutmann, Peter}
+The MD2, MD4, and HAVAL implementations were written by A.M. Kuchling,
+and the MD5 code was implemented by Colin Plumb. The SHA code was
+originally written by Peter Gutmann. The RIPEMD code was written by
+Antoon Bosselaers, and adapted for the toolkit by Hirendra Hindocha.
+
+\section{Crypto.Cipher: Encryption Algorithms}
+Encryption algorithms transform their input data (called
+\dfn{plaintext}) in some way that is
+dependent on a variable \dfn{key}, producing \dfn{ciphertext};
+this transformation can easily be reversed, if (and, hopefully, only
+if) one knows the key. The key can be varied by the user or
+application, chosen from some very large space of possible keys.
+
+For a secure encryption algorithm, it should be very difficult to
+determine the original plaintext without knowing the key; usually, no
+clever attacks on the algorithm are known, so the only way of breaking
+the algorithm is to try all possible keys. Since the number of possible
+keys is usually of the order of 2 to the power of 56 or 128, this is not
+a serious threat, although 2 to the power of 56 is now considered
+insecure in the face of custom-built parallel computers and distributed
+key guessing efforts.
+
+\index{feedback mode, ECB}
+\dfn{Block ciphers} take multibyte inputs of a fixed size
+(frequently 8 or 16 bytes long) and encrypt them. Block ciphers can
+be operated in various modes. The simplest is Electronic Code Book
+(or ECB) mode. In this mode, each block of plaintext is simply
+encrypted to produce the ciphertext. This mode can be dangerous,
+because many files will contain patterns greater than the block size;
+for example, the comments in a C program may contain long strings of
+asterisks intended to form a box. All these identical blocks will
+encrypt to identical ciphertext; an adversary may be able to use this
+structure to obtain some information about the text.
+
+\index{feedback mode, CBC}
+\index{feedback mode, CFB}
+To eliminate this weakness, there are various feedback modes, where
+the plaintext is combined with the previous ciphertext before
+encrypting; this eliminates any such structure. One mode is Cipher
+Block Chaining (CBC mode); another is Cipher FeedBack (CFB
+mode). CBC mode still encrypts in blocks, and thus is only
+slightly slower than ECB mode. CFB mode encrypts on a byte-by-byte
+basis, and is much slower than either of the other two modes. The
+chaining feedback modes require an initialization value to start off
+the encryption; this is a string of the same length as the ciphering
+algorithm's block size, and is passed to the \code{new()} function.
+
+There is also a special PGP mode, which is a variant
+of CFB used by the PGP program. While you can use it in non-PGP
+programs, it's quite non-standard.
+
+The currently available block ciphers are listed in the following table,
+and are available in the \code{Crypto.Cipher} package:
+
+\index{DES (block cipher)}
+\index{DES3 (block cipher)}
+\index{Triple DES (block cipher)}
+\index{Diamond (block cipher)}
+\index{RC5 (block cipher)}
+\index{IDEA (block cipher)}
+\index{Blowfish (block cipher)}
+\index{ARC2 (block cipher)}
+\index{CAST (block cipher)}
+
+\begin{tableii}{c|l}{}{Cipher}{Key Size/Block Size}
+\lineii{ARC2}{Variable/8 bytes}
+\lineii{Blowfish}{Variable/8 bytes}
+\lineii{CAST}{Variable/8 bytes}
+\lineii{DES}{8 bytes/8 bytes}
+\lineii{DES3 (Triple DES)}{16 bytes/8 bytes}
+\lineii{Diamond}{Variable/16 bytes}
+\lineii{IDEA}{16 bytes/8 bytes}
+\lineii{RC5}{Variable/8 bytes}
+\end{tableii}
+
+\index{stream cipher}
+In a strict formal sense, \dfn{stream ciphers} encrypt data bit-by-bit;
+practically, stream ciphers work on a character-by-character basis.
+Stream ciphers use exactly the
+same interface as block ciphers, with a block length that will always
+be 1; this is how block and stream ciphers can be distinguished.
+The only feedback mode available for stream ciphers is ECB mode.
+
+The currently available stream ciphers are listed in the following table:
+
+\index{Sapphire (stream cipher)}
+\index{ARC4 (stream cipher)}
+\begin{tableii}{c|l}{}{Cipher}{Key Size}
+\lineii{Cipher}{Key Size}
+\lineii{ARC4}{Variable}
+\lineii{Sapphire}{Variable}
+\end{tableii}
+
+\index{RSA Data Security, Inc.}
+\index{sci.crypt}
+\index{RC4 (stream cipher)}
+\index{ARC4 (stream cipher)}
+ARC4 is short for `Alleged RC4'. The real RC4 algorithm is proprietary
+to RSA Data Security Inc. In September of 1994, someone posted C code
+to both the Cypherpunks mailing list and to the Usenet newsgroup
+\code{sci.crypt}, claiming that it implemented the RC4 algorithm. This
+posted code is what I'm calling Alleged RC4, or ARC4 for short. I don't
+know if ARC4 is in fact RC4, but ARC4 has been subjected to scrutiny on
+the Cypherpunks mailing list and elsewhere, and does not seem to be
+easily breakable. The legal issues surrounding the use of ARC4 are
+unclear, but be aware that it hasn't been subject to much scrutiny, and
+may have some critical flaw that hasn't yet been discovered. The same
+is true of ARC2, which was posted in January, 1996.
+
+An example usage of the DES module:
+\begin{verbatim}
+>>> from Crypto.Cipher import DES
+>>> obj=DES.new('abcdefgh', DES.ECB)
+>>> plain="Guido van Rossum is a space alien."
+>>> len(plain)
+34
+>>> obj.encrypt(plain)
+Traceback (innermost last):
+ File "<stdin>", line 1, in ?
+ValueError: Strings for DES must be a multiple of 8 in length
+>>> ciph=obj.encrypt(plain+'XXXXXX')
+>>> ciph
+'\021,\343Nq\214DY\337T\342pA\372\255\311s\210\363,\300j\330\250\312\347\342I\3215w\03561\303dgb/\006'
+>>> obj.decrypt(ciph)
+'Guido van Rossum is a space alien.XXXXXX'
+\end{verbatim}
+
+
+All cipher algorithms share a common interface. After importing a
+given module, there is exactly one function and two variables
+available.
+
+\begin{funcdesc}{new}{key, mode\optional{, IV}}
+Returns a ciphering object, using \var{key} and feedback mode
+\var{mode}. If \var{mode} is CBC or CFB, \var{IV} must be provided,
+and must be a string of the same length as the block size. Some
+algorithms support additional keyword arguments to this function; see
+the "Algorithm-specific Notes for Encryption Algorithms" section below for the details.
+\end{funcdesc}
+
+\begin{datadesc}{blocksize}
+An integer value; the size of the blocks encrypted by this module.
+Strings passed to the \code{encrypt} and \code{decrypt} functions
+must be a multiple of this length. For stream ciphers,
+\code{blocksize} will be 1.
+\end{datadesc}
+
+\begin{datadesc}{keysize}
+An integer value; the size of the keys required by this module. If
+\code{keysize} is zero, then the algorithm accepts arbitrary-length
+keys. You cannot pass a key of length 0 (that is, the null string
+\code{''} as such a variable-length key.
+\end{datadesc}
+
+All cipher objects have at least three attributes:
+
+\begin{datadesc}{blocksize}
+An integer value equal to the size of the blocks encrypted by this object.
+Identical to the module variable of the same name.
+\end{datadesc}
+
+\begin{datadesc}{IV}
+Contains the initial value which will be used to start a cipher
+feedback mode. After encrypting or decrypting a string, this value
+will reflect the modified feedback text; it will always be one block
+in length. It is read-only, and cannot be assigned a new value.
+\end{datadesc}
+
+\begin{datadesc}{keysize}
+An integer value equal to the size of the keys used by this object. If
+\code{keysize} is zero, then the algorithm accepts arbitrary-length
+keys. For algorithms that support variable length keys, this will be 0.
+Identical to the module variable of the same name.
+\end{datadesc}
+
+All ciphering objects have the following methods:
+
+\begin{funcdesc}{decrypt}{string}
+Decrypts \var{string}, using the key-dependent data in the object, and
+with the appropriate feedback mode. The string's length must be an exact
+multiple of the algorithm's block size. Returns a string containing
+the plaintext.
+\end{funcdesc}
+
+\begin{funcdesc}{encrypt}{string}
+Encrypts a non-null \var{string}, using the key-dependent data in the
+object, and with the appropriate feedback mode. The string's length
+must be an exact multiple of the algorithm's block size; for stream
+ciphers, the string can be of any length. Returns a string containing
+the ciphertext.
+\end{funcdesc}
+
+\subsection{Algorithm-specific Notes for Encryption Algorithms}
+
+The Diamond block cipher allows you to select the number of rounds to
+apply, ranging from 5 to 15 (inclusive.) This is set via the
+\code{rounds} keyword argument to the \code{new()} function; the default
+value is 8 rounds.
+
+RC5 has even more parameters; see Ronald Rivest's paper at \url{http://theory.lcs.mit.edu/~rivest/rc5rev.ps}
+for the implementation details. The keyword parameters are:
+
+\begin{itemize}
+\item \code{version}:
+The version
+of the RC5 algorithm to use; currently the only legal value is
+\code{0x10} for RC5 1.0.
+\item \code{wordsize}:
+The word size to use;
+16 or 32 are the only legal values. (A larger word size is better, so
+usually 32 will be used. 16-bit RC5 is probably only of academic
+interest.)
+\item \code{rounds}:
+The number of rounds to apply, the larger the more secure: this
+can be any value from 0 to 255, so you will have to choose a value
+balanced between speed and security.
+\end{itemize}
+
+\subsection{Security Notes}
+Encryption algorithms can be broken in several ways. If you have some
+ciphertext and know (or can guess) the corresponding plaintext, you can
+simply try every possible key in a \dfn{known-plaintext} attack. Or, it
+might be possible to encrypt text of your choice using an unknown key;
+for example, you might mail someone a message intending it to be
+encrypted and forwarded to someone else. This is a
+\dfn{chosen-plaintext} attack, which is particularly effective if it's
+possible to choose plaintexts that reveal something about the key when
+encrypted.
+
+DES (2458 K/sec) has a 56-bit key; this is starting to become too small
+for safety. It has been estimated that it would only cost \$1,000,000 to
+build a custom DES-cracking machine that could find a key in 3 hours. A
+chosen-ciphertext attack using the technique of \dfn{linear
+cryptanalysis} can break DES in \code{pow(2, 43)} steps. However,
+unless you're encrypting data that you want to be safe from major
+governments, DES will be fine. DES3 (509 K/sec) uses three DES
+encryptions for greater security and a 112-bit or 168-bit key, but is
+correspondingly slower.
+
+There are no publicly known attacks against IDEA (2005 K/sec), and
+it's been around long enough to have been examined. There are no
+known attacks against ARC2 (1644 K/sec), ARC4 (4630 K/sec), Blowfish
+(5323 K/sec), CAST (1314 K/sec), Diamond (1670 K/sec), RC5 (1370
+K/sec), or Sapphire (3568 K/sec), but they're all relatively new
+algorithms and there hasn't been time for much analysis to be
+performed; use them for serious applications only after careful
+research. Skipjack (864 K/sec) is relatively slow, and its 80-bit key size
+is secure at the moment, but doesn't leave much of a margin of safety;
+only use it if you believe that the NSA has mystical cipher design
+abilities.
+
+
+\subsection{Credits}
+\index{Olson, Bryan}
+\index{Schneier, Bruce}
+\index{Young, Eric}
+\index{Cyphers, Graven}
+\index{Outerbridge, Richard}
+\index{Brown, Lawrence}
+\index{Kwan, Matthew}
+\index{DES (block cipher)}
+\index{IDEA (block cipher)}
+\index{Blowfish (block cipher)}
+The code for Blowfish was written by Bryan Olson, partially based on a
+previous implementation by Bruce Schneier, who also invented the
+algorithm; the Blowfish algorithm has been placed in the public domain
+and can be used freely. (See \url{http://www.counterpane.com} for more
+information about Blowfish.) The CAST implementation was written by
+Wim Lewis. The DES implementation was written by Eric Young, and the
+IDEA implementation by Colin Plumb. The RC5 implementation
+was written by A.M. Kuchling.
+
+\index{sci.crypt}
+\index{Johnson, Michael Paul}
+\index{ARC4 (stream cipher)}
+\index{Sapphire (stream cipher)}
+The Alleged RC4 code was posted to the \code{sci.crypt} newsgroup by an
+unknown party, and re-implemented by A.M. Kuchling. The Sapphire stream
+cipher was developed by Michael P. Johnson, and is in the public domain;
+the implementation used here was written by A.M. Kuchling and is based
+on Johnson's code.
+
+\section{Crypto.Protocol: Various Protocols}
+
+\subsection{Crypto.Protocol.AllOrNothing}
+
+This module implements all-or-nothing package transformations.
+An all-or-nothing package transformation is one in which some text is
+transformed into message blocks, such that all blocks must be obtained before
+the reverse transformation can be applied. Thus, if any blocks are corrupted
+or lost, the original message cannot be reproduced.
+
+An all-or-nothing package transformation is not encryption, although a block
+cipher algorithm is used. The encryption key is randomly generated and is
+extractable from the message blocks.
+
+This class implements the All-Or-Nothing package transformation
+algorithm described in Rivest: ``All-Or-Nothing Encryption and The
+Package Transform.'' To appear in the Proceedings of the 1997 Fast
+Software Encryption Conference.
+http://theory.lcs.mit.edu/~rivest/fusion.ps
+
+\begin{classdesc}{AllOrNothing}{ciphermodule, mode=None, IV=None}
+Class implementing the All-or-Nothing package transform.
+
+\var{ciphermodule} is a module implementing the cipher algorithm to
+use. Optional arguments \var{mode} and \var{IV} are passed directly
+through to the \var{ciphermodule}.\code{new()} method; they are the
+feedback mode and initialization vector to use. All three arguments
+must be the same for the object used to create the digest, and to
+undigest'ify the message blocks.
+
+The module passed as \var{ciphermodule} must provide the
+following interface:
+
+\var{ciphermodule}.\code{keysize}:
+Attribute containing the cipher algorithm's key size in
+bytes. If the cipher supports variable length keys, then
+typically \code{ciphermodule.keysize} will be zero. In that case a
+key size of 16 bytes will be used.
+
+\var{ciphermodule}.\code{blocksize}:
+Attribute containing the cipher algorithm's input block size
+in bytes.
+
+\var{ciphermodule}.\code{new}(\var{key}, \var{mode}, \var{IV}):
+ Function which returns a new instance of a cipher object,
+ initialized to \var{key}. The returned object must have an
+ \method{encrypt()} method that accepts a string of
+ \var{ciphermodule}.\code{blocksize} bytes and returns a string containing
+ the encrypted text.
+
+Note that the encryption key is randomly generated automatically
+when needed.
+\end{classdesc}
+
+The methods of the \class{AllorNothing} class are:
+
+\begin{methoddesc}{digest}{}
+Perform the All-or-Nothing package transform on the current
+string. Output is a list of message blocks describing the
+transformed text, where each block is a string of bit length equal
+to the cipher module's blocksize.
+\end{methoddesc}
+
+\begin{methoddesc}{reset}{text = ""}
+Reset the current string to be transformed to \var{text}.
+\end{methoddesc}
+
+\begin{methoddesc}{undigest}{mblocks}
+Perform the reverse package transformation on a list of message
+blocks. Note that the cipher module used for both transformations
+must be the same. \var{mblocks} is a list of strings of bit length
+equal to \var{ciphermodule}'s blocksize. The output is a string object.
+\end{methoddesc}
+
+\begin{methoddesc}{update}{text}
+Concatenate \var{text} to the string that will be transformed.
+\end{methoddesc}
+
+\subsection{Crypto.Protocol.Chaffing}
+
+Winnowing and chaffing is a technique for enhancing privacy without requiring
+strong encryption. In short, the technique takes a set of authenticated
+message blocks (the wheat) and adds a number of chaff blocks which have
+randomly chosen data and MAC fields. This means that to an adversary, the
+chaff blocks look as valid as the wheat blocks, and so the authentication
+would have to be performed on every block. By tailoring the number of chaff
+blocks added to the message, the sender can make breaking the message
+computationally infeasible. There are many other interesting properties of
+the winnow/chaff technique.
+
+For example, say Alice is sending a message to Bob. She packetizes the
+message and performs an all-or-nothing transformation on the packets. Then
+she authenticates each packet with a message authentication code (MAC). The
+MAC is a hash of the data packet, and there is a secret key which she must
+share with Bob (key distribution is an exercise left to the reader). She then
+adds a serial number to each packet, and sends the packets to Bob.
+
+Bob receives the packets, and using the shared secret authentication key,
+authenticates the MACs for each packet. Those packets that have bad MACs are
+simply discarded. The remainder are sorted by serial number, and passed
+through the reverse all-or-nothing transform. The transform means that an
+eavesdropper (say Eve) must acquire all the packets before any of the data can
+be read. If even one packet is missing, the data is useless.
+
+There's one twist: by adding chaff packets, Alice and Bob can make Eve's job
+much harder, since Eve now has to break the shared secret key, or try every
+combination of wheat and chaff packet to read any of the message. The cool
+thing is that Bob doesn't need to add any additional code; the chaff packets
+are already filtered out because their MACs don't match (in all likelihood --
+since the data and MACs for the chaff packets are randomly chosen it is
+possible, but very unlikely that a chaff MAC will match the chaff data). And
+Alice need not even be the party adding the chaff! She could be completely
+unaware that a third party, say Charles, is adding chaff packets to her
+messages as they are transmitted.
+
+For more information on winnowing and chaffing see this paper:
+
+XXX Rivest.
+
+\begin{classdesc}{Chaff}{factor=1.0, blocksper=1}
+Class implementing the chaff adding algorithm.
+\var{factor} is the number of message blocks
+ to add chaff to, expressed as a percentage between 0.0 and 1.0; the default value is 1.0.
+\var{blocksper} is the number of chaff blocks to include for each block
+ being chaffed, and defaults to 1. The default settings
+add one chaff block to every
+ message block. By changing the defaults, you can adjust how
+ computationally difficult it could be for an adversary to
+ brute-force crack the message. The difficulty is expressed as:
+
+\begin{verbatim}
+pow(blocksper, int(factor * number-of-blocks))
+\end{verbatim}
+
+For ease of implementation, when \var{factor} < 1.0, only the first
+\code{int(\var{factor}*number-of-blocks)} message blocks are chaffed.
+\end{classdesc}
+
+\class{Chaff} instances have the following methods:
+
+\begin{methoddesc}{chaff}{blocks}
+Add chaff to message blocks. \var{blocks} is a list of 3-tuples of the
+form (\var{serial-number}, \var{data}, \var{MAC}).
+
+Chaff is created by choosing a random number of the same
+byte-length as \var{data}, and another random number of the same
+byte-length as \var{MAC}. The message block's serial number is placed
+on the chaff block and all the packet's chaff blocks are randomly
+interspersed with the single wheat block. This method then
+returns a list of 3-tuples of the same form. Chaffed blocks will
+contain multiple instances of 3-tuples with the same serial
+number, but the only way to figure out which blocks are wheat and
+which are chaff is to perform the MAC hash and compare values.
+\end{methoddesc}
+
+ Subclass methods:
+
+\begin{methoddesc}{__randnum}{size}
+Returns a randomly generated number with a byte-length equal
+to \var{size}. Subclasses can use this to implement better random
+data and MAC generating algorithms. The default algorithm is
+probably not very cryptographically secure. It is most
+important that the chaff data does not contain any patterns
+that can be used to discern it from wheat data without running
+the MAC.
+\end{methoddesc}
+
+\section{Crypto.PublicKey: Public Key Algorithms}
+So far, the encryption algorithms described have all been \dfn{private
+key} ciphers. That is, the same key is used for both encryption and
+decryption, so all correspondents must know it. This poses a problem:
+you may want encryption to communicate sensitive data over an insecure
+channel, but how can you tell your correspondent what the key is? You
+can't just e-mail it to her because the channel is insecure. One
+solution is to arrange the key via some other way: over the phone or
+by meeting in person.
+
+Another solution is to use \dfn{public key} cryptography. In a public
+key system, there are two different keys: one for encryption and one for
+decryption. The encryption key can be made public by listing it in a
+directory or mailing it to your correspondent, while you keep the
+decryption key secret. Your correspondent then sends you data encrypted
+with your public key, and you use the private key to decrypt it. While
+the two keys are related, it's very difficult to derive the private key
+given only the public key; however, deriving the private key is always
+possible given enough time and computing power. This makes it very
+important to pick keys of the right size: large enough to be secure, but
+small enough to be applied fairly quickly.
+
+Many public key algorithms can also be used to sign messages; simply
+run the message to be signed through a decryption with your private
+key key. Anyone receiving the message can encrypt it with your
+publicly available key and read the message. Some algorithms do only
+one thing, others can both encrypt and authenticate.
+
+The currently available public key algorithms are listed in the
+following table:
+
+\begin{tableii}{c|l}{}{Algorithm}{Capabilities}
+\lineii{RSA}{Encryption, authentication/signatures}
+\lineii{ElGamal}{Encryption, authentication/signatures}
+\lineii{DSA}{Authentication/signatures}
+\lineii{qNEW}{Authentication/signatures}
+\end{tableii}
+
+Many of these algorithms are patented. Before using any of them in a
+commercial product, consult a patent attorney; you may have to arrange
+a license with the patent holder.
+
+An example of using the RSA module to sign a message:
+\begin{verbatim}
+>>> from Crypto.Hash import MD5
+>>> from Crypto.PublicKey import RSA
+>>> RSAkey=RSA.generate(384, randfunc) # This will take a while...
+>>> hash=MD5.new(plaintext).digest()
+>>> signature=RSAkey.sign(hash, "")
+>>> signature # Print what an RSA sig looks like--you don't really care.
+('\021\317\313\336\264\315' ...,)
+>>> RSAkey.verify(hash, signature) # This sig will check out
+1
+>>> RSAkey.verify(hash[:-1], signature)# This sig will fail
+0
+\end{verbatim}
+
+
+Public key modules make the following functions available:
+
+\begin{funcdesc}{construct}{tuple}
+Constructs a key object from a tuple of data. This is
+algorithm-specific; look at the source code for the details. (To be
+documented later.)
+\end{funcdesc}
+
+\begin{funcdesc}{generate}{size, randfunc, progress_func=\code{None}}
+Generate a fresh public/private key pair. \var{size} is a
+algorithm-dependent size parameter; the larger it is, the more
+difficult it will be to break the key. Safe key sizes vary from
+algorithm to algorithm; you'll have to research the question and
+decide on a suitable key size for your application. \code{randfunc}
+is a random number generation function; it should accept a single
+integer \var{N} and return a string of random data \var{N} bytes long.
+You should always use a cryptographically secure random number
+generator, such as the one defined in the \code{randpool} module;
+\emph{don't} just use the current time and the \code{whrandom} module.
+
+\var{progress_func} is an optional function that will be called with a short
+string containing the key parameter currently being generated; it's
+useful for interactive applications where a user is waiting for a key to
+be generated.
+\end{funcdesc}
+
+If you want to interface with some other program, you will have to know
+the details of the algorithm being used; this isn't a big loss. If you
+don't care about working with non-Python software, simply use the
+\code{pickle} module when you need to write a key or a signature to a
+file. It's portable across all the architectures that Python supports,
+and it's simple to use.
+
+Public key objects always support the following methods. Some of them
+may raise exceptions if their functionality is not supported by the
+algorithm.
+
+\begin{funcdesc}{canencrypt}{}
+Returns true if the algorithm is capable of encrypting and decrypting
+data; returns false otherwise. To test if a given key object can sign
+data, use \code{key.canencrypt() and key.hasprivate()}.
+\end{funcdesc}
+
+\begin{funcdesc}{cansign}{}
+Returns true if the algorithm is capable of signing data; returns false
+otherwise. To test if a given key object can sign data, use
+\code{key.cansign() and key.hasprivate()}.
+\end{funcdesc}
+
+\begin{funcdesc}{decrypt}{tuple}
+Decrypts \var{tuple} with the private key, returning another string.
+This requires the private key to be present, and will raise an exception
+if it isn't present. It will also raise an exception if \var{string} is
+too long.
+\end{funcdesc}
+
+\begin{funcdesc}{encrypt}{string, K}
+Encrypts \var{string} with the private key, returning a tuple of
+strings; the length of the tuple varies from algorithm to algorithm.
+\var{K} should be a string of random data that is as long as
+possible. Encryption does not require the private key to be present
+inside the key object. It will raise an exception if \var{string} is
+too long. For ElGamal objects, the value of \var{K} expressed as a
+big-endian integer must be relatively prime to \code{self.p-1}; an
+exception is raised if it is not.
+\end{funcdesc}
+
+\begin{funcdesc}{hasprivate}{}
+Returns true if the key object contains the private key data, which
+will allow decrypting data and generating signatures.
+Otherwise this returns false.
+\end{funcdesc}
+
+\begin{funcdesc}{publickey}{}
+Returns a new public key object that doesn't contain the private key
+data.
+\end{funcdesc}
+
+\begin{funcdesc}{sign}{string, K}
+Sign \var{string}, returning a signature, which is just a tuple; in
+theory the signature may be made up of any Python objects at all; in
+practice they'll be either strings or numbers. \var{K} should be a
+string of random data that is as long as possible. Different algorithms
+will return tuples of different sizes. \code{sign()} raises an
+exception if \var{string} is too long. For ElGamal objects, the value
+of \var{K} expressed as a big-endian integer must be relatively prime to
+\code{self.p-1}; an exception is raised if it is not.
+\end{funcdesc}
+
+\begin{funcdesc}{size}{}
+Returns the maximum size of a string that can be encrypted or signed,
+measured in bits. String data is treated in big-endian format; the most
+significant byte comes first. (This seems to be a \emph{de facto} standard
+for cryptographical software.) If the size is not a multiple of 8, then
+some of the high order bits of the first byte must be zero. Usually
+it's simplest to just divide the size by 8 and round down.
+\end{funcdesc}
+
+\begin{funcdesc}{verify}{string, signature}
+Returns true if the signature is valid, and false otherwise.
+\var{string} is not processed in any way; \code{verify} does
+not run a hash function over the data, but you can easily do that yourself.
+\end{funcdesc}
+
+\subsection{The ElGamal and DSA algorithms}
+For RSA, the \var{K} parameters are unused; if you like, you can just
+pass empty strings. The ElGamal and DSA algorithms require a real
+\var{K} value for technical reasons; see Schneier's book for a detailed
+explanation of the respective algorithms. This presents a possible
+hazard that can
+inadvertently reveal the private key. Without going into the
+mathematical details, the danger is as follows. \var{K} is never derived
+or needed by others; theoretically, it can be thrown away once the
+encryption or signing operation is performed. However, revealing
+\var{K} for a given message would enable others to derive the secret key
+data; worse, reusing the same value of \var{K} for two different
+messages would also enable someone to derive the secret key data. An
+adversary could intercept and store every message, and then try deriving
+the secret key from each pair of messages.
+
+This places implementors on the horns of a dilemma. On the one hand,
+you want to store the \var{K} values to avoid reusing one; on the other
+hand, storing them means they could fall into the hands of an adversary.
+One can randomly generate \var{K} values of a suitable length such as
+128 or 144 bits, and then trust that the random number generator
+probably won't produce a duplicate anytime soon. This is an
+implementation decision that depends on the desired level of security
+and the expected usage lifetime of a private key. I cannot choose and
+enforce one policy for this, so I've added the \var{K} parameter to the
+\code{encrypt} and \code{sign} functions. You must choose \var{K} by
+generating a string of random data; for ElGamal, when interpreted as a
+big-endian number (with the most significant byte being the first byte
+of the string), \var{K} must be relatively prime to \code{self.p-1}; any
+size will do, but brute force searches would probably start with small
+primes, so it's probably good to choose fairly large numbers. It might be
+simplest to generate a prime number of a suitable length using the
+\code{Crypto.Util.number} module.
+
+\subsection{Security Notes for Public-key Algorithms}
+Any of these algorithms can be trivially broken; for example, RSA can be
+broken by factoring the modulus \emph{n} into its two prime factors.
+This is easily done by the following code:
+
+\begin{verbatim}
+for i in range(2, n):
+ if (n%i)==0: print i, 'is a factor' ; break
+\end{verbatim}
+
+
+However, \emph{n} is usually a few hundred bits long, so this simple
+program wouldn't find a solution before the universe comes to an end.
+Smarter algorithms can factor numbers more quickly, but it's still
+possible to choose keys so large that they can't be broken in a
+reasonable amount of time. For ElGamal and DSA, discrete logarithms are
+used instead of factoring, but the principle is the same.
+
+Safe key sizes depend on the current state of computer science and
+technology. At the moment, one can roughly define three levels of
+security: low-security commercial, high-security commercial, and
+military-grade. For RSA, these three levels correspond roughly to 512,
+768, and 1024 bit-keys. For ElGamal and DSA, the key sizes should be
+somewhat larger for the same level of security, around 768, 1024, and
+1536 bits.
+
+\section{Crypto.Util: Odds and Ends}
+This chapter contains all the modules that don't fit into any of the
+other chapters.
+
+\subsection{Crypto.Util.number}
+
+This module contains various functions of number-theoretic functions.
+
+\begin{funcdesc}{GCD}{x,y}
+Return the greatest common divisor of \var{x} and \var{y}.
+\end{funcdesc}
+
+\begin{funcdesc}{getPrime}{N, randfunc}
+Return an \var{N}-bit random prime number, using random data obtained
+from the function \var{randfunc}. \var{randfunc} must take a single
+integer argument, and return a string of random data of the
+corresponding length; the \code{getBytes()} method of a
+\code{RandomPool} object will serve the purpose nicely, as will the
+\code{read()} method of an opened file such as \file{/dev/random}.
+\end{funcdesc}
+
+\begin{funcdesc}{getRandomNumber}{N, randfunc}
+Return an \var{N}-bit random number, using random data obtained from the
+function \var{randfunc}. As usual, \var{randfunc} must take a single
+integer argument, and return a string of random data of the
+corresponding length.
+\end{funcdesc}
+
+\begin{funcdesc}{inverse}{u, v}
+Return the inverse of \var{u} modulo \var{v}.
+\end{funcdesc}
+
+\begin{funcdesc}{isPrime}{N}
+Returns true if the number \var{N} is prime, as determined by a
+Rabin-Miller test.
+\end{funcdesc}
+
+\index{random numbers}
+\subsection{Crypto.Util.randpool}
+For cryptographic purposes, ordinary random number generators are
+frequently insufficient, because if some of their output is known, it is
+frequently possible to derive the generator's future (or past) output.
+This is obviously a Bad Thing; given the generator's state at some point
+in time, someone could try to derive any keys generated using it. The
+solution is to use strong encryption or hashing algorithms to generate
+successive data; this makes breaking the generator as difficult as
+breaking the algorithms used.
+
+\index{entropy}
+Understanding the concept of \dfn{entropy} is important for using the
+random number generator properly. In the sense we'll be using it,
+entropy measures the amount of randomness; the usual unit is in bits.
+So, a single random bit has an entropy of 1 bit; a random byte has an
+entropy of 8 bits. Now consider a one-byte field in a database containing a
+person's sex, represented as a single character \samp{M} or \samp{F}.
+What's the entropy of this field? Since there are only two possible
+values, it's not 8 bits, but one; if you were trying to guess the value,
+you wouldn't have to bother trying \samp{Q} or \samp{@}.
+
+Now imagine running that single byte field through a hash function that
+produces 128 bits of output. Is the entropy of the resulting hash value
+128 bits? No, it's still just 1 bit. The entropy is a measure of how many
+possible states of the data exist. For English
+text, the entropy of a five-character string is not 40 bits; it's
+somewhat less, because not all combinations would be seen. \samp{Guido}
+is a possible string, as is \samp{In th}; \samp{zJwvb} is not.
+
+The relevance to random number generation? We want enough bits of
+entropy to avoid making an attack on our generator possible. An
+example: One computer system had a mechanism which generated nonsense
+passwords for its users. This is a good idea, since it would prevent
+people from choosing their own name or some other easily guessed string.
+Unfortunately, the random number generator used only had 65536 states,
+which meant only 65536 different passwords would ever be generated, and
+it was easily to compute all the possible passwords and try them. The
+entropy of the random passwords was far too low. By the same token, if
+you generate an RSA key with only 32 bits of entropy available, there
+are only about 4.2 billion keys you could have generated, and an
+adversary could compute them all to find your private key. See RFC 1750:
+"Randomness Recommendations for Security" for an interesting discussion
+of the issues related to random number generation.
+
+The \code{randpool} module implements a strong random number generator
+in the \code{RandomPool} class. The internal state consists of a string
+of random data, which is returned as callers request it. The class
+keeps track of the number of bits of entropy left, and provides a function to
+add new random data; this data can be obtained in various ways, such as
+by using the variance in a user's keystroke timings.
+
+\begin{funcdesc}{RandomPool}{\optional{numbytes, cipher, hash} }
+An object of the \code{RandomPool} class can be created without
+parameters if desired. \var{numbytes} sets the number of bytes of
+random data in the pool, and defaults to 160 (1280 bits). \var{hash}
+can be a string containing the module name of the hash function to use
+in stirring the random data, or a module object supporting the hashing
+interface. The default action is to use SHA.
+
+The \var{cipher} argument is vestigial; it was removed from version
+1.1 so RandomPool would work even in the limited exportable subset of
+the code. It can have any value at all, since it's no longer used at
+all.
+
+\end{funcdesc}
+
+\code{RandomPool} objects define the following variables and methods:
+
+\begin{funcdesc}{addEvent}{time\optional{, string}}
+Adds an event to the random pool. \var{time} should be set to the
+current system time, measured at the highest resolution available.
+\var{string} can be a string of data that will be XORed into the pool,
+and can be used to increase the entropy of the pool. For example, if
+you're encrypting a document, you might use the hash value of the
+document; an adversary presumably won't have the plaintext of the
+document, and thus won't be able to use this information to break the
+generator.
+\end{funcdesc}
+
+The return value is the value of \code{self.entropy} after the data has
+been added. The function works in the following manner: the time
+between successive calls to the \code{addEvent} method is determined,
+and the entropy of the data is guessed; the larger the time between
+calls, the better. The system time is then read and added to the pool,
+along with the \var{string} parameter, if present. The hope is that the
+low-order bits of the time are effectively random. In an application,
+it is recommended that \code{addEvent()} be called as frequently as
+possible, with whatever random data can be found.
+
+\begin{datadesc}{bits}
+A constant integer value containing the number of bits of data in
+the pool, equal to the \code{bytes} variable multiplied by 8.
+\end{datadesc}
+
+\begin{datadesc}{bytes}
+A constant integer value containing the number of bytes of data in
+the pool.
+\end{datadesc}
+
+\begin{datadesc}{entropy}
+An integer value containing the number of bits of entropy currently in
+the pool. The value is incremented by the \code{addEvent()} method,
+and decreased by the \code{getBytes} method.
+\end{datadesc}
+
+\begin{funcdesc}{getBytes}{num}
+Returns a string containing \var{num} bytes of random data, and
+decrements the amount of entropy available. It is not an error to
+reduce the entropy to zero, or to call this function when the entropy
+is zero. This simply means that, in theory, enough random information has been
+extracted to derive the state of the generator. It is the caller's
+responsibility to monitor the amount of entropy remaining and decide
+whether it is sufficent for secure operation.
+\end{funcdesc}
+
+\begin{funcdesc}{stir}{}
+Scrambles the random pool using the previously chosen encryption and
+hash function. An adversary may attempt to learn or alter the state
+of the pool in order to affect its future output; this function
+destroys the existing state of the pool in a non-reversible way. It
+is recommended that \code{stir()} be called before and after using
+the \code{RandomPool} object. Even better, several calls to
+\code{stir()} can be interleaved with calls to \code{addEvent()}.
+\end{funcdesc}
+
+The \code{KeyboardRandomPool} class is a subclass of \code{RandomPool}
+that adds the capability to save and load the pool from a disk file, and
+provides a method to obtain random data from the keyboard.
+
+\begin{funcdesc}{KeyboardRandomPool}{\optional{filename, numbytes, cipher, hash}}
+The path given in \var{filename} will be automatically opened, and an
+existing random pool read; if no such file exists, the pool will be
+initialized as usual. If omitted, the filename defaults to the empty
+string, which will prevent it from being saved to a file. The other
+arguments are identical to those for the \code{RandomPool} constructor.
+\end{funcdesc}
+
+\begin{funcdesc}{randomize}{}
+(Unix systems only) Obtain random data from the keyboard. This works
+by prompting the
+user to hit keys at random, and then using the keystroke timings (and
+also the actual keys pressed) to add entropy to the pool. This works
+similarly to PGP's random pool mechanism.
+\end{funcdesc}
+
+\begin{funcdesc}{save}{}
+Opens the file named by the \code{filename} attribute, and saves the
+random data into the file using the \code{pickle} module.
+\end{funcdesc}
+
+
+\subsection{Crypto.Util.RFC1751}
+The keys for private-key algorithms should be arbitrary binary data.
+Many systems err by asking the user to enter a password, and then using
+the password as the key. This limits the space of possible keys, as
+each key byte is constrained within the range of possible ASCII
+characters, 32-127, instead of the whole 0-255 range possible with ASCII.
+Unfortunately, it's difficult for humans to remember 16 or 32 hex
+digits.
+
+One solution is to request a lengthy passphrase from the user, and then
+run it through a hash function such as SHA or MD5. Another solution is
+discussed in RFC 1751, "A Convention for Human-Readable 128-bit Keys",
+by Daniel L. McDonald. Binary keys are transformed into a list of short
+English words that should be easier to remember. For example, the hex
+key EB33F77EE73D4053 is transformed to "TIDE ITCH SLOW REIN RULE MOT".
+
+\begin{funcdesc}{Key2English}{key}
+Accepts a string of arbitrary data \var{key}, and returns a string
+containing uppercase English words separated by spaces. \var{key}'s
+length must be a multiple of 8.
+\end{funcdesc}
+
+\begin{funcdesc}{English2Key}{string}
+Accepts \var{string} containing English words, and returns a string of
+binary data representing the key. Words must be separated by
+whitespace, and can be any mixture of uppercase and lowercase
+characters. 6 words are required for 8 bytes of key data, so
+the number of words in \var{string} must be a multiple of 6.
+\end{funcdesc}
+
+\section{The Demonstration Programs}
+The Python cryptography modules comes with various demonstration
+programs, located in the \file{Demo/} directory. None of them is
+particularly well-finished, or suitable for serious use. Rather,
+they're intended to illustrate how the toolkit is used, and to provide
+some interesting possible uses. Feel free to incorporate the code (or
+modifications of it) into your own programs.
+
+\subsection{Demo 1: \file{cipher}}
+
+\index{crypt}
+\index{cipher (demo program)}
+\index{Enigma}
+\index{Crypt Breaker's Workbench}
+\file{cipher} encrypts and decrypts files. On most Unix systems, the
+\file{crypt} program uses a variant of the Enigma cipher. This is not
+secure, and there exists a freely available program called ``Crypt
+Breaker's Workbench'' which helps in breaking the cipher if you have
+some knowledge of the encrypted data.
+
+\file{cipher} is a more secure file encryption program. Simply list
+the names of the files to be encrypted on the command line.
+\file{cipher} will go through the list and encrypt or decrypt them;
+\file{cipher} can recognize files it has previously encrypted. The
+ciphertext of a file is placed in a file of the same name with
+'\samp{.cip}' appended; the original file is not deleted, since I'm
+not sure that all errors during operation are caught, and I don't want
+people to accidentally erase important files.
+
+There are two command-line options: \code{-c} and \code{-k}. Both of
+them require an argument. \code{-c \var{ciphername}} uses the
+given encryption algorithm \var{ciphername}; for example,
+\code{-c des} will use the DES algorithm. The name should be the same
+as an available module name; thus it should be in lowercase letters.
+The default cipher is IDEA.
+
+\index{Linux}
+\index{cipher}
+\code{-k \var{key}} can be used to set the encryption key to be
+used. Note that on a multiuser Unix system, the \code{ps} command can
+be used to view the arguments of commands executed by other users, so
+this is insecure; if you're the only user (say, on your home computer
+running Linux) you don't have to worry about this. If no key is set
+on the command line, \file{cipher} will prompt the user to input a key
+on standard input.
+
+\subsubsection{Technical Details}
+
+The encrypted file is not pure ciphertext. First comes a magic
+string; this is currently the sequence \samp{ctx} and a byte
+containing 1 (the version number of \file{cipher}).
+This is followed by the null-terminated name of the encryption
+algorithm, and the rest of the file contains the ciphertext.
+
+\index{feedback mode, CBC}
+The plaintext is encrypted in CBC mode. The initial value for the
+feedback is always set to a block filled with the letter 'A', and then
+a block of random data is encrypted. This garbage block will be
+discarded on decryption. Note that the random data is not generated
+in a cryptographically secure way, and this may provide a tiny foothold for
+an attacker.
+
+After the random block is generated, the magic string, length of the
+original file, and original filename are all encrypted before the file
+data is finally processed. Some extra characters of padding may be
+added to obtain an integer number of blocks. This padding will also
+be discarded on decryption. Note that the plaintext file will be
+completely read into memory before encryption is performed; no
+buffering is done. Therefore, don't encrypt 20-megabyte files unless
+you're willing to face the consequences of a 20-megabyte process.
+
+Areas for improvements to \file{cipher} are: cryptographically secure
+generation of random data
+for padding, key entry, and buffering of file
+input.
+
+\subsection{Demo 2: \file{secimp} and \file{sign}}
+
+\file{secimp} demonstrates an application of the Toolkit that may be
+useful if Python is being used as an extension language for mail and Web
+clients: secure importing of Python modules. To use it, run
+\file{sign.py} in a directory with several compiled Python files
+present. It will use the key in \file{testkey.py} to generate digital
+signatures for the compiled Python code, and save both the signature and
+the code in a file ending in \samp{.pys}. Then run \code{python -i
+secimp.py}, and import a file by using \code{secimport}.
+
+For example, if \file{foo.pys} was constructed, do
+\code{secimport('foo')}. The import should succeed. Now fire up Emacs
+or some other editor, and change a string in the code in \file{foo.pys};
+you might try changing a letter in the name of a variable. When you run
+\code{secimport('foo')}, it should raise an exception reporting the
+failed signature. If you execute the statement \code{__import__ =
+secimport}, the secure import will be used by default for all future
+module imports. Alternatively, if you were creating a restricted
+execution environment using \file{rexec.py}, you could place
+\code{secimport()} in the restricted environment's namespace as the
+default import function.
+
+\section{Extending the cryptography modules}
+Preserving the a common interface for cryptographic routines is a
+good idea. This chapter
+explains how to interface your own routines to the Toolkit.
+
+The basic process is as follows:
+\begin{enumerate}
+\item Modify the default definition of a C structure to include
+whatever instance data your algorithm requires.
+\item Write 3 or 4 standard routines. Their names and parameters are
+specified in the following subsections.
+\item Modify \file{buildkit} to contain an entry for your new
+algorithm. Then run \file{buildkit} to rebuild all the source files.
+\item Send a copy of the code to me, if you like; code for new
+algorithms will be gratefully accepted.
+\end{enumerate}
+
+\subsection{Creating a Custom Object}
+In the C code for the interpreter, Python objects are defined as a
+structure. The default structure is the following:
+\begin{verbatim}
+typedef struct
+{
+ PCTObject_HEAD
+} ALGobject;
+\end{verbatim}
+
+
+\code{PCTObject_HEAD} is a preprocessor macro which will contain various
+internal variables used by the interpreter; it must always be the
+first item in the structure definition, and must not be followed by a
+semicolon. Following it, you can put whatever instance variables you
+require. Data that does not depend on the instance or key, such as a
+static lookup table, need not be encapsulated inside objects; instead,
+it can be defined as a variable interior to the module.
+
+As an example, for IDEA encryption, a schedule of encryption and
+decryption data has to be maintained, resulting in the following
+definition:
+\begin{verbatim}
+typedef struct
+{
+ PCTObject_HEAD
+ int EK[6][9], DK[6][9];
+} IDEAobject;
+\end{verbatim}
+
+
+\subsection{Standard Routines}
+
+\index{buildkit}
+The interface to Python is implemented in the files ending in
+\samp{.in}, so \file{hash.in} contains the basic code for modules
+containing hash functions, for example. \file{buildkit}, a Python
+script, reads the configuration file and generates source code by
+interweaving the interface files and the implementation file.
+
+\index{buildkit}
+If your algorithm is called ALG, the implementation should be in the
+file \file{ALG.c}. This is case-sensitive, as are the following function
+names.
+
+\subsubsection{Hash functions}
+
+\begin{itemize}
+\item \code{void \var{ALG}init(\var{ALG}object *self);}
+\item \code{void \var{ALG}update(\var{ALG}object *self, char *buffer, int length);}
+\item \code{PyObject *\var{ALG}digest(\var{ALG}object *self);}
+\item \code{void \var{ALG}copy(\var{ALG}object *source, \var{ALG}object *dest);}
+\end{itemize}
+
+\begin{funcdesc}{void ALGinit}{\rm ALGobject *\var{self}}
+\index{ALGinit}
+This function should initialize the hashing object, setting
+state variables to their expected initial state.
+\end{funcdesc}
+
+\begin{funcdesc}{void ALGupdate}{\rm ALGobject *\var{self},
+char *\var{buffer}, int \var{length}}
+\index{ALGupdate}
+This function should perform a hash on the region pointed to by
+\var{buffer}, which will contain \var{length} bytes. The contents of
+the object pointed to by \var{self} should be updated appropriately.
+\end{funcdesc}
+
+\begin{funcdesc}{void ALGdigest}{\rm ALGobject *\var{self}}
+This function returns a string containing the value of the hash
+function. The object should not be changed in any way by this
+function. Some hash functions require some computation to be
+performed before returning a value; for example, the number of bytes
+may be hashed into the final value. If this is the case for your hash
+function, you must make a copy of the object's data, perform the final
+computation on that copy, and return the result.
+\end{funcdesc}
+
+Results are returned by calling a Python function,
+\code{PyString_FromStringAndSize(char *\var{string}, int \var{length})}. This
+function returns a string object which should be returned to the
+caller. So, the last line of the \code{ALGdigest}
+function might be:
+\begin{verbatim}
+ return PyString_FromStringAndSize(digest, 16);
+\end{verbatim}
+
+\index{ALGdigest}
+
+\begin{funcdesc}{void ALGcopy}{\rm ALGobject *\var{source}, ALGobject *\var{dest}}
+Given the source and destination objects, the state variables of the
+\var{source} object should be copied to the \var{dest} object; the
+source object should not be altered in any way by the operation.
+\index{ALGcopy}
+\end{funcdesc}
+
+\subsubsection{Block ciphers}
+\begin{itemize}
+\item \code{void ALGinit(ALGobject *\var{self}, unsigned char *\var{key}, int \var{length});}
+\item \code{PyObject *ALGencrypt(ALGobject *\var{self}, unsigned char *\var{block});}
+\item \code{PyObject *ALGdecrypt(ALGobject *\var{self}, unsigned char *\var{block});}
+\end{itemize}
+
+\begin{funcdesc}{void ALGinit}{\rm ALGobject *\var{self}, unsigned char *\var{key}, int \var{length}}
+This function initializes a block cipher object to encrypt and decrypt
+with \var{key}. If the cipher requires a fixed-length key, then the
+buffer pointed to by \var{key} will always of that length, and the
+value of \var{length} will be a random value that should be ignored.
+If the algorithm accepts a variable-length key, then \var{length} will
+be nonzero, and will contain the size of the key.
+\index{ALGinit}
+\end{funcdesc}
+
+\begin{funcdesc}{void ALGencrypt}{\rm ALGobject *\var{self}, unsigned char *\var{block}}
+This function should encrypt the data pointed to by \var{block}, using
+the key-dependent data contained in \var{self}. Only ECB mode needs
+to be implemented; \code{block.in} takes care of the other
+ciphering modes.
+\index{ALGencrypt}
+\end{funcdesc}
+
+\begin{funcdesc}{void ALGdecrypt}{\rm ALGobject *\var{self}, unsigned char *\var{block}}
+This function should decrypt the data pointed to by \var{block}, using
+the key-dependent data contained in \var{self}.
+\index{ALGdecrypt}
+\end{funcdesc}
+
+\subsection{Portability macros}
+
+Implementation code must be carefully written to produce the same
+results with any machine or compiler, without having to set any
+compile-time definitions. Code that is simply portable by nature is
+preferable, but it is possible to detect features of the host machine
+when new objects are created, and then execute special code to convert
+data to a preferred form.
+
+While portability macros are written for speed, there's no need to
+execute them on every encryption or updating operation. Instead, add
+variables to your object to hold the values of the portability macros,
+and execute the macros only once per object, in your
+\code{ALGinit} function. Then the code can simply check the
+results of the macros and act appropriately.
+
+Currently there is only one portability macro defined:
+
+\begin{funcdesc}{void TestEndianness}{variable}
+Determines the endianness of the current machine, and sets
+\var{variable} to a constant representing the value for this machine.
+Possible constants are \code{PCT_BIG_ENDIAN} and \code{PCT_LITTLE_ENDIAN};
+they are defined along with the \code{TestEndianness} macro.
+\end{funcdesc}
+
+\subsection{Informing the author}
+Code for additional cryptographic algorithms can be mailed to me at
+\email{akuchling@acm.org}. You can make things much easier for me by doing the
+following:
+\begin{itemize}
+\item If you wrote the code, please release it into the public domain
+or under the MIT X11 license. If you didn't write it, please tell me where
+to find the original author or source code, so that I can check the
+licensing conditions.
+\item Include some test data. It is not sufficient to check that
+encryption and decryption cancel out properly. An implementation
+might work fine on a single platform, but two machines with
+different endianness might produce different results. This would be
+fatal for portability and interoperating programs. So, please include
+test data; you can either send me patches to \file{test.py}, or simply
+send me documents describing the data.
+\end{itemize}
+
+\end{document}
diff --git a/Doc/pycrypt.txt b/Doc/pycrypt.txt
new file mode 100644
index 0000000..ed83488
--- /dev/null
+++ b/Doc/pycrypt.txt
@@ -0,0 +1,1400 @@
+
+ _________________________________________________________________
+
+ The Python Cryptography Modules
+
+ A.M. Kuchling
+
+ akuchling@acm.org
+ _________________________________________________________________
+
+ Abstract:
+
+ This document describes a package containing various cryptographic
+ modules available for the Python programming language. It assumes you
+ have some basic knowledge about the Python language and about
+ cryptography in general.
+
+Contents
+
+ * [1]1. Introduction
+ + [2]1.1 Design Goals
+ + [3]1.2 Acknowledgements
+ * [4]2. Crypto.Hash: Hash Functions
+ + [5]2.1 Algorithm-specific Notes for Hash Functions
+ + [6]2.2 Security Notes
+ + [7]2.3 Credits
+ * [8]3. Crypto.Cipher: Encryption Algorithms
+ + [9]3.1 Algorithm-specific Notes for Encryption Algorithms
+ + [10]3.2 Security Notes
+ + [11]3.3 Credits
+ * [12]4. Crypto.Protocol: Various Protocols
+ + [13]4.1 Crypto.Protocol.AllOrNothing
+ + [14]4.2 Crypto.Protocol.Chaffing
+ * [15]5. Crypto.PublicKey: Public Key Algorithms
+ + [16]5.1 The ElGamal and DSA algorithms
+ + [17]5.2 Security Notes for Public-key Algorithms
+ * [18]6. Crypto.Util: Odds and Ends
+ + [19]6.1 Crypto.Util.number
+ + [20]6.2 Crypto.Util.randpool
+ + [21]6.3 Crypto.Util.RFC1751
+ * [22]7. The Demonstration Programs
+ + [23]7.1 Demo 1: "cipher"
+ + [24]7.2 Demo 2: "secimp" and "sign"
+ * [25]8. Extending the cryptography modules
+ + [26]8.1 Creating a Custom Object
+ + [27]8.2 Standard Routines
+ + [28]8.3 Portability macros
+ + [29]8.4 Informing the author
+
+ 1. Introduction
+
+1.1 Design Goals
+
+ The Python cryptography modules are intended to provide a reliable and
+ stable base for writing Python programs that require cryptographic
+ functions.
+
+ A central goal of the author's has been to provide a simple,
+ consistent interface for similar classes of algorithms. For example,
+ all block cipher objects have the same methods and return values, and
+ support the same feedback modes; hash functions have a different
+ interface, but it too is consistent over all the hash functions
+ available. Individual modules also define variables to help you write
+ Python code that doesn't depend on the algorithms used; for example,
+ each block cipher module defines a variable that gives the algorithm's
+ block size. This is intended to make it easy to replace old algorithms
+ with newer, more secure ones. If you're given a bit of
+ portably-written Python code that uses the DES encryption algorithm,
+ you should be able to use IDEA instead by simply changing from
+ Crypto.Cipher import DES to from Crypto.Cipher import idea, and
+ changing all references to DES.new() to IDEA.new(). It's also fairly
+ simple to write your own modules that mimic this interface, thus
+ letting you use combinations or permutations of algorithms.
+
+ Some modules are implemented in C for performance; others are written
+ in Python for ease of modification. Generally, low-level functions
+ like ciphers and hash functions are written in C, while less
+ speed-critical functions have been written in Python. This division
+ may change in future releases. When speeds are quoted in this
+ document, they were measured on a 266 MHz Pentium II running Linux.
+ The exact speeds will obviously vary with different machines and
+ different compilers, but they provide a basis for comparing
+ algorithms. Currently the cryptographic implementations are acceptably
+ fast, but not spectacularly good. I welcome any suggestions or patches
+ for faster code.
+
+ If you live outside of Canada or the US, please do not attempt to
+ download it from a North American FTP site; you may get the site's
+ maintainer in trouble. Documentation is not covered by the ITAR
+ regulations, and can be freely sent anywhere in the world.
+
+ I have placed the code under no restrictions; you can redistribute the
+ code freely or commercially, in its original form or with any
+ modifications you make, subject to whatever local laws may apply in
+ your jurisdiction. Note that you still have to come to some agreement
+ with the holders of any patented algorithms you're using. If you're
+ intensively using these modules, please tell me about it; there's
+ little incentive for me to work on this package if I don't know of
+ anyone using it.
+
+ I also make no guarantees as to the usefulness, correctness, or
+ legality of these modules, nor does their inclusion constitute an
+ endorsement of their effectiveness. Many cryptographic algorithms are
+ patented; inclusion in this package does not necessarily mean you are
+ allowed to incorporate them in a product and sell it. Some of these
+ algorithms may have been cryptanalyzed, and may no longer be secure.
+ While I will include commentary on the relative security of the
+ algorithms in the sections entitled "Security Notes", there may be
+ more recent analyses I'm not aware of. (Or maybe I'm just clueless.)
+ If you're implementing an important system, don't just grab things out
+ of a toolbox and put them together; do some research first. On the
+ other hand, if you're just interested in keeping your co-workers or
+ your relatives out of your files, any of the components here could be
+ used.
+
+ This document is very much a work in progress. If you have any
+ questions, comments, complaints, or suggestions, please send them to
+ me at akuchling@acm.org.
+
+1.2 Acknowledgements
+
+ Much of the code that actually implements the various cryptographic
+ algorithms was not written by me. I'd like to thank all the people who
+ implemented them, and released their work under terms which allowed me
+ to use their code. The individuals are credited in the relevant
+ chapters of this documentation. Bruce Schneier's book Applied
+ Cryptography was also very useful in writing this toolkit; I highly
+ recommend it if you're interested in learning more about cryptography.
+ Mr. Schneier also has a Web site at [30]http://www.counterpane.com.
+
+ Good luck with your cryptography hacking!
+
+ A.M.K.
+
+ akuchling@acm.org
+
+ Washington, DC, USA
+
+ January 1998
+
+ 2. Crypto.Hash: Hash Functions
+
+ Hash functions take arbitrary strings as input, and produce an output
+ of fixed size that is dependent on the input; it should never be
+ possible to derive the input data given only the hash function's
+ output. One simple hash function consists of simply adding together
+ all the bytes of the input, and taking the result modulo 256. For a
+ hash function to be cryptographically secure, it must be very
+ difficult to find two messages with the same hash value, or to find a
+ message with a given hash value. The simple additive hash function
+ fails this criterion miserably; the hash functions described below do
+ not. Examples of cryptographically secure hash functions include MD2,
+ MD5, SHA, and HAVAL.
+
+ Hash functions can be used simply as a checksum, or, in association
+ with a public-key algorithm, can be used to implement digital
+ signatures. The hashing algorithms currently implemented are listed in
+ the following table:
+
+ Hash function Digest length
+ HAVAL Variable size: 128, 160, 192, 224, or 256 bits
+ MD2 128 bits
+ MD4 128 bits
+ MD5 128 bits
+ RIPEMD 160 bits
+ SHA 160 bits
+
+ All hashing modules share the same interface. After importing a given
+ hashing module, call the new() function to create a new hashing
+ object. (In older versions of the Python interpreter, the md5()
+ function was used to perform this task. If you're modifying an old
+ script, you should change any calls to md5() to use new() instead.)
+ You can now feed arbitrary strings into the object, and can ask for
+ the hash value at any time. The new() function can also be passed an
+ optional string parameter, which will be hashed immediately.
+
+ Hash function modules define one variable:
+
+ digestsize
+ An integer value; the size of the digest produced by the
+ hashing objects. You could also obtain this value by creating a
+ sample object, and taking the length of the digest string it
+ returns, but using digestsize is faster.
+
+ The methods for hashing objects are always the following:
+
+ copy ()
+ Return a separate copy of this hashing object. An update to
+ this copy won't affect the original object.
+
+ digest ()
+ Return the hash value of this hashing object, as a string
+ containing 8-bit data. The object is not altered in any way by
+ this function; you can continue updating the object after
+ calling this function.
+
+ digest ()
+ Return the hash value of this hashing object, as a string
+ containing the digest data as hexadecimal digits. The resulting
+ string will be twice as long as that returned by digest(). The
+ object is not altered in any way by this function; you can
+ continue updating the object after calling this function.
+
+ update (arg)
+ Update this hashing object with the string arg.
+
+ Here's an example, using RSA Data Security's MD5 algorithm:
+
+
+>>> from Crypto.Hash import MD5
+>>> m = MD5.new()
+>>> m.update('abc')
+>>> m.digest()
+'\220\001P\230<\322O\260\326\226?@}(\341\177r'
+
+ Or, more compactly:
+
+
+>>> MD5.new('abc').digest()
+'\220\001P\230<\322O\260\326\226?@}(\341\177r'
+
+2.1 Algorithm-specific Notes for Hash Functions
+
+ HAVAL provides a variable-size digest, and allows for a variable
+ number of rounds. It's believed that increasing the number of rounds
+ increases the security; at least, I don't know of any results to the
+ contrary. The HAVAL.new() accordingly has two keyword arguments,
+ rounds and digestsize. rounds can be 3, 4, or 5, and has a default
+ value of 5. digestsize can be 128, 160, 192, 224, or 256 bits, and has
+ a default value of 256.
+
+2.2 Security Notes
+
+ Hashing algorithms are broken when it's easy to compute a string that
+ produces a given hash value, or to find two messages that produce the
+ same hash value. Consider an example where Alice and Bob are using
+ digital signatures to sign a contract. Alice computes the hash value
+ of the text of the contract and signs it. Bob could then compute a
+ different contract that has the same hash value, and it would appear
+ that Alice has signed that bogus contract; she'd have no way to prove
+ otherwise. Finding such a message by brute force takes pow(2, b-1)
+ operations, where the hash function produces b-bit hashes.
+
+ If Bob can only find two messages with the same hash value but can't
+ choose the resulting hash value, he can look for two messages with
+ different meanings, such as "I will mow Bob's lawn for 10" and "I owe
+ Bob1,000,000", and ask Alice to sign the first, innocuous contract.
+ This attack is easier for Bob, since finding two such messages by
+ brute force will take pow(2, b/2) operations on average. However,
+ Alice can protect herself by changing the protocol; she can simply
+ append a random string to the contract before hashing and signing it;
+ the random string can then be kept with the signature.
+
+ None of the algorithms implemented here have been completely broken.
+ There are no attacks on MD2, but it's rather slow at 376 K/sec. MD4 is
+ faster at 11946 K/sec but there have been some partial attacks on it.
+ MD4 operates in three iterations of a basic mixing operation; two of
+ the three rounds have been cryptanalyzed, but the attack can't be
+ extended to the full algorithm. MD5 is a strengthened version of MD4
+ with four rounds; an attack against one round has been found. XXX
+ Dobbertin's attack. Because MD5 is more commonly used, the
+ implementation is better optimized and thus faster on x86 processors
+ (27193 K/sec). MD4 may be faster than MD5 when other processors and
+ compilers are used.
+
+ All the MD algorithms produce 128-bit hashes; SHA produces a larger
+ 160-bit hash, and there are no known attacks against it. The first
+ version of SHA had a weakness which was later corrected; the code used
+ here implements the second, corrected, version. It operates at 13157
+ K/sec. RIPEMD also has a 160-bit output, and operates at 5869 K/sec.
+ HAVAL is a variable-size hash function; it can generate hash values
+ that are 128, 160, 192, 224, or 256 bits in size, and can use 3, 4, or
+ 5 rounds. 5-round HAVAL runs at 5371 K/sec.
+
+2.3 Credits
+
+ The MD2, MD4, and HAVAL implementations were written by A.M. Kuchling,
+ and the MD5 code was implemented by Colin Plumb. The SHA code was
+ originally written by Peter Gutmann. The RIPEMD code was written by
+ Antoon Bosselaers, and adapted for the toolkit by Hirendra Hindocha.
+
+ 3. Crypto.Cipher: Encryption Algorithms
+
+ Encryption algorithms transform their input data (called plaintext) in
+ some way that is dependent on a variable key, producing ciphertext;
+ this transformation can easily be reversed, if (and, hopefully, only
+ if) one knows the key. The key can be varied by the user or
+ application, chosen from some very large space of possible keys.
+
+ For a secure encryption algorithm, it should be very difficult to
+ determine the original plaintext without knowing the key; usually, no
+ clever attacks on the algorithm are known, so the only way of breaking
+ the algorithm is to try all possible keys. Since the number of
+ possible keys is usually of the order of 2 to the power of 56 or 128,
+ this is not a serious threat, although 2 to the power of 56 is now
+ considered insecure in the face of custom-built parallel computers and
+ distributed key guessing efforts.
+
+ Block ciphers take multibyte inputs of a fixed size (frequently 8 or
+ 16 bytes long) and encrypt them. Block ciphers can be operated in
+ various modes. The simplest is Electronic Code Book (or ECB) mode. In
+ this mode, each block of plaintext is simply encrypted to produce the
+ ciphertext. This mode can be dangerous, because many files will
+ contain patterns greater than the block size; for example, the
+ comments in a C program may contain long strings of asterisks intended
+ to form a box. All these identical blocks will encrypt to identical
+ ciphertext; an adversary may be able to use this structure to obtain
+ some information about the text.
+
+ To eliminate this weakness, there are various feedback modes, where
+ the plaintext is combined with the previous ciphertext before
+ encrypting; this eliminates any such structure. One mode is Cipher
+ Block Chaining (CBC mode); another is Cipher FeedBack (CFB mode). CBC
+ mode still encrypts in blocks, and thus is only slightly slower than
+ ECB mode. CFB mode encrypts on a byte-by-byte basis, and is much
+ slower than either of the other two modes. The chaining feedback modes
+ require an initialization value to start off the encryption; this is a
+ string of the same length as the ciphering algorithm's block size, and
+ is passed to the new() function.
+
+ There is also a special PGP mode, which is a variant of CFB used by
+ the PGP program. While you can use it in non-PGP programs, it's quite
+ non-standard.
+
+ The currently available block ciphers are listed in the following
+ table, and are available in the Crypto.Cipher package:
+
+ Cipher Key Size/Block Size
+ ARC2 Variable/8 bytes
+ Blowfish Variable/8 bytes
+ CAST Variable/8 bytes
+ DES 8 bytes/8 bytes
+ DES3 (Triple DES) 16 bytes/8 bytes
+ Diamond Variable/16 bytes
+ IDEA 16 bytes/8 bytes
+ RC5 Variable/8 bytes
+
+ In a strict formal sense, stream ciphers encrypt data bit-by-bit;
+ practically, stream ciphers work on a character-by-character basis.
+ Stream ciphers use exactly the same interface as block ciphers, with a
+ block length that will always be 1; this is how block and stream
+ ciphers can be distinguished. The only feedback mode available for
+ stream ciphers is ECB mode.
+
+ The currently available stream ciphers are listed in the following
+ table:
+
+ Cipher Key Size
+ Cipher Key Size
+ ARC4 Variable
+ Sapphire Variable
+
+ ARC4 is short for `Alleged RC4'. The real RC4 algorithm is proprietary
+ to RSA Data Security Inc. In September of 1994, someone posted C code
+ to both the Cypherpunks mailing list and to the Usenet newsgroup
+ sci.crypt, claiming that it implemented the RC4 algorithm. This posted
+ code is what I'm calling Alleged RC4, or ARC4 for short. I don't know
+ if ARC4 is in fact RC4, but ARC4 has been subjected to scrutiny on the
+ Cypherpunks mailing list and elsewhere, and does not seem to be easily
+ breakable. The legal issues surrounding the use of ARC4 are unclear,
+ but be aware that it hasn't been subject to much scrutiny, and may
+ have some critical flaw that hasn't yet been discovered. The same is
+ true of ARC2, which was posted in January, 1996.
+
+ An example usage of the DES module:
+
+
+>>> from Crypto.Cipher import DES
+>>> obj=DES.new('abcdefgh', DES.ECB)
+>>> plain="Guido van Rossum is a space alien."
+>>> len(plain)
+34
+>>> obj.encrypt(plain)
+Traceback (innermost last):
+ File "<stdin>", line 1, in ?
+ValueError: Strings for DES must be a multiple of 8 in length
+>>> ciph=obj.encrypt(plain+'XXXXXX')
+>>> ciph
+'\021,\343Nq\214DY\337T\342pA\372\255\311s\210\363,\300j\330\250\312\347\342I\3
+215w\03561\303dgb/\006'
+>>> obj.decrypt(ciph)
+'Guido van Rossum is a space alien.XXXXXX'
+
+ All cipher algorithms share a common interface. After importing a
+ given module, there is exactly one function and two variables
+ available.
+
+ new (key, mode[, IV])
+ Returns a ciphering object, using key and feedback mode mode.
+ If mode is CBC or CFB, IV must be provided, and must be a
+ string of the same length as the block size. Some algorithms
+ support additional keyword arguments to this function; see the
+ "Algorithm-specific Notes for Encryption Algorithms" section
+ below for the details.
+
+ blocksize
+ An integer value; the size of the blocks encrypted by this
+ module. Strings passed to the encrypt and decrypt functions
+ must be a multiple of this length. For stream ciphers,
+ blocksize will be 1.
+
+ keysize
+ An integer value; the size of the keys required by this module.
+ If keysize is zero, then the algorithm accepts arbitrary-length
+ keys. You cannot pass a key of length 0 (that is, the null
+ string '' as such a variable-length key.
+
+ All cipher objects have at least three attributes:
+
+ blocksize
+ An integer value equal to the size of the blocks encrypted by
+ this object. Identical to the module variable of the same name.
+
+ IV
+ Contains the initial value which will be used to start a cipher
+ feedback mode. After encrypting or decrypting a string, this
+ value will reflect the modified feedback text; it will always
+ be one block in length. It is read-only, and cannot be assigned
+ a new value.
+
+ keysize
+ An integer value equal to the size of the keys used by this
+ object. If keysize is zero, then the algorithm accepts
+ arbitrary-length keys. For algorithms that support variable
+ length keys, this will be 0. Identical to the module variable
+ of the same name.
+
+ All ciphering objects have the following methods:
+
+ decrypt (string)
+ Decrypts string, using the key-dependent data in the object,
+ and with the appropriate feedback mode. The string's length
+ must be an exact multiple of the algorithm's block size.
+ Returns a string containing the plaintext.
+
+ encrypt (string)
+ Encrypts a non-null string, using the key-dependent data in the
+ object, and with the appropriate feedback mode. The string's
+ length must be an exact multiple of the algorithm's block size;
+ for stream ciphers, the string can be of any length. Returns a
+ string containing the ciphertext.
+
+3.1 Algorithm-specific Notes for Encryption Algorithms
+
+ The Diamond block cipher allows you to select the number of rounds to
+ apply, ranging from 5 to 15 (inclusive.) This is set via the rounds
+ keyword argument to the new() function; the default value is 8 rounds.
+
+ RC5 has even more parameters; see Ronald Rivest's paper at
+ [31]http://theory.lcs.mit.edu/~rivest/rc5rev.ps for the implementation
+ details. The keyword parameters are:
+
+ * version: The version of the RC5 algorithm to use; currently the
+ only legal value is 0x10 for RC5 1.0.
+ * wordsize: The word size to use; 16 or 32 are the only legal
+ values. (A larger word size is better, so usually 32 will be used.
+ 16-bit RC5 is probably only of academic interest.)
+ * rounds: The number of rounds to apply, the larger the more secure:
+ this can be any value from 0 to 255, so you will have to choose a
+ value balanced between speed and security.
+
+3.2 Security Notes
+
+ Encryption algorithms can be broken in several ways. If you have some
+ ciphertext and know (or can guess) the corresponding plaintext, you
+ can simply try every possible key in a known-plaintext attack. Or, it
+ might be possible to encrypt text of your choice using an unknown key;
+ for example, you might mail someone a message intending it to be
+ encrypted and forwarded to someone else. This is a chosen-plaintext
+ attack, which is particularly effective if it's possible to choose
+ plaintexts that reveal something about the key when encrypted.
+
+ DES (2458 K/sec) has a 56-bit key; this is starting to become too
+ small for safety. It has been estimated that it would only cost
+ $1,000,000 to build a custom DES-cracking machine that could find a
+ key in 3 hours. A chosen-ciphertext attack using the technique of
+ linear cryptanalysis can break DES in pow(2, 43) steps. However,
+ unless you're encrypting data that you want to be safe from major
+ governments, DES will be fine. DES3 (509 K/sec) uses three DES
+ encryptions for greater security and a 112-bit or 168-bit key, but is
+ correspondingly slower.
+
+ There are no publicly known attacks against IDEA (2005 K/sec), and
+ it's been around long enough to have been examined. There are no known
+ attacks against ARC2 (1644 K/sec), ARC4 (4630 K/sec), Blowfish (5323
+ K/sec), CAST (1314 K/sec), Diamond (1670 K/sec), RC5 (1370 K/sec), or
+ Sapphire (3568 K/sec), but they're all relatively new algorithms and
+ there hasn't been time for much analysis to be performed; use them for
+ serious applications only after careful research. Skipjack (XXX) is
+ relatively slow, and its 80-bit key size is secure at the moment, but
+ doesn't leave much of a margin of safety; only use it if you believe
+ that the NSA has mystical cipher design abilities.
+
+3.3 Credits
+
+ The code for Blowfish was written by Bryan Olson, partially based on a
+ previous implementation by Bruce Schneier, who also invented the
+ algorithm; the Blowfish algorithm has been placed in the public domain
+ and can be used freely. (See [32]http://www.counterpane.com for more
+ information about Blowfish.) The CAST implementation was written by
+ Wim Lewis. The DES implementation was written by Eric Young, and the
+ IDEA implementation by Colin Plumb. The RC5 implementation was written
+ by A.M. Kuchling.
+
+ The Alleged RC4 code was posted to the sci.crypt newsgroup by an
+ unknown party, and re-implemented by A.M. Kuchling. The Sapphire
+ stream cipher was developed by Michael P. Johnson, and is in the
+ public domain; the implementation used here was written by A.M.
+ Kuchling and is based on Johnson's code.
+
+ 4. Crypto.Protocol: Various Protocols
+
+4.1 Crypto.Protocol.AllOrNothing
+
+ This module implements all-or-nothing package transformations. An
+ all-or-nothing package transformation is one in which some text is
+ transformed into message blocks, such that all blocks must be obtained
+ before the reverse transformation can be applied. Thus, if any blocks
+ are corrupted or lost, the original message cannot be reproduced.
+
+ An all-or-nothing package transformation is not encryption, although a
+ block cipher algorithm is used. The encryption key is randomly
+ generated and is extractable from the message blocks.
+
+ This class implements the All-Or-Nothing package transformation
+ algorithm described in Rivest: ``All-Or-Nothing Encryption and The
+ Package Transform.'' To appear in the Proceedings of the 1997 Fast
+ Software Encryption Conference.
+ http://theory.lcs.mit.edu/ rivest/fusion.ps
+
+ AllOrNothing (ciphermodule, mode=None, IV=None)
+ Class implementing the All-or-Nothing package transform.
+
+ ciphermodule is a module implementing the cipher algorithm to
+ use. Optional arguments mode and IV are passed directly through
+ to the ciphermodule.new() method; they are the feedback mode
+ and initialization vector to use. All three arguments must be
+ the same for the object used to create the digest, and to
+ undigest'ify the message blocks.
+
+ The module passed as ciphermodule must provide the following
+ interface:
+
+ ciphermodule.keysize: Attribute containing the cipher
+ algorithm's key size in bytes. If the cipher supports variable
+ length keys, then typically ciphermodule.keysize will be zero.
+ In that case a key size of 16 bytes will be used.
+
+ ciphermodule.blocksize: Attribute containing the cipher
+ algorithm's input block size in bytes.
+
+ ciphermodule.new(key, mode, IV): Function which returns a new
+ instance of a cipher object, initialized to key. The returned
+ object must have an encrypt() method that accepts a string of
+ ciphermodule.blocksize bytes and returns a string containing
+ the encrypted text.
+
+ Note that the encryption key is randomly generated
+ automatically when needed.
+
+ The methods of the AllorNothing class are:
+
+ digest ()
+ Perform the All-or-Nothing package transform on the current
+ string. Output is a list of message blocks describing the
+ transformed text, where each block is a string of bit length
+ equal to the cipher module's blocksize.
+
+ reset (text = "")
+ Reset the current string to be transformed to text.
+
+ undigest (mblocks)
+ Perform the reverse package transformation on a list of message
+ blocks. Note that the cipher module used for both
+ transformations must be the same. mblocks is a list of strings
+ of bit length equal to ciphermodule's blocksize. The output is
+ a string object.
+
+ update (text)
+ Concatenate text to the string that will be transformed.
+
+4.2 Crypto.Protocol.Chaffing
+
+ Winnowing and chaffing is a technique for enhancing privacy without
+ requiring strong encryption. In short, the technique takes a set of
+ authenticated message blocks (the wheat) and adds a number of chaff
+ blocks which have randomly chosen data and MAC fields. This means that
+ to an adversary, the chaff blocks look as valid as the wheat blocks,
+ and so the authentication would have to be performed on every block.
+ By tailoring the number of chaff blocks added to the message, the
+ sender can make breaking the message computationally infeasible. There
+ are many other interesting properties of the winnow/chaff technique.
+
+ For example, say Alice is sending a message to Bob. She packetizes the
+ message and performs an all-or-nothing transformation on the packets.
+ Then she authenticates each packet with a message authentication code
+ (MAC). The MAC is a hash of the data packet, and there is a secret key
+ which she must share with Bob (key distribution is an exercise left to
+ the reader). She then adds a serial number to each packet, and sends
+ the packets to Bob.
+
+ Bob receives the packets, and using the shared secret authentication
+ key, authenticates the MACs for each packet. Those packets that have
+ bad MACs are simply discarded. The remainder are sorted by serial
+ number, and passed through the reverse all-or-nothing transform. The
+ transform means that an eavesdropper (say Eve) must acquire all the
+ packets before any of the data can be read. If even one packet is
+ missing, the data is useless.
+
+ There's one twist: by adding chaff packets, Alice and Bob can make
+ Eve's job much harder, since Eve now has to break the shared secret
+ key, or try every combination of wheat and chaff packet to read any of
+ the message. The cool thing is that Bob doesn't need to add any
+ additional code; the chaff packets are already filtered out because
+ their MACs don't match (in all likelihood - since the data and MACs
+ for the chaff packets are randomly chosen it is possible, but very
+ unlikely that a chaff MAC will match the chaff data). And Alice need
+ not even be the party adding the chaff! She could be completely
+ unaware that a third party, say Charles, is adding chaff packets to
+ her messages as they are transmitted.
+
+ For more information on winnowing and chaffing see this paper:
+
+ XXX Rivest.
+
+ Chaff (factor=1.0, blocksper=1)
+ Class implementing the chaff adding algorithm. factor is the
+ number of message blocks to add chaff to, expressed as a
+ percentage between 0.0 and 1.0; the default value is 1.0.
+ blocksper is the number of chaff blocks to include for each
+ block being chaffed, and defaults to 1. The default settings
+ add one chaff block to every message block. By changing the
+ defaults, you can adjust how computationally difficult it could
+ be for an adversary to brute-force crack the message. The
+ difficulty is expressed as:
+
+
+pow(blocksper, int(factor * number-of-blocks))
+
+ For ease of implementation, when factor < 1.0, only the first
+ int(factor*number-of-blocks) message blocks are chaffed.
+
+ Chaff instances have the following methods:
+
+ chaff (blocks)
+ Add chaff to message blocks. blocks is a list of 3-tuples of
+ the form (serial-number, data, MAC).
+
+ Chaff is created by choosing a random number of the same
+ byte-length as data, and another random number of the same
+ byte-length as MAC. The message block's serial number is placed
+ on the chaff block and all the packet's chaff blocks are
+ randomly interspersed with the single wheat block. This method
+ then returns a list of 3-tuples of the same form. Chaffed
+ blocks will contain multiple instances of 3-tuples with the
+ same serial number, but the only way to figure out which blocks
+ are wheat and which are chaff is to perform the MAC hash and
+ compare values.
+
+ Subclass methods:
+
+ __randnum (size)
+ Returns a randomly generated number with a byte-length equal to
+ size. Subclasses can use this to implement better random data
+ and MAC generating algorithms. The default algorithm is
+ probably not very cryptographically secure. It is most
+ important that the chaff data does not contain any patterns
+ that can be used to discern it from wheat data without running
+ the MAC.
+
+ 5. Crypto.PublicKey: Public Key Algorithms
+
+ So far, the encryption algorithms described have all been private key
+ ciphers. That is, the same key is used for both encryption and
+ decryption, so all correspondents must know it. This poses a problem:
+ you may want encryption to communicate sensitive data over an insecure
+ channel, but how can you tell your correspondent what the key is? You
+ can't just e-mail it to her because the channel is insecure. One
+ solution is to arrange the key via some other way: over the phone or
+ by meeting in person.
+
+ Another solution is to use public key cryptography. In a public key
+ system, there are two different keys: one for encryption and one for
+ decryption. The encryption key can be made public by listing it in a
+ directory or mailing it to your correspondent, while you keep the
+ decryption key secret. Your correspondent then sends you data
+ encrypted with your public key, and you use the private key to decrypt
+ it. While the two keys are related, it's very difficult to derive the
+ private key given only the public key; however, deriving the private
+ key is always possible given enough time and computing power. This
+ makes it very important to pick keys of the right size: large enough
+ to be secure, but small enough to be applied fairly quickly.
+
+ Many public key algorithms can also be used to sign messages; simply
+ run the message to be signed through a decryption with your private
+ key key. Anyone receiving the message can encrypt it with your
+ publicly available key and read the message. Some algorithms do only
+ one thing, others can both encrypt and authenticate.
+
+ The currently available public key algorithms are listed in the
+ following table:
+
+ Algorithm Capabilities
+ RSA Encryption, authentication/signatures
+ ElGamal Encryption, authentication/signatures
+ DSA Authentication/signatures
+ qNEW Authentication/signatures
+
+ Many of these algorithms are patented. Before using any of them in a
+ commercial product, consult a patent attorney; you may have to arrange
+ a license with the patent holder.
+
+ An example of using the RSA module to sign a message:
+
+
+>>> from Crypto.Hash import MD5
+>>> from Crypto.PublicKey import RSA
+>>> RSAkey=RSA.generate(384, randfunc) # This will take a while...
+>>> hash=MD5.new(plaintext).digest()
+>>> signature=RSAkey.sign(hash, "")
+>>> signature # Print what an RSA sig looks like--you don't really care.
+('\021\317\313\336\264\315' ...,)
+>>> RSAkey.verify(hash, signature) # This sig will check out
+1
+>>> RSAkey.verify(hash[:-1], signature)# This sig will fail
+0
+
+ Public key modules make the following functions available:
+
+ construct (tuple)
+ Constructs a key object from a tuple of data. This is
+ algorithm-specific; look at the source code for the details.
+ (To be documented later.)
+
+ generate (size, randfunc, progress_func=None)
+ Generate a fresh public/private key pair. size is a
+ algorithm-dependent size parameter; the larger it is, the more
+ difficult it will be to break the key. Safe key sizes vary from
+ algorithm to algorithm; you'll have to research the question
+ and decide on a suitable key size for your application.
+ randfunc is a random number generation function; it should
+ accept a single integer N and return a string of random data N
+ bytes long. You should always use a cryptographically secure
+ random number generator, such as the one defined in the
+ randpool module; don't just use the current time and the
+ whrandom module.
+
+ progress_func is an optional function that will be called with
+ a short string containing the key parameter currently being
+ generated; it's useful for interactive applications where a
+ user is waiting for a key to be generated.
+
+ If you want to interface with some other program, you will have to
+ know the details of the algorithm being used; this isn't a big loss.
+ If you don't care about working with non-Python software, simply use
+ the pickle module when you need to write a key or a signature to a
+ file. It's portable across all the architectures that Python supports,
+ and it's simple to use.
+
+ Public key objects always support the following methods. Some of them
+ may raise exceptions if their functionality is not supported by the
+ algorithm.
+
+ canencrypt ()
+ Returns true if the algorithm is capable of encrypting and
+ decrypting data; returns false otherwise. To test if a given
+ key object can sign data, use key.canencrypt() and
+ key.hasprivate().
+
+ cansign ()
+ Returns true if the algorithm is capable of signing data;
+ returns false otherwise. To test if a given key object can sign
+ data, use key.cansign() and key.hasprivate().
+
+ decrypt (tuple)
+ Decrypts tuple with the private key, returning another string.
+ This requires the private key to be present, and will raise an
+ exception if it isn't present. It will also raise an exception
+ if string is too long.
+
+ encrypt (string, K)
+ Encrypts string with the private key, returning a tuple of
+ strings; the length of the tuple varies from algorithm to
+ algorithm. K should be a string of random data that is as long
+ as possible. Encryption does not require the private key to be
+ present inside the key object. It will raise an exception if
+ string is too long. For ElGamal objects, the value of K
+ expressed as a big-endian integer must be relatively prime to
+ self.p-1; an exception is raised if it is not.
+
+ hasprivate ()
+ Returns true if the key object contains the private key data,
+ which will allow decrypting data and generating signatures.
+ Otherwise this returns false.
+
+ publickey ()
+ Returns a new public key object that doesn't contain the
+ private key data.
+
+ sign (string, K)
+ Sign string, returning a signature, which is just a tuple; in
+ theory the signature may be made up of any Python objects at
+ all; in practice they'll be either strings or numbers. K should
+ be a string of random data that is as long as possible.
+ Different algorithms will return tuples of different sizes.
+ sign() raises an exception if string is too long. For ElGamal
+ objects, the value of K expressed as a big-endian integer must
+ be relatively prime to self.p-1; an exception is raised if it
+ is not.
+
+ size ()
+ Returns the maximum size of a string that can be encrypted or
+ signed, measured in bits. String data is treated in big-endian
+ format; the most significant byte comes first. (This seems to
+ be a de facto standard for cryptographical software.) If the
+ size is not a multiple of 8, then some of the high order bits
+ of the first byte must be zero. Usually it's simplest to just
+ divide the size by 8 and round down.
+
+ verify (string, signature)
+ Returns true if the signature is valid, and false otherwise.
+ string is not processed in any way; verify does not run a hash
+ function over the data, but you can easily do that yourself.
+
+5.1 The ElGamal and DSA algorithms
+
+ For RSA, the K parameters are unused; if you like, you can just pass
+ empty strings. The ElGamal and DSA algorithms require a real K value
+ for technical reasons; see Schneier's book for a detailed explanation
+ of the respective algorithms. This presents a possible hazard that can
+ inadvertently reveal the private key. Without going into the
+ mathematical details, the danger is as follows. K is never derived or
+ needed by others; theoretically, it can be thrown away once the
+ encryption or signing operation is performed. However, revealing K for
+ a given message would enable others to derive the secret key data;
+ worse, reusing the same value of K for two different messages would
+ also enable someone to derive the secret key data. An adversary could
+ intercept and store every message, and then try deriving the secret
+ key from each pair of messages.
+
+ This places implementors on the horns of a dilemma. On the one hand,
+ you want to store the K values to avoid reusing one; on the other
+ hand, storing them means they could fall into the hands of an
+ adversary. One can randomly generate K values of a suitable length
+ such as 128 or 144 bits, and then trust that the random number
+ generator probably won't produce a duplicate anytime soon. This is an
+ implementation decision that depends on the desired level of security
+ and the expected usage lifetime of a private key. I cannot choose and
+ enforce one policy for this, so I've added the K parameter to the
+ encrypt and sign functions. You must choose K by generating a string
+ of random data; for ElGamal, when interpreted as a big-endian number
+ (with the most significant byte being the first byte of the string), K
+ must be relatively prime to self.p-1; any size will do, but brute
+ force searches would probably start with small primes, so it's
+ probably good to choose fairly large numbers. It might be simplest to
+ generate a prime number of a suitable length using the
+ Crypto.Util.number module.
+
+5.2 Security Notes for Public-key Algorithms
+
+ Any of these algorithms can be trivially broken; for example, RSA can
+ be broken by factoring the modulus n into its two prime factors. This
+ is easily done by the following code:
+
+
+for i in range(2, n):
+ if (n%i)==0: print i, 'is a factor' ; break
+
+ However, n is usually a few hundred bits long, so this simple program
+ wouldn't find a solution before the universe comes to an end. Smarter
+ algorithms can factor numbers more quickly, but it's still possible to
+ choose keys so large that they can't be broken in a reasonable amount
+ of time. For ElGamal and DSA, discrete logarithms are used instead of
+ factoring, but the principle is the same.
+
+ Safe key sizes depend on the current state of computer science and
+ technology. At the moment, one can roughly define three levels of
+ security: low-security commercial, high-security commercial, and
+ military-grade. For RSA, these three levels correspond roughly to 512,
+ 768, and 1024 bit-keys. For ElGamal and DSA, the key sizes should be
+ somewhat larger for the same level of security, around 768, 1024, and
+ 1536 bits.
+
+ 6. Crypto.Util: Odds and Ends
+
+ This chapter contains all the modules that don't fit into any of the
+ other chapters.
+
+6.1 Crypto.Util.number
+
+ This module contains various functions of number-theoretic functions.
+
+ GCD (x,y)
+ Return the greatest common divisor of x and y.
+
+ getPrime (N, randfunc)
+ Return an N-bit random prime number, using random data obtained
+ from the function randfunc. randfunc must take a single integer
+ argument, and return a string of random data of the
+ corresponding length; the getBytes() method of a RandomPool
+ object will serve the purpose nicely, as will the read() method
+ of an opened file such as "/dev/random".
+
+ getRandomNumber (N, randfunc)
+ Return an N-bit random number, using random data obtained from
+ the function randfunc. As usual, randfunc must take a single
+ integer argument, and return a string of random data of the
+ corresponding length.
+
+ inverse (u, v)
+ Return the inverse of u modulo v.
+
+ isPrime (N)
+ Returns true if the number N is prime, as determined by a
+ Rabin-Miller test.
+
+6.2 Crypto.Util.randpool
+
+ For cryptographic purposes, ordinary random number generators are
+ frequently insufficient, because if some of their output is known, it
+ is frequently possible to derive the generator's future (or past)
+ output. This is obviously a Bad Thing; given the generator's state at
+ some point in time, someone could try to derive any keys generated
+ using it. The solution is to use strong encryption or hashing
+ algorithms to generate successive data; this makes breaking the
+ generator as difficult as breaking the algorithms used.
+
+ Understanding the concept of entropy is important for using the random
+ number generator properly. In the sense we'll be using it, entropy
+ measures the amount of randomness; the usual unit is in bits. So, a
+ single random bit has an entropy of 1 bit; a random byte has an
+ entropy of 8 bits. Now consider a one-byte field in a database
+ containing a person's sex, represented as a single character "M" or
+ "F". What's the entropy of this field? Since there are only two
+ possible values, it's not 8 bits, but two; if you were trying to guess
+ the value, you wouldn't have to bother trying "Q" or "@".
+
+ Now imagine running that single byte field through a hash function
+ that produces 128 bits of output. Is the entropy of the resulting hash
+ value 128 bits? No, it's still just 1 bit. The entropy is a measure of
+ how many possible states of the data exist. For English text, the
+ entropy of a five-character string is not 40 bits; it's somewhat less,
+ because not all combinations would be seen. "Guido" is a possible
+ string, as is "In th"; "zJwvb" is not.
+
+ The relevance to random number generation? We want enough bits of
+ entropy to avoid making an attack on our generator possible. An
+ example: One computer system had a mechanism which generated nonsense
+ passwords for its users. This is a good idea, since it would prevent
+ people from choosing their own name or some other easily guessed
+ string. Unfortunately, the random number generator used only had 65536
+ states, which meant only 65536 different passwords would ever be
+ generated, and it was easily to compute all the possible passwords and
+ try them. The entropy of the random passwords was far too low. By the
+ same token, if you generate an RSA key with only 32 bits of entropy
+ available, there are only about 4.2 billion keys you could have
+ generated, and an adversary could compute them all to find your
+ private key. See RFC 1750: "Randomness Recommendations for Security"
+ for an interesting discussion of the issues related to random number
+ generation.
+
+ The randpool module implements a strong random number generator in the
+ RandomPool class. The internal state consists of a string of random
+ data, which is returned as callers request it. The class keeps track
+ of the number of bits of entropy left, and provides a function to add
+ new random data; this data can be obtained in various ways, such as by
+ using the variance in a user's keystroke timings.
+
+ RandomPool ([numbytes, cipher, hash])
+ An object of the RandomPool class can be created without
+ parameters if desired. numbytes sets the number of bytes of
+ random data in the pool, and defaults to 160 (1280 bits). hash
+ can be a string containing the module name of the hash function
+ to use in stirring the random data, or a module object
+ supporting the hashing interface. The default action is to use
+ SHA.
+
+ The cipher argument is vestigial; it was removed from version
+ 1.1 so RandomPool would work even in the limited exportable
+ subset of the code. It can have any value at all, since it's no
+ longer used at all.
+
+ RandomPool objects define the following variables and methods:
+
+ addEvent (time[, string])
+ Adds an event to the random pool. time should be set to the
+ current system time, measured at the highest resolution
+ available. string can be a string of data that will be XORed
+ into the pool, and can be used to increase the entropy of the
+ pool. For example, if you're encrypting a document, you might
+ use the hash value of the document; an adversary presumably
+ won't have the plaintext of the document, and thus won't be
+ able to use this information to break the generator.
+
+ The return value is the value of self.entropy after the data has been
+ added. The function works in the following manner: the time between
+ successive calls to the addEvent method is determined, and the entropy
+ of the data is guessed; the larger the time between calls, the better.
+ The system time is then read and added to the pool, along with the
+ string parameter, if present. The hope is that the low-order bits of
+ the time are effectively random. In an application, it is recommended
+ that addEvent() be called as frequently as possible, with whatever
+ random data can be found.
+
+ bits
+ A constant integer value containing the number of bits of data
+ in the pool, equal to the bytes variable multiplied by 8.
+
+ bytes
+ A constant integer value containing the number of bytes of data
+ in the pool.
+
+ entropy
+ An integer value containing the number of bits of entropy
+ currently in the pool. The value is incremented by the
+ addEvent() method, and decreased by the getBytes method.
+
+ getBytes (num)
+ Returns a string containing num bytes of random data, and
+ decrements the amount of entropy available. It is not an error
+ to reduce the entropy to zero, or to call this function when
+ the entropy is zero. This simply means that, in theory, enough
+ random information has been extracted to derive the state of
+ the generator. It is the caller's responsibility to monitor the
+ amount of entropy remaining and decide whether it is sufficent
+ for secure operation.
+
+ stir ()
+ Scrambles the random pool using the previously chosen
+ encryption and hash function. An adversary may attempt to learn
+ or alter the state of the pool in order to affect its future
+ output; this function destroys the existing state of the pool
+ in a non-reversible way. It is recommended that stir() be
+ called before and after using the RandomPool object. Even
+ better, several calls to stir() can be interleaved with calls
+ to addEvent().
+
+ The KeyboardRandomPool class is a subclass of RandomPool that adds the
+ capability to save and load the pool from a disk file, and provides a
+ method to obtain random data from the keyboard.
+
+ KeyboardRandomPool ([filename, numbytes, cipher, hash])
+ The path given in filename will be automatically opened, and an
+ existing random pool read; if no such file exists, the pool
+ will be initialized as usual. If omitted, the filename defaults
+ to the empty string, which will prevent it from being saved to
+ a file. The other arguments are identical to those for the
+ RandomPool constructor.
+
+ randomize ()
+ (Unix systems only) Obtain random data from the keyboard. This
+ works by prompting the user to hit keys at random, and then
+ using the keystroke timings (and also the actual keys pressed)
+ to add entropy to the pool. This works similarly to PGP's
+ random pool mechanism.
+
+ save ()
+ Opens the file named by the filename attribute, and saves the
+ random data into the file using the pickle module.
+
+6.3 Crypto.Util.RFC1751
+
+ The keys for private-key algorithms should be arbitrary binary data.
+ Many systems err by asking the user to enter a password, and then
+ using the password as the key. This limits the space of possible keys,
+ as each key byte is constrained within the range of possible ASCII
+ characters, 32-127, instead of the whole 0-255 range possible with
+ ASCII. Unfortunately, it's difficult for humans to remember 16 or 32
+ hex digits.
+
+ One solution is to request a lengthy passphrase from the user, and
+ then run it through a hash function such as SHA or MD5. Another
+ solution is discussed in RFC 1751, "A Convention for Human-Readable
+ 128-bit Keys", by Daniel L. McDonald. Binary keys are transformed into
+ a list of short English words that should be easier to remember. For
+ example, the hex key EB33F77EE73D4053 is transformed to "TIDE ITCH
+ SLOW REIN RULE MOT".
+
+ Key2English (key)
+ Accepts a string of arbitrary data key, and returns a string
+ containing uppercase English words separated by spaces. key's
+ length must be a multiple of 8.
+
+ English2Key (string)
+ Accepts string containing English words, and returns a string
+ of binary data representing the key. Words must be separated by
+ whitespace, and can be any mixture of uppercase and lowercase
+ characters. 6 words are required for 8 bytes of key data, so
+ the number of words in string must be a multiple of 6.
+
+ 7. The Demonstration Programs
+
+ The Python cryptography modules comes with various demonstration
+ programs, located in the "Demo/" directory. None of them is
+ particularly well-finished, or suitable for serious use. Rather,
+ they're intended to illustrate how the toolkit is used, and to provide
+ some interesting possible uses. Feel free to incorporate the code (or
+ modifications of it) into your own programs.
+
+7.1 Demo 1: "cipher"
+
+ "cipher" encrypts and decrypts files. On most Unix systems, the
+ "crypt" program uses a variant of the Enigma cipher. This is not
+ secure, and there exists a freely available program called ``Crypt
+ Breaker's Workbench'' which helps in breaking the cipher if you have
+ some knowledge of the encrypted data.
+
+ "cipher" is a more secure file encryption program. Simply list the
+ names of the files to be encrypted on the command line. "cipher" will
+ go through the list and encrypt or decrypt them; "cipher" can
+ recognize files it has previously encrypted. The ciphertext of a file
+ is placed in a file of the same name with '".cip"' appended; the
+ original file is not deleted, since I'm not sure that all errors
+ during operation are caught, and I don't want people to accidentally
+ erase important files.
+
+ There are two command-line options: -c and -k. Both of them require an
+ argument. -c ciphername uses the given encryption algorithm
+ ciphername; for example, -c des will use the DES algorithm. The name
+ should be the same as an available module name; thus it should be in
+ lowercase letters. The default cipher is IDEA.
+
+ -k key can be used to set the encryption key to be used. Note that on
+ a multiuser Unix system, the ps command can be used to view the
+ arguments of commands executed by other users, so this is insecure; if
+ you're the only user (say, on your home computer running Linux) you
+ don't have to worry about this. If no key is set on the command line,
+ "cipher" will prompt the user to input a key on standard input.
+
+ 7.1.1 Technical Details
+
+ The encrypted file is not pure ciphertext. First comes a magic string;
+ this is currently the sequence "ctx" and a byte containing 1 (the
+ version number of "cipher"). This is followed by the null-terminated
+ name of the encryption algorithm, and the rest of the file contains
+ the ciphertext.
+
+ The plaintext is encrypted in CBC mode. The initial value for the
+ feedback is always set to a block filled with the letter 'A', and then
+ a block of random data is encrypted. This garbage block will be
+ discarded on decryption. Note that the random data is not generated in
+ a cryptographically secure way, and this may provide a tiny foothold
+ for an attacker.
+
+ After the random block is generated, the magic string, length of the
+ original file, and original filename are all encrypted before the file
+ data is finally processed. Some extra characters of padding may be
+ added to obtain an integer number of blocks. This padding will also be
+ discarded on decryption. Note that the plaintext file will be
+ completely read into memory before encryption is performed; no
+ buffering is done. Therefore, don't encrypt 20-megabyte files unless
+ you're willing to face the consequences of a 20-megabyte process.
+
+ Areas for improvements to "cipher" are: cryptographically secure
+ generation of random data for padding, key entry, and buffering of
+ file input.
+
+7.2 Demo 2: "secimp" and "sign"
+
+ "secimp" demonstrates an application of the Toolkit that may be useful
+ if Python is being used as an extension language for mail and Web
+ clients: secure importing of Python modules. To use it, run "sign.py"
+ in a directory with several compiled Python files present. It will use
+ the key in "testkey.py" to generate digital signatures for the
+ compiled Python code, and save both the signature and the code in a
+ file ending in ".pys". Then run python -i secimp.py, and import a file
+ by using secimport.
+
+ For example, if "foo.pys" was constructed, do secimport('foo'). The
+ import should succeed. Now fire up Emacs or some other editor, and
+ change a string in the code in "foo.pys"; you might try changing a
+ letter in the name of a variable. When you run secimport('foo'), it
+ should raise an exception reporting the failed signature. If you
+ execute the statement __import__ = secimport, the secure import will
+ be used by default for all future module imports. Alternatively, if
+ you were creating a restricted execution environment using "rexec.py",
+ you could place secimport() in the restricted environment's namespace
+ as the default import function.
+
+ 8. Extending the cryptography modules
+
+ Preserving the a common interface for cryptographic routines is a good
+ idea. This chapter explains how to interface your own routines to the
+ Toolkit.
+
+ The basic process is as follows:
+ 1.
+ Modify the default definition of a C structure to include
+ whatever instance data your algorithm requires.
+ 2.
+ Write 3 or 4 standard routines. Their names and parameters are
+ specified in the following subsections.
+ 3.
+ Modify "buildkit" to contain an entry for your new algorithm.
+ Then run "buildkit" to rebuild all the source files.
+ 4.
+ Send a copy of the code to me, if you like; code for new
+ algorithms will be gratefully accepted.
+
+8.1 Creating a Custom Object
+
+ In the C code for the interpreter, Python objects are defined as a
+ structure. The default structure is the following:
+
+
+typedef struct
+{
+ PCTObject_HEAD
+} ALGobject;
+
+ PCTObject_HEAD is a preprocessor macro which will contain various
+ internal variables used by the interpreter; it must always be the
+ first item in the structure definition, and must not be followed by a
+ semicolon. Following it, you can put whatever instance variables you
+ require. Data that does not depend on the instance or key, such as a
+ static lookup table, need not be encapsulated inside objects; instead,
+ it can be defined as a variable interior to the module.
+
+ As an example, for IDEA encryption, a schedule of encryption and
+ decryption data has to be maintained, resulting in the following
+ definition:
+
+
+typedef struct
+{
+ PCTObject_HEAD
+ int EK[6][9], DK[6][9];
+} IDEAobject;
+
+8.2 Standard Routines
+
+ The interface to Python is implemented in the files ending in ".in",
+ so "hash.in" contains the basic code for modules containing hash
+ functions, for example. "buildkit", a Python script, reads the
+ configuration file and generates source code by interweaving the
+ interface files and the implementation file.
+
+ If your algorithm is called ALG, the implementation should be in the
+ file "ALG.c". This is case-sensitive, as are the following function
+ names.
+
+ 8.2.1 Hash functions
+
+ * void ALGinit(ALGobject *self);
+ * void ALGupdate(ALGobject *self, char *buffer, int length);
+ * PyObject *ALGdigest(ALGobject *self);
+ * void ALGcopy(ALGobject *source, ALGobject *dest);
+
+ void ALGinit ( ALGobject *self)
+ This function should initialize the hashing object, setting
+ state variables to their expected initial state.
+
+ void ALGupdate ( ALGobject *self, char *buffer, int length)
+ This function should perform a hash on the region pointed to by
+ buffer, which will contain length bytes. The contents of the
+ object pointed to by self should be updated appropriately.
+
+ void ALGdigest ( ALGobject *self)
+ This function returns a string containing the value of the hash
+ function. The object should not be changed in any way by this
+ function. Some hash functions require some computation to be
+ performed before returning a value; for example, the number of
+ bytes may be hashed into the final value. If this is the case
+ for your hash function, you must make a copy of the object's
+ data, perform the final computation on that copy, and return
+ the result.
+
+ Results are returned by calling a Python function,
+ PyString_FromStringAndSize(char *string, int length). This function
+ returns a string object which should be returned to the caller. So,
+ the last line of the ALGdigest function might be:
+
+
+ return PyString_FromStringAndSize(digest, 16);
+
+ void ALGcopy ( ALGobject *source, ALGobject *dest)
+ Given the source and destination objects, the state variables
+ of the source object should be copied to the dest object; the
+ source object should not be altered in any way by the
+ operation.
+
+ 8.2.2 Block ciphers
+
+ * void ALGinit(ALGobject *self, unsigned char *key, int length);
+ * PyObject *ALGencrypt(ALGobject *self, unsigned char *block);
+ * PyObject *ALGdecrypt(ALGobject *self, unsigned char *block);
+
+ void ALGinit ( ALGobject *self, unsigned char *key, int length)
+ This function initializes a block cipher object to encrypt and
+ decrypt with key. If the cipher requires a fixed-length key,
+ then the buffer pointed to by key will always of that length,
+ and the value of length will be a random value that should be
+ ignored. If the algorithm accepts a variable-length key, then
+ length will be nonzero, and will contain the size of the key.
+
+ void ALGencrypt ( ALGobject *self, unsigned char *block)
+ This function should encrypt the data pointed to by block,
+ using the key-dependent data contained in self. Only ECB mode
+ needs to be implemented; block.in takes care of the other
+ ciphering modes.
+
+ void ALGdecrypt ( ALGobject *self, unsigned char *block)
+ This function should decrypt the data pointed to by block,
+ using the key-dependent data contained in self.
+
+8.3 Portability macros
+
+ Implementation code must be carefully written to produce the same
+ results with any machine or compiler, without having to set any
+ compile-time definitions. Code that is simply portable by nature is
+ preferable, but it is possible to detect features of the host machine
+ when new objects are created, and then execute special code to convert
+ data to a preferred form.
+
+ While portability macros are written for speed, there's no need to
+ execute them on every encryption or updating operation. Instead, add
+ variables to your object to hold the values of the portability macros,
+ and execute the macros only once per object, in your ALGinit function.
+ Then the code can simply check the results of the macros and act
+ appropriately.
+
+ Currently there is only one portability macro defined:
+
+ void TestEndianness (variable)
+ Determines the endianness of the current machine, and sets
+ variable to a constant representing the value for this machine.
+ Possible constants are PCT_BIG_ENDIAN and PCT_LITTLE_ENDIAN;
+ they are defined along with the TestEndianness macro.
+
+8.4 Informing the author
+
+ Code for additional cryptographic algorithms can be mailed to me at
+ akuchling@acm.org. You can make things much easier for me by doing the
+ following:
+ * If you wrote the code, please release it into the public domain or
+ under the MIT X11 license. If you didn't write it, please tell me
+ where to find the original author or source code, so that I can
+ check the licensing conditions.
+ * Include some test data. It is not sufficient to check that
+ encryption and decryption cancel out properly. An implementation
+ might work fine on a single platform, but two machines with
+ different endianness might produce different results. This would
+ be fatal for portability and interoperating programs. So, please
+ include test data; you can either send me patches to "test.py", or
+ simply send me documents describing the data.
+
+ About this document ...
+
+ The Python Cryptography Modules
+
+ This document was generated using the [33]LaTeX2HTML translator
+ Version 98.2beta (June 26th, 1998)
+
+ Copyright © 1993, 1994, 1995, 1996, 1997, [34]Nikos Drakos, Computer
+ Based Learning Unit, University of Leeds.
+
+ The command line arguments were:
+ latex2html -init_file
+ /home/akuchlin/src/Python-1.5/Doc/perl/l2hinit.perl -link 3 -split 1
+ -dir pycrypt ./pycrypt.tex.
+
+ The translation was initiated by on 1998-07-13
+ _________________________________________________________________
+
+References
+
+ 1. file://localhost/tmp/pycrypt.html
+ 2. file://localhost/tmp/pycrypt.html#SECTION000210000000000000000
+ 3. file://localhost/tmp/pycrypt.html#SECTION000220000000000000000
+ 4. file://localhost/tmp/pycrypt.html#SECTION000300000000000000000
+ 5. file://localhost/tmp/pycrypt.html#SECTION000310000000000000000
+ 6. file://localhost/tmp/pycrypt.html#SECTION000320000000000000000
+ 7. file://localhost/tmp/pycrypt.html#SECTION000330000000000000000
+ 8. file://localhost/tmp/pycrypt.html#SECTION000400000000000000000
+ 9. file://localhost/tmp/pycrypt.html#SECTION000410000000000000000
+ 10. file://localhost/tmp/pycrypt.html#SECTION000420000000000000000
+ 11. file://localhost/tmp/pycrypt.html#SECTION000430000000000000000
+ 12. file://localhost/tmp/pycrypt.html#SECTION000500000000000000000
+ 13. file://localhost/tmp/pycrypt.html#SECTION000510000000000000000
+ 14. file://localhost/tmp/pycrypt.html#SECTION000520000000000000000
+ 15. file://localhost/tmp/pycrypt.html#SECTION000600000000000000000
+ 16. file://localhost/tmp/pycrypt.html#SECTION000610000000000000000
+ 17. file://localhost/tmp/pycrypt.html#SECTION000620000000000000000
+ 18. file://localhost/tmp/pycrypt.html#SECTION000700000000000000000
+ 19. file://localhost/tmp/pycrypt.html#SECTION000710000000000000000
+ 20. file://localhost/tmp/pycrypt.html#SECTION000720000000000000000
+ 21. file://localhost/tmp/pycrypt.html#SECTION000730000000000000000
+ 22. file://localhost/tmp/pycrypt.html#SECTION000800000000000000000
+ 23. file://localhost/tmp/pycrypt.html#SECTION000810000000000000000
+ 24. file://localhost/tmp/pycrypt.html#SECTION000820000000000000000
+ 25. file://localhost/tmp/pycrypt.html#SECTION000900000000000000000
+ 26. file://localhost/tmp/pycrypt.html#SECTION000910000000000000000
+ 27. file://localhost/tmp/pycrypt.html#SECTION000920000000000000000
+ 28. file://localhost/tmp/pycrypt.html#SECTION000930000000000000000
+ 29. file://localhost/tmp/pycrypt.html#SECTION000940000000000000000
+ 30. http://www.counterpane.com/
+ 31. http://theory.lcs.mit.edu/~rivest/rc5rev.ps
+ 32. http://www.counterpane.com/
+ 33. http://www-dsed.llnl.gov/files/programs/unix/latex2html/manual/
+ 34. http://cbl.leeds.ac.uk/nikos/personal.html
diff --git a/Hash/HAVAL.c b/Hash/HAVAL.c
new file mode 100644
index 0000000..612937d
--- /dev/null
+++ b/Hash/HAVAL.c
@@ -0,0 +1,398 @@
+
+/*
+ * haval.c : Implementation code for the HAVAL hash function
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+#define VERSION 1 /* Version of HAVAL algorithm */
+
+static int Endianness=-1;
+
+typedef unsigned int U32;
+typedef unsigned char U8;
+
+#define rotate(x,n) (((x) >> (n)) | ((x) << (32-(n))))
+#define f1(x6,x5,x4,x3,x2,x1,x0) ((x1&x4)^(x2&x5)^(x3&x6)^(x0&x1)^(x0))
+#define f2(x6,x5,x4,x3,x2,x1,x0) (((x4&x5)|x2) ^ (x0|x2) ^ x2&(x1&(~x3)^x6)\
+ ^ x3&x5 ^ x1&x4)
+#define f3(x6,x5,x4,x3,x2,x1,x0) ((x1&x2&x3) ^ (x1&x4) ^ (x2&x5) ^ (x3&x6) \
+ ^ (x0&x3) ^ (x0))
+#define f4(x6,x5,x4,x3,x2,x1,x0) ((((~x2&x5)^(x3|x6)^x1^x0)&x4) ^ ((x1&x2^x5^x6)&x3) ^ (x2&x6) ^ x0)
+#define f5(x6,x5,x4,x3,x2,x1,x0) ((((x0&x2&x3)^x4)&x1) ^ ((x0^x2)&x5) ^ (x3&x6) ^ x0)
+
+static int W2[32]={5,14,26,18,11,28,7,16,0,23,20,22,1,10,4,8,
+ 30,3,21,9,17,24,29,6,19,12,15,13,2,25,31,27};
+static int W3[32]={19,9,4,20,28,17,8,22,29,14,25,12,24,30,16,26,
+ 31,15,7,3,1,0,18,27,13,6,21,10,23,11,5,2};
+static int W4[32]={24,4,0,14,2,7,28,23,26,6,30,20,18,25,19,3,
+ 22,11,31,21,8,27,12,9,1,29,5,15,17,10,16,13};
+static int W5[32]={27,3,21,26,17,11,20,29,19,0,12,7,13,8,31,10,
+ 5,9,14,30,18,6,28,24,2,23,16,22,4,1,25,15};
+static U32 K2[32]={0x452821E6U, 0x38D01377U, 0xBE5466CFU, 0x34E90C6CU, 0xC0AC29B7U,
+ 0xC97C50DDU, 0x3F84D5B5U, 0xB5470917U, 0x9216D5D9U, 0x8979FB1BU,
+ 0xD1310BA6U, 0x98DFB5ACU, 0x2FFD72DBU, 0xD01ADFB7U, 0xB8E1AFEDU,
+ 0x6A267E96U, 0xBA7C9045U, 0xF12C7F99U, 0x24A19947U, 0xB3916CF7U,
+ 0x0801F2E2U, 0x858EFC16U, 0x636920D8U, 0x71574E69U, 0xA458FEA3U,
+ 0xF4933D7EU, 0x0D95748FU, 0x728EB658U, 0x718BCD58U, 0x82154AEEU,
+ 0x7B54A41DU, 0xC25A59B5};
+static U32 K3[32]={0x9C30D539U, 0x2AF26013U, 0xC5D1B023U, 0x286085F0U, 0xCA417918U,
+ 0xB8DB38EFU, 0x8E79DCB0U, 0x603A180EU, 0x6C9E0E8BU, 0xB01E8A3EU,
+ 0xD71577C1U, 0xBD314B27U, 0x78AF2FDAU, 0x55605C60U, 0xE65525F3U,
+ 0xAA55AB94U, 0x57489862U, 0x63E81440U, 0x55CA396AU, 0x2AAB10B6U,
+ 0xB4CC5C34U, 0x1141E8CEU, 0xA15486AFU, 0x7C72E993U, 0xB3EE1411U,
+ 0x636FBC2AU, 0x2BA9C55DU, 0x741831F6U, 0xCE5C3E16U, 0x9B87931EU,
+ 0xAFD6BA33U, 0x6C24CF5CU};
+static U32 K4[32]={0x7A325381U, 0x28958677U, 0x3B8F4898U, 0x6B4BB9AFU, 0xC4BFE81BU, 0x66282193U, 0x61D809CCU, 0xFB21A991U, 0x487CAC60U, 0x5DEC8032U, 0xEF845D5DU, 0xE98575B1U, 0xDC262302U, 0xEB651B88U, 0x23893E81U, 0xD396ACC5U, 0x0F6D6FF3U, 0x83F44239U, 0x2E0B4482U, 0xA4842004U, 0x69C8F04AU, 0x9E1F9B5EU, 0x21C66842U, 0xF6E96C9AU, 0x670C9C61U, 0xABD388F0U, 0x6A51A0D2U, 0xD8542F68U, 0x960FA728U, 0xAB5133A3U, 0x6EEF0B6CU, 0x137A3BE4U};
+static U32 K5[32]={0xBA3BF050U, 0x7EFB2A98U, 0xA1F1651DU, 0x39AF0176U, 0x66CA593EU, 0x82430E88U, 0x8CEE8619U, 0x456F9FB4U, 0x7D84A5C3U, 0x3B8B5EBEU, 0xE06F75D8U, 0x85C12073U, 0x401A449FU, 0x56C16AA6U, 0x4ED3AA62U, 0x363F7706U, 0x1BFEDF72U, 0x429B023DU, 0x37D0D724U, 0xD00A1248U, 0xDB0FEAD3U, 0x49F1C09BU, 0x075372C9U, 0x80991B7BU, 0x25D479D8U, 0xF6E8DEF7U, 0xE3FE501AU, 0xB6794C3BU, 0x976CE0BDU, 0x04C006BAU, 0xC1A94FB6U, 0x409F60C4U};
+
+enum ePASS {P3=3, P4=4, P5=5};
+enum eFPTLEN {L128=128, L160=160, L192=192, L224=224, L256=256};
+
+typedef struct {
+ PCTObject_HEAD
+ U32 D[8], msglen1, msglen2;
+ U8 buf[128];
+ int buflen;
+ enum eFPTLEN digestsize;
+ enum ePASS rounds;
+} HAVALobject;
+
+
+static void HV_Hash(s, D, buf)
+ HAVALobject *s;
+ U32 *D;
+ U8 *buf;
+{
+ U32 temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ U32 w[32];
+ int i, j;
+
+ for(i=0, j=0; i<32; i++,j+=4)
+ w[i]=buf[j]+(buf[j+1]<<8)+(buf[j+2]<<16)+(buf[j+3]<<24);
+
+ /* e1 = H1(D, B) */
+
+ temp0=D[0]; temp1=D[1]; temp2=D[2]; temp3=D[3]; temp4=D[4]; temp5=D[5]; temp6=D[6]; temp7=D[7];
+#ifdef DEBUG
+ printf("start: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+ for(i=0; i<32; i++)
+ {
+ U32 P = 0, R;
+
+ switch(s->rounds)
+ {
+ case(P3):
+ P=f1(temp1, temp0, temp3, temp5, temp6, temp2, temp4);
+ break;
+ case(P4):
+ P=f1(temp2, temp6, temp1, temp4, temp5, temp3, temp0);
+ break;
+ case(P5):
+ P=f1(temp3, temp4, temp1, temp0, temp5, temp2, temp6);
+ break;
+ }
+ R=rotate(P,7) + rotate(temp7,11) + w[i];
+ temp7=temp6; temp6=temp5; temp5=temp4; temp4=temp3;
+ temp3=temp2; temp2=temp1; temp1=temp0; temp0=R;
+ }
+
+#ifdef DEBUG
+ printf(" h1: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+ /* e2 = H2(e1, B) */
+
+ for(i=0; i<32; i++)
+ {
+ U32 P,R;
+ switch(s->rounds)
+ {
+ case(P3):
+ P=f2(temp4, temp2, temp1, temp0, temp5, temp3, temp6);
+ break;
+ case(P4):
+ P=f2(temp3, temp5, temp2, temp0, temp1, temp6, temp4);
+ break;
+ case(P5):
+ P=f2(temp6, temp2, temp1, temp0, temp3, temp4, temp5);
+ break;
+ }
+ R=rotate(P, 7) + rotate(temp7, 11) + K2[i]+ w[W2[i]];
+ temp7=temp6; temp6=temp5; temp5=temp4; temp4=temp3;
+ temp3=temp2; temp2=temp1; temp1=temp0; temp0=R;
+ }
+#ifdef DEBUG
+ printf(" h2: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+
+ /* e3 = H3(e2, B) */
+
+ for(i=0; i<32; i++)
+ {
+ U32 P,R;
+ switch(s->rounds)
+ {
+ case(P3):
+ P=f3(temp6, temp1, temp2, temp3, temp4, temp5, temp0);
+ break;
+ case(P4):
+ P=f3(temp1, temp4, temp3, temp6, temp0, temp2, temp5);
+ break;
+ case(P5):
+ P=f3(temp2, temp6, temp0, temp4, temp3, temp1, temp5);
+ break;
+ }
+ R=rotate(P, 7) + rotate(temp7, 11) + K3[i]+ w[W3[i]];
+ temp7=temp6; temp6=temp5; temp5=temp4; temp4=temp3;
+ temp3=temp2; temp2=temp1; temp1=temp0; temp0=R;
+ }
+
+#ifdef DEBUG
+ printf(" h3: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+
+ if (s->rounds==P3) /* Final output */
+ {
+ D[0]+=temp0; D[1]+=temp1; D[2]+=temp2; D[3]+=temp3;
+ D[4]+=temp4; D[5]+=temp5; D[6]+=temp6; D[7]+=temp7;
+ return;
+ }
+
+ /* e4 = H4(e3, B) */
+ for(i=0; i<32; i++)
+ {
+ U32 P,R;
+ switch(s->rounds)
+ {
+ case(P4):
+ P=f4(temp6, temp4, temp0, temp5, temp2, temp1, temp3);
+ break;
+ case(P5):
+ P=f4(temp1, temp5, temp3, temp2, temp0, temp4, temp6);
+ break;
+ }
+ R=rotate(P, 7) + rotate(temp7, 11) + K4[i]+ w[W4[i]];
+ temp7=temp6; temp6=temp5; temp5=temp4; temp4=temp3;
+ temp3=temp2; temp2=temp1; temp1=temp0; temp0=R;
+ }
+
+#ifdef DEBUG
+ printf(" h4: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+ if (s->rounds==P4) /* Final output */
+ {
+ D[0]+=temp0; D[1]+=temp1; D[2]+=temp2; D[3]+=temp3;
+ D[4]+=temp4; D[5]+=temp5; D[6]+=temp6; D[7]+=temp7;
+ return;
+ }
+
+ /* e5 = H5(e4, B) */
+
+ for(i=0; i<32; i++)
+ {
+ U32 P,R;
+ P=f5(temp2, temp5, temp0, temp6, temp4, temp3, temp1);
+ R=rotate(P, 7) + rotate(temp7, 11) + K5[i]+ w[W5[i]];
+ temp7=temp6; temp6=temp5; temp5=temp4; temp4=temp3;
+ temp3=temp2; temp2=temp1; temp1=temp0; temp0=R;
+ }
+#ifdef DEBUG
+ printf(" h5: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7);
+#endif
+ D[0]+=temp0; D[1]+=temp1; D[2]+=temp2; D[3]+=temp3;
+ D[4]+=temp4; D[5]+=temp5; D[6]+=temp6; D[7]+=temp7;
+ return;
+}
+
+static void HAVALinit (s)
+ HAVALobject *s; /* context */
+{
+ if (Endianness==-1) TestEndianness(Endianness);
+ if (s->rounds<P3 || P5<s->rounds)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "HAVAL: rounds must be 3, 4, or 5");
+ return;
+ }
+ if (s->digestsize!=L128 && s->digestsize!=L160 && s->digestsize!=L192 &&
+ s->digestsize!=L224 && s->digestsize!=L256)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "HAVAL: digest size must be 128, 160, 192, 224, or 256");
+ return;
+ }
+ s->buflen=0;
+ s->msglen1=s->msglen2=0;
+ s->D[0]=0x243f6a88U;
+ s->D[1]=0x85a308d3U;
+ s->D[2]=0x13198a2eU;
+ s->D[3]=0x03707344U;
+ s->D[4]=0xa4093822U;
+ s->D[5]=0x299f31d0U;
+ s->D[6]=0x082efa98U;
+ s->D[7]=0xec4e6c89U;
+}
+
+static void HAVALupdate (s, buf, len)
+HAVALobject *s;
+U8 *buf; /* input block */
+unsigned int len; /* length of input block */
+{
+ int temp;
+
+ temp=s->msglen2;
+ s->msglen2+=len*8;
+ if (s->msglen2<temp) /* Did an overflow occur on the 32-bit msg length? */
+ {
+ s->msglen1++;
+ }
+ while (len>0)
+ {
+ temp = ((128-s->buflen)>len) ? len : 128-s->buflen;
+ memcpy(s->buf+s->buflen, buf, temp);
+ len-=temp;
+ buf+=temp;
+ s->buflen+=temp;
+ if (s->buflen==128)
+ {
+ HV_Hash(s, s->D, s->buf); s->buflen=0;
+ }
+ }
+}
+
+static PyObject *HAVALdigest (s)
+ HAVALobject *s;
+{
+ int i, j;
+ U32 value, D[8];
+ U8 buf[128];
+
+ for(i=0; i<8; i++) D[i]=s->D[i];
+ memcpy(buf, s->buf, s->buflen);
+ i=s->buflen;
+ buf[i++]=128;
+ if (i>944/8)
+ {
+ memset(buf+i, 0, 128-i);
+ HV_Hash(s, D, buf);
+ i=0;
+ }
+ memset(buf+i, 0, (944/8)-i);
+ i=944/8;
+ value=VERSION | (s->rounds<<3) | (s->digestsize<<6);
+ buf[i++]=value & 0xff;
+ buf[i++]=(value >> 8) & 0xff;
+
+ /* Append the message length */
+ buf[i++]=(s->msglen2 ) & 0xff;
+ buf[i++]=(s->msglen2 >> 8 ) & 0xff;
+ buf[i++]=(s->msglen2 >> 16 ) & 0xff;
+ buf[i++]=(s->msglen2 >> 24 ) & 0xff;
+
+ buf[i++]=(s->msglen1 ) & 0xff;
+ buf[i++]=(s->msglen1 >> 8 ) & 0xff;
+ buf[i++]=(s->msglen1 >> 16 ) & 0xff;
+ buf[i++]=(s->msglen1 >> 24 ) & 0xff;
+
+ HV_Hash(s, D, buf);
+
+ /* Tailor the output to the appropriate length */
+/* 256-byte output
+ D[0]=0xac869783U; D[1]=0x6aee894fU; D[2]=0x65207fe8U; D[3]=0x971068acU;
+ D[4]=0x996a27d7U; D[5]=0x72e9b703U; D[6]=0x6d5692e9U; D[7]=0xc8ee30dU; */
+/* 128-byte output
+ D[0]=0xd7b8185dU; D[1]=0x59d1f164U; D[2]=0x87bba84dU; D[3]=0x4b7f55dcU;
+ D[4]=0xbcc5be6bU; D[5]=0xbbc32906U; D[6]=0x9dabd130U; D[7]=0x3bde9293U; */
+
+ if (s->digestsize==128)
+ {
+ D[3] += (D[7] & 0xff000000U) | (D[6] & 0x00ff0000U) |
+ (D[5] & 0x0000ff00U) | (D[4] & 0x000000ffU);
+ D[2] += ((
+ (D[7] & 0x00ff0000U) | (D[6] & 0x0000ff00U) |
+ (D[5] & 0x000000ffU)
+ )<<8) | ((D[4] & 0xff000000U)>>24);
+ D[1] += ((
+ (D[7] & 0x0000ff00U) | (D[6] & 0x000000ffU)
+ )<<16) |
+ ((
+ (D[5] & 0xff000000U) | (D[4] & 0x00ff0000U)
+ )>>16);
+ D[0] +=
+ ((
+ D[7] & 0x000000ffU
+ )<<24) |
+ ((
+ (D[6] & 0xff000000U) | (D[5] & 0x00ff0000U) |
+ (D[4] & 0x0000ff00U)
+ )>>8);
+ }
+ if (s->digestsize==L160)
+ {
+ D[4] += ((D[7] & 0xfe000000U) | (D[6] & 0x01f80000U) |
+ (D[5] & 0x0007f000U)) >>12;
+ D[3] += ((D[7] & 0x01f80000U) | (D[6] & 0x0007f000U) |
+ (D[5] & 0x00000fc0U)) >> 6;
+ D[2] += ((D[7] & 0x0007f000U) | (D[6] & 0x00000fc0U) |
+ (D[5] & 0x0000003fU)) ;
+ D[1] += (((D[7] & 0x00000fc0U) | (D[6] & 0x0000003fU)) <<7) |
+ ((D[5] & 0xfe000000U)>>25);
+ D[0] += (((D[6] & 0xfe000000U) | (D[5] & 0x01f80000U)) >>19) |
+ ((D[7] & 0x0000003fU)<<13);
+ }
+ if (s->digestsize==L192)
+ {
+ D[5] += ((D[7] & 0xfc000000U) | (D[6] & 0x03e00000U)) >> 21;
+ D[4] += ((D[7] & 0x03e00000U) | (D[6] & 0x001f0000U)) >> 16;
+ D[3] += ((D[7] & 0x001f0000U) | (D[6] & 0x0000fc00U)) >> 10;
+ D[2] += ((D[7] & 0x0000fc00U) | (D[6] & 0x000003e0U)) >> 5;
+ D[1] += ((D[7] & 0x000003e0U) | (D[6] & 0x0000001fU)) ;
+ D[0] += ((D[7] & 0x0000001fU)<<6) | ((D[6] & 0xfc000000U) >>26);
+ }
+ if (s->digestsize==L224)
+ {
+ D[6] += (D[7] & 0x0000000fU);
+ D[5] += (D[7] & 0x000001f0U) >> 4;
+ D[4] += (D[7] & 0x00001e00U) >> 9;
+ D[3] += (D[7] & 0x0003e000U) >> 13;
+ D[2] += (D[7] & 0x003c0000U) >> 18;
+ D[1] += (D[7] & 0x07c00000U) >> 22;
+ D[0] += (D[7] & 0xf8000000U) >> 27;
+ }
+ for(i=0,j=0; i<s->digestsize/32; i++)
+ {
+ buf[j++]=D[i] & 0xff; D[i] >>= 8;
+ buf[j++]=D[i] & 0xff; D[i] >>= 8;
+ buf[j++]=D[i] & 0xff; D[i] >>= 8;
+ buf[j++]=D[i] & 0xff;
+ }
+ return PyString_FromStringAndSize((unsigned char *)buf, s->digestsize/8);
+}
+
+
+static void
+HAVALcopy(src, dest)
+ HAVALobject *src, *dest;
+{
+ int i;
+ memcpy(dest->buf, src->buf, src->buflen);
+ dest->buflen =src->buflen;
+ dest->msglen1=src->msglen1;
+ dest->msglen2=src->msglen2;
+ dest->rounds =src->rounds;
+ dest->digestsize =src->digestsize;
+
+ for(i=0; i<8; i++) dest->D[i]=src->D[i];
+}
diff --git a/Hash/HMAC.py b/Hash/HMAC.py
new file mode 100644
index 0000000..f1eb8bd
--- /dev/null
+++ b/Hash/HMAC.py
@@ -0,0 +1,141 @@
+"""This file implements message authentication (HMAC).
+
+A MAC is a message authentication code, which is essentially a fancy hash of
+some input text. The text is sent along with the MAC and the receiver can
+verify the text by computing their own MAC and comparing results. The sender
+and receiver share a secret key which is used by HMAC.
+
+HMAC is defined in the informational RFC 2104, which describes a procedure for
+authenticating messages using pluggable hash functions. The user of HMAC must
+choose which hash function to use (e.g. SHA-1 or MD5) and this is designated
+by HMAC-SHA or HMAC-MD5. See the RFC for details.
+
+This package can be integrated with Andrew Kuchling's Python Cryptography
+Toolkit, http://starship.skyport.net/crew/amk/maintained/crypto.html
+
+"""
+
+from Crypto.Util.number import bytestolong, longtobytes
+
+
+
+class HMAC:
+ """Class implementing HMAC as defined in RFC 2104.
+
+ Public Methods:
+
+ __init__(hashmodule)
+ Constructor for the class. hashmodule is a module implementing
+ the hashing algorithm to use. In essence it must provide the
+ following interface:
+
+ hashmodule.digestsize
+ The length of the hash's output in bytes
+
+ hashmodule.new(key)
+ Function which returns a new instance of a hash object,
+ initialized to key. The returned object must have a digest()
+ method that returns a string of size hashmodule.digestsize,
+ and an update() method that accepts strings to add to the
+ digest.
+
+ hash(key, blocks):
+ Produce the HMAC hashes for the given blocks. Key is the shared
+ secret authentication key, as a string. For best results RFC 2104
+ recommends that the length of key should be at least as large as
+ the underlying hash's output block size, but this is not
+ enforced.
+
+ If the key length is greater than the hash algorithm's basic
+ compression function's block size (typically 64 bytes), then it is
+ hashed to get the used key value. If it is less than this block
+ size, it is padded by appending enough zero bytes to the key.
+
+ blocks is a list of strings to generate message authentication
+ codes for. Output is a list of strings containing the MACs.
+
+ """
+ def __init__(self, hashmodule):
+ self.__hashmodule = hashmodule
+
+ __IPAD = 0x36
+ __OPAD = 0x5c
+
+ def hash(self, key, blocks):
+ # L is the byte length of hash outputs.
+ # B is the byte length of hash algorithm's basic compression
+ # function's block size (64 for most hashes)
+ #
+ # Sanitize the key. RFC 2104 recommends key length be at least L and
+ # if it is longer than B, it should be hashed and the resulting L
+ # bytes will be used as the key
+ #
+ L = self.__hashmodule.digestsize
+ B = 64 # can't get from module
+ keylen = len(key)
+ if keylen > B:
+ key = self.__hashmodule.new(key).digest()
+ keylen = len(key)
+ assert keylen == L
+ elif keylen < B:
+ # append enough zeros to get it to length B
+ key = key + '\000' * (B - keylen)
+ keylen = len(key)
+ #
+ # Precompute the inner and outer intermediate values
+ kipad = bytestolong(key) ^ bytestolong(chr(self.__IPAD) * keylen)
+ kopad = bytestolong(key) ^ bytestolong(chr(self.__OPAD) * keylen)
+ kipad = longtobytes(kipad)
+ kopad = longtobytes(kopad)
+ #
+ # perform the inner hashes
+ inners = []
+ for text in blocks:
+ hash = self.__hashmodule.new(kipad)
+ hash.update(text)
+ inners.append(hash.digest())
+ #
+ # preform the outer hashes
+ outers = []
+ for inner in inners:
+ hash = self.__hashmodule.new(kopad)
+ hash.update(inner)
+ outers.append(hash.digest())
+ return outers
+
+
+
+if __name__ == '__main__':
+ from types import StringType
+
+ # Test data taken from RFC 2104
+ testdata = [
+ # (key, data, digest)
+ (0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0bL,
+ 'Hi There',
+ 0x9294727a3638bb1c13f48ef8158bfc9dL),
+ ("Jefe",
+ "what do ya want for nothing?",
+ 0x750c783e6ab0b503eaa86e310a5db738L),
+ (0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL,
+ 0xDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDL,
+ 0x56be34521d144c88dbb8c733f0e8b3f6L),
+ ]
+
+ # RFC 2104 uses MD5
+ from Crypto.Hash import MD5
+ for key, data, digest in testdata:
+ if type(key) <> StringType:
+ key = longtobytes(key)
+ if type(data) <> StringType:
+ data = longtobytes(data)
+
+ h = HMAC(MD5)
+ d = h.hash(key, [data])
+ d = bytestolong(d[0])
+ if d == digest:
+ print 'They match!'
+ else:
+ print 'They differ...'
+ print ' expected:', hex(digest)
+ print ' got:', hex(d)
diff --git a/Hash/MD2.c b/Hash/MD2.c
new file mode 100644
index 0000000..66f912f
--- /dev/null
+++ b/Hash/MD2.c
@@ -0,0 +1,120 @@
+
+/*
+ * md2.c : MD2 hash algorithm.
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+
+#include <string.h>
+
+typedef unsigned char U8;
+typedef unsigned int U32;
+
+typedef struct {
+ PCTObject_HEAD
+ U8 C[16], X[48];
+ int count;
+ U8 buf[16];
+} MD2object;
+
+static void MD2init (ptr)
+ MD2object *ptr;
+{
+ memset(ptr->X, 0, 48);
+ memset(ptr->C, 0, 16);
+ ptr->count=0;
+}
+
+static U8 S[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static void
+MD2copy(src, dest)
+ MD2object *src, *dest;
+{
+ dest->count=src->count;
+ memcpy(dest->buf, src->buf, dest->count);
+ memcpy(dest->X, src->X, 48);
+ memcpy(dest->C, src->C, 16);
+}
+
+
+static void MD2update (self, buf, len)
+MD2object *self;
+const U8 *buf;
+U32 len;
+{
+ U32 L;
+ while (len)
+ {
+ L=(16-self->count) < len ? (16-self->count) : len;
+ memcpy(self->buf+self->count, buf, L);
+ self->count+=L;
+ buf+=L;
+ len-=L;
+ if (self->count==16)
+ {
+ U8 t;
+ int i,j;
+
+ self->count=0;
+ memcpy(self->X+16, self->buf, 16);
+ t=self->C[15];
+ for(i=0; i<16; i++)
+ {
+ self->X[32+i]=self->X[16+i]^self->X[i];
+ t=self->C[i]^=S[self->buf[i]^t];
+ }
+
+ t=0;
+ for(i=0; i<18; i++)
+ {
+ for(j=0; j<48; j++)
+ t=self->X[j]^=S[t];
+ t=(t+i) & 0xFF;
+ }
+ }
+ }
+}
+
+static PyObject *
+MD2digest (self)
+ const MD2object *self;
+{
+ U8 padding[16];
+ U32 padlen;
+ MD2object temp;
+ int i;
+
+ memcpy(&temp, self, sizeof(MD2object));
+ padlen= 16-self->count;
+ for(i=0; i<padlen; i++) padding[i]=padlen;
+ MD2update(&temp, padding, padlen);
+ MD2update(&temp, temp.C, 16);
+ return PyString_FromStringAndSize(temp.X, 16);
+}
+
diff --git a/Hash/MD4.c b/Hash/MD4.c
new file mode 100644
index 0000000..f79fc33
--- /dev/null
+++ b/Hash/MD4.c
@@ -0,0 +1,203 @@
+
+/*
+ * md4.c : MD4 hash algorithm.
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+
+#include <string.h>
+
+typedef unsigned int U32;
+typedef unsigned char U8;
+#define U32_MAX (U32)4294967295
+
+typedef struct {
+ PCTObject_HEAD
+ U32 A,B,C,D, count;
+ U32 len1, len2;
+ U8 buf[64];
+} MD4object;
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits */
+#define ROL(x, n) (((x) << n) | ((x) >> (32-n) ))
+
+static void MD4init (ptr)
+ MD4object *ptr;
+{
+ ptr->A=(U32)0x67452301;
+ ptr->B=(U32)0xefcdab89;
+ ptr->C=(U32)0x98badcfe;
+ ptr->D=(U32)0x10325476;
+ ptr->count=ptr->len1=ptr->len2=0;
+}
+
+static void
+MD4copy(src, dest)
+ MD4object *src, *dest;
+{
+ dest->len1=src->len1;
+ dest->len2=src->len2;
+ dest->A=src->A;
+ dest->B=src->B;
+ dest->C=src->C;
+ dest->D=src->D;
+ dest->count=src->count;
+ memcpy(dest->buf, src->buf, dest->count);
+}
+
+static void MD4update (self, buf, len)
+MD4object *self;
+const U8 *buf;
+U32 len;
+{
+ U32 L;
+
+ if ((self->len1+(len<<3))<self->len1)
+ {
+ self->len2++;
+ }
+ self->len1+=len<< 3;
+ self->len2+=len>>29;
+ while (len>0)
+ {
+ L=(64-self->count) < len ? (64-self->count) : len;
+ memcpy(self->buf+self->count, buf, L);
+ self->count+=L;
+ buf+=L;
+ len-=L;
+ if (self->count==64)
+ {
+ U32 X[16], A, B, C, D;
+ int i,j;
+ self->count=0;
+ for(i=j=0; j<16; i+=4, j++)
+ X[j]=((U32)self->buf[i] + ((U32)self->buf[i+1]<<8) +
+ ((U32)self->buf[i+2]<<16) + ((U32)self->buf[i+3]<<24));
+
+
+ A=self->A; B=self->B; C=self->C; D=self->D;
+
+#define function(a,b,c,d,k,s) a=ROL(a+F(b,c,d)+X[k],s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 1, 7);
+ function(C,D,A,B, 2,11);
+ function(B,C,D,A, 3,19);
+ function(A,B,C,D, 4, 3);
+ function(D,A,B,C, 5, 7);
+ function(C,D,A,B, 6,11);
+ function(B,C,D,A, 7,19);
+ function(A,B,C,D, 8, 3);
+ function(D,A,B,C, 9, 7);
+ function(C,D,A,B,10,11);
+ function(B,C,D,A,11,19);
+ function(A,B,C,D,12, 3);
+ function(D,A,B,C,13, 7);
+ function(C,D,A,B,14,11);
+ function(B,C,D,A,15,19);
+
+#undef function
+#define function(a,b,c,d,k,s) a=ROL(a+G(b,c,d)+X[k]+(U32)0x5a827999,s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 4, 5);
+ function(C,D,A,B, 8, 9);
+ function(B,C,D,A,12,13);
+ function(A,B,C,D, 1, 3);
+ function(D,A,B,C, 5, 5);
+ function(C,D,A,B, 9, 9);
+ function(B,C,D,A,13,13);
+ function(A,B,C,D, 2, 3);
+ function(D,A,B,C, 6, 5);
+ function(C,D,A,B,10, 9);
+ function(B,C,D,A,14,13);
+ function(A,B,C,D, 3, 3);
+ function(D,A,B,C, 7, 5);
+ function(C,D,A,B,11, 9);
+ function(B,C,D,A,15,13);
+
+#undef function
+#define function(a,b,c,d,k,s) a=ROL(a+H(b,c,d)+X[k]+(U32)0x6ed9eba1,s);
+ function(A,B,C,D, 0, 3);
+ function(D,A,B,C, 8, 9);
+ function(C,D,A,B, 4,11);
+ function(B,C,D,A,12,15);
+ function(A,B,C,D, 2, 3);
+ function(D,A,B,C,10, 9);
+ function(C,D,A,B, 6,11);
+ function(B,C,D,A,14,15);
+ function(A,B,C,D, 1, 3);
+ function(D,A,B,C, 9, 9);
+ function(C,D,A,B, 5,11);
+ function(B,C,D,A,13,15);
+ function(A,B,C,D, 3, 3);
+ function(D,A,B,C,11, 9);
+ function(C,D,A,B, 7,11);
+ function(B,C,D,A,15,15);
+
+ self->A+=A; self->B+=B; self->C+=C; self->D+=D;
+ }
+ }
+}
+
+static PyObject *
+MD4digest (self)
+ const MD4object *self;
+{
+ U8 digest[16];
+ static U8 s[8];
+ U32 padlen, oldlen1, oldlen2;
+ MD4object temp;
+ static U8 padding[64] = {
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ memcpy(&temp, self, sizeof(MD4object));
+ oldlen1=temp.len1; oldlen2=temp.len2; /* Save current length */
+ padlen= (56<=self->count) ? 56-self->count+64: 56-self->count;
+ MD4update(&temp, padding, padlen);
+ s[0]= oldlen1 & 255;
+ s[1]=(oldlen1 >> 8) & 255;
+ s[2]=(oldlen1 >> 16) & 255;
+ s[3]=(oldlen1 >> 24) & 255;
+ s[4]= oldlen2 & 255;
+ s[5]=(oldlen2 >> 8) & 255;
+ s[6]=(oldlen2 >> 16) & 255;
+ s[7]=(oldlen2 >> 24) & 255;
+ MD4update(&temp, s, 8);
+
+ digest[ 0]= temp.A & 255;
+ digest[ 1]=(temp.A >> 8) & 255;
+ digest[ 2]=(temp.A >> 16) & 255;
+ digest[ 3]=(temp.A >> 24) & 255;
+ digest[ 4]= temp.B & 255;
+ digest[ 5]=(temp.B >> 8) & 255;
+ digest[ 6]=(temp.B >> 16) & 255;
+ digest[ 7]=(temp.B >> 24) & 255;
+ digest[ 8]= temp.C & 255;
+ digest[ 9]=(temp.C >> 8) & 255;
+ digest[10]=(temp.C >> 16) & 255;
+ digest[11]=(temp.C >> 24) & 255;
+ digest[12]= temp.D & 255;
+ digest[13]=(temp.D >> 8) & 255;
+ digest[14]=(temp.D >> 16) & 255;
+ digest[15]=(temp.D >> 24) & 255;
+
+ return PyString_FromStringAndSize(digest, 16);
+}
+
diff --git a/Hash/MD5.c b/Hash/MD5.c
new file mode 100644
index 0000000..ec5e030
--- /dev/null
+++ b/Hash/MD5.c
@@ -0,0 +1,289 @@
+
+/*
+ * md5.c : Implementation of the MD5 hash function
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ * Colin Plumb's original code modified by A.M. Kuchling
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+#if HAVE_PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+typedef unsigned int uint32;
+
+typedef struct {
+ PCTObject_HEAD
+ uint32 buf[4];
+ uint32 bits[2];
+ int Endianness;
+ unsigned char in[64];
+} MD5object;
+
+static void MD5Transform PROTO_LIST((uint32 buf[4], uint32 const in[16]));
+static void MD5init PROTO_LIST((MD5object *));
+static void MD5update PROTO_LIST((MD5object *, unsigned char *, unsigned int));
+static PyObject *MD5digest PROTO_LIST((MD5object *));
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ */
+#include <string.h> /* for memcpy() */
+
+#define byteReverse(ptr, field, num) if (ptr->Endianness==PCT_BIG_ENDIAN)\
+{uint32 t, longs=num; unsigned char *buf=(unsigned char*)&(ptr->field);\
+ do {\
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |\
+ ((unsigned) buf[1] << 8 | buf[0]);\
+ *(uint32 *) buf = t;\
+ buf += 4;\
+ } while (--longs);\
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+static void MD5init(ptr)
+ MD5object *ptr;
+{
+ ptr->buf[0] = 0x67452301;
+ ptr->buf[1] = 0xefcdab89;
+ ptr->buf[2] = 0x98badcfe;
+ ptr->buf[3] = 0x10325476;
+
+ ptr->bits[0] = 0;
+ ptr->bits[1] = 0;
+ TestEndianness(ptr->Endianness)
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD5update(ptr, buf, len)
+ MD5object *ptr;
+ unsigned char *buf;
+ unsigned int len;
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ptr->bits[0];
+ if ((ptr->bits[0] = t + ((uint32) len << 3)) < t)
+ ptr->bits[1]++; /* Carry from low to high */
+ ptr->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ptr->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ptr, in, 16);
+ MD5Transform(ptr->buf, (uint32 *) ptr->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ptr->in, buf, 64);
+ byteReverse(ptr, in, 16);
+ MD5Transform(ptr->buf, (uint32 *) ptr->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ptr->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+
+static PyObject *
+MD5digest(ptr)
+ MD5object *ptr;
+{
+ unsigned count;
+ unsigned char *p;
+ MD5object temp;
+
+ memcpy(&temp, ptr, sizeof(MD5object));
+ /* Compute number of bytes mod 64 */
+ count = (temp.bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = temp.in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse((&temp), in, 16);
+ MD5Transform(temp.buf, (uint32 *) temp.in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(temp.in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse((&temp), in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) temp.in)[14] = temp.bits[0];
+ ((uint32 *) temp.in)[15] = temp.bits[1];
+
+ MD5Transform(temp.buf, (uint32 *) temp.in);
+ byteReverse((&temp), buf, 4);
+
+ return PyString_FromStringAndSize((unsigned char *)temp.buf, 16);
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(buf, in)
+ uint32 buf[4];
+ const uint32 in[16];
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+static void
+MD5copy(src, dest)
+ MD5object *src, *dest;
+{
+ dest->Endianness = src->Endianness;
+ memcpy(dest->in, src->in, 64);
+ memcpy(&(dest->bits), &(src->bits), 2*sizeof(uint32));
+ memcpy(&(dest->buf), &(src->buf), 4*sizeof(uint32));
+}
+
+
+
+
diff --git a/Hash/RIPEMD.c b/Hash/RIPEMD.c
new file mode 100644
index 0000000..5fc3dde
--- /dev/null
+++ b/Hash/RIPEMD.c
@@ -0,0 +1,519 @@
+/* header files */
+
+/********************************************************************\
+ * FILE: rmd160.c
+ * CONTENTS: A sample C-implementation of the RIPEMD-160 hash-function.
+ * TARGET: any computer with an ANSI C compiler
+ * AUTHOR: Antoon Bosselaers, Dept. Electrical Eng.-ESAT/COSIC
+ * DATE: 1 March 1996 VERSION: 1.0
+ **********************************************************************
+ * Copyright (c) Katholieke Universiteit Leuven 1996, All Rights Reserved
+ * The Katholieke Universiteit Leuven makes no representations concerning
+ * either the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is" without
+ * express or implied warranty of any kind. These notices must be retained
+ * in any copies of any part of this documentation and/or software.
+\********************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+/********************************************************************/
+/* Macro definitions */
+
+/* ROL(x, n) cyclically rotates x over n bits to the left
+ x must be of an unsigned 32 bits type and 0 <= n < 32.
+*/
+#define ROL(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* The five basic RIPEMD-160 functions F1(), F2(), F3(), F4(), and F5()
+*/
+#define F1(x, y, z) ((x) ^ (y) ^ (z))
+#define F2(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define F3(x, y, z) (((x) | ~(y)) ^ (z))
+#define F4(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define F5(x, y, z) ((x) ^ ((y) | ~(z)))
+
+/* The ten basic RIPEMD-160 transformations FF1() through FFF5()
+*/
+#define FF1(a, b, c, d, e, x, s) {\
+ (a) += F1((b), (c), (d)) + (x);\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FF2(a, b, c, d, e, x, s) {\
+ (a) += F2((b), (c), (d)) + (x) + 0x5a827999UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FF3(a, b, c, d, e, x, s) {\
+ (a) += F3((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FF4(a, b, c, d, e, x, s) {\
+ (a) += F4((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FF5(a, b, c, d, e, x, s) {\
+ (a) += F5((b), (c), (d)) + (x) + 0xa953fd4eUL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FFF1(a, b, c, d, e, x, s) {\
+ (a) += F1((b), (c), (d)) + (x);\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FFF2(a, b, c, d, e, x, s) {\
+ (a) += F2((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FFF3(a, b, c, d, e, x, s) {\
+ (a) += F3((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FFF4(a, b, c, d, e, x, s) {\
+ (a) += F4((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+#define FFF5(a, b, c, d, e, x, s) {\
+ (a) += F5((b), (c), (d)) + (x) + 0x50a28be6UL;\
+ (a) = ROL((a), (s)) + (e);\
+ (c) = ROL((c), 10);\
+ }
+
+typedef unsigned char byte; /* unsigned 8-bit integer */
+#ifdef __alpha__
+typedef unsigned int word; /* unsigned 32-bit integer */
+typedef unsigned int LONG;
+#else
+typedef unsigned long word; /* unsigned 32-bit integer */
+typedef unsigned long LONG;
+#endif
+typedef unsigned char BYTE;
+typedef unsigned int WORD;
+#define RMD_DATASIZE 64
+#define RMD_DIGESTSIZE 20
+#define RMDsize 160
+/* collect four bytes into one word using a Little-endian convention */
+#define BYTES_TO_DWORD(strptr) \
+ (((word) *((strptr)+3) << 24) | \
+ ((word) *((strptr)+2) << 16) | \
+ ((word) *((strptr)+1) << 8) | \
+ ((word) *(strptr)))
+typedef struct {
+ PCTObject_HEAD
+ word digest[ 5 ]; /* Message digest */
+ word countLo, countHi; /* 64-bit bit count */
+ word data[ 16 ]; /* data buffer*/
+ int nbytes;
+ int Endianness;
+ } RIPEMDobject;
+
+/* Function Prototype */
+
+static void RIPEMDinit(RIPEMDobject *rmdInfo);
+static PyObject *RIPEMDdigest(RIPEMDobject *self);
+static void RIPEMDcopy(RIPEMDobject *src,RIPEMDobject *dest);
+static void RIPEMDupdate(RIPEMDobject *self,char *buffer, int length);
+static void MDinit(word *MDbuf);
+static void MDcompress(word *MDbuf, word *X);
+static void MDfinish(RIPEMDobject *self);
+/********************************************************************/
+static void RIPEMDinit(RIPEMDobject *rmdInfo)
+/* Initialization of the 5-word MDbuf array to the magic
+ initialization constants
+ */
+{
+ TestEndianness(rmdInfo->Endianness)
+ MDinit(rmdInfo->digest);
+ rmdInfo->countLo = rmdInfo->countHi =rmdInfo->nbytes = 0;
+}
+
+#if 0
+/* When run on a little-endian CPU we need to perform byte reversal on an
+ array of longwords. */
+
+static void longReverse( buffer, byteCount, Endianness )
+ LONG *buffer;
+ int byteCount, Endianness;
+ {
+ LONG value;
+
+ if (Endianness==BIG_ENDIAN) return;
+ byteCount /= sizeof( LONG );
+ while( byteCount-- )
+ {
+ value = *buffer;
+ value = ( ( value & 0xFF00FF00L ) >> 8 ) | \
+ ( ( value & 0x00FF00FFL ) << 8 );
+ *buffer++ = ( value << 16 ) | ( value >> 16 );
+ }
+ }
+#endif
+
+static void RIPEMDupdate(RIPEMDobject *shsInfo,char *buffer, int count)
+{
+ LONG tmp;
+ int dataCount;
+ BYTE *p;
+
+ /* Update bitcount */
+ tmp = shsInfo->countLo;
+ if ( ( shsInfo->countLo = tmp + ( ( LONG ) count << 3 ) ) < tmp )
+ shsInfo->countHi++; /* Carry from low to high */
+ shsInfo->countHi += count >> 29;
+
+ /* Get count of bytes already in data */
+ dataCount = ( int ) ( tmp >> 3 ) & 0x3F;
+
+ /* Handle any leading odd-sized chunks */
+ if( dataCount )
+ {
+ p = ( BYTE * ) shsInfo->data + dataCount;
+
+ dataCount = RMD_DATASIZE - dataCount;
+ if( count < dataCount )
+ {
+ memcpy( p, buffer, count );
+ return;
+ }
+ memcpy( p, buffer, dataCount );
+ /*longReverse( shsInfo->data, RMD_DATASIZE, shsInfo->Endianness);*/
+ MDcompress(shsInfo->digest,shsInfo->data);
+ buffer += dataCount;
+ count -= dataCount;
+ }
+
+ /* Process data in RMD_DATASIZE chunks */
+ while( count >= RMD_DATASIZE )
+ {
+ memcpy( shsInfo->data, buffer, RMD_DATASIZE );
+/* longReverse( shsInfo->data, RMD_DATASIZE, shsInfo->Endianness );*/
+ MDcompress(shsInfo->digest,shsInfo->data);
+ buffer += RMD_DATASIZE;
+ count -= RMD_DATASIZE;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy( shsInfo->data, buffer, count );
+}
+
+static PyObject *RIPEMDdigest(RIPEMDobject *self)
+{
+ RIPEMDobject temp;
+ int i;
+ byte hashcode[RMDsize/8]; /* final hash-value */
+
+ temp.Endianness=self->Endianness;
+ temp.countLo=self->countLo;
+ temp.countHi=self->countHi;
+ for(i=0; i<5; i++) temp.digest[i]=self->digest[i];
+ for(i=0; i<16; i++) temp.data[i]=self->data[i];
+
+ MDfinish(&temp);
+ /* Convert word to a string of bytes using a Little-endian convention */
+ for (i=0; i<RMDsize/8; i+=4) {
+ hashcode[i] = temp.digest[i>>2];
+ hashcode[i+1] = (temp.digest[i>>2] >> 8);
+ hashcode[i+2] = (temp.digest[i>>2] >> 16);
+ hashcode[i+3] = (temp.digest[i>>2] >> 24);
+ }
+ return PyString_FromStringAndSize(hashcode, RMD_DIGESTSIZE);
+}
+
+static void RIPEMDcopy(RIPEMDobject *src,RIPEMDobject *dest)
+{
+ int i;
+
+ dest->Endianness=src->Endianness;
+ dest->countLo=src->countLo;
+ dest->countHi=src->countHi;
+ for(i=0; i<5; i++) dest->digest[i]=src->digest[i];
+ for(i=0; i<16; i++) dest->data[i]=src->data[i];
+}
+/********************************************************************/
+static void MDinit(word *MDbuf)
+/* Initialization of the 5-word MDbuf array to the magic
+ initialization constants
+ */
+{
+ MDbuf[0] = 0x67452301UL;
+ MDbuf[1] = 0xefcdab89UL;
+ MDbuf[2] = 0x98badcfeUL;
+ MDbuf[3] = 0x10325476UL;
+ MDbuf[4] = 0xc3d2e1f0UL;
+}
+
+/********************************************************************/
+static void MDcompress(word *MDbuf, word *X)
+/* The compression function is called for every complete 64-byte
+ message block. The 5-word internal state MDbuf is updated using
+ message words X[0] through X[15]. The conversion from a string
+ of 64 bytes to an array of 16 words using a Little-endian
+ convention is the responsibility of the calling function.
+*/
+{
+ /* make two copies of the old state */
+ word aa = MDbuf[0], bb = MDbuf[1], cc = MDbuf[2],
+ dd = MDbuf[3], ee = MDbuf[4];
+ word aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2],
+ ddd = MDbuf[3], eee = MDbuf[4];
+
+/* {int i;
+ printf("\nWords: ");
+ for(i=0; i<16; i++) printf("%x ", X[i]);
+ printf("\n");}
+ printf("before compress: %x %x %x %x %x\n",
+ MDbuf[0], MDbuf[1], MDbuf[2], MDbuf[3], MDbuf[4]);
+ for(i=0;i<16;i++){printf("%08x ", X[i]);}printf("\n");*/
+
+ /* round 1 */
+ FF1(aa, bb, cc, dd, ee, X[ 0], 11);
+ FF1(ee, aa, bb, cc, dd, X[ 1], 14);
+ FF1(dd, ee, aa, bb, cc, X[ 2], 15);
+ FF1(cc, dd, ee, aa, bb, X[ 3], 12);
+ FF1(bb, cc, dd, ee, aa, X[ 4], 5);
+ FF1(aa, bb, cc, dd, ee, X[ 5], 8);
+ FF1(ee, aa, bb, cc, dd, X[ 6], 7);
+ FF1(dd, ee, aa, bb, cc, X[ 7], 9);
+ FF1(cc, dd, ee, aa, bb, X[ 8], 11);
+ FF1(bb, cc, dd, ee, aa, X[ 9], 13);
+ FF1(aa, bb, cc, dd, ee, X[10], 14);
+ FF1(ee, aa, bb, cc, dd, X[11], 15);
+ FF1(dd, ee, aa, bb, cc, X[12], 6);
+ FF1(cc, dd, ee, aa, bb, X[13], 7);
+ FF1(bb, cc, dd, ee, aa, X[14], 9);
+ FF1(aa, bb, cc, dd, ee, X[15], 8);
+
+ /* round 2 */
+ FF2(ee, aa, bb, cc, dd, X[ 7], 7);
+ FF2(dd, ee, aa, bb, cc, X[ 4], 6);
+ FF2(cc, dd, ee, aa, bb, X[13], 8);
+ FF2(bb, cc, dd, ee, aa, X[ 1], 13);
+ FF2(aa, bb, cc, dd, ee, X[10], 11);
+ FF2(ee, aa, bb, cc, dd, X[ 6], 9);
+ FF2(dd, ee, aa, bb, cc, X[15], 7);
+ FF2(cc, dd, ee, aa, bb, X[ 3], 15);
+ FF2(bb, cc, dd, ee, aa, X[12], 7);
+ FF2(aa, bb, cc, dd, ee, X[ 0], 12);
+ FF2(ee, aa, bb, cc, dd, X[ 9], 15);
+ FF2(dd, ee, aa, bb, cc, X[ 5], 9);
+ FF2(cc, dd, ee, aa, bb, X[ 2], 11);
+ FF2(bb, cc, dd, ee, aa, X[14], 7);
+ FF2(aa, bb, cc, dd, ee, X[11], 13);
+ FF2(ee, aa, bb, cc, dd, X[ 8], 12);
+
+ /* round 3 */
+ FF3(dd, ee, aa, bb, cc, X[ 3], 11);
+ FF3(cc, dd, ee, aa, bb, X[10], 13);
+ FF3(bb, cc, dd, ee, aa, X[14], 6);
+ FF3(aa, bb, cc, dd, ee, X[ 4], 7);
+ FF3(ee, aa, bb, cc, dd, X[ 9], 14);
+ FF3(dd, ee, aa, bb, cc, X[15], 9);
+ FF3(cc, dd, ee, aa, bb, X[ 8], 13);
+ FF3(bb, cc, dd, ee, aa, X[ 1], 15);
+ FF3(aa, bb, cc, dd, ee, X[ 2], 14);
+ FF3(ee, aa, bb, cc, dd, X[ 7], 8);
+ FF3(dd, ee, aa, bb, cc, X[ 0], 13);
+ FF3(cc, dd, ee, aa, bb, X[ 6], 6);
+ FF3(bb, cc, dd, ee, aa, X[13], 5);
+ FF3(aa, bb, cc, dd, ee, X[11], 12);
+ FF3(ee, aa, bb, cc, dd, X[ 5], 7);
+ FF3(dd, ee, aa, bb, cc, X[12], 5);
+
+ /* round 4 */
+ FF4(cc, dd, ee, aa, bb, X[ 1], 11);
+ FF4(bb, cc, dd, ee, aa, X[ 9], 12);
+ FF4(aa, bb, cc, dd, ee, X[11], 14);
+ FF4(ee, aa, bb, cc, dd, X[10], 15);
+ FF4(dd, ee, aa, bb, cc, X[ 0], 14);
+ FF4(cc, dd, ee, aa, bb, X[ 8], 15);
+ FF4(bb, cc, dd, ee, aa, X[12], 9);
+ FF4(aa, bb, cc, dd, ee, X[ 4], 8);
+ FF4(ee, aa, bb, cc, dd, X[13], 9);
+ FF4(dd, ee, aa, bb, cc, X[ 3], 14);
+ FF4(cc, dd, ee, aa, bb, X[ 7], 5);
+ FF4(bb, cc, dd, ee, aa, X[15], 6);
+ FF4(aa, bb, cc, dd, ee, X[14], 8);
+ FF4(ee, aa, bb, cc, dd, X[ 5], 6);
+ FF4(dd, ee, aa, bb, cc, X[ 6], 5);
+ FF4(cc, dd, ee, aa, bb, X[ 2], 12);
+
+ /* round 5 */
+ FF5(bb, cc, dd, ee, aa, X[ 4], 9);
+ FF5(aa, bb, cc, dd, ee, X[ 0], 15);
+ FF5(ee, aa, bb, cc, dd, X[ 5], 5);
+ FF5(dd, ee, aa, bb, cc, X[ 9], 11);
+ FF5(cc, dd, ee, aa, bb, X[ 7], 6);
+ FF5(bb, cc, dd, ee, aa, X[12], 8);
+ FF5(aa, bb, cc, dd, ee, X[ 2], 13);
+ FF5(ee, aa, bb, cc, dd, X[10], 12);
+ FF5(dd, ee, aa, bb, cc, X[14], 5);
+ FF5(cc, dd, ee, aa, bb, X[ 1], 12);
+ FF5(bb, cc, dd, ee, aa, X[ 3], 13);
+ FF5(aa, bb, cc, dd, ee, X[ 8], 14);
+ FF5(ee, aa, bb, cc, dd, X[11], 11);
+ FF5(dd, ee, aa, bb, cc, X[ 6], 8);
+ FF5(cc, dd, ee, aa, bb, X[15], 5);
+ FF5(bb, cc, dd, ee, aa, X[13], 6);
+
+ /* parallel round 1 */
+ FFF5(aaa, bbb, ccc, ddd, eee, X[ 5], 8);
+ FFF5(eee, aaa, bbb, ccc, ddd, X[14], 9);
+ FFF5(ddd, eee, aaa, bbb, ccc, X[ 7], 9);
+ FFF5(ccc, ddd, eee, aaa, bbb, X[ 0], 11);
+ FFF5(bbb, ccc, ddd, eee, aaa, X[ 9], 13);
+ FFF5(aaa, bbb, ccc, ddd, eee, X[ 2], 15);
+ FFF5(eee, aaa, bbb, ccc, ddd, X[11], 15);
+ FFF5(ddd, eee, aaa, bbb, ccc, X[ 4], 5);
+ FFF5(ccc, ddd, eee, aaa, bbb, X[13], 7);
+ FFF5(bbb, ccc, ddd, eee, aaa, X[ 6], 7);
+ FFF5(aaa, bbb, ccc, ddd, eee, X[15], 8);
+ FFF5(eee, aaa, bbb, ccc, ddd, X[ 8], 11);
+ FFF5(ddd, eee, aaa, bbb, ccc, X[ 1], 14);
+ FFF5(ccc, ddd, eee, aaa, bbb, X[10], 14);
+ FFF5(bbb, ccc, ddd, eee, aaa, X[ 3], 12);
+ FFF5(aaa, bbb, ccc, ddd, eee, X[12], 6);
+
+ /* parallel round 2 */
+ FFF4(eee, aaa, bbb, ccc, ddd, X[ 6], 9);
+ FFF4(ddd, eee, aaa, bbb, ccc, X[11], 13);
+ FFF4(ccc, ddd, eee, aaa, bbb, X[ 3], 15);
+ FFF4(bbb, ccc, ddd, eee, aaa, X[ 7], 7);
+ FFF4(aaa, bbb, ccc, ddd, eee, X[ 0], 12);
+ FFF4(eee, aaa, bbb, ccc, ddd, X[13], 8);
+ FFF4(ddd, eee, aaa, bbb, ccc, X[ 5], 9);
+ FFF4(ccc, ddd, eee, aaa, bbb, X[10], 11);
+ FFF4(bbb, ccc, ddd, eee, aaa, X[14], 7);
+ FFF4(aaa, bbb, ccc, ddd, eee, X[15], 7);
+ FFF4(eee, aaa, bbb, ccc, ddd, X[ 8], 12);
+ FFF4(ddd, eee, aaa, bbb, ccc, X[12], 7);
+ FFF4(ccc, ddd, eee, aaa, bbb, X[ 4], 6);
+ FFF4(bbb, ccc, ddd, eee, aaa, X[ 9], 15);
+ FFF4(aaa, bbb, ccc, ddd, eee, X[ 1], 13);
+ FFF4(eee, aaa, bbb, ccc, ddd, X[ 2], 11);
+
+ /* parallel round 3 */
+ FFF3(ddd, eee, aaa, bbb, ccc, X[15], 9);
+ FFF3(ccc, ddd, eee, aaa, bbb, X[ 5], 7);
+ FFF3(bbb, ccc, ddd, eee, aaa, X[ 1], 15);
+ FFF3(aaa, bbb, ccc, ddd, eee, X[ 3], 11);
+ FFF3(eee, aaa, bbb, ccc, ddd, X[ 7], 8);
+ FFF3(ddd, eee, aaa, bbb, ccc, X[14], 6);
+ FFF3(ccc, ddd, eee, aaa, bbb, X[ 6], 6);
+ FFF3(bbb, ccc, ddd, eee, aaa, X[ 9], 14);
+ FFF3(aaa, bbb, ccc, ddd, eee, X[11], 12);
+ FFF3(eee, aaa, bbb, ccc, ddd, X[ 8], 13);
+ FFF3(ddd, eee, aaa, bbb, ccc, X[12], 5);
+ FFF3(ccc, ddd, eee, aaa, bbb, X[ 2], 14);
+ FFF3(bbb, ccc, ddd, eee, aaa, X[10], 13);
+ FFF3(aaa, bbb, ccc, ddd, eee, X[ 0], 13);
+ FFF3(eee, aaa, bbb, ccc, ddd, X[ 4], 7);
+ FFF3(ddd, eee, aaa, bbb, ccc, X[13], 5);
+
+ /* parallel round 4 */
+ FFF2(ccc, ddd, eee, aaa, bbb, X[ 8], 15);
+ FFF2(bbb, ccc, ddd, eee, aaa, X[ 6], 5);
+ FFF2(aaa, bbb, ccc, ddd, eee, X[ 4], 8);
+ FFF2(eee, aaa, bbb, ccc, ddd, X[ 1], 11);
+ FFF2(ddd, eee, aaa, bbb, ccc, X[ 3], 14);
+ FFF2(ccc, ddd, eee, aaa, bbb, X[11], 14);
+ FFF2(bbb, ccc, ddd, eee, aaa, X[15], 6);
+ FFF2(aaa, bbb, ccc, ddd, eee, X[ 0], 14);
+ FFF2(eee, aaa, bbb, ccc, ddd, X[ 5], 6);
+ FFF2(ddd, eee, aaa, bbb, ccc, X[12], 9);
+ FFF2(ccc, ddd, eee, aaa, bbb, X[ 2], 12);
+ FFF2(bbb, ccc, ddd, eee, aaa, X[13], 9);
+ FFF2(aaa, bbb, ccc, ddd, eee, X[ 9], 12);
+ FFF2(eee, aaa, bbb, ccc, ddd, X[ 7], 5);
+ FFF2(ddd, eee, aaa, bbb, ccc, X[10], 15);
+ FFF2(ccc, ddd, eee, aaa, bbb, X[14], 8);
+
+ /* parallel round 5 */
+ FFF1(bbb, ccc, ddd, eee, aaa, X[12] , 8);
+ FFF1(aaa, bbb, ccc, ddd, eee, X[15] , 5);
+ FFF1(eee, aaa, bbb, ccc, ddd, X[10] , 12);
+ FFF1(ddd, eee, aaa, bbb, ccc, X[ 4] , 9);
+ FFF1(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);
+ FFF1(bbb, ccc, ddd, eee, aaa, X[ 5] , 5);
+ FFF1(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);
+ FFF1(eee, aaa, bbb, ccc, ddd, X[ 7] , 6);
+ FFF1(ddd, eee, aaa, bbb, ccc, X[ 6] , 8);
+ FFF1(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);
+ FFF1(bbb, ccc, ddd, eee, aaa, X[13] , 6);
+ FFF1(aaa, bbb, ccc, ddd, eee, X[14] , 5);
+ FFF1(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);
+ FFF1(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);
+ FFF1(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);
+ FFF1(bbb, ccc, ddd, eee, aaa, X[11] , 11);
+
+ /* combine results into new state */
+ ddd += cc + MDbuf[1];
+ MDbuf[1] = MDbuf[2] + dd + eee;
+ MDbuf[2] = MDbuf[3] + ee + aaa;
+ MDbuf[3] = MDbuf[4] + aa + bbb;
+ MDbuf[4] = MDbuf[0] + bb + ccc;
+ MDbuf[0] = ddd;
+/* printf("after compress: %x %x %x %x %x\n",
+ MDbuf[0], MDbuf[1], MDbuf[2], MDbuf[3], MDbuf[4]); */
+}
+
+/********************************************************************/
+static void MDfinish( RIPEMDobject *shsInfo)
+/* The final value of the 5-word MDbuf array is calculated.
+ lswlen and mswlen contain, respectively, the least and most significant
+ 32 bits of the message bit length mod 2^64, and string is an incomplete
+ block containing the (lswlen mod 512) remaining message bits.
+ (In case the message is already a multiple of 512 bits, string
+ is not used.) The conversion of the 5-word final state MDbuf to
+ the 20-byte hash result using a Little-endian convention is the
+ responsibility of the calling function.
+*/
+{
+ word *MDbuf = shsInfo->digest;
+ byte *string = (byte *)shsInfo->data;
+ word lswlen = shsInfo->countLo ;
+ word mswlen = shsInfo->countHi ;
+/* word lswlen = shsInfo->countLo << 3;*/
+/* word mswlen = (shsInfo->countLo >>29)|(shsInfo->countHi <<3);*/
+
+ size_t i, length;
+ byte mask;
+ word X[16];
+
+ /* clear 16-word message block */
+ memset(X, 0, 16*sizeof(word));
+
+ /* copy (lswlen mod 512) bits from string into X */
+ length = ((lswlen&511)+7)/8; /* number of bytes */
+ mask = (lswlen&7) ? ((byte)1 << (lswlen&7)) - 1 : 0xff;
+ for (i=0; i<length; i++) {
+ /* byte i goes into word X[i div 4] at bit position 8*(i mod 4) */
+ if (i == length-1)
+ X[i>>2] ^= (word) (*string&mask) << (8*(i&3));
+ else
+ X[i>>2] ^= (word) *string++ << (8*(i&3));
+ }
+
+ /* append a single 1 */
+ X[(lswlen>>5)&15] ^= (word)1 << (8*((lswlen>>3)&3)+7-(lswlen&7));
+
+ if ((lswlen & 511) > 447) {
+ /* length doesn't fit in this block anymore.
+ Compress, and put length in the next block */
+ /* longReverse( X, RMD_DATASIZE, shsInfo->Endianness);*/
+ MDcompress(MDbuf, X);
+ memset(X, 0, 16*sizeof(word));
+ }
+ /* append length in bits*/
+ X[14] = lswlen;
+ X[15] = mswlen;
+ MDcompress(MDbuf, X);
+}
+
+
diff --git a/Hash/SHA.c b/Hash/SHA.c
new file mode 100644
index 0000000..749a6c2
--- /dev/null
+++ b/Hash/SHA.c
@@ -0,0 +1,436 @@
+/*
+ * sha.c : Implementation of the Secure Hash Algorithm
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+/* SHA: NIST's Secure Hash Algorithm */
+
+/* Based on SHA code originally posted to sci.crypt by Peter Gutmann
+ in message <30ajo5$oe8@ccu2.auckland.ac.nz>.
+ Modified to test for endianness on creation of SHA objects by AMK.
+ Also, the original specification of SHA was found to have a weakness
+ by NSA/NIST. This code implements the fixed version of SHA.
+*/
+
+/* Here's the first paragraph of Peter Gutmann's posting:
+
+The following is my SHA (FIPS 180) code updated to allow use of the "fixed"
+SHA, thanks to Jim Gillogly and an anonymous contributor for the information on
+what's changed in the new version. The fix is a simple change which involves
+adding a single rotate in the initial expansion function. It is unknown
+whether this is an optimal solution to the problem which was discovered in the
+SHA or whether it's simply a bandaid which fixes the problem with a minimum of
+effort (for example the reengineering of a great many Capstone chips).
+*/
+
+/* Some useful types */
+
+typedef unsigned char BYTE;
+#ifndef __alpha__
+typedef unsigned long LONG;
+#else
+typedef unsigned int LONG;
+#endif
+/* The SHS block size and message digest sizes, in bytes */
+
+#define SHS_DATASIZE 64
+#define SHS_DIGESTSIZE 20
+
+/* The structure for storing SHS info */
+
+typedef struct {
+ PCTObject_HEAD
+ LONG digest[ 5 ]; /* Message digest */
+ LONG countLo, countHi; /* 64-bit bit count */
+ LONG data[ 16 ]; /* SHS data buffer */
+ int Endianness;
+ } SHAobject;
+
+/* Message digest functions */
+
+static void SHAinit();
+static void SHAupdate();
+static PyObject *SHAdigest();
+static void SHAFinal();
+static void SHAcopy();
+
+static void SHAcopy(src, dest)
+ SHAobject *src, *dest;
+{
+ int i;
+
+ dest->Endianness=src->Endianness;
+ dest->countLo=src->countLo;
+ dest->countHi=src->countHi;
+ for(i=0; i<5; i++) dest->digest[i]= src->digest[i];
+ for(i=0; i<16; i++) dest->data[i] = src->data[i];
+}
+
+
+/* The SHS f()-functions. The f1 and f3 functions can be optimized to
+ save one boolean operation each - thanks to Rich Schroeppel,
+ rcs@cs.arizona.edu for discovering this */
+
+/*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) // Rounds 0-19 */
+#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
+#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
+/*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) // Rounds 40-59 */
+#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
+#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
+
+/* The SHS Mysterious Constants */
+
+#define K1 0x5A827999L /* Rounds 0-19 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59 */
+#define K4 0xCA62C1D6L /* Rounds 60-79 */
+
+/* SHS initial values */
+
+#define h0init 0x67452301L
+#define h1init 0xEFCDAB89L
+#define h2init 0x98BADCFEL
+#define h3init 0x10325476L
+#define h4init 0xC3D2E1F0L
+
+/* Note that it may be necessary to add parentheses to these macros if they
+ are to be called with expressions as arguments */
+/* 32-bit rotate left - kludged with shifts */
+
+#define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
+
+/* The initial expanding function. The hash function is defined over an
+ 80-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+
+ The updated SHS changes the expanding function by adding a rotate of 1
+ bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
+ for this information */
+
+#define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
+ W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
+
+
+/* The prototype SHS sub-round. The fundamental sub-round is:
+
+ a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
+ b' = a;
+ c' = ROTL( 30, b );
+ d' = c;
+ e' = d;
+
+ but this is implemented by unrolling the loop 5 times and renaming the
+ variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
+ This code is then replicated 20 times for each of the 4 functions, using
+ the next 20 values from the W[] array each time */
+
+#define subRound(a, b, c, d, e, f, k, data) \
+ ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
+
+/* Initialize the SHS values */
+
+static void SHAinit( shsInfo )
+ SHAobject *shsInfo;
+ {
+ TestEndianness(shsInfo->Endianness)
+ /* Set the h-vars to their initial values */
+ shsInfo->digest[ 0 ] = h0init;
+ shsInfo->digest[ 1 ] = h1init;
+ shsInfo->digest[ 2 ] = h2init;
+ shsInfo->digest[ 3 ] = h3init;
+ shsInfo->digest[ 4 ] = h4init;
+
+ /* Initialise bit count */
+ shsInfo->countLo = shsInfo->countHi = 0;
+ }
+
+
+/* Perform the SHS transformation. Note that this code, like MD5, seems to
+ break some optimizing compilers due to the complexity of the expressions
+ and the size of the basic block. It may be necessary to split it into
+ sections, e.g. based on the four subrounds
+
+ Note that this corrupts the shsInfo->data area */
+
+static void SHSTransform( digest, data )
+ LONG *digest, *data ;
+ {
+ LONG A, B, C, D, E; /* Local vars */
+ LONG eData[ 16 ]; /* Expanded data */
+
+ /* Set up first buffer and local data buffer */
+ A = digest[ 0 ];
+ B = digest[ 1 ];
+ C = digest[ 2 ];
+ D = digest[ 3 ];
+ E = digest[ 4 ];
+ memcpy( eData, data, SHS_DATASIZE );
+
+#ifdef DEBUG
+ printf("start: %08x %08x %08x %08x %08x\n", A, B, C, D, E);
+#endif
+ /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+ subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
+ subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
+ subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
+ subRound( C, D, E, A, B, f1, K1, eData[ 3 ] );
+ subRound( B, C, D, E, A, f1, K1, eData[ 4 ] );
+ subRound( A, B, C, D, E, f1, K1, eData[ 5 ] );
+ subRound( E, A, B, C, D, f1, K1, eData[ 6 ] );
+ subRound( D, E, A, B, C, f1, K1, eData[ 7 ] );
+ subRound( C, D, E, A, B, f1, K1, eData[ 8 ] );
+ subRound( B, C, D, E, A, f1, K1, eData[ 9 ] );
+ subRound( A, B, C, D, E, f1, K1, eData[ 10 ] );
+ subRound( E, A, B, C, D, f1, K1, eData[ 11 ] );
+ subRound( D, E, A, B, C, f1, K1, eData[ 12 ] );
+ subRound( C, D, E, A, B, f1, K1, eData[ 13 ] );
+ subRound( B, C, D, E, A, f1, K1, eData[ 14 ] );
+ subRound( A, B, C, D, E, f1, K1, eData[ 15 ] );
+ subRound( E, A, B, C, D, f1, K1, expand( eData, 16 ) );
+ subRound( D, E, A, B, C, f1, K1, expand( eData, 17 ) );
+ subRound( C, D, E, A, B, f1, K1, expand( eData, 18 ) );
+ subRound( B, C, D, E, A, f1, K1, expand( eData, 19 ) );
+
+#ifdef DEBUG
+ printf("2 : %08x %08x %08x %08x %08x\n", A, B, C, D, E);
+#endif
+
+ subRound( A, B, C, D, E, f2, K2, expand( eData, 20 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( eData, 21 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( eData, 22 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( eData, 23 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( eData, 24 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( eData, 25 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( eData, 26 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( eData, 27 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( eData, 28 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( eData, 29 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( eData, 30 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( eData, 31 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( eData, 32 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( eData, 33 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( eData, 34 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( eData, 35 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( eData, 36 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( eData, 37 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( eData, 38 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( eData, 39 ) );
+
+#ifdef DEBUG
+ printf("3 : %08x %08x %08x %08x %08x\n", A, B, C, D, E);
+#endif
+
+ subRound( A, B, C, D, E, f3, K3, expand( eData, 40 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( eData, 41 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( eData, 42 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( eData, 43 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( eData, 44 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( eData, 45 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( eData, 46 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( eData, 47 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( eData, 48 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( eData, 49 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( eData, 50 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( eData, 51 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( eData, 52 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( eData, 53 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( eData, 54 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( eData, 55 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( eData, 56 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( eData, 57 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( eData, 58 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( eData, 59 ) );
+
+#ifdef DEBUG
+ printf("4 : %08x %08x %08x %08x %08x\n", A, B, C, D, E);
+#endif
+
+ subRound( A, B, C, D, E, f4, K4, expand( eData, 60 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( eData, 61 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( eData, 62 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( eData, 63 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( eData, 64 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( eData, 65 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( eData, 66 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( eData, 67 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( eData, 68 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( eData, 69 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( eData, 70 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( eData, 71 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( eData, 72 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( eData, 73 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( eData, 74 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( eData, 75 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( eData, 76 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( eData, 77 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( eData, 78 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( eData, 79 ) );
+
+#ifdef DEBUG
+ printf("5 : %08x %08x %08x %08x %08x\n", A, B, C, D, E);
+#endif
+
+ /* Build message digest */
+ digest[ 0 ] += A;
+ digest[ 1 ] += B;
+ digest[ 2 ] += C;
+ digest[ 3 ] += D;
+ digest[ 4 ] += E;
+ }
+
+/* When run on a little-endian CPU we need to perform byte reversal on an
+ array of longwords. */
+
+static void longReverse( buffer, byteCount, Endianness )
+ LONG *buffer;
+ int byteCount, Endianness;
+ {
+ LONG value;
+
+ if (Endianness==PCT_BIG_ENDIAN) return;
+ byteCount /= sizeof( LONG );
+ while( byteCount-- )
+ {
+ value = *buffer;
+ value = ( ( value & 0xFF00FF00L ) >> 8 ) | \
+ ( ( value & 0x00FF00FFL ) << 8 );
+ *buffer++ = ( value << 16 ) | ( value >> 16 );
+ }
+ }
+
+/* Update SHS for a block of data */
+
+static void SHAupdate( shsInfo, buffer, count )
+ SHAobject *shsInfo;
+ BYTE *buffer;
+ int count;
+ {
+ LONG tmp;
+ int dataCount;
+
+ /* Update bitcount */
+ tmp = shsInfo->countLo;
+ if ( ( shsInfo->countLo = tmp + ( ( LONG ) count << 3 ) ) < tmp )
+ shsInfo->countHi++; /* Carry from low to high */
+ shsInfo->countHi += count >> 29;
+
+ /* Get count of bytes already in data */
+ dataCount = ( int ) ( tmp >> 3 ) & 0x3F;
+
+ /* Handle any leading odd-sized chunks */
+ if( dataCount )
+ {
+ BYTE *p = ( BYTE * ) shsInfo->data + dataCount;
+
+ dataCount = SHS_DATASIZE - dataCount;
+ if( count < dataCount )
+ {
+ memcpy( p, buffer, count );
+ return;
+ }
+ memcpy( p, buffer, dataCount );
+ longReverse( shsInfo->data, SHS_DATASIZE, shsInfo->Endianness);
+ SHSTransform( shsInfo->digest, shsInfo->data );
+ buffer += dataCount;
+ count -= dataCount;
+ }
+
+ /* Process data in SHS_DATASIZE chunks */
+ while( count >= SHS_DATASIZE )
+ {
+ memcpy( shsInfo->data, buffer, SHS_DATASIZE );
+ longReverse( shsInfo->data, SHS_DATASIZE, shsInfo->Endianness );
+ SHSTransform( shsInfo->digest, shsInfo->data );
+ buffer += SHS_DATASIZE;
+ count -= SHS_DATASIZE;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy( shsInfo->data, buffer, count );
+ }
+
+/* Final wrapup - pad to SHS_DATASIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+
+static void SHAFinal( shsInfo )
+ SHAobject *shsInfo;
+ {
+ int count;
+ BYTE *dataPtr;
+
+ /* Compute number of bytes mod 64 */
+ count = ( int ) shsInfo->countLo;
+ count = ( count >> 3 ) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ dataPtr = ( BYTE * ) shsInfo->data + count;
+ *dataPtr++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = SHS_DATASIZE - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if( count < 8 )
+ {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset( dataPtr, 0, count );
+ longReverse( shsInfo->data, SHS_DATASIZE, shsInfo->Endianness );
+ SHSTransform( shsInfo->digest, shsInfo->data );
+
+ /* Now fill the next block with 56 bytes */
+ memset( shsInfo->data, 0, SHS_DATASIZE - 8 );
+ }
+ else
+ /* Pad block to 56 bytes */
+ memset( dataPtr, 0, count - 8 );
+
+ /* Append length in bits and transform */
+ shsInfo->data[ 14 ] = shsInfo->countHi;
+ shsInfo->data[ 15 ] = shsInfo->countLo;
+
+ longReverse( shsInfo->data, SHS_DATASIZE - 8, shsInfo->Endianness );
+ SHSTransform( shsInfo->digest, shsInfo->data );
+}
+
+static PyObject *SHAdigest(shsInfo)
+ SHAobject *shsInfo;
+{
+ SHAobject temp;
+ int i, j;
+ unsigned char digest[SHS_DIGESTSIZE];
+
+ temp.Endianness=shsInfo->Endianness;
+ temp.countLo=shsInfo->countLo;
+ temp.countHi=shsInfo->countHi;
+ for(i=0; i<5; i++) temp.digest[i]=shsInfo->digest[i];
+ for(i=0; i<16; i++) temp.data[i]=shsInfo->data[i];
+
+ SHAFinal(&temp);
+ for(i=j=0; i<SHS_DIGESTSIZE; i+=4, j++)
+ {
+ digest[i+3]=(temp.digest[j] ) & 255;
+ digest[i+2]=(temp.digest[j] >> 8) & 255;
+ digest[i+1]=(temp.digest[j] >> 16) & 255;
+ digest[i ]=(temp.digest[j] >> 24) & 255;
+ }
+ return PyString_FromStringAndSize(digest, SHS_DIGESTSIZE);
+}
+
+
+
+
+
+
diff --git a/Hash/__init__.py b/Hash/__init__.py
new file mode 100644
index 0000000..bf32a43
--- /dev/null
+++ b/Hash/__init__.py
@@ -0,0 +1,3 @@
+
+__all__ = ['MD2', 'MD4', 'MD5', 'SHA', 'HAVAL', 'HMAC']
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3861bac
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,47 @@
+
+PYTHON = /usr/bin/env python
+CRYPTO_DIR = Crypto-1.1a2
+
+all : source
+ -ln -f Makefile.pre.in src/Makefile.pre.in
+ # If the block/ directory is present, this must be the full
+ # kit, not the suitable-for-export subset
+ if [ -d block ] ; then \
+ ln -f Setup.in src/Setup.in; \
+ else \
+ ln -f Setup.in-export src/Setup.in; \
+ fi
+ (cd src ; make VERSION=1.5 -f Makefile.pre.in boot ; make)
+# mv src/python .
+
+source :
+ $(PYTHON) buildkit
+
+clean :
+ -rm -f `find . -name '*~'` python
+ -rm -f `find . -name '*.pyc'`
+ -rm -f Demo/secimp/*.pys src/* Cipher/*.so Cipher/*.sl Hash/*.so Hash/*.sl
+ -rm -f sedscript config.c
+ -(cd Doc ; rm -f *.ps *.log *.aux *.ilg *.toc)
+ -rm -f err out
+
+install:
+ cd src ; make install
+ if [ -d block ] ; then \
+ cd src ; make cipherinstall; \
+ fi
+
+test:
+ cd src ; make links
+ python test.py --quiet
+
+distrib : clean
+ rm -f src/*
+# python buildkit
+# cd Doc ; rm -f html/* ; texi2html pycrypt.texi html ; makeinfo pycrypt.texi
+ cd .. ; tar -cvf /scratch/pycrypt-export.tar -X $(CRYPTO_DIR)/not-for-export -X $(CRYPTO_DIR)/excludefiles $(CRYPTO_DIR)
+ cd .. ; tar -cvf /scratch/pycrypt-US.tar `cat $(CRYPTO_DIR)/not-for-export` -X $(CRYPTO_DIR)/excludefiles
+ cd Doc ; rm -f *.?? *.log *.aux *.ilg
+
+links:
+ cd src ; make links
diff --git a/Makefile.pre.in b/Makefile.pre.in
new file mode 100644
index 0000000..01dfa40
--- /dev/null
+++ b/Makefile.pre.in
@@ -0,0 +1,369 @@
+# Universal Unix Makefile for Python extensions
+# =============================================
+
+# Short Instructions
+# ------------------
+
+# 1. Build and install Python (1.5 or newer).
+# 2. "make -f Makefile.pre.in boot"
+# 3. "make"
+# You should now have a shared library.
+
+# Long Instructions
+# -----------------
+
+# Build *and install* the basic Python 1.5 distribution. See the
+# Python README for instructions. (This version of Makefile.pre.in
+# only withs with Python 1.5, alpha 3 or newer.)
+
+# Create a file Setup.in for your extension. This file follows the
+# format of the Modules/Setup.in file; see the instructions there.
+# For a simple module called "spam" on file "spammodule.c", it can
+# contain a single line:
+# spam spammodule.c
+# You can build as many modules as you want in the same directory --
+# just have a separate line for each of them in the Setup.in file.
+
+# If you want to build your extension as a shared library, insert a
+# line containing just the string
+# *shared*
+# at the top of your Setup.in file.
+
+# Note that the build process copies Setup.in to Setup, and then works
+# with Setup. It doesn't overwrite Setup when Setup.in is changed, so
+# while you're in the process of debugging your Setup.in file, you may
+# want to edit Setup instead, and copy it back to Setup.in later.
+# (All this is done so you can distribute your extension easily and
+# someone else can select the modules they actually want to build by
+# commenting out lines in the Setup file, without editing the
+# original. Editing Setup is also used to specify nonstandard
+# locations for include or library files.)
+
+# Copy this file (Misc/Makefile.pre.in) to the directory containing
+# your extension.
+
+# Run "make -f Makefile.pre.in boot". This creates Makefile
+# (producing Makefile.pre and sedscript as intermediate files) and
+# config.c, incorporating the values for sys.prefix, sys.exec_prefix
+# and sys.version from the installed Python binary. For this to work,
+# the python binary must be on your path. If this fails, try
+# make -f Makefile.pre.in Makefile VERSION=1.5 installdir=<prefix>
+# where <prefix> is the prefix used to install Python for installdir
+# (and possibly similar for exec_installdir=<exec_prefix>).
+
+# Note: "make boot" implies "make clobber" -- it assumes that when you
+# bootstrap you may have changed platforms so it removes all previous
+# output files.
+
+# If you are building your extension as a shared library (your
+# Setup.in file starts with *shared*), run "make" or "make sharedmods"
+# to build the shared library files. If you are building a statically
+# linked Python binary (the only solution of your platform doesn't
+# support shared libraries, and sometimes handy if you want to
+# distribute or install the resulting Python binary), run "make
+# python".
+
+# Note: Each time you edit Makefile.pre.in or Setup, you must run
+# "make Makefile" before running "make".
+
+# Hint: if you want to use VPATH, you can start in an empty
+# subdirectory and say (e.g.):
+# make -f ../Makefile.pre.in boot srcdir=.. VPATH=..
+
+
+# === Bootstrap variables (edited through "make boot") ===
+
+# The prefix used by "make inclinstall libainstall" of core python
+installdir= /usr/local
+
+# The exec_prefix used by the same
+exec_installdir=$(installdir)
+
+# Source directory and VPATH in case you want to use VPATH.
+# (You will have to edit these two lines yourself -- there is no
+# automatic support as the Makefile is not generated by
+# config.status.)
+srcdir= .
+VPATH= .
+
+# === Variables that you may want to customize (rarely) ===
+
+# (Static) build target
+TARGET= python
+
+# Installed python binary (used only by boot target)
+PYTHON= python
+
+# Add more -I and -D options here
+CFLAGS= $(OPT) -I$(INCLUDEPY) -I$(EXECINCLUDEPY) $(DEFS)
+
+# These two variables can be set in Setup to merge extensions.
+# See example[23].
+BASELIB=
+BASESETUP=
+
+# === Variables set by makesetup ===
+
+MODOBJS= _MODOBJS_
+MODLIBS= _MODLIBS_
+
+# === Definitions added by makesetup ===
+
+# === Variables from configure (through sedscript) ===
+
+VERSION= @VERSION@
+CC= @CC@
+LINKCC= @LINKCC@
+SGI_ABI= @SGI_ABI@
+OPT= @OPT@
+LDFLAGS= @LDFLAGS@
+LDLAST= @LDLAST@
+DEFS= @DEFS@
+LIBS= @LIBS@
+LIBM= @LIBM@
+LIBC= @LIBC@
+RANLIB= @RANLIB@
+MACHDEP= @MACHDEP@
+SO= @SO@
+LDSHARED= @LDSHARED@
+CCSHARED= @CCSHARED@
+LINKFORSHARED= @LINKFORSHARED@
+#@SET_CCC@
+
+# Install prefix for architecture-independent files
+prefix= /usr/local
+
+# Install prefix for architecture-dependent files
+exec_prefix= $(prefix)
+
+# === Fixed definitions ===
+
+# Shell used by make (some versions default to the login shell, which is bad)
+SHELL= /bin/sh
+
+# Expanded directories
+BINDIR= $(exec_installdir)/bin
+LIBDIR= $(exec_prefix)/lib
+MANDIR= $(installdir)/man
+INCLUDEDIR= $(installdir)/include
+SCRIPTDIR= $(prefix)/lib
+
+# Detailed destination directories
+BINLIBDEST= $(LIBDIR)/python$(VERSION)
+LIBDEST= $(SCRIPTDIR)/python$(VERSION)
+INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)
+EXECINCLUDEPY= $(exec_installdir)/include/python$(VERSION)
+LIBP= $(exec_installdir)/lib/python$(VERSION)
+DESTSHARED= $(BINLIBDEST)/site-packages
+
+LIBPL= $(LIBP)/config
+
+PYTHONLIBS= $(LIBPL)/libpython$(VERSION).a
+
+MAKESETUP= $(LIBPL)/makesetup
+MAKEFILE= $(LIBPL)/Makefile
+CONFIGC= $(LIBPL)/config.c
+CONFIGCIN= $(LIBPL)/config.c.in
+SETUP= $(LIBPL)/Setup
+
+SYSLIBS= $(LIBM) $(LIBC)
+
+ADDOBJS= $(LIBPL)/python.o config.o
+
+# Portable install script (configure doesn't always guess right)
+INSTALL= $(LIBPL)/install-sh -c
+# Shared libraries must be installed with executable mode on some systems;
+# rather than figuring out exactly which, we always give them executable mode.
+# Also, making them read-only seems to be a good idea...
+INSTALL_SHARED= ${INSTALL} -m 555
+INSTALL_DATA= ${INSTALL} -m 644
+
+# === Fixed rules ===
+
+# Default target. This builds shared libraries only
+default: sharedmods
+
+# Build everything
+all: static sharedmods
+
+# Build shared libraries from our extension modules
+sharedmods: $(SHAREDMODS)
+
+# Build a static Python binary containing our extension modules
+static: $(TARGET)
+$(TARGET): $(ADDOBJS) lib.a $(PYTHONLIBS) $(BASELIB)
+ $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) \
+ $(ADDOBJS) lib.a $(PYTHONLIBS) \
+ $(LINKPATH) $(BASELIB) $(MODLIBS) $(LIBS) $(SYSLIBS) \
+ -o $(TARGET) $(LDLAST)
+
+# Build the library containing our extension modules
+lib.a: $(MODOBJS)
+ -rm -f lib.a
+ ar cr lib.a $(MODOBJS)
+ -$(RANLIB) lib.a
+
+# This runs makesetup *twice* to use the BASESETUP definition from Setup
+config.c Makefile: Makefile.pre Setup $(BASESETUP) $(MAKESETUP)
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+ $(MAKE) -f Makefile do-it-again
+
+# Internal target to run makesetup for the second time
+do-it-again:
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+
+# Make config.o from the config.c created by makesetup
+config.o: config.c
+ $(CC) $(CFLAGS) -c config.c
+
+# Setup is copied from Setup.in *only* if it doesn't yet exist
+Setup:
+ cp $(srcdir)/Setup.in Setup
+
+# Make the intermediate Makefile.pre from Makefile.pre.in
+Makefile.pre: Makefile.pre.in sedscript
+ sed -f sedscript $(srcdir)/Makefile.pre.in >Makefile.pre
+
+# Shortcuts to make the sed arguments on one line
+P=prefix
+E=exec_prefix
+H=Generated automatically from Makefile.pre.in by sedscript.
+L=LINKFORSHARED
+
+# Make the sed script used to create Makefile.pre from Makefile.pre.in
+sedscript: $(MAKEFILE)
+ sed -n \
+ -e '1s/.*/1i\\/p' \
+ -e '2s%.*%# $H%p' \
+ -e '/^VERSION=/s/^VERSION=[ ]*\(.*\)/s%@VERSION[@]%\1%/p' \
+ -e '/^CC=/s/^CC=[ ]*\(.*\)/s%@CC[@]%\1%/p' \
+ -e '/^CCC=/s/^CCC=[ ]*\(.*\)/s%#@SET_CCC[@]%CCC=\1%/p' \
+ -e '/^LINKCC=/s/^LINKCC=[ ]*\(.*\)/s%@LINKCC[@]%\1%/p' \
+ -e '/^OPT=/s/^OPT=[ ]*\(.*\)/s%@OPT[@]%\1%/p' \
+ -e '/^LDFLAGS=/s/^LDFLAGS=[ ]*\(.*\)/s%@LDFLAGS[@]%\1%/p' \
+ -e '/^DEFS=/s/^DEFS=[ ]*\(.*\)/s%@DEFS[@]%\1%/p' \
+ -e '/^LIBS=/s/^LIBS=[ ]*\(.*\)/s%@LIBS[@]%\1%/p' \
+ -e '/^LIBM=/s/^LIBM=[ ]*\(.*\)/s%@LIBM[@]%\1%/p' \
+ -e '/^LIBC=/s/^LIBC=[ ]*\(.*\)/s%@LIBC[@]%\1%/p' \
+ -e '/^RANLIB=/s/^RANLIB=[ ]*\(.*\)/s%@RANLIB[@]%\1%/p' \
+ -e '/^MACHDEP=/s/^MACHDEP=[ ]*\(.*\)/s%@MACHDEP[@]%\1%/p' \
+ -e '/^SO=/s/^SO=[ ]*\(.*\)/s%@SO[@]%\1%/p' \
+ -e '/^LDSHARED=/s/^LDSHARED=[ ]*\(.*\)/s%@LDSHARED[@]%\1%/p' \
+ -e '/^CCSHARED=/s/^CCSHARED=[ ]*\(.*\)/s%@CCSHARED[@]%\1%/p' \
+ -e '/^LDLAST=/s/^LDLAST=[ ]*\(.*\)/s%@LDLAST[@]%\1%/p' \
+ -e '/^$L=/s/^$L=[ ]*\(.*\)/s%@$L[@]%\1%/p' \
+ -e '/^$P=/s/^$P=\(.*\)/s%^$P=.*%$P=\1%/p' \
+ -e '/^$E=/s/^$E=\(.*\)/s%^$E=.*%$E=\1%/p' \
+ $(MAKEFILE) >sedscript
+ echo "/^#@SET_CCC@/d" >>sedscript
+ echo "/^installdir=/s%=.*%= $(installdir)%" >>sedscript
+ echo "/^exec_installdir=/s%=.*%=$(exec_installdir)%" >>sedscript
+ echo "/^srcdir=/s%=.*%= $(srcdir)%" >>sedscript
+ echo "/^VPATH=/s%=.*%= $(VPATH)%" >>sedscript
+ echo "/^LINKPATH=/s%=.*%= $(LINKPATH)%" >>sedscript
+ echo "/^BASELIB=/s%=.*%= $(BASELIB)%" >>sedscript
+ echo "/^BASESETUP=/s%=.*%= $(BASESETUP)%" >>sedscript
+
+# Bootstrap target
+boot: clobber
+ VERSION=`$(PYTHON) -c "import sys; print sys.version[:3]"`; \
+ installdir=`$(PYTHON) -c "import sys; print sys.prefix"`; \
+ exec_installdir=`$(PYTHON) -c "import sys; print sys.exec_prefix"`; \
+ $(MAKE) -f $(srcdir)/Makefile.pre.in VPATH=$(VPATH) srcdir=$(srcdir) \
+ VERSION=$$VERSION \
+ installdir=$$installdir \
+ exec_installdir=$$exec_installdir \
+ Makefile
+
+# Handy target to remove intermediate files and backups
+clean:
+ -rm -f *.o *~
+
+# Handy target to remove everything that is easily regenerated
+clobber: clean
+ -rm -f *.a tags TAGS config.c Makefile.pre $(TARGET) sedscript
+ -rm -f *.so *.sl so_locations
+
+
+# Handy target to remove everything you don't want to distribute
+distclean: clobber
+ -rm -f Makefile Setup
+
+CRYPTO_DIR= $(LIBDEST)/site-packages/Crypto
+HASHMODS= MD2 MD4 MD5 SHA HAVAL RIPEMD
+CIPHERMODS= ARC2 ARC4 Blowfish CAST DES DES3 Diamond IDEA RC5 Sapphire \
+ Skipjack XOR
+
+links: $(SHAREDMODS)
+ # Make links in the Hash directory
+ -for i in $(HASHMODS) ; do \
+ ln -f $${i}module$(SO) ../Hash/$${i}module$(SO) ; \
+ done
+ # Make links in the Cipher directory
+ -for i in $(CIPHERMODS) ; do \
+ ln -f $${i}module$(SO) ../Cipher/$${i}module$(SO) ; \
+ done
+
+install: $(SHAREDMODS)
+ # Create package directories
+ @for i in $(CRYPTO_DIR) $(CRYPTO_DIR)/Cipher \
+ $(CRYPTO_DIR)/PublicKey $(CRYPTO_DIR)/Hash \
+ $(CRYPTO_DIR)/Protocol $(CRYPTO_DIR)/Util \
+ $(CRYPTO_DIR)/Protocol/Winnow ; \
+ do \
+ if test ! -d $$i; then \
+ echo "Creating directory $$i"; \
+ mkdir $$i; \
+ chmod 755 $$i; \
+ else true; \
+ fi; \
+ done
+
+ $(INSTALL_DATA) ../_checkversion.py $(CRYPTO_DIR)
+
+ # Copy the __init__.py files
+ -for i in "" Cipher Hash Protocol; do \
+ $(INSTALL_DATA) ../$$i/__init__.py $(CRYPTO_DIR)/$$i/__init__.py ; \
+ done
+
+ # Copy things into the Hash directory
+ -for i in $(HASHMODS) ; do \
+ $(INSTALL_SHARED) $${i}module$(SO) $(CRYPTO_DIR)/Hash/ ; \
+ done
+
+ # Copy *.py files into the Hash directory
+ -for i in ../Hash/*.py ; do \
+ base=`basename $$i`; \
+ $(INSTALL_DATA) $$i $(CRYPTO_DIR)/Hash/$$base ; \
+ done
+ # Copy things into the PublicKey directory
+ -for i in ../PublicKey/*.py ; do \
+ base=`basename $$i`; \
+ $(INSTALL_DATA) $$i $(CRYPTO_DIR)/PublicKey/$$base ; \
+ done
+ # Copy things into the Util directory
+ -for i in ../Util/*.py ; do \
+ base=`basename $$i`; \
+ $(INSTALL_DATA) $$i $(CRYPTO_DIR)/Util/$$base ; \
+ done
+ # Copy things into the Winnow directory
+ -for i in ../Protocol/Winnow/*.py ; do \
+ base=`basename $$i`; \
+ $(INSTALL_DATA) $$i $(CRYPTO_DIR)/Protocol/Winnow/$$base ; \
+ done
+ python -c 'from compileall import *;compile_dir("$(CRYPTO_DIR)")'
+ python -O -c 'from compileall import *;compile_dir("$(CRYPTO_DIR)")'
+
+cipherinstall:
+ # Copy things into the Cipher directory
+ for i in $(CIPHERMODS) ; do \
+ $(INSTALL_SHARED) $${i}module$(SO) $(CRYPTO_DIR)/Cipher/ ; \
+ done
+
+
+
+
+
+
diff --git a/Protocol/AllOrNothing.py b/Protocol/AllOrNothing.py
new file mode 100644
index 0000000..aae7dba
--- /dev/null
+++ b/Protocol/AllOrNothing.py
@@ -0,0 +1,306 @@
+"""This file implements all-or-nothing package transformations.
+
+An all-or-nothing package transformation is one in which some text is
+transformed into message blocks, such that all blocks must be obtained before
+the reverse transformation can be applied. Thus, if any blocks are corrupted
+or lost, the original message cannot be reproduced.
+
+An all-or-nothing package transformation is not encryption, although a block
+cipher algorithm is used. The encryption key is randomly generated and is
+extractable from the message blocks.
+
+This class implements the All-Or-Nothing package transformation algorithm
+described in:
+
+Rivest. All-Or-Nothing Encryption and The Package Transform. To appear in
+the Proceedings of the 1997 Fast Software Encryption Conference.
+http://theory.lcs.mit.edu/~rivest/fusion.ps
+
+"""
+
+import operator
+import string
+from Crypto.Util.number import bytestolong, longtobytes
+
+
+
+class AllOrNothing:
+ """Class implementing the All-or-Nothing package transform.
+
+ Public Methods:
+
+ __init__(ciphermodule, mode=None, IV=None):
+ Constructor for the class. ciphermodule is a module implementing
+ the cipher algorithm to use. In essence it must provide the
+ following interface:
+
+ ciphermodule.keysize
+ Attribute containing the cipher algorithm's key size in
+ bytes. If the cipher supports variable length keys, then
+ typically ciphermodule.keysize will be zero. In that case a
+ key size of 16 bytes will be used.
+
+ ciphermodule.blocksize
+ Attribute containing the cipher algorithm's input block size
+ in bytes
+
+ ciphermodule.new(key, mode, IV)
+ Function which returns a new instance of a cipher object,
+ initialized to key. The returned object must have an
+ encrypt() method that accepts a string of
+ ciphermodule.blocksize bytes and returns a string containing
+ the encrypted text.
+
+ Note that the encryption key is randomly generated automatically
+ when needed. Optional arguments mode and IV are passed directly
+ through to the ciphermodule.new() method; they are the feedback
+ mode and initialization vector to use. All three arguments must
+ be the same for the object used to create the digest, and to
+ undigest'ify the message blocks.
+
+ update(text):
+ Concatenate text to the string that will be transformed.
+
+ reset(text=''):
+ Reset the current string to be transformed to text.
+
+ digest():
+ Perform the All-or-Nothing package transform on the current
+ string. Output is a list of message blocks describing the
+ transformed text, where each block is a string of bit length equal
+ to the ciphermodule's blocksize.
+
+ undigest(mblocks):
+ Perform the reverse package transformation on a list of message
+ blocks. Note that the ciphermodule used for both transformations
+ must be the same. mblocks is a list of strings of bit length
+ equal to the ciphermodule's blocksize. Output is a string object.
+
+ Subclass methods:
+
+ _inventkey(keysize):
+ Returns a randomly generated key. Subclasses can use this to
+ implement better random key generating algorithms. The default
+ algorithm is probably not very cryptographically secure.
+
+ """
+ def __init__(self, ciphermodule, mode=None, IV=None):
+ self.__ciphermodule = ciphermodule
+ self.__mode = mode
+ self.__IV = IV
+ self.__text = ''
+ self.__keysize = ciphermodule.keysize
+ if self.__keysize == 0:
+ self.__keysize = 16
+
+ def update(self, text):
+ self.__text = self.__text + text
+
+ def reset(self, text=''):
+ self.__text = text
+
+ __K0digit = chr(0x69)
+
+ def digest(self):
+ text = self.__text
+ # generate a random session key and K0, the key used to encrypt the
+ # hash blocks. Rivest calls this a fixed, publically-known encryption
+ # key, but says nothing about the security implications of this key or
+ # how to choose it.
+ key = self._inventkey(self.__keysize)
+ K0 = self.__K0digit * self.__keysize
+ # we need to cipher objects here, one that is used to encrypt the
+ # message blocks and one that is used to encrypt the hashes. The
+ # former uses the randomly generated key, while the latter uses the
+ # well-known key.
+ mcipher = self.__newcipher(key)
+ hcipher = self.__newcipher(K0)
+ # Pad the text so that it's length is a multiple of the cipher's
+ # blocksize. Pad with trailing spaces, which will be eliminated in
+ # the undigest() step.
+ blocksize = self.__ciphermodule.blocksize
+ padbytes = blocksize - (len(text) % blocksize)
+ text = text + ' ' * padbytes
+ # Run through the algorithm:
+ # s: number of message blocks (size of text / blocksize)
+ # input sequence: m1, m2, ... ms
+ # random key K' (`key' in the code)
+ # Compute output sequence: m'1, m'2, ... m's' for s' = s + 1
+ # Let m'i = mi ^ E(K', i) for i = 1, 2, 3, ..., s
+ # Let m's' = K' ^ h1 ^ h2 ^ ... hs
+ # where hi = E(K0, m'i ^ i) for i = 1, 2, ... s
+ #
+ # The one complication I add is that the last message block is hard
+ # coded to the number of padbytes added, so that these can be stripped
+ # during the undigest() step
+ s = len(text) / blocksize
+ blocks = []
+ hashes = []
+ for i in range(1, s+1):
+ start = (i-1) * blocksize
+ end = start + blocksize
+ mi = text[start:end]
+ assert len(mi) == blocksize
+ cipherblock = mcipher.encrypt(longtobytes(i, blocksize))
+ mticki = bytestolong(mi) ^ bytestolong(cipherblock)
+ blocks.append(mticki)
+ # calculate the hash block for this block
+ hi = hcipher.encrypt(longtobytes(mticki ^ i, blocksize))
+ hashes.append(bytestolong(hi))
+ # Add the padbytes length as a message block
+ i = i + 1
+ cipherblock = mcipher.encrypt(longtobytes(i, blocksize))
+ mticki = padbytes ^ bytestolong(cipherblock)
+ blocks.append(mticki)
+ # calculate this block's hash
+ hi = hcipher.encrypt(longtobytes(mticki ^ i, blocksize))
+ hashes.append(bytestolong(hi))
+ # Now calculate the last message block of the sequence 1..s'. This
+ # will contain the random session key XOR'd with all the hash blocks,
+ # so that for undigest(), once all the hash blocks are calculated, the
+ # session key can be trivially extracted. Calculating all the hash
+ # blocks requires that all the message blocks be received, thus the
+ # All-or-Nothing algorithm succeeds.
+ mtick_stick = bytestolong(key) ^ reduce(operator.xor, hashes)
+ blocks.append(mtick_stick)
+ # we convert the blocks to strings since in Python, byte sequences are
+ # always represented as strings. This is more consistent with the
+ # model that encryption and hash algorithm always operates on strings.
+ return map(longtobytes, blocks)
+
+ def undigest(self, blocks):
+ # better have at least 2 blocks, for the padbytes package and the hash
+ # block accumulator
+ if len(blocks) < 2:
+ raise ValueError, "List must be at least length 2."
+ # blocks is a list of strings. We need to deal with them as long
+ # integers
+ blocks = map(bytestolong, blocks)
+ # Calculate the well-known key, to which the hash blocks are
+ # encrypted, and create the hash cipher.
+ K0 = self.__K0digit * self.__keysize
+ hcipher = self.__newcipher(K0)
+ # Since we have all the blocks (or this method would have been called
+ # prematurely), we can calcualte all the hash blocks.
+ hashes = []
+ for i in range(1, len(blocks)):
+ mticki = blocks[i-1] ^ i
+ hi = hcipher.encrypt(longtobytes(mticki))
+ hashes.append(bytestolong(hi))
+ # now we can calculate K' (key). remember the last block contains
+ # m's' which we don't include here
+ key = blocks[-1] ^ reduce(operator.xor, hashes)
+ # and now we can create the cipher object
+ mcipher = self.__newcipher(longtobytes(key))
+ blocksize = self.__ciphermodule.blocksize
+ # And we can now decode the original message blocks
+ parts = []
+ for i in range(1, len(blocks)):
+ cipherblock = mcipher.encrypt(longtobytes(i, blocksize))
+ mi = blocks[i-1] ^ bytestolong(cipherblock)
+ parts.append(mi)
+ # The last message block contains the number of pad bytes appended to
+ # the original text string, such that its length was an even multiple
+ # of the cipher's blocksize. This number should be small enough that
+ # the conversion from long integer to integer should never overflow
+ padbytes = int(parts[-1])
+ text = string.join(map(longtobytes, parts[:-1]), '')
+ return text[:-padbytes]
+
+ def _inventkey(self, keysize):
+ # TBD: Not a very secure algorithm. Eventually, I'd like to use JHy's
+ # kernelrand module
+ import time
+ from Crypto.Util import randpool
+ # TBD: keysize * 2 to work around possible bug in RandomPool?
+ pool = randpool.RandomPool(keysize * 2)
+ while keysize > pool.addEvent(time.time()) / 8:
+ pass
+ # we now have enough entropy in the pool to get a keysize'd key
+ return pool.getBytes(keysize)
+
+ def __newcipher(self, key):
+ if self.__mode is None and self.__IV is None:
+ return self.__ciphermodule.new(key)
+ elif self.__IV is None:
+ return self.__ciphermodule.new(key, self.__mode)
+ else:
+ return self.__ciphermodule.new(key, self.__mode, self.__IV)
+
+
+
+if __name__ == '__main__':
+ import sys
+ import getopt
+ import base64
+
+ usagemsg = '''\
+Test module usage: %(program)s [-c cipher] [-l] [-h]
+
+Where:
+ --cipher module
+ -c module
+ Cipher module to use. Default: %(ciphermodule)s
+
+ --aslong
+ -l
+ Print the encoded message blocks as long integers instead of base64
+ encoded strings
+
+ --help
+ -h
+ Print this help message
+'''
+
+ ciphermodule = 'XOR'
+ aslong = 0
+
+ def usage(code, msg=None):
+ if msg:
+ print msg
+ print usagemsg % {'program': sys.argv[0],
+ 'ciphermodule': ciphermodule}
+ sys.exit(code)
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:],
+ 'c:l', ['cipher=', 'aslong'])
+ except getopt.error, msg:
+ usage(1, msg)
+
+ if args:
+ usage(1, 'Too many arguments')
+
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage(0)
+ elif opt in ('-c', '--cipher'):
+ ciphermodule = arg
+ elif opt in ('-l', '--aslong'):
+ aslong = 1
+
+ # ugly hack to force __import__ to give us the end-path module
+ module = __import__('Crypto.Cipher.'+ciphermodule, None, None, ['new'])
+
+ a = AllOrNothing(module)
+ print 'Original text:\n=========='
+ print __doc__
+ print '=========='
+ a.update(__doc__)
+ msgblocks = a.digest()
+ print 'message blocks:'
+ for i, blk in map(None, range(len(msgblocks)), msgblocks):
+ # base64 adds a trailing newline
+ print ' %3d' % i,
+ if aslong:
+ print bytestolong(blk)
+ else:
+ print base64.encodestring(blk)[:-1]
+ #
+ # get a new undigest-only object so there's no leakage
+ b = AllOrNothing(module)
+ text = b.undigest(msgblocks)
+ if text == __doc__:
+ print 'They match!'
+ else:
+ print 'They differ!'
diff --git a/Protocol/Chaffing.py b/Protocol/Chaffing.py
new file mode 100644
index 0000000..de14925
--- /dev/null
+++ b/Protocol/Chaffing.py
@@ -0,0 +1,220 @@
+"""This file implements the chaffing algorithm.
+
+Winnowing and chaffing is a technique for enhancing privacy without requiring
+strong encryption. In short, the technique takes a set of authenticated
+message blocks (the wheat) and adds a number of chaff blocks which have
+randomly chosen data and MAC fields. This means that to an adversary, the
+chaff blocks look as valid as the wheat blocks, and so the authentication
+would have to be performed on every block. By tailoring the number of chaff
+blocks added to the message, the sender can make breaking the message
+computationally infeasible. There are many other interesting properties of
+the winnow/chaff technique.
+
+For example, say Alice is sending a message to Bob. She packetizes the
+message and performs an all-or-nothing transformation on the packets. Then
+she authenticates each packet with a message authentication code (MAC). The
+MAC is a hash of the data packet, and there is a secret key which she must
+share with Bob (key distribution is an exercise left to the reader). She then
+adds a serial number to each packet, and sends the packets to Bob.
+
+Bob receives the packets, and using the shared secret authentication key,
+authenticates the MACs for each packet. Those packets that have bad MACs are
+simply discarded. The remainder are sorted by serial number, and passed
+through the reverse all-or-nothing transform. The transform means that an
+eavesdropper (say Eve) must acquire all the packets before any of the data can
+be read. If even one packet is missing, the data is useless.
+
+There's one twist: by adding chaff packets, Alice and Bob can make Eve's job
+much harder, since Eve now has to break the shared secret key, or try every
+combination of wheat and chaff packet to read any of the message. The cool
+thing is that Bob doesn't need to add any additional code; the chaff packets
+are already filtered out because their MACs don't match (in all likelihood --
+since the data and MACs for the chaff packets are randomly chosen it is
+possible, but very unlikely that a chaff MAC will match the chaff data). And
+Alice need not even be the party adding the chaff! She could be completely
+unaware that a third party, say Charles, is adding chaff packets to her
+messages as they are transmitted.
+
+For more information on winnowing and chaffing see this paper:
+
+XXX Rivest.
+
+"""
+
+from Crypto.Util.number import longtobytes, bytestolong
+
+class Chaff:
+ """Class implementing the chaff adding algorithm.
+
+ Public Methods:
+
+ __init__(factor=1.0, blocksper=1):
+ Constructor for the class. factor is the number of message blocks
+ to add chaff to, expressed as a percentage between 0.0 and 1.0.
+ blocksper is the number of chaff blocks to include for each block
+ being chaffed. Thus the defaults add one chaff block to every
+ message block. By changing the defaults, you can adjust how
+ computationally difficult it could be for an adversary to
+ brute-force crack the message. The difficulty is expressed as:
+
+ pow(blocksper, int(factor * number-of-blocks))
+
+ For ease of implementation, when factor < 1.0, only the first
+ int(factor*number-of-blocks) message blocks are chaffed.
+
+ chaff(blocks):
+ Add chaff to message blocks. blocks is a list of 3-tuples of the
+ form:
+
+ (serial-number, data, MAC)
+
+ Chaff is created by choosing a random number of the same
+ byte-length as data, and another random number of the same
+ byte-length as MAC. The message block's serial number is placed
+ on the chaff block and all the packet's chaff blocks are randomly
+ interspersed with the single wheat block. This method then
+ returns a list of 3-tuples of the same form. Chaffed blocks will
+ contain multiple instances of 3-tuples with the same serial
+ number, but the only way to figure out which blocks are wheat and
+ which are chaff is to perform the MAC hash and compare values.
+
+ Subclass methods:
+
+ __randnum(size):
+ Returns a randomly generated number with a byte-length equal
+ to size. Subclasses can use this to implement better random
+ data and MAC generating algorithms. The default algorithm is
+ probably not very cryptographically secure. It is most
+ important that the chaff data does not contain any patterns
+ that can be used to discern it from wheat data without running
+ the MAC.
+
+ """
+ def __init__(self, factor=1.0, blocksper=1):
+ self.__factor = factor
+ self.__blocksper = blocksper
+
+ def chaff(self, blocks):
+ chaffedblocks = []
+ # count is the number of blocks to add chaff to. blocksper is the
+ # number of chaff blocks to add per message block that is being
+ # chaffed.
+ count = len(blocks) * self.__factor
+ blocksper = range(self.__blocksper)
+ for i, wheat in map(None, range(len(blocks)), blocks):
+ # it shouldn't matter which of the n blocks we add chaff to so for
+ # ease of implementation, we'll just add them to the first count
+ # blocks
+ if i < count:
+ serial, data, mac = wheat
+ datasize = len(data)
+ macsize = len(mac)
+ addwheat = 1
+ # add chaff to this block
+ for j in blocksper:
+ import sys
+ chaffdata = self._randnum(datasize)
+ chaffmac = self._randnum(macsize)
+ chaff = (serial, chaffdata, chaffmac)
+ # mix up the order, if the 5th bit is on then put the
+ # wheat on the list
+ if addwheat and bytestolong(self._randnum(16)) & 0x40:
+ chaffedblocks.append(wheat)
+ addwheat = 0
+ chaffedblocks.append(chaff)
+ if addwheat:
+ chaffedblocks.append(wheat)
+ else:
+ # just add the wheat
+ chaffedblocks.append(wheat)
+ return chaffedblocks
+
+ def _randnum(self, size):
+ # TBD: Not a very secure algorithm.
+ # TBD: size * 2 to work around possible bug in RandomPool
+ from Crypto.Util import randpool
+ import time
+ pool = randpool.RandomPool(size * 2)
+ while size > pool.addEvent(time.time()) / 8:
+ pass
+ # we now have enough entropy in the pool to get size bytes of random
+ # data... well, probably
+ return pool.getBytes(size)
+
+
+
+if __name__ == '__main__':
+ text = """\
+When in the Course of human events, it becomes necessary for one people to
+dissolve the political bands which have connected them with another, and to
+assume among the powers of the earth, the separate and equal station to which
+the Laws of Nature and of Nature's God entitle them, a decent respect to the
+opinions of mankind requires that they should declare the causes which impel
+them to the separation.
+
+We hold these truths to be self-evident, that all men are created equal, that
+they are endowed by their Creator with certain unalienable Rights, that among
+these are Life, Liberty, and the pursuit of Happiness. That to secure these
+rights, Governments are instituted among Men, deriving their just powers from
+the consent of the governed. That whenever any Form of Government becomes
+destructive of these ends, it is the Right of the People to alter or to
+abolish it, and to institute new Government, laying its foundation on such
+principles and organizing its powers in such form, as to them shall seem most
+likely to effect their Safety and Happiness.
+"""
+ print 'Original text:\n=========='
+ print text
+ print '=========='
+
+ # first transform the text into packets
+ blocks = [] ; size = 40
+ for i in range(0, len(text), size):
+ blocks.append( text[i:i+size] )
+
+ # now get MACs for all the text blocks. The key is obvious...
+ print 'Calculating MACs...'
+ from Crypto.Hash import SHA
+ from Crypto.Hash.HMAC import HMAC
+ h = HMAC(SHA)
+ macs = h.hash('Jefferson', blocks)
+
+ assert len(blocks) == len(macs)
+
+ # put these into a form acceptable as input to the chaffing procedure
+ source = []
+ m = map(None, range(len(blocks)), blocks, macs)
+ for i, data, mac in m:
+ source.append((i, data, mac))
+
+ # now chaff these
+ print 'Adding chaff...'
+ c = Chaff(factor=0.5, blocksper=2)
+ chaffed = c.chaff(source)
+
+ from base64 import encodestring
+
+ # print the chaffed message blocks. meanwhile, separate the wheat from
+ # the chaff
+
+ wheat = []
+ print 'chaffed message blocks:'
+ for i, data, mac in chaffed:
+ # do the authentication
+ pmac = h.hash('Jefferson', [data])[0]
+ if pmac == mac:
+ tag = '-->'
+ wheat.append(data)
+ else:
+ tag = ' '
+ # base64 adds a trailing newline
+ print tag, '%3d' % i, \
+ repr(data), encodestring(mac)[:-1]
+
+ # now decode the message packets and check it against the original text
+ print 'Undigesting wheat...'
+ import string
+ newtext = string.join(wheat, "")
+ if newtext == text:
+ print 'They match!'
+ else:
+ print 'They differ!'
diff --git a/Protocol/PGP/Info/draft-ietf-openpgp-formats b/Protocol/PGP/Info/draft-ietf-openpgp-formats
new file mode 100644
index 0000000..6c1406a
--- /dev/null
+++ b/Protocol/PGP/Info/draft-ietf-openpgp-formats
@@ -0,0 +1,2356 @@
+Network Working Group Jon Callas
+Category: INTERNET-DRAFT Pretty Good Privacy
+draft-ietf-openpgp-formats-00.txt Lutz Donnerhacke
+Expires May 1998 IN-Root-CA Individual Network e.V.
+November 1997 Hal Finney
+ Pretty Good Privacy
+ Rodney Thayer
+ Sable Technology
+
+ OP Formats - OpenPGP Message Format
+ draft-ietf-openpgp-formats-00.txt
+
+Copyright 1997 by The Internet Society. All Rights Reserved.
+
+Status of this Memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas, and
+its working groups. Note that other groups may also distribute working
+documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six months
+and may be updated, replaced, or obsoleted by other documents at any
+time. It is inappropriate to use Internet-Drafts as reference material
+or to cite them other than as "work in progress."
+
+To learn the current status of any Internet-Draft, please check the
+"1id-abstracts.txt" listing contained in the Internet-Drafts Shadow
+Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast), or
+ftp.isi.edu (US West Coast).
+
+Abstract
+
+This document is maintained in order to publish all necessary
+information needed to develop interoperable applications based on the
+OP format. It is not a step-by-step cookbook for writing an
+application, it describes only the format and methods needed to read,
+check, generate and write conforming packets crossing any network. It
+does not deal with storing and implementation questions albeit it is
+necessary to avoid security flaws.
+
+OP (Open-PGP) software uses a combination of strong public-key and
+conventional cryptography to provide security services for electronic
+communications and data storage. These services include
+confidentiality, key management, authentication and digital signatures.
+This document specifies the message formats used in OP.
+
+
+
+
+
+
+
+Callas, et. al. Expires May 1998 [Page 1]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+Table of Contents
+
+1. Introduction
+1.1 Terms
+2. General functions
+2.1 Confidentiality
+2.2 Digital signature
+2.3 Compression
+2.4 Conversion to Radix-64
+2.4.1 Forming ASCII Armor
+2.4.2 Encoding Binary in Radix-64
+2.4.3 Decoding Radix-64
+2.4.4 Examples of Radix-64
+2.5 Example of an ASCII Armored Message
+2.6 Cleartext signature framework
+3.0 Data Element Formats
+3.1 Scalar numbers
+3.2 Multi-Precision Integers
+3.3 Counted Strings
+3.4 Time fields
+3.5 String-to-key (S2K) specifiers
+3.5.1 String-to-key (S2k) specifier types
+3.5.1.1 Simple S2K
+3.5.1.2 Salted S2K
+3.5.1.3 Iterated and Salted S2K
+3.5.2 String-to-key usage
+3.5.2.1 Secret key encryption
+3.5.2.2 Conventional message encryption
+3.5.3 String-to-key algorithms
+3.5.3.1 Simple S2K algorithm
+3.5.3.2 Salted S2K algorithm
+3.5.3.3 Iterated-Salted S2K algorithm
+4.0 Packet Syntax
+4.1 Overview
+4.2 Packet Headers
+4.3 Packet Tags
+5.0 Packet Types
+5.1 Encrypted Session Key Packets (Tag 1)
+5.2 Signature Packet (Tag 2)
+5.2.1 Version 3 Signature Packet Format
+5.2.2 Version 4 Signature Packet Format
+5.2.2.1 Signature Subpacket Specification
+5.2.2.2 Signature Subpacket Types
+5.2.3 Signature Types
+5.3 Conventional Encrypted Session-Key Packets (Tag 3)
+5.4 One-Pass Signature Packets (Tag 4)
+5.5 Key Material Packet
+5.5.1 Key Packet Variants
+5.5.1.1 Public Key Packet (Tag 6)
+5.5.1.2 Public Subkey Packet (Tag 14)
+5.5.1.3 Secret Key Packet (Tag 5)
+5.5.1.4 Secret Subkey Packet (Tag 7)
+5.5.2 Public Key Packet Formats
+
+
+Callas, et. al. Expires May 1998 [Page 2]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+5.5.3 Secret Key Packet Formats
+5.6 Compressed Data Packet (Tag 8)
+5.7 Symmetrically Encrypted Data Packet (Tag 9)
+5.8 Marker Packet (Obsolete Literal Packet) (Tag 10)
+5.9 Literal Data Packet (Tag 11)
+5.10 Trust Packet (Tag 12)
+5.11 User ID Packet (Tag 13)
+5.12 Comment Packet (Tag 16)
+6. Constants
+6.1 Public Key Algorithms
+6.2 Symmetric Key Algorithms
+6.3 Compression Algorithms
+6.4 Hash Algorithms
+7. Packet Composition
+7.1 Transferable Public Keys
+7.2 OP Messages
+8. Enhanced Key Formats
+8.1 Key Structures
+8.4 V4 Key IDs and Fingerprints
+9. Security Considerations
+10. Authors and Working Group Chair
+11. References
+12. Full Copyright Statement
+
+1. Introduction
+
+This document provides information on the message-exchange packet
+formats used by OP to provide encryption, decryption, signing, key
+management and functions. It builds on the foundation provided RFC
+1991 "PGP Message Exchange Formats" [1].
+
+1.1 Terms
+
+OP - OpenPGP. This is a definition for security software that uses PGP
+5.x as a basis.
+
+PGP - Pretty Good Privacy. PGP is a family of software systems
+developed by Philip R. Zimmermann from which OP is based.
+
+PGP 2.6.x - This version of PGP has many variants, hence the term PGP
+2.6.x. It used only RSA and IDEA for its cryptography.
+
+PGP 5.x - This version of PGP is formerly known as "PGP 3" in the
+community and also in the predecessor of this document, RFC1991. It
+has new formats and corrects a number of problems in the PGP 2.6.x. It
+is referred to here as PGP 5.x because that software was the first
+release of the "PGP 3" code base.
+
+"PGP", "Pretty Good", and "Pretty Good Privacy" are trademarks of
+Pretty Good Privacy, Inc.
+
+
+2. General functions
+
+
+Callas, et. al. Expires May 1998 [Page 3]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+OP provides data integrity services for messages and data files by
+using these core technologies:
+
+-digital signature -encryption -compression -radix-64 conversion
+
+In addition, OP provides key management and certificate services.
+
+2.1 Confidentiality via Encryption
+
+OP offers two encryption options to provide confidentiality:
+conventional (symmetric-key) encryption and public key encryption.
+With public-key encryption, the message is actually encrypted using a
+conventional encryption algorithm. In this mode, each conventional key
+is used only once. That is, a new key is generated as a random number
+for each message. Since it is used only once, the "session key" is
+bound to the message and transmitted with it. To protect the key, it
+is encrypted with the receiver's public key. The sequence is as
+follows:
+
+ 1. The sender creates a message.
+ 2. The sending OP generates a random number to be used as a
+ session key for this message only.
+ 3. The session key is encrypted using each recipient's public key.
+ These "encrypted session keys" start the message.
+ 4. The sending OP encrypts the message using the session key, which
+ forms the remainder of the message. Note that the message is
+ also usually compressed.
+ 5. The receiving OP decrypts the session key using the recipient's
+ private key.
+ 6. The receiving OP decrypts the message using the session key.
+ If the message was compressed, it will be decompressed.
+
+Both digital signature and confidentiality services may be applied to
+the same message. First, a signature is generated for the message and
+attached to the message. Then, the message plus signature is encrypted
+using a conventional session key. Finally, the session key is
+encrypted using public-key encryption and prepended to the encrypted
+block.
+
+2.2 Authentication via Digital signature
+
+The digital signature uses a hash code or message digest algorithm, and
+a public-key signature algorithm. The sequence is as follows:
+
+ 1. The sender creates a message.
+ 2. The sending software generates a hash code of the message
+ 3. The sending software generates a signature from the hash code using
+ the sender's private key.
+ 4. The binary signature is attached to the message.
+ 5. The receiving software keeps a copy of the message signature.
+ 6. The receiving software generates a new hash code for the received
+ message and verifies it using the message's signature. If the
+
+
+Callas, et. al. Expires May 1998 [Page 4]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ verification is successful, the message is accepted as authentic.
+
+2.3 Compression
+
+OP implementations MAY compress the message after applying the
+signature but before encryption.
+
+2.4 Conversion to Radix-64
+
+OP's underlying native representation for encrypted messages, signature
+certificates, and keys is a stream of arbitrary octets. Some systems
+only permit the use of blocks consisting of seven-bit, printable text.
+For transporting OP's native raw binary octets through email channels,
+a printable encoding of these binary octets is needed. OP provides the
+service of converting the raw 8-bit binary octet stream to a stream of
+printable ASCII characters, called Radix-64 encoding or ASCII Armor.
+
+In principle, any printable encoding scheme that met the requirements
+of the email channel would suffice, since it would not change the
+underlying binary bit streams of the native OP data structures. The OP
+standard specifies one such printable encoding scheme to ensure
+interoperability.
+
+OP's Radix-64 encoding is composed of two parts: a base64 encoding of
+the binary data, and a checksum. The base64 encoding is identical to
+the MIME base64 content-transfer-encoding [RFC 2045, Section 6.8]. An
+OP implementation MAY use ASCII Armor to protect the raw binary data.
+
+The checksum is a 24-bit CRC converted to four characters of radix-64
+encoding by the same MIME base64 transformation, preceded by an equals
+sign (=). The CRC is computed by using the generator 0x864CFB and an
+initialization of 0xB704CE. The accumulation is done on the data
+before it is converted to radix-64, rather than on the converted data.
+(For more information on CRC functions, see chapter 19 of [CAMPBELL].)
+
+{{Editor's note: This is old text, dating back to RFC 1991. I have
+never liked the glib way the CRC has been dismissed, but I also know
+that this is no place to start a discussion of CRC theory. Should we
+construct a sample implementation in C and put it in an appendix? --
+jdcc}}
+
+The checksum with its leading equal sign MAY appear on the first line
+after the Base64 encoded data.
+
+Rationale for CRC-24: The size of 24 bits fits evenly into printable
+base64. The nonzero initialization can detect more errors than a zero
+initialization.
+
+2.4.1 Forming ASCII Armor
+
+When OP encodes data into ASCII Armor, it puts specific headers around
+the data, so OP can reconstruct the data later. OP informs the user
+what kind of data is encoded in the ASCII armor through the use of the
+
+
+Callas, et. al. Expires May 1998 [Page 5]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+headers.
+
+Concatenating the following data creates ASCII Armor:
+
+- An Armor Header Line, appropriate for the type of data - Armor
+Headers - A blank (zero-length, or containing only whitespace) line -
+The ASCII-Armored data - An Armor Checksum - The Armor Tail, which
+depends on the Armor Header Line.
+
+An Armor Header Line consists of the appropriate header line text
+surrounded by five (5) dashes ('-', 0x2D) on either side of the header
+line text. The header line text is chosen based upon the type of data
+that is being encoded in Armor, and how it is being encoded. Header
+line texts include the following strings:
+
+BEGIN PGP MESSAGE used for signed, encrypted, or compressed files
+
+BEGIN PGP PUBLIC KEY BLOCK used for armoring public keys
+
+BEGIN PGP PRIVATE KEY BLOCK used for armoring private keys
+
+BEGIN PGP MESSAGE, PART X/Y used for multi-part messages, where the
+armor is split amongst Y parts, and this is the Xth part out of Y.
+
+BEGIN PGP MESSAGE, PART X used for multi-part messages, where this is
+the Xth part of an unspecified number of parts. Requires the MESSAGE-ID
+Armor Header to be used.
+
+BEGIN PGP SIGNATURE used for detached signatures, OP/MIME signatures,
+and signatures following clearsigned messages
+
+The Armor Headers are pairs of strings that can give the user or the
+receiving OP message block some information about how to decode or use
+the message. The Armor Headers are a part of the armor, not a part of
+the message, and hence are not protected by any signatures applied to
+the message.
+
+The format of an Armor Header is that of a key-value pair. A colon
+(':' 0x38) and a single space (0x20) separate the key and value. OP
+should consider improperly formatted Armor Headers to be corruption of
+the ASCII Armor. Unknown keys should be reported to the user, but OP
+should continue to process the message. Currently defined Armor Header
+Keys include "Version" and "Comment", which define the OP Version used
+to encode the message and a user-defined comment.
+
+The "MessageID" Armor Header specifies a 32-character string of
+printable characters. The string must be the same for all parts of a
+multi-part message that uses the "PART X" Armor Header. MessageID
+strings should be chosen with enough internal randomness that no two
+messages would have the same MessageID string.
+
+The MessageID should not appear unless it is in a multi-part message.
+If it appears at all, it should be computed from the message in a
+
+
+Callas, et. al. Expires May 1998 [Page 6]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+deterministic fashion, rather than contain a purely random value. This
+is to allow anyone to determine that the MessageID cannot serve as a
+covert means of leaking cryptographic key information.
+
+{{Editor's note: This needs to be cleaned up, with a table of the
+defined headers. Also, the MessageID description is too vague about
+how random the id has to be.}}
+
+The Armor Tail Line is composed in the same manner as the Armor Header
+Line, except the string "BEGIN" is replaced by the string "END."
+
+2.4.2 Encoding Binary in Radix-64
+
+The encoding process represents 24-bit groups of input bits as output
+strings of 4 encoded characters. Proceeding from left to right, a
+24-bit input group is formed by concatenating three 8-bit input groups.
+These 24 bits are then treated as four concatenated 6-bit groups, each
+of which is translated into a single digit in the Radix-64 alphabet.
+When encoding a bit stream with the Radix-64 encoding, the bit stream
+must be presumed to be ordered with the most-significant-bit first.
+That is, the first bit in the stream will be the high-order bit in the
+first 8-bit byte, and the eighth bit will be the low-order bit in the
+first 8-bit byte, and so on.
+
+ +--first octet--+-second octet--+--third octet--+
+ |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|
+ +-----------+---+-------+-------+---+-----------+
+ |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|
+ +--1.index--+--2.index--+--3.index--+--4.index--+
+
+Each 6-bit group is used as an index into an array of 64 printable
+characters from the table below. The character referenced by the index
+is placed in the output string.
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+
+
+Callas, et. al. Expires May 1998 [Page 7]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+The encoded output stream must be represented in lines of no more than
+76 characters each.
+
+Special processing is performed if fewer than 24 bits are available at
+the end of the data being encoded. There are three possibilities:
+
+- The last data group has 24 bits (3 octets). No special processing is
+needed.
+
+- The last data group has 16 bits (2 octets). The first two 6-bit
+groups are processed as above. The third (incomplete) data group has
+two zero-value bits added to it, and is processed as above. A pad
+character (=) is added to the output.
+
+- The last data group has 8 bits (1 octet). The first 6-bit group is
+processed as above. The second (incomplete) data group has four
+zero-value bits added to it, and is processed as above. Two pad
+characters (=) are added to the output.
+
+2.4.3 Decoding Radix-64
+
+Any characters outside of the base64 alphabet are ignored in Radix-64
+data. Decoding software must ignore all line breaks or other
+characters not found in the table above.
+
+In Radix-64 data, characters other than those in the table, line
+breaks, and other white space probably indicate a transmission error,
+about which a warning message or even a message rejection might be
+appropriate under some circumstances.
+
+Because it is used only for padding at the end of the data, the
+occurrence of any "=" characters may be taken as evidence that the end
+of the data has been reached (without truncation in transit). No such
+assurance is possible, however, when the number of octets transmitted
+was a multiple of three and no "=" characters are present.
+
+
+2.4.4 Examples of Radix-64
+
+Input data: 0x14fb9c03d97e
+Hex: 1 4 f b 9 c | 0 3 d 9 7 e
+8-bit: 00010100 11111011 10011100 | 00000011 11011001 11111110
+6-bit: 000101 001111 101110 011100 | 000000 111101 100111 111110
+Decimal: 5 15 46 28 0 61 37 63
+Output: F P u c A 9 l /
+
+Input data: 0x14fb9c03d9
+Hex: 1 4 f b 9 c | 0 3 d 9
+8-bit: 00010100 11111011 10011100 | 00000011 11011001
+ pad with 00
+6-bit: 000101 001111 101110 011100 | 000000 111101 100100
+Decimal: 5 15 46 28 0 61 36
+ pad with =
+
+
+Callas, et. al. Expires May 1998 [Page 8]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+Output: F P u c A 9 k =
+
+Input data: 0x14fb9c03
+Hex: 1 4 f b 9 c | 0 3
+8-bit: 00010100 11111011 10011100 | 00000011
+ pad with 0000
+6-bit: 000101 001111 101110 011100 | 000000 110000
+Decimal: 5 15 46 28 0 48
+ pad with = =
+Output: F P u c A w = =
+
+
+2.5 Example of an ASCII Armored Message
+
+ -----BEGIN PGP MESSAGE-----
+ Version: OP V0.0
+
+ owFbx8DAYFTCWlySkpkHZDKEFCXmFedmFhdn5ucpZKdWFiv4hgaHKPj5hygUpSbn
+ l6UWpabo8XIBAA==
+ =3m1o
+ -----END PGP MESSAGE-----
+
+Note that this example is indented by two spaces.
+
+2.6 Cleartext signature framework
+
+Sometimes it is necessary to sign a textual octet stream without ASCII
+armoring the stream itself, so the signed text is still readable
+without special software. In order to bind a signature to such a
+cleartext, this framework is used. (Note that RFC 2015 defines another
+way to clear sign messages for environments that support MIME.)
+
+The cleartext signed message consists of:
+ - The cleartext header '-----BEGIN PGP SIGNED MESSAGE-----' on a
+ single line,
+ - Zero or more "Hash" Armor Headers (3.1.2.4),
+ - Exactly one empty line not included into the message digest,
+ - The dash-escaped cleartext that is included into the message digest,
+ - The ASCII armored signature(s) including the Armor Header and Armor
+ Tail Lines.
+
+If the "Hash" armor header is given, the specified message digest
+algorithm is used for the signature. If this header is missing, SHA-1
+is assumed. If more than one message digest is used in the signature,
+the "Hash" armor header contains a comma-delimited list of used message
+digests. As an abbreviation, the "Hash" armor header may be placed on
+the cleartext header line, inserting a comma after the word 'MESSAGE',
+as follows:
+
+'-----BEGIN PGP SIGNED MESSAGE, Hash: MD5, SHA1'.
+
+{{Editor's note: Should the above armor header line stay or go?
+There's no reason that the "Hash:" armor header can't have multiple
+
+
+Callas, et. al. Expires May 1998 [Page 9]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+hashes in it. I think anything that reduces parsing complexity is a
+Good Thing. --jdcc}}
+
+Current message digest names are:
+
+ - "SHA1"
+ - "MD5"
+ - "RIPEMD160"
+
+Dash escaped cleartext is the ordinary cleartext where every line
+starting with a dash '-' (0x2D) is prepended by the sequence dash '-'
+(0x2D) and space ' ' (0x20). This prevents the parser from recognizing
+armor headers of the cleartext itself. The message digest is computed
+using the cleartext itself, not the dash escaped form.
+
+As with binary signatures on text documents (see below), the cleartext
+signature is calculated on the text using canonical <CR><LF> line
+endings. The line ending (i.e. the <CR><LF>) before the '-----BEGIN
+PGP SIGNATURE-----' line that terminates the signed text is not
+considered part of the signed text.
+
+Also, any trailing whitespace (spaces, and tabs, 0x09) at the end of
+any line is ignored when the cleartext signature is calculated.
+
+3. Data Element Formats
+
+This section describes the data elements used by OP.
+
+3.1 Scalar numbers
+
+Scalar numbers are unsigned, and are always stored in big-endian
+format. Using n[k] to refer to the kth octet being interpreted, the
+value of a two-octet scalar is ((n[0] << 8) + n[1]). The value of a
+four-octet scalar is ((n[0] << 24) + (n[1] << 16) + (n[2] << 8) +
+n[3]).
+
+3.2 Multi-Precision Integers
+
+Multi-Precision Integers (also called MPIs) are unsigned integers used
+to hold large integers such as the ones used in cryptographic
+calculations.
+
+An MPI consists of two pieces: a two-octet scalar that is the length of
+the MPI in bits followed by a string of octets that contain the actual
+integer.
+
+These octets form a big-endian number; a big-endian number can be made
+into an MPI by prefixing it with the appropriate length.
+
+Examples:
+
+(all numbers are in hexadecimal)
+
+
+
+Callas, et. al. Expires May 1998 [Page 10]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+The string of octets [00 01 01] forms an MPI with the value 1. The
+string [00 09 01 FF] forms an MPI with the value of 511.
+
+Additional rules:
+
+The size of an MPI is ((MPI.length + 7) / 8) + 2.
+
+The length field of an MPI describes the length starting from its most
+significant non-zero bit. Thus, the MPI [00 02 01] is not formed
+correctly. It should be [00 01 01].
+
+
+3.3 Counted Strings
+
+A counted string consists of a length and then N octets of string data.
+Its default character set is UTF-8 [RFC2044] encoding of Unicode
+[ISO10646].
+
+3.4 Time fields
+
+A time field is an unsigned four-octet number containing the number of
+seconds elapsed since midnight, 1 January 1970 UTC.
+
+3.5 String-to-key (S2K) specifiers
+
+String-to-key (S2K) specifiers are used to convert passphrase strings
+into conventional encryption/decryption keys. They are used in two
+places, currently: to encrypt the secret part of private keys in the
+private keyring, and to convert passphrases to encryption keys for
+conventionally encrypted messages.
+
+3.5.1 String-to-key (S2k) specifier types
+
+There are three types of S2K specifiers currently supported, as
+follows:
+
+3.5.1.1 Simple S2K
+
+This directly hashes the string to produce the key data. See below for
+how this hashing is done.
+
+ Octet 0: 0x00
+ Octet 1: hash algorithm
+
+3.5.1.2 Salted S2K
+
+This includes a "salt" value in the S2K specifier -- some arbitrary
+data -- that gets hashed along with the passphrase string, to help
+prevent dictionary attacks.
+
+ Octet 0: 0x01
+ Octet 1: hash algorithm
+ Octets 2-9: 8-octet salt value
+
+
+Callas, et. al. Expires May 1998 [Page 11]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+3.5.1.3 Iterated and Salted S2K
+
+This includes both a salt and an octet count. The salt is combined
+with the passphrase and the resulting value is hashed repeatedly. This
+further increases the amount of work an attacker must do to try
+dictionary attacks.
+
+ Octet 0: 0x03
+ Octet 1: hash algorithm
+ Octets 2-9: 8-octet salt value
+ Octet 10: count, in special format (described below)
+
+3.5.2 String-to-key usage
+
+Implementations MUST implement simple S2K and salted S2K specifiers.
+Implementations MAY implement iterated and salted S2K specifiers.
+Implementations SHOULD use salted S2K specifiers, as simple S2K
+specifiers are more vulnerable to dictionary attacks.
+
+3.5.2.1 Secret key encryption
+
+An S2K specifier can be stored in the secret keyring to specify how to
+convert the passphrase to a key that unlocks the secret data. Older
+versions of PGP just stored a cipher algorithm octet preceding the
+secret data or a zero to indicate that the secret data was unencrypted.
+The MD5 hash function was always used to convert the passphrase to a
+key for the specified cipher algorithm.
+
+For compatibility, when an S2K specifier is used, the special value 255
+is stored in the position where the hash algorithm octet would have
+been in the old data structure. This is then followed immediately by a
+one-octet algorithm identifier, and then by the S2K specifier as
+encoded above.
+
+Therefore, preceding the secret data there will be one of these
+possibilities:
+
+ 0 secret data is unencrypted (no pass phrase)
+ 255 followed by algorithm octet and S2K specifier
+ Cipher alg use Simple S2K algorithm using MD5 hash
+
+This last possibility, the cipher algorithm number with an implicit use
+of MD5 is provided for backward compatibility; it should be understood,
+but not generated.
+
+These are followed by an 8-octet Initial Vector for the decryption of
+the secret values, if they are encrypted, and then the secret key
+values themselves.
+
+3.5.2.2 Conventional message encryption
+
+PGP 2.X always used IDEA with Simple string-to-key conversion when
+
+
+Callas, et. al. Expires May 1998 [Page 12]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+conventionally encrypting a message. PGP 5 can create a Conventional
+Encrypted Session Key packet at the front of a message. This can be
+used to allow S2K specifiers to be used for the passphrase conversion,
+to allow other ciphers than IDEA to be used, or to create messages with
+a mix of conventional ESKs and public key ESKs. This allows a message
+to be decrypted either with a passphrase or a public key.
+
+3.5.3 String-to-key algorithms
+
+3.5.3.1 Simple S2K algorithm
+
+Simple S2K hashes the passphrase to produce the session key. The
+manner in which this is done depends on the size of the session key
+(which will depend on the cipher used) and the size of the hash
+algorithm's output. If the hash size is greater than or equal to the
+session key size, the leftmost octets of the hash are used as the key.
+
+If the hash size is less than the key size, multiple instances of the
+hash context are created -- enough to produce the required key data.
+These instances are preloaded with 0, 1, 2, ... octets of zeros (that
+is to say, the first instance has no preloading, the second gets
+preloaded with 1 octet of zero, the third is preloaded with two octets
+of zeros, and so forth).
+
+As the data is hashed, it is given independently to each hash context.
+Since the contexts have been initialized differently, they will each
+produce different hash output. Once the passphrase is hashed, the
+output data from the multiple hashes is concatenated, first hash
+leftmost, to produce the key data, with any excess octets on the right
+discarded.
+
+3.5.3.2 Salted S2K algorithm
+
+Salted S2K is exactly like Simple S2K, except that the input to the
+hash function(s) consists of the 8 octets of salt from the S2K
+specifier, followed by the passphrase.
+
+3.5.3.3 Iterated-Salted S2K algorithm
+
+{{Editor's note: This is very complex, with bizarre things like an
+8-bit floating point format. Should we just drop it? --jdcc}}
+
+Iterated-Salted S2K hashes the passphrase and salt data multiple times.
+The total number of octets to be hashed is encoded in the count octet
+that follows the salt in the S2K specifier. The count value is stored
+as a normalized floating-point value with 4 bits of exponent and 4 bits
+of mantissa. The formula to convert from the count octet to a count of
+the number of octets to be hashed is as follows, letting the high 4
+bits of the count octet be CEXP and the low four bits be CMANT:
+
+ count of octets to be hashed = (16 + CMANT) << (CEXP + 6)
+
+This allows encoding hash counts as low as 16 << 6 or 1024 (using an
+
+
+Callas, et. al. Expires May 1998 [Page 13]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+octet value of 0), and as high as 31 << 21 or 65011712 (using an octet
+value of 0xff). Note that the resulting count value is an octet count
+of how many octets will be hashed, not an iteration count.
+
+Initially, one or more hash contexts are set up as with the other S2K
+algorithms, depending on how many octets of key data are needed. Then
+the salt, followed by the passphrase data is repeatedly hashed until
+the number of octets specified by the octet count has been hashed. The
+one exception is that if the octet count is less than the size of the
+salt plus passphrase, the full salt plus passphrase will be hashed even
+though that is greater than the octet count. After the hashing is done
+the data is unloaded from the hash context(s) as with the other S2K
+algorithms.
+
+4. Packet Syntax
+
+This section describes the packets used by OP.
+
+4.1 Overview
+
+An OP message is constructed from a number of records that are
+traditionally called packets. A packet is a chunk of data that has a
+tag specifying its meaning. An OP message, keyring, certificate, and
+so forth consists of a number of packets. Some of those packets may
+contain other OP packets (for example, a compressed data packet, when
+uncompressed, contains OP packets).
+
+Each packet consists of a packet header, followed by the packet body.
+The packet header is of variable length.
+
+4.2 Packet Headers
+
+The first octet of the packet header is called the "Packet Tag." It
+determines the format of the header and denotes the packet contents.
+The remainder of the packet header is the length of the packet.
+
+Note that the most significant bit is the left-most bit, called bit 7.
+A mask for this bit is 0x80 in hexadecimal.
+
+ +---------------+
+ PTag |7 6 5 4 3 2 1 0|
+ +---------------+
+ Bit 7 -- Always one
+ Bit 6 -- New packet format if set
+
+
+PGP 2.6.X only uses old format packets. Thus, software that
+interoperates with those versions of PGP must only use old format
+packets. If interoperability is not an issue, either format may be
+used.
+
+Old format packets contain:
+ Bits 5-2 -- content tag
+
+
+Callas, et. al. Expires May 1998 [Page 14]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ Bits 1-0 - length-type
+
+New format packets contain:
+ Bits 5-0 -- content tag
+
+The meaning of the length-type in old-format packets is:
+
+0 - The packet has a one-octet length. The header is 2 octets long.
+
+1 - The packet has a two-octet length. The header is 3 octets long.
+
+2 - The packet has a four-octet length. The header is 5 octets long.
+
+3 - The packet is of indeterminate length. The header is 1 byte long,
+and the application must determine how long the packet is. If the
+packet is in a file, this means that the packet extends until the end
+of the file. In general, an application should not use indeterminate
+length packets except where the end of the data will be clear from the
+context.
+
+New format packets have three possible ways of encoding length. A
+one-octet Body Length header encodes packet lengths of up to 191
+octets, and a two-octet Body Length header encodes packet lengths of
+192 to 8383 octets. For cases where longer packet body lengths are
+needed, or where the length of the packet body is not known in advance
+by the issuer, Partial Body Length headers can be used. These are
+one-octet length headers that encode the length of only part of the
+data packet.
+
+Each Partial Body Length header is followed by a portion of the packet
+body data. The Partial Body Length header specifies this portion's
+length. Another length header (of one of the three types) follows that
+portion. The last length header in the packet must always be a regular
+Body Length header. Partial Body Length headers may only be used for
+the non-final parts of the packet.
+
+A one-octet Body Length header encodes a length of from 0 to 191
+octets. This type of length header is recognized because the one octet
+value is less than 192. The body length is equal to:
+
+bodyLen = length_octet;
+
+A two-octet Body Length header encodes a length of from 192 to 8383
+octets. It is recognized because its first octet is in the range 192
+to 223. The body length is equal to:
+
+bodyLen = (1st_octet - 192) * 256 + (2nd_octet) + 192
+
+A Partial Body Length header is one octet long and encodes a length
+which is a power of 2, from 1 to 2147483648 (2 to the 31st power). It
+is recognized because its one octet value is greater than or equal to
+224. The partial body length is equal to:
+
+
+
+Callas, et. al. Expires May 1998 [Page 15]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+partialBodyLen = 1 << (length_octet & 0x1f);
+
+Examples:
+
+A packet with length 100 may have its length encoded in one octet:
+0x64. This is followed by 100 octets of data.
+
+A packet with length 1723 may have its length coded in two octets:
+0xC5, 0xFB. This header is followed by the 1723 octets of data.
+
+A packet with length 100000 might be encoded in the following octet
+stream: 0xE1, first two octets of data, 0xE0, next one octet of data,
+0xEF, next 32768 octets of data, 0xF0, next 65536 octets of data, 0xC5,
+0xDD, last 1693 octets of data. This is just one possible encoding,
+and many variations are possible on the size of the Partial Body Length
+headers, as long as a regular Body Length header encodes the last
+portion of the data. Note also that the last Body Length header can be
+a zero-length header.
+
+
+Please note that in all of these explanations, the total length of the
+packet is the length of the header(s) plus the length of the body.
+
+4.3 Packet Tags
+
+The packet tag denotes what type of packet the body holds. Note that
+old format packets can only have tags less than 16, whereas new format
+packets can have tags as great as 63. The defined tags (in decimal)
+are:
+
+0 -- Reserved. A packet must not have a tag with this value.
+1 -- Encrypted Session Key Packet
+2 -- Signature Packet
+3 -- Conventionally Encrypted Session Key Packet
+4 -- One-Pass Signature Packet
+5 -- Secret Key Packet
+6 -- Public Key Packet
+7 -- Secret Subkey Packet
+8 -- Compressed Data Packet
+9 -- Symmetrically Encrypted Data Packet
+10 -- Marker Packet
+11 -- Literal Data Packet
+12 -- Trust Packet
+13 -- Name Packet
+14 -- Subkey Packet
+15 -- Reserved
+16 -- Comment Packet
+60 to 63 -- Private or Experimental Values
+
+5. Packet Types
+
+5.1 Encrypted Session Key Packets (Tag 1)
+
+
+
+Callas, et. al. Expires May 1998 [Page 16]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+An Encrypted Session Key packet holds the key used to encrypt a message
+that is itself encrypted with a public key. Zero or more Encrypted
+Session Key packets and/or Conventional Encrypted Session Key packets
+may precede a Symmetrically Encrypted Data Packet, which holds an
+encrypted message. The message is encrypted with a session key, and
+the session key is itself encrypted and stored in the Encrypted Session
+Key packet or the Conventional Encrypted Session Key packet. The
+Symmetrically Encrypted Data Packet is preceded by one Encrypted
+Session Key packet for each OP key to which the message is encrypted.
+The recipient of the message finds a session key that is encrypted to
+their public key, decrypts the session key, and then uses the session
+key to decrypt the message.
+
+The body of this packet consists of:
+
+ - A one-octet number giving the version number of the packet type.
+ The currently defined value for packet version is 3. An
+ implementation should accept, but not generate a version of 2,
+ which is equivalent to V3 in all other respects.
+ - An eight-octet number that gives the key ID of the public key that
+ the session key is encrypted to.
+ - A one-octet number giving the public key algorithm used.
+ - A string of octets that is the encrypted session key. This
+ string takes up the remainder of the packet, and its contents are
+ dependent on the public key algorithm used.
+
+ Algorithm Specific Fields for RSA encryption
+ - multiprecision integer (MPI) of RSA encrypted value m**e.
+
+ Algorithm Specific Fields for Elgamal encryption:
+ - MPI of DSA value g**k.
+ - MPI of DSA value m * y**k.
+
+The encrypted value "m" in the above formulas is derived from the
+session key as follows. First the session key is prepended with a
+one-octet algorithm identifier that specifies the conventional
+encryption algorithm used to encrypt the following Symmetrically
+Encrypted Data Packet. Then a two-octet checksum is appended which is
+equal to the sum of the preceding octets, including the algorithm
+identifier and session key, modulo 65536. This value is then padded as
+described in PKCS-1 block type 02 [PKCS1] to form the "m" value used in
+the formulas above.
+
+5.2 Signature Packet (Tag 2)
+
+A signature packet describes a binding between some public key and some
+data. The most common signatures are a signature of a file or a block
+of text, and a signature that is a certification of a user ID.
+
+Two versions of signature packets are defined. Version 3 provides
+basic signature information, while version 4 provides an expandable
+format with subpackets that can specify more information about the
+signature. PGP 2.6.X only accepts version 3 signatures.
+
+
+Callas, et. al. Expires May 1998 [Page 17]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+Implementations MUST accept V3 signatures. Implementations SHOULD
+generate V4 signatures, unless there is a need to generate a signature
+that can be verified by PGP 2.6.x.
+
+5.2.1 Version 3 Signature Packet Format
+
+A version 3 Signature packet contains:
+ - One-octet version number (3).
+ - One-octet length of following hashed material. MUST be 5.
+ - One-octet signature type.
+ - Four-octet creation time.
+ - Eight-octet key ID of signer.
+ - One-octet public key algorithm.
+ - One-octet hash algorithm.
+ - Two-octet field holding left 16 bits of signed hash value.
+ - One or more multi-precision integers comprising the signature.
+ This portion is algorithm specific, as described below.
+
+The data being signed is hashed, and then the signature type and
+creation time from the signature packet are hashed (5 additional
+octets). The resulting hash value is used in the signature algorithm.
+The high 16 bits (first two octets) of the hash are included in the
+signature packet to provide a quick test to reject some invalid
+signatures.
+
+ Algorithm Specific Fields for RSA signatures:
+ - multiprecision integer (MPI) of RSA signature value m**d.
+
+ Algorithm Specific Fields for DSA signatures:
+ - MPI of DSA value r.
+ - MPI of DSA value s.
+
+The signature calculation is based on a hash of the signed data, as
+described above. The details of the calculation are different for DSA
+signature than for RSA signatures.
+
+With RSA signatures, the hash value is encoded as described in PKCS-1
+section 10.1.2, "Data encoding", producing an ASN.1 value of type
+DigestInfo, and then padded using PKCS-1 block type 01 [PKCS1]. This
+requires inserting the hash value as an octet string into an ASN.1
+structure. The object identifier for the type of hash being used is
+included in the structure. The hexadecimal representations for the
+currently defined hash algorithms are:
+
+ - SHA-1: 0x2b, 0x0e, 0x03, 0x02, 0x1a
+ - MD5: 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05
+ - RIPEMD-160: 0x2b, 0x24, 0x03, 0x02, 0x01
+
+The ASN.1 OIDs are:
+ - MD5: 1.2.840.113549.2.5
+ - SHA-1: 1.3.14.3.2.26
+ - RIPEMD160: 1.3.36.3.2.1
+
+
+Callas, et. al. Expires May 1998 [Page 18]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+
+DSA signatures SHOULD use hashes with a size of 160 bits, to match q,
+the size of the group generated by the DSA key's generator value. The
+hash function result is treated as a 160 bit number and used directly
+in the DSA signature algorithm.
+
+5.2.2 Version 4 Signature Packet Format
+
+A version 4 Signature packet contains:
+ - One-octet version number (4).
+ - One-octet signature type.
+ - One-octet public key algorithm.
+ - One-octet hash algorithm.
+ - Two-octet octet count for following hashed subpacket data.
+ - Hashed subpacket data.
+ - Two-octet octet count for following unhashed subpacket data.
+ - Unhashed subpacket data.
+ - Two-octet field holding left 16 bits of signed hash value.
+ - One or more multi-precision integers comprising the signature.
+ This portion is algorithm specific, as described above.
+
+The data being signed is hashed, and then the signature data from the
+version number through the hashed subpacket data is hashed. The
+resulting hash value is what is signed. The left 16 bits of the hash
+are included in the signature packet to provide a quick test to reject
+some invalid signatures.
+
+There are two fields consisting of signature subpackets. The first
+field is hashed with the rest of the signature data, while the second
+is unhashed. The second set of subpackets is not cryptographically
+protected by the signature and should include only advisory
+information.
+
+The algorithms for converting the hash function result to a signature
+are described above.
+
+5.2.2.1 Signature Subpacket Specification
+
+The subpacket fields consist of zero or more signature subpackets.
+Each set of subpackets is preceded by a two-octet count of the length
+of the set of subpackets.
+
+Each subpacket consists of a subpacket header and a body. The header
+consists of:
+
+ - subpacket length (1 or 2 octets):
+ Length includes the type octet but not this length,
+ 1st octet < 192, then length is octet value
+ 1st octet >= 192, then length is 2 octets and equal to
+ (1st octet - 192) * 256 + (2nd octet) + 192
+ - subpacket type (1 octet):
+ If bit 7 is set, subpacket understanding is critical,
+
+
+Callas, et. al. Expires May 1998 [Page 19]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ 2 = signature creation time,
+ 3 = signature expiration time,
+ 4 = exportable,
+ 5 = trust signature,
+ 6 = regular expression,
+ 7 = revocable,
+ 9 = key expiration time,
+ 10 = additional recipient request,
+ 11 = preferred symmetric algorithms,
+ 12 = revocation key,
+ 16 = issuer key ID,
+ 20 = notation data,
+ 21 = preferred hash algorithms,
+ 22 = preferred compression algorithms,
+ 23 = key server preferences,
+ 24 = preferred key server
+
+ - subpacket specific data:
+
+Bit 7 of the subpacket type is the "critical" bit. If set, it implies
+that it is critical that the subpacket be one which is understood by
+the software. If a subpacket is encountered which is marked critical
+but the software does not understand, the handling depends on the
+relationship between the issuing key and the key that is signed. If
+the signature is a valid self-signature (for which the issuer is the
+key that is being signed, either directly or via a username binding),
+then the key should not be used. In other cases, the signature
+containing the critical subpacket should be ignored.
+
+5.2.2.2 Signature Subpacket Types
+
+Several types of subpackets are currently defined. Some subpackets
+apply to the signature itself and some are attributes of the key.
+Subpackets that are found on a self-signature are placed on a user name
+certification made by the key itself. Note that a key may have more
+than one user name, and thus may have more than one self-signature, and
+differing subpackets.
+
+Implementing software should interpret a self-signature's preference
+subpackets as narrowly as possible. For example, suppose a key has two
+usernames, Alice and Bob. Suppose that Alice prefers the symmetric
+algorithm CAST5, and Bob prefers IDEA or Triple-DES. If the software
+locates this key via Alice's name, then the preferred algorithm is
+CAST5, if software locates the key via Bob's name, then the preferred
+algorithm is IDEA. If the key is located by key id, then algorithm of
+the default user name of the key provides the default symmetric
+algorithm.
+
+The descriptions below describe whether a subpacket is typically found
+in the hashed or unhashed subpacket sections. If a subpacket is not
+hashed, then it cannot be trusted.
+
+ Signature creation time (4 octet time field) (Hashed)
+
+
+Callas, et. al. Expires May 1998 [Page 20]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+The time the signature was made. Always included with new signatures.
+
+ Issuer (8 octet key ID) (Non-hashed)
+
+The OP key ID of the key issuing the signature.
+
+ Key expiration time (4 octet time field) (Hashed)
+
+The validity period of the key. This is the number of seconds after
+the key creation time that the key expires. If this is not present or
+has a value of zero, the key never expires. This is found only on a
+self-signature.
+
+ Preferred symmetric algorithms (array of one-octet values) (Hashed)
+
+Symmetric algorithm numbers that indicate which algorithms the key
+holder prefers to use. This is an ordered list of octets with the most
+preferred listed first. It should be assumed that only algorithms
+listed are supported by the recipient's software. Algorithm numbers in
+section 6. This is only found on a self-signature.
+
+ Preferred hash algorithms (array of one-octet values) (Hashed)
+
+Message digest algorithm numbers that indicate which algorithms the key
+holder prefers to receive. Like the preferred symmetric algorithms,
+the list is ordered. Algorithm numbers are in section 6. This is only
+found on a self-signature.
+
+{{Editor's note: The above preference (hash algs) is controversial. I
+included it in for symmetry, because if someone wants to build a
+minimal OP implementation, there needs to be a way to tell someone that
+you won't be able to verify a signature unless it's made with some set
+of algorithms. It also permits to prefer DSA with RIPEMD-160, for
+example. If you have an opinion, please state it.}}
+
+ Preferred compression algorithms (array of one-octet values)
+ (Hashed)
+
+Compression algorithm numbers that indicate which algorithms the key
+holder prefers to use. Like the preferred symmetric algorithms, the
+list is ordered. Algorithm numbers are in section 6. If this
+subpacket is not included, ZIP is preferred. A zero denotes that no
+compression is preferred; the key holder's software may not have
+compression software. This is only found on a self-signature.
+
+ Signature expiration time (4 octet time field) (Hashed)
+
+The validity period of the signature. This is the number of seconds
+after the signature creation time that the signature expires. If this
+is not present or has a value of zero, it never expires.
+
+ Exportable (1 octet of exportability, 0 for not, 1 for exportable)
+
+
+Callas, et. al. Expires May 1998 [Page 21]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ (Hashed)
+
+Signature's exportability status. Packet body contains a boolean flag
+indicating whether the signature is exportable. Signatures which are
+not exportable are ignored during export and import operations. If
+this packet is not present the signature is assumed to be exportable.
+
+ Revocable (1 octet of revocability, 0 for not, 1 for revocable)
+ (Hashed)
+
+Signature's revocability status. Packet body contains a boolean flag
+indicating whether the signature is revocable. Signatures which are
+not revocable get any later revocation signatures ignored. They
+represent a commitment by the signer that he cannot revoke his
+signature for the life of his key. If this packet is not present the
+signature is assumed to be revocable.
+
+ Trust signature (1 octet of "level" (depth), 1 octet of trust amount)
+ (Hashed)
+Signer asserts that the key is not only valid, but also trustworthy, at
+the specified level. Level 0 has the same meaning as an ordinary
+validity signature. Level 1 means that the signed key is asserted to
+be a valid trusted introducer, with the 2nd octet of the body
+specifying the degree of trust. Level 2 means that the signed key is
+asserted to be trusted to issue level 1 trust signatures, i.e. that it
+is a "meta introducer". Generally, a level n trust signature asserts
+that a key is trusted to issue level n-1 trust signatures. The trust
+amount is in a range from 0-255, interpreted such that values less than
+120 indicate partial trust and values of 120 or greater indicate
+complete trust. Implementations SHOULD emit values of 60 for partial
+trust and 120 for complete trust.
+
+ Regular expression (null-terminated regular expression) (Hashed)
+
+Used in conjunction with trust signature packets (of level > 0) to
+limit the scope of trust which is extended. Only signatures by the
+target key on user IDs which match the regular expression in the body
+of this packet have trust extended by the trust packet.
+
+ Additional recipient request (1 octet of class, 1 octet of algid,
+ 20 octets of fingerprint) (Hashed)
+
+Key holder requests encryption to additional recipient when data is
+encrypted to this username. If the class octet contains 0x80, then the
+key holder strongly requests that the additional recipient be added to
+an encryption. Implementing software may treat this subpacket in any
+way it sees fit. This is found only on a self-signature.
+
+ Revocation key (1 octet of class, 1 octet of algid, 20 octets of
+ fingerprint) (Hashed)
+
+Authorizes the specified key to issue revocation self-signatures on
+this key. Class octet must have bit 0x80 set, other bits are for
+
+
+Callas, et. al. Expires May 1998 [Page 22]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+future expansion to other kinds of signature authorizations. This is
+found on a self-signature.
+
+ Notation Data (4 octets of flags, 2 octets of name length,
+ 2 octets of value length, M octets of name data,
+ N octets of value data) (Hashed)
+
+This subpacket describes a "notation" on the signature that the issuer
+wishes to make. The notation has a name and a value, each of which are
+strings of octets. There may be more than one notation in a signature.
+Notations can be used for any extension the issuer of the signature
+cares to make. The "flags" field holds four octets of flags. All
+undefined flags MUST be zero. Defined flags are:
+ First octet: 0x80 = human-readable. This note is text, a note
+ from one person to another, and has no
+ meaning to software.
+ Other octets: none.
+
+ Key server preferences (N octets of flags) (Hashed)
+
+This is a list of flags that indicate preferences that the key holder
+has about how the key is handled on a key server. All undefined flags
+MUST be zero.
+
+ First octet: 0x80 = No-modify -- the key holder requests that
+ this key only be modified or updated by the
+ key holder or an authorized administrator of
+ the key server.
+This is found only on a self-signature.
+
+ Preferred key server (String) (Hashed)
+
+This is a URL of a key server that the key holder prefers be used for
+updates. Note that keys with multiple user names can have a preferred
+key server for each user name. This is found only on a self-signature.
+
+Implementations SHOULD implement a "preference" and MAY implement a
+"request."
+
+{{Editor's note: None of the preferences have a way to specify a
+negative preference (for example, I like Triple-DES, don't use
+algorithm X). Tacitly, the absence of an algorithm from a set is a
+negative preference, but should there be an explicit way to give a
+negative preference? -jdcc}}
+
+{{Editor's note: A missing feature is to invalidate (or revoke) a user
+id, rather than the entire key. Lots of people want this, and many
+people have keys cluttered with old work email addresses. There is
+another related issue, that that is with key rollover -- suppose I'm
+retiring an old key, but I don't want to have to lose all my
+certification signatures. It would be nice if there were a way for a
+key to transfer itself to a new one. Lastly, if either (or both) of
+these is desirable, do we handle them with a new signature type, or
+
+
+Callas, et. al. Expires May 1998 [Page 23]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+with notations, which are an extension mechanism. I think that it
+makes sense to make a revocation type (because it's analogous to the
+other forms of revocation), but rollover might be best implemented as
+an extension. --jdcc}}
+
+{{Editor's note: PGP 3 designed, but never implemented a number of
+other subpacket types. They were: A signature version number; A set
+of key usage flags (signing key, encryption key for communication, and
+encryption key for storage); User ID of the signer; Policy URL; net
+location of the key.
+
+Some of these options are things the WG has talked about as being a
+Good Thing -- like flags denoting if a key is a comm key or a storage
+key. My design of such a feature would be different than the other
+one, though. I think it would be a great idea to have a URL that's a
+location to find the key, so people who prefer to have a web, ftp, or
+finger location can use those. However, some of them (like a URL) are
+also perfect for designing in with extensions. After all, we only have
+128 subpacket constants.
+
+--jdcc}}
+
+5.2.3 Signature Types
+
+There are a number of possible meanings for a signature, which are
+specified in a signature type octet in any given signature. These
+meanings are:
+
+ - 0x00: Signature of a binary document.
+Typically, this means the signer owns it, created it, or certifies that
+it has not been modified.
+
+ - 0x01: Signature of a canonical text document.
+Typically, this means the signer owns it, created it, or certifies that
+it has not been modified. The signature will be calculated over the
+textual data with its line endings converted to <CR><LF>.
+
+ - 0x02: Standalone signature.
+This signature is a signature of only its own subpacket contents. It
+is calculated identically to a signature over a zero-length binary
+document.
+
+ - 0x10: The generic certification of a User ID and Public Key
+ packet.
+The issuer of this certification does not make any particular assertion
+as to how well the certifier has checked that the owner of the key is
+in fact the person described by the user ID. Note that all PGP "key
+signatures" are this type of certification.
+
+ - 0x11: This is a persona certification of a User ID and
+ Public Key packet.
+It means that the issuer of this certification has not done any
+verification of the claim that the owner of this key is the user ID
+
+
+Callas, et. al. Expires May 1998 [Page 24]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+specified. Note that no released version of PGP has generated this
+type of certification.
+
+ - 0x12: This is the casual certification of a User ID and
+ Public Key packet.
+It means that the issuer of this certification has done some casual
+verification of the claim of identity. Note that no version of PGP has
+generated this type of certification, nor is there any definition of
+what constitutes a casual certification.
+
+ - 0x13: This is the positive certification of a User ID and
+ Public Key packet.
+It means that the issuer of this certification has done substantial
+verification of the claim of identity. Note that no version of PGP has
+generated this type of certification, nor is there any definition of
+what constitutes a positive certification. Please also note that the
+vagueness of these certification systems is not a flaw, but a feature
+of the system. Because PGP places final authority for validity upon
+the receiver of a certification, it may be that one authority's casual
+certification might be more rigorous than some other authority's
+positive certification.
+
+{{Editor's note: While there is a scale of identification signatures
+in the range 0x10 to 0x13, most of them have never been implemented or
+used. Current implementations only use 0x10, the "generic
+certification." Should the others be removed? RFC 1991 went to some
+trouble to explain which ones were defined but not implemented, or read
+but not generated. I think we should not do that. If we define them,
+they should be MAY features at the very least. If we're not going to
+use them, they shouldn't be in the spec. --jdcc}}
+
+ - 0x18: This is used for a signature by a signature key to bind a
+ subkey which will be used for encryption.
+The signature is calculated directly on the subkey itself, not on any
+User ID or other packets.
+
+ - 0x20: This signature is used to revoke a key.
+The signature is calculated directly on the key being revoked. A
+revoked key is not to be used. Only revocation signatures by the key
+being revoked, or by an authorized revocation key, should be
+considered.
+
+ - 0x28: This is used to revoke a subkey.
+The signature is calculated directly on the subkey being revoked. A
+revoked subkey is not to be used. Only revocation signatures by the
+top-level signature key which is bound to this subkey, or by an
+authorized revocation key, should be considered.
+
+ - 0x30: This signature revokes an earlier user ID certification
+ signature (signature class 0x10 - 0x13).
+It should be issued by the same key which issued the revoked signature,
+and should have a later creation date.
+
+
+
+Callas, et. al. Expires May 1998 [Page 25]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ - 0x40: Timestamp signature.
+
+{{Editor's note: The timestamp signature is left over from RFC 1991,
+and has never been fully designed nor implemented. Is this the sort of
+thing best handled by notations? --jdcc}}
+
+{{Editor's note: It would be nice to have a signature that applied to
+the key alone, rather than a key plus a user name. Perhaps this is
+best done with a notation. --jdcc}}
+
+{{Editor's note: There is presently no way for a key-signer (a.k.a.
+certifier) to sign a main key along with a subkey. There are a number
+of useful situations for a set of keys (main plus subkeys) to all be
+signed together. How do we solve this? --jdcc}}
+
+5.3 Conventional Encrypted Session-Key Packets (Tag 3)
+
+The Conventional Encrypted Session Key packet holds the
+conventional-cipher encryption of a session key used to encrypt a
+message. Zero or more Encrypted Session Key packets and/or
+Conventional Encrypted Session Key packets may precede a Symmetrically
+Encrypted Data Packet that holds an encrypted message. The message is
+encrypted with a session key, and the session key is itself encrypted
+and stored in the Encrypted Session Key packet or the Conventional
+Encrypted Session Key packet.
+
+If the Symmetrically Encrypted Data Packet is preceded by one or more
+Conventional Encrypted Session Key packets, each specifies a passphrase
+which may be used to decrypt the message. This allows a message to be
+encrypted to a number of public keys, and also to one or more pass
+phrases. This packet type is new, and is not generated by PGP 2.x or
+PGP 5.0.
+
+The body of this packet consists of:
+ - A one-octet version number. The only currently defined version is
+ 4.
+ - A one-octet number describing the symmetric algorithm used.
+ - A string-to-key (S2K) specifier, length as defined above.
+ - Optionally, the encrypted session key itself, which is decrypted
+ with the string-to-key object.
+
+If the encrypted session key is not present (which can be detected on
+the basis of packet length and S2K specifier size), then the S2K
+algorithm applied to the passphrase produces the session key for
+decrypting the file, using the symmetric cipher algorithm from the
+Conventional Encrypted Session Key packet.
+
+If the encrypted session key is present, the result of applying the S2K
+algorithm to the passphrase is used to decrypt just that encrypted
+session key field, using CFB mode with an IV of all zeros. The
+decryption result consists of a one-octet algorithm identifier that
+specifies the conventional encryption algorithm used to encrypt the
+following Symmetrically Encrypted Data Packet, followed by the session
+
+
+Callas, et. al. Expires May 1998 [Page 26]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+key octets themselves.
+
+Note: because an all-zero IV is used for this decryption, the S2K
+specifier MUST use a salt value, either a a Salted S2K or an
+Iterated-Salted S2K. The salt value will insure that the decryption
+key is not repeated even if the passphrase is reused.
+
+
+5.4 One-Pass Signature Packets (Tag 4)
+
+The One-Pass Signature packet precedes the signed data and contains
+enough information to allow the receiver to begin calculating any
+hashes needed to verify the signature. It allows the Signature Packet
+to be placed at the end of the message, so that the signer can compute
+the entire signed message in one pass.
+
+A One-Pass Signature does not interoperate with PGP 2.6.x or earlier.
+
+The body of this packet consists of:
+ - A one-octet version number. The current version is 3.
+ - A one-octet signature type. Signature types are described
+ in section 5.2.3.
+ - A one-octet number describing the hash algorithm used.
+ - A one-octet number describing the public key algorithm used.
+ - An eight-octet number holding the key ID of the signing key.
+ - A one-octet number holding a flag showing whether the signature
+is nested. A zero value indicates that the next packet is
+another One-Pass Signature packet which describes another
+signature to be applied to the same message data.
+
+
+5.5 Key Material Packet
+
+A key material packet contains all the information about a public or
+private key. There are four variants of this packet type, and two
+major versions. Consequently, this section is complex.
+
+5.5.1 Key Packet Variants
+
+5.5.1.1 Public Key Packet (Tag 6)
+
+A Public Key packet starts a series of packets that forms an OP key
+(sometimes called an OP certificate).
+
+5.5.1.2 Public Subkey Packet (Tag 14)
+
+A Public Subkey packet (tag 14) has exactly the same format as a Public
+Key packet, but denotes a subkey. One or more subkeys may be
+associated with a top-level key. By convention, the top-level key
+provides signature services, and the subkeys provide encryption
+services.
+
+Note: in PGP 2.6.X, tag 14 was intended to indicate a comment packet.
+
+
+Callas, et. al. Expires May 1998 [Page 27]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+This tag was selected for reuse because no previous version of PGP ever
+emitted comment packets but they did properly ignore them. Public
+Subkey packets are ignored by PGP 2.6.X and do not cause it to fail,
+providing a limited degree of backwards compatibility.
+
+5.5.1.3 Secret Key Packet (Tag 5)
+
+A Secret Key packet contains all the information that is found in a
+Public Key packet, including the public key material, but also includes
+the secret key material after all the public key fields.
+
+5.5.1.4 Secret Subkey Packet (Tag 7)
+
+A Secret Subkey packet (tag 7) is the subkey analog of the Secret Key
+packet, and has exactly the same format.
+
+5.5.2 Public Key Packet Formats
+
+There are two versions of key-material packets. Version 3 packets were
+first generated PGP 2.6. Version 2 packets are identical in format to
+Version 3 packets, but are generated by PGP 2.5 or before. PGP 5.0
+introduces version 4 packets, with new fields and semantics. PGP 2.6.X
+will not accept key-material packets with versions greater than 3.
+
+OP implementations SHOULD create keys with version 4 format. An
+implementation MAY generate a V3 key to ensure interoperability with
+old software; note, however, that V4 keys correct some security
+deficiencies in V3 keys. These deficiencies are described below. An
+implementation MUST NOT create a V3 key with a public key algorithm
+other than RSA.
+
+A version 3 public key or public subkey packet contains:
+ - A one-octet version number (3).
+ - A four-octet number denoting the time that the key was created.
+ - A two-octet number denoting the time in days that this key is
+ valid. If this number is zero, then it does not expire.
+ - A one-octet number denoting the public key algorithm of this key
+ - A series of multi-precision integers comprising the key
+ material:
+ - a multiprecision integer (MPI) of RSA public modulus n;
+ - an MPI of RSA public encryption exponent e.
+
+The fingerprint of the key is formed by hashing the body (but not the
+two-octet length) of the MPIs that form the key material (public
+modulus n, followed by exponent e) with MD5.
+
+The eight-octet key ID of the key consists of the low 64 bits of the
+public modulus of an RSA key.
+
+Since the release of V3 keys, there have been a number of improvements
+desired in the key format. For example, if the key ID is a function of
+the public modulus, it is easy for a person to create a key that has
+the same key ID as some existing key. Similarly, MD5 is no longer the
+
+
+Callas, et. al. Expires May 1998 [Page 28]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+preferred hash algorithm, and not hashing the length of an MPI with its
+body increases the chances of a fingerprint collision.
+
+The version 4 format is similar to the version 3 format except for the
+absence of a validity period. This has been moved to the signature
+packet. In addition, fingerprints of version 4 keys are calculated
+differently from version 3 keys, as described elsewhere.
+
+A version 4 packet contains:
+ - A one-octet version number (4).
+ - A four-octet number denoting the time that the key was created.
+ - A one-octet number denoting the public key algorithm of this key
+ - A series of multi-precision integers comprising the key
+ material. This algorithm-specific portion is:
+
+ Algorithm Specific Fields for RSA public keys:
+ - multiprecision integer (MPI) of RSA public modulus n;
+ - MPI of RSA public encryption exponent e.
+
+ Algorithm Specific Fields for DSA public keys:
+ - MPI of DSA prime p;
+ - MPI of DSA group order q (q is a prime divisor of p-1);
+ - MPI of DSA group generator g;
+ - MPI of DSA public key value y (= g**x where x is secret).
+
+ Algorithm Specific Fields for Elgamal public keys:
+ - MPI of Elgamal prime p;
+ - MPI of Elgamal group generator g;
+ - MPI of Elgamal public key value y (= g**x where x
+ is secret).
+
+
+5.5.3 Secret Key Packet Formats
+
+The Secret Key and Secret Subkey packets contain all the data of the
+Public Key and Public Subkey packets, with additional
+algorithm-specific secret key data appended, in encrypted form.
+
+The packet contains:
+ - A Public Key or Public Subkey packet, as described above
+ - One octet indicating string-to-key usage conventions. 0 indicates
+ that the secret key data is not encrypted. 255 indicates that a
+ string-to-key specifier is being given. Any other value
+ is a conventional encryption algorithm specifier.
+ - [Optional] If string-to-key usage octet was 255, a one-octet
+ conventional encryption algorithm.
+ - [Optional] If string-to-key usage octet was 255, a string-to-key
+ specifier. The length of the string-to-key specifier is implied
+ by its type, as described above.
+ - [Optional] If secret data is encrypted, eight-octet Initial Vector
+ (IV).
+ - Encrypted multi-precision integers comprising the secret key data.
+ These algorithm-specific fields are as described below.
+
+
+Callas, et. al. Expires May 1998 [Page 29]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ - Two-octet checksum of the plaintext of the algorithm-specific
+ portion (sum of all octets, mod 65536).
+
+ Algorithm Specific Fields for RSA secret keys:
+ - multiprecision integer (MPI) of RSA secret exponent d.
+ - MPI of RSA secret prime value p.
+ - MPI of RSA secret prime value q (p < q).
+ - MPI of u, the multiplicative inverse of p, mod q.
+
+ Algorithm Specific Fields for DSA secret keys:
+ - MPI of DSA secret exponent x.
+
+ Algorithm Specific Fields for Elgamal secret keys:
+ - MPI of Elgamal secret exponent x.
+
+Secret MPI values can be encrypted using a passphrase. If a
+string-to-key specifier is given, that describes the algorithm for
+converting the passphrase to a key, else a simple MD5 hash of the
+passphrase is used. Implementations SHOULD use a string-to-key
+specifier; the simple hash is for backwards compatibility. The cipher
+for encrypting the MPIs is specified in the secret key packet.
+
+Encryption/decryption of the secret data is done in CFB mode using the
+key created from the passphrase and the Initial Vector from the packet.
+A different mode is used with RSA keys than with other key formats.
+With RSA keys, the MPI bit count prefix (i.e., the first two octets) is
+not encrypted. Only the MPI non-prefix data is encrypted.
+Furthermore, the CFB state is resynchronized at the beginning of each
+new MPI value, so that the CFB block boundary is aligned with the start
+of the MPI data.
+
+With non-RSA keys, a simpler method is used. All secret MPI values are
+encrypted in CFB mode, including the MPI bitcount prefix.
+
+The 16-bit checksum that follows the algorithm-specific portion is the
+algebraic sum, mod 65536, of the plaintext of all the
+algorithm-specific octets (including MPI prefix and data). With RSA
+keys, the checksum is stored in the clear. With non-RSA keys, the
+checksum is encrypted like the algorithm-specific data. This value is
+used to check that the passphrase was correct.
+
+5.6 Compressed Data Packet (Tag 8)
+
+The Compressed Data packet contains compressed data. Typically, this
+packet is found as the contents of an encrypted packet, or following a
+Signature or One-Pass Signature packet, and contains literal data
+packets.
+
+The body of this packet consists of:
+ - One octet that gives the algorithm used to compress the packet.
+ - The remainder of the packet is compressed data.
+
+A Compressed Data Packet's body contains an RFC1951 DEFLATE block that
+
+
+Callas, et. al. Expires May 1998 [Page 30]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+compresses some set of packets. See section 7 for details on how
+messages are formed.
+
+5.7 Symmetrically Encrypted Data Packet (Tag 9)
+
+The Symmetrically Encrypted Data packet contains data encrypted with a
+conventional (symmetric-key) algorithm. When it has been decrypted, it
+will typically contain other packets (often literal data packets or
+compressed data packets).
+
+The body of this packet consists of:
+
+ - Encrypted data, the output of the selected conventional cipher
+ operating in PGP's variant of Cipher Feedback (CFB) mode.
+
+The conventional cipher used may be specified in an Encrypted Session
+Key or Conventional Encrypted Session Key packet which precedes the
+Symmetrically Encrypted Data Packet. In that case, the cipher
+algorithm octet is prepended to the session key before it is encrypted.
+If no packets of these types precede the encrypted data, the IDEA
+algorithm is used with the session key calculated as the MD5 hash of
+the passphrase.
+
+The data is encrypted in CFB mode, with a CFB shift size equal to the
+cipher's block size [Ref]. The Initial Vector (IV) is specified as all
+zeros. Instead of using an IV, OP prepends a 10 octet string to the
+data before it is encrypted. The first eight octets are random, and
+the 9th and 10th octets are copies of the 7th and 8th octets,
+respectivelly. After encrypting the first 10 octets, the CFB state is
+resynchronized if the cipher block size is 8 octets or less. The last
+8 octets of ciphertext are passed through the cipher and the block
+boundary is reset.
+
+The repetition of 16 bits in the 80 bits of random data prepended to
+the message allows the receiver to immediately check whether the
+session key is correct.
+
+5.8 Marker Packet (Obsolete Literal Packet) (Tag 10)
+
+An experimental version of PGP used this packet as the Literal packet,
+but no released version of PGP generated Literal packets with this tag.
+With PGP 5.x, this packet has been re-assigned and is reserved for use
+as the Marker packet.
+
+The body of this packet consists of:
+ - The three octets 0x60, 0x47, 0x60 (which spell "PGP" in UTF-8).
+
+Such a packet should be ignored on input. It may be placed at the
+beginning of a message that uses features not available in PGP 2.6.X in
+order to cause that version to report that newer software necessary to
+process the message.
+
+5.9 Literal Data Packet (Tag 11)
+
+
+Callas, et. al. Expires May 1998 [Page 31]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+A Literal Data packet contains the body of a message; data that is not
+to be further interpreted.
+
+The body of this packet consists of:
+ - A one-octet field that describes how the data is formatted.
+If it is a 'b' (0x62), then the literal packet contains binary data. If
+it is a 't' (0x74), then it contains text data, and thus may need line
+ends converted to local form, or other text-mode changes. RFC 1991
+also defined a value of 'l' as a 'local' mode for machine-local
+conversions. This use is now deprecated.
+
+ - File name as a string (one-octet length, followed by file name),
+ if the encrypted data should be saved as a file.
+If the special name "_CONSOLE" is used, the message is considered to be
+"for your eyes only". This advises that the message data is unusually
+sensitive, and the receiving program should process it more carefully,
+perhaps avoiding storing the received data to disk, for example.
+
+ - A four-octet number that indicates the modification date of the
+file, or the creation time of the packet, or a zero that indicates the
+present time.
+
+ - The remainder of the packet is literal data.
+
+Text data is stored with <CR><LF> text endings. This should be
+converted to native line endings by the receiving software.
+
+5.10 Trust Packet (Tag 12)
+
+The Trust packet is used only within keyrings and is not normally
+exported. Trust packets contain data that record the user's
+specifications of which key holders are trustworthy introducers, along
+with other information that implementing software uses for trust
+information.
+
+Trust packets SHOULD NOT be emitted to output streams that are
+transferred to other users, and they SHOULD be ignored on any input
+other than local keyring files.
+
+{{Editor's note: I have brushed aside the description of the old PGP
+trust packets for a number of reasons. They are context dependent;
+their meaning depends on the packet preceding them in a keyring.
+
+There is also a security problem with trust packets. For example,
+malicious software can write a new public key into a user's key ring
+with trust packets that make it trusted.
+
+A number of us have discussed this problem, and think that trust
+information should always be self-signed to act as an integrity check,
+but other people may have other solutions.
+
+My solution is to make trust packets implementation dependent. They
+
+
+Callas, et. al. Expires May 1998 [Page 32]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+are not emitted on export and ignored on import. Because of this, they
+are arguably out of scope of this document anyway. Given that the PGP
+implementation of trust packets has security flaws, this seems to be
+the best way to deal with them.
+
+--jdcc}}
+
+5.11 User ID Packet (Tag 13)
+
+A User ID packet consists of data which is intended to represent the
+name and email address of the key holder. By convention, it includes
+an RFC822 mail name, but there are no restrictions on its content. The
+packet length in the header specifies the length of the user name. If
+it is text, it is encoded in UTF-8.
+
+{{Editor's note: PRZ thinks there should be more types of "user ids"
+other than the traditional name, such as photos, and so on. The above
+definition, which assiduously avoids saying that the content of the
+packet is a counted string, is one potential way to handle it. Another
+would be to explicitly state that this packet is a string, and
+introduce a free-form user identification packet.
+
+A related issue with this document is that sometimes it says "user id"
+and sometimes "user name." We need some work here. Present plan is to
+use "User ID" everywhere. --jdcc}}
+
+{{Editor's note: Carl Ellison pointed out to me that if we have
+non-exportable (local to one's own keyring) usernames that I can assign
+to keys I use, then essentially we have SDSI naming in PGP. This is a
+Good Thing, in my opinion, but we have to have a way to define it.
+--jdcc}}
+
+5.12 Comment Packet (Tag 16)
+
+A Comment packet is used for holding data that is not relevant to
+software. Comment packets should be ignored.
+
+{{Editor's note: should? Must? What does it mean to ignore them? For
+example, if it's desirable to show a comment to a user, then how does
+that interact with should/must and a suitable definition of "ignore." I
+believe that they MUST be ignored, but displaying them to a user is
+ignoring them. Looking inside them for cryptographic content (like OP
+packets) is *not* ignoring them.}}
+
+{{Editor's note: should we put in an X.509 encapsulation packet type?}}
+
+6. Constants
+
+This section describes the constants used in OP.
+
+Note that these tables are not exhaustive lists; an implementation MAY
+implement an algorithm not on these lists.
+
+
+
+Callas, et. al. Expires May 1998 [Page 33]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+6.1 Public Key Algorithms
+
+1 - RSA (Encrypt or Sign)
+2 - RSA Encrypt-Only
+3 - RSA Sign-Only
+16 - Elgamal
+17 - DSA (Digital Signature Standard)
+100 to 110 - Private/Experimental algorithm.
+
+Implementations MUST implement DSA for signatures, and Elgamal for
+encryption. Implementations SHOULD implement RSA encryption.
+Implementations MAY implement any other algorithm.
+
+{{Editor's note: reserve an algorithm for elliptic curve? Note that
+I've left Elgamal signatures completely unmentioned. I think this is
+good. --jdcc}}
+
+6.2 Symmetric Key Algorithms
+
+0 - Plaintext
+1 - IDEA
+2 - Triple-DES (DES-EDE, as per spec -
+ 168 bit key derived from 192)
+3 - CAST5 (128 bit key)
+4 - Blowfish (128 bit key)
+5 - ROT-N (128 bit N)
+6 - SAFER-SK128
+7 - DES/SK
+100 to 110 - Private/Experimental algorithm.
+
+Implementations MUST implement Triple-DES. Implementations SHOULD
+implement IDEA and CAST5.Implementations MAY implement any other
+algorithm.
+
+6.3 Compression Algorithms
+
+0 - Uncompressed
+1 - ZIP
+100 to 110 - Private/Experimental algorithm.
+
+Implementations MUST implement uncompressed data. Implementations
+SHOULD implement ZIP.
+
+6.4 Hash Algorithms
+
+1 - MD5
+2 - SHA-1
+3 - RIPE-MD/160
+4 - HAVAL
+100 to 110 - Private/Experimental algorithm.
+
+Implementations MUST implement SHA-1. Implementations SHOULD implement
+MD5.
+
+
+Callas, et. al. Expires May 1998 [Page 34]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+7. Packet Composition
+
+OP packets may be assembled into sequences in order to create messages
+and transfer keys. Not all possible packet sequences are meaningful
+and correct. This describes the rules for how packets should be placed
+into sequences.
+
+7.1 Transferable Public Keys
+
+OP users may transfer public keys. The essential elements of a
+transferable public key are:
+
+ - One Public Key packet
+ - Zero or more revocation signatures
+ - One or more User ID packets
+ - After each User ID packet, zero or more Signature packets
+ - Zero or more Subkey packets
+ - After each Subkey packet, one or more Signature packets
+
+The Public Key packet occurs first. Each of the following User ID
+packets provides the identity of the owner of this public key. If
+there are multiple User ID packets, this corresponds to multiple means
+of identifying the same unique individual user; for example, a user may
+enjoy the use of more than one e-mail address, and construct a User ID
+packet for each one.
+
+Immediately following each User ID packet, there are zero or more
+signature packets. Each signature packet is calculated on the
+immediately preceding User ID packet and the initial Public Key packet.
+The signature serves to certify the corresponding public key and user
+ID. In effect, the signer is testifying to his or her belief that this
+public key belongs to the user identified by this user ID.
+
+After the User ID packets there may be one or more Subkey packets.
+Subkeys are used in cases where the top-level public key is a
+signature-only key. The subkeys are then encryption-only keys that are
+bound to the signature key. Each Subkey packet must be followed by at
+least one Signature packet, which should be of the subkey binding
+signature type, and issued by the top level key.
+
+{{Editor's note: I think it is a good idea to have signature-only
+subkeys, too (or even encrypt-and-sign subkeys), but no implementation
+does this. Should we generalize here? --jdcc}}
+
+Subkey and Key packets may each be followed by a revocation Signature
+packet to indicate that the key is revoked. Revocation signatures are
+only accepted if they are issued by the key itself, or by a key which
+is authorized to issue revocations via a revocation key subpacket in a
+self-signature by the top level key.
+
+Transferable public key packet sequences may be concatenated to allow
+transferring multiple public keys in one operation.
+
+
+Callas, et. al. Expires May 1998 [Page 35]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+7.2 OP Messages
+
+An OP message is a packet or sequence of packets that corresponds to
+the following grammatical rules (comma represents sequential
+composition, and vertical bar separates alternatives):
+
+ OP Message :- Encrypted Message | Signed Message | Compressed Message
+ | Literal Message.
+
+ Compressed Message :- Compressed Data Packet.
+
+ Literal Message :- Literal Data Packet.
+
+ ESK :- Encrypted Session Key Packet |
+ Conventionally Encrypted Session Key Packet.
+
+ ESK Sequence :- ESK | ESK Sequence, ESK.
+
+ Encrypted Message :- Symmetrically Encrypted Data Packet |
+ ESK Sequence, Symmetrically Encrypted Data Packet.
+
+ One-Pass Signed Message :- One-Pass Signature Packet, OP Message,
+ Signature Packet.
+
+ Signed Message :- Signature Packet, OP Message |
+ One-Pass Signed Message.
+
+In addition, the decrypting a Symmetrically Encrypted Data packet and
+decompressing a Compressed Data packet must yield a valid OP Message.
+
+
+8. Enhanced Key Formats
+
+8.1 Key Structures
+
+The format of V3 OP key using RSA is as follows. Entries in square
+brackets are optional and ellipses indicate repetition.
+
+ RSA Public Key
+ [Revocation Self Signature]
+ User ID [Signature ...]
+ [User ID [Signature ...] ...]
+
+Each signature certifies the RSA public key and the preceding user ID.
+The RSA public key can have many user IDs and each user ID can have
+many signatures.
+
+The format of an OP V4 key that uses two public keys is very similar
+except that the second key is added to the end as a 'subkey' of the
+primary key.
+
+ Primary-Key
+
+
+Callas, et. al. Expires May 1998 [Page 36]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+ [Revocation Self Signature]
+ User ID [Signature ...]
+ [User ID [Signature ...] ...]
+ [Subkey Primary-Key-Signature]
+
+The subkey always has a single signature after it that is issued using
+the primary key to tie the two keys together. The new format can use
+either the new signature packets or the old signature packets.
+
+In an Elgamal/DSA key, the DSA public key is the primary key, the
+Elgamal public key is the subkey, and either version 3 or 4 of the
+signature packet can be used. There may be other types of V4 keys,
+too. For example, there may be a single-key RSA key in V4 format, a DSA
+primary key with an RSA encryption key, etc, or RSA primary key with an
+Elgamal subkey.
+
+It is also possible to have a signature-only subkey. This permits a
+primary key that collects certifications (key signatures) but is used
+only used for certifying subkeys that are used for encryption and
+signatures.
+
+
+8.2 V4 Key IDs and Fingerprints
+
+A V4 fingerprint is the 160-bit SHA-1 hash of the one-octet Packet Tag,
+followed by the two-octet packet length, followed by the entire Public
+Key packet starting with the version field. The key ID is either the
+low order 32 bits or 64 bits of the fingerprint. Here are the fields
+of the hash material, with the example of a DSA key:
+
+ a.1) 0x99 (1 byte)
+ a.2) high order length byte of (b)-(f) (1 byte)
+ a.3) low order length byte of (b)-(f) (1 byte)
+ b) version number = 4 (1 byte);
+ c) time stamp of key creation (4 bytes);
+ e) algorithm (1 byte):
+ 17 = DSA;
+ f) Algorithm specific fields.
+
+ Algorithm Specific Fields for DSA keys (example):
+ f.1) MPI of DSA prime p;
+ f.2) MPI of DSA group order q (q is a prime divisor of p-1);
+ f.3) MPI of DSA group generator g;
+ f.4) MPI of DSA public key value y (= g**x where x is secret).
+
+
+9. Security Considerations
+
+As with any technology involving cryptography, you should check the
+current literature to determine if any algorithms used here have been
+found to be vulnerable to attack.
+
+This specification uses Public Key Cryptography technologies.
+
+
+Callas, et. al. Expires May 1998 [Page 37]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+Possession of the private key portion of a public-private key pair is
+assumed to be controlled by the proper party or parties.
+
+Certain operations in this specification involve the use of random
+numbers. An appropriate entropy source should be used to generate
+these numbers. See RFC 1750.
+
+The MD5 hash algorithm has been found to have weaknesses
+(pseudo-collisions in the compress function) that make some people
+deprecate its use. They consider the SHA-1 algorithm better.
+
+If you are building an authentication system, the recipient may specify
+a preferred signing algorithm. However, the signer would be foolish to
+use a weak algorithm simply because the recipient requests it.
+
+Some of the encryption algorithms mentioned in this document have been
+analyzed less than others. For example, although CAST5 is presently
+considered strong, it has been analyzed less than Triple-DES. Other
+algorithms may have other controversies surrounding them.
+
+Some technologies mentioned here may be subject to government control
+in some countries.
+
+10. Authors and Working Group Chair
+
+The working group can be contacted via the current chair:
+
+John W. Noerenberg, II Qualcomm, Inc 6455 Lusk Blvd San Diego, CA
+92131 USA Email: jwn2@qualcomm.com Tel: +1 619 658 3510
+
+The principal authors of this draft are (in alphabetical order):
+
+Jon Callas Pretty Good Privacy, Inc. 555 Twin Dolphin Drive, #570
+Redwood Shores, CA 94065, USA Email: jon@pgp.com Tel: +1-650-596-1960
+
+Lutz Donnerhacke IKS GmbH Wildenbruchstr. 15 07745 Jena, Germany EMail:
+lutz@iks-jena.de Tel: +49-3641-675642
+
+Hal Finney Pretty Good Privacy, Inc. 555 Twin Dolphin Drive, #570
+Redwood Shores, CA 94065, USA Email: hal@pgp.com Tel: +1-650-572-0430
+
+Rodney Thayer Sable Technology Corporation 246 Walnut Street Newton, MA
+02160 USA Email: rodney@sabletech.com Tel: +1-617-332-7292
+
+
+
+This draft also draws on much previous work from a number of other
+authors who include: Derek Atkins, Charles Breed, Dave Del Torto, Marc
+Dyksterhouse, Gail Haspert, Gene Hoffman, Paul Hoffman, Raph Levine,
+Colin Plumb, Will Price, William Stallings, Mark Weaver, and Philip R.
+Zimmermann.
+
+11. References
+
+
+Callas, et. al. Expires May 1998 [Page 38]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+
+[CAMPBELL} Campbell, Joe, "C Programmer's Guide to Serial
+Communications"
+
+[DONNERHACKE] Donnerhacke, L., et. al, "PGP263in - an improved
+international version of PGP",
+ftp://ftp.iks-jena.de/mitarb/lutz/crypt/software/pgp/
+
+[ISO-10646] ISO/IEC 10646-1:1993. International Standard --
+Information technology -- Universal Multiple-Octet Coded Character Set
+(UCS) -- Part 1: Architecture and Basic Multilingual Plane. UTF-8 is
+described in Annex R, adopted but not yet published. UTF-16 is
+described in Annex Q, adopted but not yet published.
+
+[PKCS1] RSA Laboratories, "PKCS #1: RSA Encryption Standard," version
+1.5, November 1993
+
+[RFC822] D. Crocker, "Standard for the format of ARPA Internet text
+messages", RFC 822, August 1982
+
+[RFC1423] D. Balenson, "Privacy Enhancement for Internet Electronic
+Mail: Part III: Algorithms, Modes, and Identifiers", RFC 1423,
+October 1993
+
+[RFC1641] Goldsmith, D., and M. Davis, "Using Unicode with MIME", RFC
+1641, Taligent inc., July 1994.
+
+[RFC1750] Eastlake, Crocker, & Schiller., Randomness Recommendations
+for Security. December 1994.
+
+[RFC1951] Deutsch, P., DEFLATE Compressed Data Format Specification
+version 1.3. May 1996.
+
+[RFC1983] G. Malkin., Internet Users' Glossary. August 1996.
+
+[RFC1991] Atkins, D., Stallings, W., and P. Zimmermann, "PGP Message
+Exchange Formats", RFC 1991, August 1996.
+
+[RFC2015] Elkins, M., "MIME Security with Pretty Good Privacy (PGP)",
+RFC 2015, October 1996.
+
+[RFC2044] F. Yergeau., UTF-8, a transformation format of Unicode and
+ISO 10646. October 1996.
+
+[RFC2045] Borenstein, N., and Freed, N., "Multipurpose Internet Mail
+Extensions (MIME) Part One: Format of Internet Message Bodies.",
+November 1996
+
+[RFC2119] Bradner, S., Key words for use in RFCs to Indicate
+Requirement Level. March 1997.
+
+12. Full Copyright Statement
+
+
+
+Callas, et. al. Expires May 1998 [Page 39]
+ Internet Draft OpenPGP Message Format Nov 1998
+
+
+Copyright 1997 by The Internet Society. All Rights Reserved.
+
+This document and translations of it may be copied and furnished to
+others, and derivative works that comment on or otherwise explain it or
+assist in its implementation may be prepared, copied, published and
+distributed, in whole or in part, without restriction of any kind,
+provided that the above copyright notice and this paragraph are
+included on all such copies and derivative works. However, this
+document itself may not be modified in any way, such as by removing the
+copyright notice or references to the Internet Society or other
+Internet organizations, except as needed for the purpose of developing
+Internet standards in which case the procedures for copyrights defined
+in the Internet Standards process must be followed, or as required to
+translate it into languages other than English.
+
+The limited permissions granted above are perpetual and will not be
+revoked by the Internet Society or its successors or assigns.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Callas, et. al. Expires May 1998 [Page 40]
diff --git a/Protocol/PGP/Info/penguin1.tgz b/Protocol/PGP/Info/penguin1.tgz
new file mode 100644
index 0000000..db1b947
--- /dev/null
+++ b/Protocol/PGP/Info/penguin1.tgz
Binary files differ
diff --git a/Protocol/PGP/Info/pgformat.doc b/Protocol/PGP/Info/pgformat.doc
new file mode 100644
index 0000000..a2c97f3
--- /dev/null
+++ b/Protocol/PGP/Info/pgformat.doc
@@ -0,0 +1,343 @@
+File Formats Used by PGP 2.6 (22 May 94)
+========================================
+
+***Note: packets that contain a version byte of 2 will contain a version
+ byte of 3 when using versions of PGP >= 2.6 after 9/1/94.
+
+This appendix describes the file formats used externally by Pretty
+Good Privacy (PGP), the RSA public key cryptography application. The
+intended audience includes software engineers trying to port PGP to
+other hardware environments or trying to implement other PGP-
+compatible cryptography products, or anyone else who is curious.
+
+[To be included: a description of ASCII armor. An ASCII armored
+file is just like a binary file described here, but with an extra
+layer of encoding added, framing lines, and a 24-bit CRC at the end.]
+
+
+Byte Order
+----------
+
+All integer data used by PGP is externally stored most significant byte
+(MSB) first, regardless of the byte order used internally by the host
+CPU architecture. This is for portability of messages and keys between
+hosts. This covers multiprecision RSA integers, bit count prefix
+fields, byte count prefix fields, checksums, key IDs, and timestamps.
+
+The MSB-first byte order for external packet representation was
+chosen only because many other crypto standards use it.
+
+
+Multiprecision Integers
+-----------------------
+
+RSA arithmetic involves a lot of multiprecision integers, often
+having hundreds of bits of precision. PGP externally stores a
+multiprecision integer (MPI) with a 16-bit prefix that gives the
+number of significant bits in the integer that follows. The integer
+that follows this bitcount field is stored in the usual byte order,
+with the MSB padded with zero bits if the bitcount is not a multiple
+of 8. The bitcount always specifies the exact number of significant
+bits. For example, the integer value 5 would be stored as these
+three bytes:
+
+ 00 03 05
+
+An MPI with a value of zero is simply stored with the 16-bit bitcount
+prefix field containing a 0, with no value bytes following it.
+
+
+
+Key ID
+------
+
+Some packets use a "key ID" field. The key ID is the least
+significant 64 bits of the RSA public modulus that was involved in
+creating the packet. For all practical purposes it unique to each
+RSA public key.
+
+
+User ID
+-------
+
+Some packets contain a "user ID", which is an ASCII string that
+contains the user's name. Unlike a C string, the user ID has a
+length byte at the beginning that has a byte count of the rest of the
+string. This length byte does not include itself in the count.
+
+
+Timestamp
+---------
+
+Some packets contain a timestamp, which is a 32-bit unsigned integer
+of the number of seconds elapsed since 1970 Jan 1 00:00:00 GMT. This
+is the standard format used by Unix timestamps. It spans 136 years.
+
+
+
+Cipher Type Byte (CTB)
+----------------------
+
+Many of these data structures begin with a Cipher Type Byte (CTB),
+which specifies the type of data structure that follows it. The CTB
+bit fields have the following meaning (bit 0 is the LSB, bit 7 is the
+MSB):
+
+Bit 7: Always 1, which designates this as a CTB
+Bit 6: Reserved.
+Bits 5-2: CTB type field, specifies type of packet that follows
+ 0001 - public-key-encrypted packet
+ 0010 - secret-key-encrypted (signature) packet
+ 0101 - Secret key certificate
+ 0110 - Public key certificate
+ 1000 - Compressed data packet
+ 1001 - Conventional-Key-Encrypted data
+ 1011 - Raw literal plaintext data, with filename and mode
+ 1100 - Keyring trust packet
+ 1101 - User ID packet, associated with public or secret key
+ 1110 - Comment packet
+ Other CTB packet types are unimplemented.
+Bits 1-0: Length-of-length field:
+ 00 - 1 byte packet length field follows CTB
+ 01 - 2 byte packet length field follows CTB
+ 10 - 4 byte packet length field follows CTB
+ 11 - no length field follows CTB, unknown packet length.
+ The 8-, 16-, or 32-bit packet length field after the CTB
+ gives the length in bytes of the rest of the packet, not
+ counting the CTB and the packet length field.
+
+
+
+RSA public-key-encrypted packet
+-------------------------------
+
+Offset Length Meaning
+0 1 CTB for RSA public-key-encrypted packet
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte (=2). May affect rest of fields that follow.
+4 8 64-bit Key ID
+12 1 Algorithm byte for RSA (=1 for RSA).
+ --Algorithm byte affects field definitions that follow.
+13 ? RSA-encrypted integer, encrypted conventional key
+ packet. (MPI with bitcount prefix)
+
+The conventionally-encrypted ciphertext packet begins right after the
+RSA public-key-encrypted packet that contains the conventional key.
+
+
+
+Signature packet
+----------------
+
+Offset Length Meaning
+0 1 CTB for secret-key-encrypted (signed) packet
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte (=2). May affect rest of fields that follow.
+ Version byte (=3) for >= PGP2.6 after 9/1/94
+4 1 Length of following material that is implicitly included
+ in MD calculation (=5).
+5 1 Signature classification field (see below).
+ Implicitly append this to message for MD calculation.
+6 4 32-bit timestamp of when signature was made.
+ Implicitly append this to message for MD calculation.
+10 8 64-bit Key ID
+18 1 Algorithm byte for public key scheme (RSA=0x01).
+ --Algorithm byte affects field definitions that follow.
+19 1 Algorithm byte for message digest (MD5=0x01).
+20 2 First 2 bytes of the Message Digest inside the
+ RSA-encrypted integer, to help us figure out if we
+ used the right RSA key to check the signature.
+22 ? RSA-encrypted integer, encrypted message digest
+ (MPI with bitcount prefix).
+
+If the plaintext that was signed is included in the same file as the
+signature packet, it begins right after the RSA secret-key-signed
+packet that contains the message digest. The plaintext has a
+"literal" CTB prefix.
+
+The original idea had a variable length field following the length
+of following material byte, before the Key ID. In particular, the
+possibility of a 2-byte validity period was defined, although no
+previous version of PGP ever generated those bytes.
+
+Owing to the way the MD5 is computed for the signature, if that field
+is variable length, it is possible to generate two different messages
+with the same MD5 hash. One would be a file of length N, with a 7-byte
+following section consisting of a signature type byte, 4 bytes of
+timestamp, and 2 of validity period, while the other would be a file of
+length N+2, whose last two bytes would be the siganture type byte and
+the first byte of timestamp, and the last three bytes of timestamp and
+the validity period would instead be interpreted as a signature type
+byte and a timestmap.
+
+It should be emphasized that the messages are barely different and
+special circumstances must arise for this to be possible, so it is
+extremely unlilely that this would be exploitable, but it is a
+potential weakness. It has been plugged by allowing only the currently
+implemented 5-byte option. Validity periods will be added later with
+a different format.
+
+The signature classification field describes what kind of
+signature certificate this is. There are various hex values:
+ 00 - Signature of a message or document, binary image.
+ 01 - Signature of a message or document, canonical text.
+ 10 - Key certification, generic. Only version of key
+ certification supported by PGP 2.5.
+ Material signed is public key pkt and User ID pkt.
+ 11 - Key certification, persona. No attempt made at all
+ to identify the user with a real name.
+ Material signed is public key pkt and User ID pkt.
+ 12 - Key certification, casual identification. Some
+ casual attempt made to identify user with his name.
+ Material signed is public key pkt and User ID pkt.
+ 13 - Key certification, positive ID. Heavy-duty
+ identification efforts, photo ID, direct contact
+ with personal friend, etc.
+ Material signed is public key pkt and User ID pkt.
+ 20 - Key compromise. User signs his own compromise
+ certificate. Independent of user ID associations.
+ Material signed is public key pkt ONLY.
+ 30 - Key/userid revocation. User can sign his own
+ revocation to dissolve an association between a key
+ and a user ID, or certifier may revoke his previous
+ certification of this key/userid pair.
+ Material signed is public key pkt and User ID pkt.
+ 40 - Timestamping a signature certificate made by someone
+ else. Can be used to apply trusted timestamp, and
+ log it in notary's log. Signature of a signature.
+ (Planned, not implemented.)
+
+When a signature is made to certify a key/UserID pair, it is computed
+across two packets-- the public key packet, and the separate User ID
+packet. See below.
+
+The packet headers (CTB and length fields) for the public key packet
+and the user ID packet are both omitted from the signature
+calculation for a key certification.
+
+A key compromise certificate may be issued by someone to revoke his
+own key when his secret key is known to be compromised. If that
+happens, a user would sign his own key compromise certificate with
+the very key that is being revoked. A key revoked by its own
+signature means that this key should never be used or trusted again,
+in any form, associated with any user ID. A key compromise
+certificate issued by the keyholder shall take precedence over any
+other key certifications made by anyone else for that key. A key
+compromise signed by someone other than the key holder is invalid.
+
+Note that a key compromise certificate just includes the key packet
+in its signature calculation, because it kills the whole key without
+regard to any userid associations. It isn't tied to any particular
+userid association. It should be inserted after the key packet,
+before the first userid packet.
+
+When a key compromise certificate is submitted to PGP, PGP will place
+it on the public keyring. A key compromise certificate is always
+accompanied in its travels by the public key and userIDs it affects.
+If the affected key is NOT already on the keyring, the compromise
+certificate (and its key and user ID) is merely added to the keyring
+anywhere. If the affected key IS already on the keyring, the
+compromise certificate is inserted after the affected key packet.
+This assumes that the actual key packet is identical to the one
+already on the key ring, so no duplicate key packet is needed.
+If a key has been revoked, PGP will not allow its use to encipher any
+messages, and if an incoming signature uses it, PGP will display a
+stern warning that this key has been revoked.
+
+NOTE: Key/userid revocation certificates ARE NOT SUPPORTED in
+this version of PGP. But if we ever get around to supporting them,
+here are some ideas on how they should work...
+
+A key/userid revocation certificate may be issued by someone to
+dissolve the association between his own key and a user ID. He would
+sign it with the very key that is being revoked. A key/userid
+revocation certificate issued by the keyholder shall take precedence
+over any other key certifications made by anyone else for that
+key/userid pair. Also, a third party certifier may revoke his own
+previous certification of this key/userid pair by issuing a
+key/userid revocation certificate. Such a revocation should not
+affect the certifications by other third parties for this same
+key/userid pair.
+
+When a key/userid revocation certificate is submitted to PGP, PGP
+will place it on the public keyring. A key/userid revocation
+certificate is always accompanied in its travels by the public key it
+affects (the key packet and user ID packet precedes the revocation
+certificate). If the affected key is NOT already on the keyring, the
+revocation certificate (and its key and user ID) is merely added to
+the keyring anywhere. If the affected key IS already on the keyring,
+the revocation certificate is integrated in with the key's other
+certificates as though it were just another key certification. This
+assumes that the actual key packet is identical to the one already on
+the key ring, so no duplicate key packet is needed.
+
+
+
+Message digest "packet"
+-----------------------
+
+The Message digest has no CTB packet framing. It is stored
+packetless and naked, with padding, encrypted inside the MPI in the
+Signature packet.
+
+PGP versions 2.3 and later use a new format for encoding the message
+digest into the MPI in the signature packet, a format which is
+compatible with RFC1425 (formerly RFC1115). This format is accepted
+but not written by version 2.2. The older format used by versions 2.2
+is acepted by versions up to 2.4, but the RSAREF code in 2.5 is
+not capable of parsing it.
+
+PGP versions 2.2 and earlier encode the MD into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 MD(16 bytes) 0 FF(n bytes) 1
+
+Enough bytes of FF padding are added to make the length of this
+whole string equal to the number of bytes in the modulus.
+
+PGP versions 2.3 and later encode the MD into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 FF(n bytes) 0 ASN(18 bytes) MD(16 bytes)
+
+See RFC1423 for an explanation of the meaning of the ASN string.
+It is the following 18 byte long hex value:
+
+ 3020300c06082a864886f70d020505000410
+
+Enough bytes of FF padding are added to make the length of this
+whole string equal to the number of bytes in the modulus.
+
+All this mainly affects the rsa_private_encrypt() and rsa_public_decrypt()
+functions in rsaglue.c.
+
+There is no checksum included. The padding serves to verify that the
+correct RSA key was used.
+
+
+Conventional Data Encryption Key (DEK) "packet"
+-----------------------------------------------
+
+The DEK has no CTB packet framing. The DEK is stored packetless and
+naked, with padding, encrypted inside the MPI in the RSA
+public-key-encrypted packet.
+
+PGP versions 2.3 and later use a new format for encoding the message
+digest into the MPI in the signature packet. (This format is not
+presently based on any RFCs due to the use of the IDEA encryption
+system.) This format is accepted but not written by version 2.2. The
+older format used by versions 2.2 and earlier is also accepted by
+versions up to 2.4, but the RSAREF code in 2.5 is unable to cope
+with it.
+
+PGP versions 2.2 and earlier encode the MD into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
+
+CSUM refers to a 16-bit checksum appended to the high end of the DEK.
+RND is a string of NONZERO pseudorandom bytes, enough to make the length
+of t \ No newline at end of file
diff --git a/Protocol/PGP/Info/pgpdoc1.txt b/Protocol/PGP/Info/pgpdoc1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Protocol/PGP/Info/pgpdoc1.txt
diff --git a/Protocol/PGP/Info/pgpdoc2.txt b/Protocol/PGP/Info/pgpdoc2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Protocol/PGP/Info/pgpdoc2.txt
diff --git a/Protocol/PGP/Info/rfc1991.txt b/Protocol/PGP/Info/rfc1991.txt
new file mode 100644
index 0000000..aa50183
--- /dev/null
+++ b/Protocol/PGP/Info/rfc1991.txt
@@ -0,0 +1,1179 @@
+
+
+
+
+
+
+Network Working Group D. Atkins
+Request for Comments: 1991 MIT
+Category: Informational W. Stallings
+ Comp-Comm Consulting
+ P. Zimmermann
+ Boulder Software Engineering
+ August 1996
+
+
+ PGP Message Exchange Formats
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+Table of Contents
+
+ 1. Introduction............................................2
+ 2. PGP Services............................................2
+ 2.1 Digital signature.......................................3
+ 2.2 Confidentiality.........................................3
+ 2.3 Compression.............................................4
+ 2.4 Radix-64 conversion.....................................4
+ 2.4.1 ASCII Armor Formats.....................................5
+ 3. Data Element Formats....................................6
+ 3.1 Byte strings............................................6
+ 3.2 Whole number fields.....................................7
+ 3.3 Multiprecision fields...................................7
+ 3.4 String fields...........................................8
+ 3.5 Time fields.............................................8
+ 4. Common Fields...........................................8
+ 4.1 Packet structure fields.................................8
+ 4.2 Number ID fields.......................................10
+ 4.3 Version fields.........................................10
+ 5. Packets................................................10
+ 5.1 Overview...............................................10
+ 5.2 General Packet Structure...............................11
+ 5.2.1 Message component......................................11
+ 5.2.2 Signature component....................................11
+ 5.2.3 Session key component..................................11
+ 6. PGP Packet Types.......................................12
+ 6.1 Literal data packets...................................12
+ 6.2 Signature packets......................................13
+ 6.2.1 Message-digest-related fields..........................14
+ 6.2.2 Public-key-related fields..............................15
+ 6.2.3 RSA signatures.........................................16
+
+
+
+Atkins, et. al. Informational [Page 1]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ 6.2.4 Miscellaneous fields...................................16
+ 6.3 Compressed data packets................................17
+ 6.4 Conventional-key-encrypted data packets................17
+ 6.4.1 Conventional-encryption type byte......................18
+ 6.5 Public-key-encrypted packets...........................18
+ 6.5.1 RSA-encrypted data encryption key (DEK)................19
+ 6.6 Public-key Packets.....................................19
+ 6.7 User ID packets........................................20
+ 7. Transferable Public Keys...............................20
+ 8. Acknowledgments........................................20
+ 9. Security Considerations................................21
+ 10. Authors' Addresses.....................................21
+
+1. Introduction
+
+ PGP (Pretty Good Privacy) uses a combination of public-key and
+ conventional encryption to provide security services for electronic
+ mail messages and data files. These services include confidentiality
+ and digital signature. PGP is widely used throughout the global
+ computer community. This document describes the format of "PGP
+ files", i.e., messages that have been encrypted and/or signed with
+ PGP.
+
+ PGP was created by Philip Zimmermann and first released, in Version
+ 1.0, in 1991. Subsequent versions have been designed and implemented
+ by an all-volunteer collaborative effort under the design guidance of
+ Philip Zimmermann. PGP and Pretty Good Privacy are trademarks of
+ Philip Zimmermann.
+
+ This document describes versions 2.x of PGP. Specifically, versions
+ 2.6 and 2.7 conform to this specification. Version 2.3 conforms to
+ this specification with minor differences.
+
+ A new release of PGP, known as PGP 3.0, is anticipated in 1995. To
+ the maximum extent possible, this version will be upwardly compatible
+ with version 2.x. At a minimum, PGP 3.0 will be able to read messages
+ and signatures produced by version 2.x.
+
+2. PGP Services
+
+ PGP provides four services related to the format of messages and data
+ files: digital signature, confidentiality, compression, and radix-64
+ conversion.
+
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 2]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+2.1 Digital signature
+
+ The digital signature service involves the use of a hash code, or
+ message digest, algorithm, and a public-key encryption algorithm. The
+ sequence is as follows:
+
+ -the sender creates a message
+ -the sending PGP generates a hash code of the message
+ -the sending PGP encrypts the hash code using the sender's private
+ key
+ -the encrypted hash code is prepended to the message
+ -the receiving PGP decrypts the hash code using the sender's public
+ key
+ -the receiving PGP generates a new hash code for the received
+ message and compares it to the decrypted hash code. If the two
+ match, the message is accepted as authentic
+
+ Although signatures normally are found attached to the message or
+ file that they sign, this is not always the case: detached signatures
+ are supported. A detached signature may be stored and transmitted
+ separately from the message it signs. This is useful in several
+ contexts. A user may wish to maintain a separate signature log of all
+ messages sent or received. A detached signature of an executable
+ program can detect subsequent virus infection. Finally, detached
+ signatures can be used when more than one party must sign a document,
+ such as a legal contract. Each person's signature is independent and
+ therefore is applied only to the document. Otherwise, signatures
+ would have to be nested, with the second signer signing both the
+ document and the first signature, and so on.
+
+2.2 Confidentiality
+
+ PGP provides confidentiality by encrypting messages to be transmitted
+ or data files to be stored locally using conventional encryption. In
+ PGP, each conventional key is used only once. That is, a new key is
+ generated as a random 128-bit number for each message. Since it is to
+ be used only once, the session key is bound to the message and
+ transmitted with it. To protect the key, it is encrypted with the
+ receiver's public key. The sequence is as follows:
+
+ -the sender creates a message
+ -the sending PGP generates a random number to be used as a session
+ key for this message only
+ -the sending PGP encrypts the message using the session key
+ -the session key is encrypted using the recipient's public key and
+ prepended to the encrypted message
+ -the receiving PGP decrypts the session key using the recipient's
+ private key
+
+
+
+Atkins, et. al. Informational [Page 3]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ -the receiving PGP decrypts the message using the session key
+
+ Both digital signature and confidentiality services may be applied to
+ the same message. First, a signature is generated for the message and
+ prepended to the message. Then, the message plus signature is
+ encrypted using a conventional session key. Finally, the session key
+ is encrypted using public-key encryption and prepended to the
+ encrypted block.
+
+2.3 Compression
+
+ As a default, PGP compresses the message after applying the signature
+ but before encryption.
+
+2.4 Radix-64 conversion
+
+ When PGP is used, usually part of the block to be transmitted is
+ encrypted. If only the signature service is used, then the message
+ digest is encrypted (with the sender's private key). If the
+ confidentiality service is used, the message plus signature (if
+ present) are encrypted (with a one-time conventional key). Thus, part
+ or all of the resulting block consists of a stream of arbitrary 8-bit
+ bytes. However, many electronic mail systems only permit the use of
+ blocks consisting of ASCII text. To accommodate this restriction, PGP
+ provides the service of converting the raw 8-bit binary stream to a
+ stream of printable ASCII characters, called ASCII Armor.
+
+ The scheme used for this purpose is radix-64 conversion. Each group
+ of three bytes of binary data is mapped into 4 ASCII characters. This
+ format also appends a CRC to detect transmission errors. This
+ radix-64 conversion, also called Ascii Armor, is a wrapper around the
+ binary PGP messages, and is used to protect the binary messages
+ during transmission over non-binary channels, such as Internet Email.
+
+ The following table defines the mapping. The characters used are the
+ upper- and lower-case letters, the digits 0 through 9, and the
+ characters + and /. The carriage-return and linefeed characters
+ aren't used in the conversion, nor is the tab or any other character
+ that might be altered by the mail system. The result is a text file
+ that is "immune" to the modifications inflicted by mail systems.
+
+
+
+
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 4]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ 6-bit character 6-bit character 6-bit character 6-bit character
+ value encoding value encoding value encoding value encoding
+ 0 A 16 Q 32 g 48 w
+ 1 B 17 R 33 h 49 x
+ 2 C 18 S 34 i 50 y
+ 3 D 19 T 35 j 51 z
+ 4 E 20 U 36 k 52 0
+ 5 F 21 V 37 l 53 1
+ 6 G 22 W 38 m 54 2
+ 7 H 23 X 39 n 55 3
+ 8 I 24 Y 40 o 56 4
+ 9 J 25 Z 41 p 57 5
+ 1 K 26 a 42 q 58 6
+ 11 L 27 b 43 r 59 7
+ 12 M 28 c 44 s 60 8
+ 13 N 29 d 45 t 61 9
+ 14 O 30 e 46 u 62 +
+ 15 P 31 f 47 v 63 /
+ (pad) =
+
+ It is possible to use PGP to convert any arbitrary file to ASCII
+ Armor. When this is done, PGP tries to compress the data before it
+ is converted to Radix-64.
+
+2.4.1 ASCII Armor Formats
+
+ When PGP encodes data into ASCII Armor, it puts specific headers
+ around the data, so PGP can reconstruct the data at a future time.
+ PGP tries to inform the user what kind of data is encoded in the
+ ASCII armor through the use of the headers.
+
+ ASCII Armor is created by concatenating the following data:
+
+ - An Armor Headerline, appropriate for the type of data
+ - Armor Headers
+ - A blank line
+ - The ASCII-Armored data
+ - An Armor Checksum
+ - The Armor Tail (which depends on the Armor Headerline).
+
+ An Armor Headerline is composed by taking the appropriate headerline
+ text surrounded by five (5) dashes (-) on either side of the
+ headerline text. The headerline text is chosen based upon the type
+ of data that is being encoded in Armor, and how it is being encoded.
+ Headerline texts include the following strings:
+
+ BEGIN PGP MESSAGE -- used for signed, encrypted, or compressed files
+ BEGIN PGP PUBLIC KEY BLOCK -- used for transferring public keys
+
+
+
+Atkins, et. al. Informational [Page 5]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ BEGIN PGP MESSAGE, PART X/Y -- used for multi-part messages, where
+ the armor is split amongst Y files,
+ and this is the Xth file out of Y.
+
+ The Armor Headers are pairs of strings that can give the user or the
+ receiving PGP program some information about how to decode or use the
+ message. The Armor Headers are a part of the armor, not a part of
+ the message, and hence should not be used to convey any important
+ information, since they can be changed in transport.
+
+ The format of an Armor Header is that of a key-value pair, the
+ encoding of RFC-822 headers. PGP should consider improperly
+ formatted Armor Headers to be corruption of the ASCII Armor. Unknown
+ Keys should be reported to the user, but so long as the RFC-822
+ formatting is correct, PGP should continue to process the message.
+ Currently defined Armor Header Keys include "Version" and "Comment",
+ which define the PGP Version used to encode the message and a user-
+ defined comment.
+
+ The Armor Checksum is a 24-bit CRC converted to four bytes of radix-
+ 64 encoding, prepending an equal-sign (=) to the four-byte code. The
+ CRC is computed by using the generator 0x864CFB and an initialization
+ of 0xB704CE. The accumulation is done on the data before it is
+ converted to radix-64, rather than on the converted data. For more
+ information on CRC functions, the reader is asked to look at chapter
+ 19 of the book "C Programmer's Guide to Serial Communications," by
+ Joe Campbell.
+
+ The Armor Tail is composed in the same manner as the Armor
+ Headerline, except the string "BEGIN" is replaced by the string
+ "END".
+
+3. Data Element Formats
+
+3.1 Byte strings
+
+ The objects considered in this document are all "byte strings." A
+ byte string is a finite sequence of bytes. The concatenation of byte
+ string X of length M with byte string Y of length N is a byte string
+ Z of length M + N; the first M bytes of Z are the bytes of X in the
+ same order, and the remaining N bytes of Z are the bytes of Y in the
+ same order.
+
+ Literal byte strings are written from left to right, with pairs of
+ hex nibbles separated by spaces, enclosed by angle brackets: for
+ instance, <05 ff 07> is a byte string of length 3 whose bytes have
+ numeric values 5, 255, and 7 in that order. All numbers in this
+ document outside angle brackets are written in decimal.
+
+
+
+Atkins, et. al. Informational [Page 6]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ The byte string of length 0 is called "empty" and written <>.
+
+3.2 Whole number fields
+
+ Purpose. A whole number field can represent any nonnegative integer,
+ in a format where the field length is known in advance.
+
+ Definition. A whole number field is any byte string. It is stored
+ in radix-256 MSB-first format. This means that a whole number field
+ of length N with bytes b_0 b_1 ... b_{N-2} b_{N-1} in that order has
+ value
+
+ b_0 * 256^{N-1} + b_1 * 256^{N-2} + ... + b_{N-2} * 256 + b_{N-1}.
+
+ Examples. The byte string <00 0D 64 11 00 00> is a valid whole
+ number field with value 57513410560. The byte string <FF> is a valid
+ whole number field with value 255. The byte string <00 00> is a
+ valid whole number field with value 0. The empty byte string <> is a
+ valid whole number field with value 0.
+
+3.3 Multiprecision fields
+
+ Purpose. A multiprecision field can represent any nonnegative
+ integer which is not too large. The field length need not be known
+ in advance. Multiprecision fields are designed to waste very little
+ space: a small integer uses a short field.
+
+ Definition. A multiprecision field is the concatenation of two
+ fields:
+
+ (a) a whole number field of length 2, with value B;
+ (b) a whole number field, with value V.
+
+ Field (b) is of length [(B+7)/8], i.e., the greatest integer which is
+ no larger than (B+7)/8. The value of the multiprecision field is
+ defined to be V. V must be between 2^{B-1} and 2^B - 1 inclusive.
+ In other words B must be exactly the number of significant bits in V.
+
+ Some implementations may limit the possible range of B. The
+ implementor must document which values of B are allowed by an
+ implementation.
+
+ Examples. The byte string <00 00> is a valid multiprecision integer
+ with value 0. The byte string <00 03 05> is a valid multiprecision
+ field with value 5. The byte strings <00 03 85> and <00 00 00> are
+ not valid multiprecision fields. The former is invalild because <85>
+ has 8 significant bits, not 3; the latter is invalid because the
+ second field has too many bytes of data given the value of the first
+
+
+
+Atkins, et. al. Informational [Page 7]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ field. The byte string <00 09 01 ff> is a valid multiprecision field
+ with value 511. The byte string <01 00 80 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 07> is
+ a valid multiprecision field with value 2^255 + 7.
+
+3.4 String fields
+
+ Purpose. A string field represents any sequence of bytes of length
+ between 0 and 255 inclusive. The length need not be known in
+ advance. By convention, the content of a string field is normally
+ interpreted as ASCII codes when it is displayed.
+
+ Definition. A string field is the concatenation of the following:
+
+ (a) a whole number field of length 1, with value L;
+ (b) a byte string of length L.
+
+ The content of the string field is defined to be field (b).
+
+ Examples: <05 48 45 4c 4c 4f> is a valid string field which would
+ normally be displayed as the string HELLO. <00> is a valid string
+ field which would normally be displayed as the empty string. <01 00>
+ is a valid string field.
+
+3.5 Time fields
+
+ Purpose. A time field represents the number of seconds elapsed since
+ 1970 Jan 1 00:00:00 GMT. It is compatible with the usual
+ representation of times under UNIX.
+
+ Definition. A time field is a whole number field of length 4, with
+ value V. The time represented by the time field is the one-second
+ interval beginning V seconds after 1970 Jan 1 00:00:00 GMT.
+
+4. Common Fields
+
+ This section defines fields found in more than one packet format.
+
+4.1 Packet structure fields
+
+ Purpose. The packet structure field distinguishes between different
+ types of packets, and indicates the length of packets.
+
+ Definition. A packet structure field is a byte string of length 1,
+ 2, 3, or 5. Its first byte is the cipher type byte (CTB), with bits
+ labeled 76543210, 7 the most significant bit and 0 the least
+ significant bit. As indicated below the length of the packet
+ structure field is determined by the CTB.
+
+
+
+Atkins, et. al. Informational [Page 8]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ CTB bits 76 have values listed in the following table:
+
+ 10 - normal CTB
+ 11 - reserved for future experimental work
+ all others - reserved
+
+ CTB bits 5432, the "packet type bits", have values listed in the
+ following table:
+
+ 0001 - public-key-encrypted packet
+ 0010 - signature packet
+ 0101 - secret-key certificate packet
+ 0110 - public-key certificate packet
+ 1000 - compressed data packet
+ 1001 - conventional-key-encrypted packet
+ 1011 - literal data packet
+ 1100 - keyring trust packet
+ 1101 - user id packet
+ 1110 - comment packet (*)
+ all others - reserved
+
+ CTB bits 10, the "packet-length length bits", have values listed in
+ the following table:
+
+ 00 - 1-byte packet-length field
+ 01 - 2-byte packet-length field
+ 10 - 4-byte packet-length field
+ 11 - no packet length supplied, unknown packet length
+
+ As indicated in this table, depending on the packet-length length
+ bits, the remaining 1, 2, 4, or 0 bytes of the packet structure field
+ are a "packet-length field". The packet-length field is a whole
+ number field. The value of the packet-length field is defined to be
+ the value of the whole number field.
+
+ A value of 11 is currently used in one place: on compressed data.
+ That is, a compressed data block currently looks like <A3 01 . . .>,
+ where <A3>, binary 10 1000 11, is an indefinite-length packet. The
+ proper interpretation is "until the end of the enclosing structure",
+ although it should never appear outermost (where the enclosing
+ structure is a file).
+
+ Options marked with an asterisk (*) are not implemented yet; PGP
+ 2.6.2 will never output this packet type.
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 9]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+4.2 Number ID fields
+
+ Purpose. The ID of a whole number is its 64 least significant bits.
+ The ID is a convenient way to distinguish between large numbers such
+ as keys, without having to transmit the number itself. Thus, a number
+ that may be hundreds or thousands of decimal digits in length can be
+ identified with a 64-bit identifier. Two keys may have the same ID by
+ chance or by malice; although the probability that two large keys
+ chosen at random would have the same ID is extremely small.
+
+ Definition. A number ID field is a whole number field of length 8.
+ The value of the number ID field is defined to be the value of the
+ whole number field.
+
+4.3 Version fields
+
+ Many packet types include a version number as the first byte of the
+ body. The format and meaning of the body depend on the version
+ number. More versions of packets, with new version numbers, may be
+ defined in the future. An implementation need not support every
+ version of each packet type. However, the implementor must document
+ which versions of each packet type are supported by the
+ implementation.
+
+ A version number of 2 or 3 is currently allowed for each packet
+ format. New versions will probably be numbered sequentially up from
+ 3. For backwards compatibility, implementations will usually be
+ expected to support version N of a packet whenever they support
+ version N+1. Version 255 may be used for experimental purposes.
+
+5. Packets
+
+5.1 Overview
+
+ A packet is a digital envelope with data inside. A PGP file, by
+ definition, is the concatenation of one or more packets. In addition,
+ one or more of the packets in a file may be subject to a
+ transformation using encryption, compression, or radix-64 conversion.
+
+ A packet is the concatenation of the following:
+
+ (a) a packet structure field;
+ (b) a byte string of some length N.
+
+ Byte string (b) is called the "body" of the packet. The value of the
+ packet-length field inside the packet structure field (a) must equal
+ N, the length of the body.
+
+
+
+
+Atkins, et. al. Informational [Page 10]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ Other characteristics of the packet are determined by the type of the
+ packet. See the definitions of particular packet types for further
+ details. The CTB packet-type bits inside the packet structure always
+ indicate the packet type.
+
+ Note that packets may be nested: one digital envelope may be placed
+ inside another. For example, a conventional-key-encrypted packet
+ contains a disguised packet, which in turn might be a compressed data
+ packet.
+
+5.2 General packet structure
+
+ A pgp file consists of three components: a message component, a
+ signature (optional), and a session key component (optional).
+
+5.2.1 Message component
+
+ The message component includes the actual data to be stored or
+ transmitted as well as a header that includes control information
+ generated by PGP. The message component consists of a single literal
+ data packet.
+
+5.2.2 Signature component
+
+ The signature component is the signature of the message component,
+ formed using a hash code of the message component and the public key
+ of the sending PGP entity. The signature component consists of a
+ single signature packet.
+
+ If the default option of compression is chosen, then the block
+ consisting of the literal data packet and the signature packet is
+ compressed to form a compressed data packet.
+
+5.2.3 Session key component
+
+ The session key component includes the encrypted session key and the
+ identifier of the recipients public key used by the sender to encrypt
+ the session key. The session key component consists of a single
+ public-key-encrypted packet for each recipient of the message.
+
+ If compression has been used, then conventional encryption is applied
+ to the compressed data packet formed from the compression of the
+ signature packet and the literal data packet. Otherwise, conventional
+ encryption is applied to the block consisting of the signature packet
+ and the literal data packet. In either case, the cyphertext is
+ referred to as a conventional-key-encrypted data packet.
+
+
+
+
+
+Atkins, et. al. Informational [Page 11]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+6. PGP Packet Types
+
+ PGP includes the following types of packets:
+
+ -literal data packet
+ -signature packet
+ -compressed data packet
+ -conventional-key-encrypted data packet
+ -public-key-encrypted packet
+ -public-key packet
+ -User ID packet
+
+6.1 Literal data packets
+
+ Purpose. A literal data packet is the lowest level of contents of a
+ digital envelope. The data inside a literal data packet is not
+ subject to any further interpretation by PGP.
+
+ Definition. A literal data packet is the concatenation of the
+ following fields:
+
+ (a) a packet structure field;
+ (b) a byte, giving a mode;
+ (c) a string field, giving a filename;
+ (d) a time field;
+ (e) a byte string of literal data.
+
+
+ Fields (b), (c), and (d) suggest how the data should be written to a
+ file. Byte (b) is either ASCII b <62>, for binary, or ASCII t <74>,
+ for text. Byte (b) may also take on the value ASCII 1, indicating a
+ machine-local conversion. It is not defined how PGP will convert this
+ across platforms.
+
+ Field (c) suggests a filename. Field (d) should be the time at which
+ the file was last modified, or the time at which the data packet was
+ created, or 0.
+
+ Note that only field (e) of a literal data packet is fed to a
+ message-digest function for the formation of a signature. The
+ exclusion of the other fields ensures that detached signatures are
+ exactly the same as attached signatures prefixed to the message.
+ Detached signatures are calculated on a separate file that has none
+ of the literal data packet header fields.
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 12]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+6.2 Signature packet
+
+ Purpose. Signatures are attached to data, in such a way that only
+ one entity, called the "writer," can create the signature. The
+ writer must first create a "public key" K and distribute it. The
+ writer keeps certain private data related to K. Only someone
+ cooperating with the writer can sign data using K, enveloping the
+ data in a signature packet (also known as a private-key-encrypted
+ packet). Anyone can look through the glass in the envelope and
+ verify that the signature was attached to the data using K. If the
+ data is altered in any way then the verification will fail.
+
+ Signatures have different meanings. For example, a signature might
+ mean "I wrote this document," or "I received this document." A
+ signature packet includes a "classification" which expresses its
+ meaning.
+
+ Definition. A signature packet, version 2 or 3, is the concatenation
+ of the following fields:
+
+ (a) packet structure field (2, 3, or 5 bytes);
+ (b) version number = 2 or 3 (1 byte);
+ (c) length of following material included in MD calculation
+ (1 byte, always the value 5);
+ (d1) signature classification (1 byte);
+ (d2) signature time stamp (4 bytes);
+ (e) key ID for key used for singing (8 bytes);
+ (f) public-key-cryptosystem (PKC) type (1 byte);
+ (g) message digest algorithm type (1 byte);
+ (h) first two bytes of the MD output, used as a checksum
+ (2 bytes);
+ (i) a byte string of encrypted data holding the RSA-signed digest.
+
+ The message digest is taken of the bytes of the file, followed by the
+ bytes of field (d). It was originally intended that the length (c)
+ could vary, but now it seems that it will alwaye remain a constant
+ value of 5, and that is the only value that will be accepted. Thus,
+ only the fields (d1) and (d2) will be hashed into the signature along
+ with the main message.
+
+
+
+
+
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 13]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+6.2.1 Message-digest-related fields
+
+ The message digest algorithm is specified by the message digest (MD)
+ number of field (g). The following MD numbers are currently defined:
+
+ 1 - MD5 (output length 16)
+ 255 - experimental
+
+ More MD numbers may be defined in the future. An implementation need
+ not support every MD number. The implementor must document the MD
+ numbers understood by an implementation.
+
+ A message digest algorithm reads a byte string of any length, and
+ writes a byte string of some fixed length, as indicated in the table
+ above.
+
+ The input to the message digest algorithm is the concatenation of
+ some "primary input" and some "appended input."
+
+ The appended input is specified by field (c), which gives a number of
+ bytes to be taken from the following fields: (d1), (d2), and so on.
+ The current implementation uses the value 5 for this number, for
+ fields (d1) and (d2). Any field not included in the appended input
+ is not "signed" by field (i).
+
+ The primary input is determined by the signature classification byte
+ (d1). Byte (d1) is one of the following hex numbers, with these
+ meanings:
+
+ <00> - document signature, binary image ("I wrote this document")
+ <01> - document signature, canonical text ("I wrote this document")
+ <10> - public key packet and user ID packet, generic certification
+ ("I think this key was created by this user, but I won't say
+ how sure I am")
+ <11> - public key packet and user ID packet, persona certification
+ ("This key was created by someone who has told me that he is
+ this user") (#)
+ <12> - public key packet and user ID packet, casual certification
+ ("This key was created by someone who I believe, after casual
+ verification, to be this user") (#)
+ <13> - public key packet and user ID packet, positive certification
+ ("This key was created by someone who I believe, after
+ heavy-duty identification such as picture ID, to be this
+ user") (#)
+ <20> - public key packet, key compromise ("This is my key, and I
+ have revoked it")
+
+
+
+
+
+Atkins, et. al. Informational [Page 14]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ <30> - public key packet and user ID packet, revocation ("I retract
+ all my previous statements that this key is related to this
+ user") (*)
+ <40> - time stamping ("I saw this document") (*)
+
+ More classification numbers may be defined in the future to handle
+ other meanings of signatures, but only the above numbers may be used
+ with version 2 or version 3 of a signature packet. It should be
+ noted that PGP 2.6.2 has not implemented the packets marked with an
+ asterisk (*), and the packets marked with a hash (#) are not output
+ by PGP 2.6.2.
+
+ Signature packets are used in two different contexts. One (signature
+ type <00> or <01>) is of text (either the contents of a literal
+ packet or a separate file), while types <10> through <1F> appear only
+ in key files, after the keys and user IDs that they sign. Type <20>
+ appears in key files, after the keys that it signs, and type <30>
+ also appears after a key/userid combination. Type <40> is intended to
+ be a signature of a signature, as a notary seal on a signed document.
+
+ The output of the message digest algorithm is a message digest, or
+ hash code. Field i contains the cyphertext produced by encrypting the
+ message digest with the signer's private key. Field h contains the
+ first two bytes of the unencrypted message digest. This enables the
+ recipient to determine if the correct public key was used to decrypt
+ the message digest for authentication, by comparing this plaintext
+ copy of the first two byes with the first two bytes of the decrypted
+ digest. These two bytes also serve as a 16-bit frame check sequence
+ for the message.
+
+6.2.2 Public-key-related fields
+
+ The message digest is signed by encrypting it using the writer's
+ private key. Field (e) is the ID of the corresponding public key.
+
+ The public-key-encryption algorithm is specified by the public-key
+ cryptosystem (PKC) number of field (f). The following PKC numbers are
+ currently defined:
+
+ 1 - RSA
+ 255 - experimental
+
+ More PKC numbers may be defined in the future. An implementation
+ need not support every PKC number. The implementor must document the
+ PKC numbers understood by an implementation.
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 15]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ A PKC number identifies both a public-key encryption method and a
+ signature method. Both of these methods are fully defined as part of
+ the definition of the PKC number. Some cryptosystems are usable only
+ for encryption, or only for signatures; if any such PKC numbers are
+ defined in the future, they will be marked appropriately.
+
+6.2.3 RSA signatures
+
+ An RSA-signed byte string is a multiprecision field that is formed by
+ taking the message digest and filling in an ASN structure, and then
+ encrypting the whole byte string in the RSA key of the signer.
+
+ PGP versions 2.3 and later encode the MD into a PKCS-format signature
+ string, which has the following format:
+
+ MSB . . . LSB
+ 0 1 <FF>(n bytes) 0 ASN(18 bytes) MD(16 bytes)
+
+ See RFC1423 for an explanation of the meaning of the ASN string. It
+ is the following 18 byte long hex value:
+
+ <30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 05 05 00 04 10>
+
+ Enough bytes of <FF> padding are added to make the length of this
+ whole string equal to the number of bytes in the modulus.
+
+6.2.4 Miscellaneous fields
+
+ The timestamp field (d2) is analogous to the date box next to a
+ signature box on a form. It represents a time which is typically
+ close to the moment that the signature packet was created. However,
+ this is not a requirement. Users may choose to date their signatures
+ as they wish, just as they do now in handwritten signatures.
+
+ If an application requires the creation of trusted timestamps on
+ signatures, a detached signature certificate with an untrusted
+ timestamp may be submitted to a trusted timestamp notary service to
+ sign the signature packet with another signature packet, creating a
+ signature of a signature. The notary's signature's timestamp could
+ be used as the trusted "legal" time of the original signature.
+
+
+
+
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 16]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+6.3 Compressed data packets
+
+ Purpose. A compressed data packet is an envelope which safely
+ squeezes its contents into a small space.
+
+ Definition. A compressed data packet is the concatenation of the
+ following fields:
+
+ (a) a packet structure field;
+ (b) a byte, giving a compression type;
+ (c) a byte string of compressed data.
+
+ Byte string (c) is a packet which may be decompressed using the
+ algorithm identified in byte (b). Typically, the data that are
+ compressed consist of a literal data packet or a signature packet
+ concatenated to a literal data packet.
+
+ A compression type selects a compression algorithm for use in
+ compressed data packets. The following compression numbers are
+ currently defined.
+
+ 1 - ZIP
+ 255 - experimental
+
+ More compression numbers may be defined in the future. An
+ implementation need not support every MD number. The implementor
+ must document the compression numbers understood by an
+ implementation.
+
+6.4 Conventional-key-encrypted data packets
+
+ Purpose. A conventional-key-encrypted data packet is formed by
+ encrypting a block of data with a conventional encryption algorithm
+ using a one-time session key. Typically, the block to be encrypted is
+ a compressed data packet.
+
+ Definition. A conventional-key-encrypted data packet is the
+ concatenation of the following fields:
+
+ (a) a packet structure field;
+ (b) a byte string of encrypted data.
+
+ The plaintext or compressed plaintext that is encrypted to form field
+ (b) is first prepended with 64 bits of random data plus 16 "key
+ check" bits. The random prefix serves to start off the cipher
+ feedback chaining process with 64 bits of random material; this
+ serves the same function as an initialization vector (IV) for a
+ cipher-block-chaining encryption scheme. The key check prefix is
+
+
+
+Atkins, et. al. Informational [Page 17]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ equal to the last 16 bits of the random prefix. During decryption, a
+ comparison is made to see if the 7th and 8th byte of the decrypted
+ material match the 9th and 10th bytes. If so, then the conventional
+ session key used for decryption is assumed to be correct.
+
+6.4.1 Conventional-encryption type byte
+
+ Purpose. The conventional-encryption type byte is used to determine
+ what conventional encryption algorithm is in use. The algorithm type
+ byte will also define how long the conventional encryption key is,
+ based upon the algorithm in use.
+
+ Definition. A conventional-encryption type byte is a single byte
+ which defines the algorithm in use. It is possible that the
+ algorithm in use may require further definition, such as key-length.
+ It is up to the implementor to document the supported key-length in
+ such a situation.
+
+ 1 - IDEA (16-byte key)
+ 255 - experimental
+
+6.5 Public-key-encrypted packets
+
+ Purpose. The public-key-encrypted packet is the format for the
+ session key component of a message. The purpose of this packet is to
+ convey the one-time session key used to encrypt the message to the
+ recipient in a secure manner. This is done by encrypting the session
+ key with the recipient's public key, so that only the recipient can
+ recover the session key.
+
+ Definition. A public-key-encrypted packet, version 2 or 3, is the
+ concatenation of the following fields:
+
+ (a) a packet structure field;
+ (b) a byte, giving the version number, 2 or 3;
+ (c) a number ID field, giving the ID of a key;
+ (d) a byte, giving a PKC number;
+ (e) a byte string of encrypted data (DEK).
+
+ Byte string (e) represents the value of the session key, encrypted
+ using the reader's public key K, under the cryptosystem identified in
+ byte (d).
+
+ The value of field (c) is the ID of K.
+
+ Note that the packet does not actually identify K: two keys may have
+ the same ID, by chance or by malice. Normally it will be obvious
+ from the context which key K was used to create the packet. But
+
+
+
+Atkins, et. al. Informational [Page 18]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+ sometimes it is not obvious. In this case field (c) is useful. If,
+ for example, a reader has created several keys, and receives a
+ message, then he should attempt to decrypt the message only with the
+ key whose ID matches the value of field (c). If he has accidentally
+ generated two keys with the same ID, then he must attempt to decrypt
+ the message with both keys, but this case is highly unlikely to occur
+ by chance.
+
+6.5.1 RSA-encrypted data encryption key (DEK)
+
+ The Data Encryption Key (DEK) is a multiprecision field which stores
+ an RSA encrypted byte string. The byte string is a PKCS encoding of
+ the secret key used the encrypt the message, with random padding for
+ each Public-Key encrypted packet.
+
+ PGP version 2.3 and later encode the DEK into an MPI using the
+ following format:
+
+ MSB . . . LSB
+ 0 2 RND(n bytes) 0 ALG(1 byte) DEK(k bytes) CSUM(2 bytes)
+
+ ALG refers to the algorithm byte for the secret key algorithm used to
+ encrypt the data packet. The DEK is the actual Data Encryption Key,
+ and its size is dependent upon the encryption algorithm defined by
+ ALG. For the IDEA encryption algorithm, type byte 1, the DEK is 16
+ bytes long. CSUM is a 16-bit checksum of the DEK, used to determine
+ that the correct Private key was used to decrypt this packet. The
+ checksum is computed by the 16-bit sum of the bytes in the DEK. RND
+ is random padding to expand the byte to fill the size of the RSA
+ Public Key that is used to encrypt the whole byte.
+
+6.6 Public Key Packet
+
+ Purpose. A public key packet defines an RSA public key.
+
+ Definition. A public key packet is the concatenation of the
+ following fields:
+
+ (a) packet structure field (2 or 3 bytes);
+ (b) version number = 2 or 3 (1 byte);;
+ (c) time stamp of key creation (4 bytes);
+ (d) validity period in days (0 means forever) (2 bytes);
+ (e) public-key-cryptosystem (PKC) type (1 byte);
+ (f) MPI of RSA public modulus n;
+ (g) MPI of RSA public encryption exponent e.
+
+ The validity period is always set to 0.
+
+
+
+
+Atkins, et. al. Informational [Page 19]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+6.7 User ID Packet
+
+ Purpose. A user ID packet identifies a user and is associated with a
+ public or private key.
+
+ Definition. A user ID packet is the concatenation of the following
+ fields:
+
+ (a) packet structure field (2 bytes);
+ (b) User ID string.
+
+ The User ID string may be any string of printable ASCII characters.
+ However, since the purpose of this packet is to uniquely identify an
+ individual, the usual practice is for the User ID string to consist
+ of the user's name followed by an e-mail address for that user, the
+ latter enclosed in angle brackets.
+
+7. Transferable Public Keys
+
+ Public keys may transferred between PGP users. The essential elements
+ of a transferable public key are
+
+ (a) One public key packet;
+ (b) One or more user ID packets;
+ (c) Zero or more signature packets
+
+ The public key packet occurs first. Each of the following user ID
+ packets provides the identity of the owner of this public key. If
+ there are multiple user ID packets, this corresponds to multiple
+ means of identifying the same unique individual user; for example, a
+ user may enjoy the use of more than one e-mail address, and construct
+ a user ID packet for each one. Immediately following each user ID
+ packet, there are zero or more signature packets. Each signature
+ packet is calculated on the immediately preceding user ID packet and
+ the initial public key packet. The signature serves to certify the
+ corresponding public key and user ID. In effect, the signer is
+ testifying to his or her belief that this public key belongs to the
+ user identified by this user ID.
+
+8. Acknowledgments
+
+ Philip Zimmermann is the creator of PGP 1.0, which is the precursor
+ of PGP 2.x. Major parts of later versions of PGP have been
+ implemented by an international collaborative effort involving a
+ large number of contributors, under the design guidance of Philip
+ Zimmermann.
+
+
+
+
+
+Atkins, et. al. Informational [Page 20]
+
+RFC 1991 PGP Message Exchange Formats August 1996
+
+
+9. Security Considerations
+
+ Security issues are discussed throughout this memo.
+
+10. Authors' Addresses
+
+ Derek Atkins
+ 12 Rindge Ave. #1R
+ Cambridge, MA
+
+ Phone: +1 617 868-4469
+ EMail: warlord@MIT.EDU
+
+
+ William Stallings
+ Comp-Comm Consulting
+ P. O. Box 2405
+ Brewster, MA 02631
+
+ EMail: stallings@ACM.org
+
+
+ Philip Zimmermann
+ Boulder Software Engineering
+ 3021 Eleventh Street
+ Boulder, Colorado 80304 USA
+
+ Phone: +1-303-541-0140
+ EMail: prz@acm.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Atkins, et. al. Informational [Page 21]
+
diff --git a/Protocol/PGP/Info/scaleweb.txt b/Protocol/PGP/Info/scaleweb.txt
new file mode 100644
index 0000000..c072e01
--- /dev/null
+++ b/Protocol/PGP/Info/scaleweb.txt
@@ -0,0 +1,719 @@
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+ Scaling the Web of Trust:
+ Combining Kerberos and PGP to Provide Large Scale Authentication
+
+ Jeffrey I. Schiller
+ Massachusetts Institute of Technology
+
+ Derek Atkins
+ Massachusetts Institute of Technology
+
+Abstract
+
+Internet Security has become more important recently as the Internet
+grows exponentially and security breaches become more publicized. An
+important area of concern for many Internet users is the privacy and
+integrity of their electronic files and messages. Phil Zimmermann's
+Pretty Good Privacy (PGP) provides a general purpose utility for file
+and message protection. However PGP requires that communicating users be
+"introduced" to each other. This paper describes a scheme that permits
+an enterprise using Kerberos to create an automated introducer called
+the PGP Key Signer Service. Using this service people in the enterprise
+who have no common acquaintances to act as introducers can be introduced
+through the Key Signer.
+
+1. Introduction
+
+The Internet Community has grown from a small collection of Computer
+Science researchers into the International Information
+Infrastructure. Yet the security technology currently deployed on the
+Network reflects its original experimental roots. There are many and
+varied reasons why things are today the way they are. However, one of
+the key reasons is because most Internet users are unaware of the
+inherent lack of security on the net. When most people login using their
+password they assume that only they may use their computer
+accounts. Similarly when they send electronic mail they assume that only
+the marked recipients will see the message. When they receive electronic
+mail they assume that it originated from the person labeled in the
+"From" field of the message.
+
+As the Internet has grown, so has the quantity of security
+problems. Recently these problems have received significant publicity
+and the public's understanding of the lack of security is growing. With
+this growth in understanding comes a demand for security.
+
+Several systems now exist to provide security for computers and
+networks. Two of the more popular security programs are Kerberos [Kerb1,
+Kerb2] and PGP [PGP]. Kerberos is MIT's real time authentication system,
+it provides for the security of login sessions and client server
+transactions. PGP is Phil Zimmermann's "Pretty Good Privacy" public key
+encryption program. It provides for confidentiality and authentication
+of electronic mail (e-mail) and other "store and forward" types of
+transactions as well as encryption of private files.
+
+Each of these systems has its strengths, weaknesses and applicable
+problem domains. This paper will show how the two can be combined to
+provide a hybrid security service which neither alone can provide.
+
+In the sections that follow we will provide a brief introduction to PGP
+and Public Key Cryptography, the underlying technology that makes PGP
+possible. We will then briefly describe Kerberos. Readers who desire a
+more thorough background should read the papers referenced
+above. Finally we will discuss how PGP can make use of Kerberos in a
+significant way.
+
+1.1 The Problem with Electronic Mail
+
+SMTP, or Simple Mail Transport Protocol is the Internet standard for the
+delivery of electronic mail between computer systems. A tried and true
+protocol, it provides message services to millions of Internet users
+everyday. Yet it provides for no security services at all. Perhaps more
+to the point, SMTP servers believe that mail originates from where it
+claims to.
+
+Forging e-mail messages is child's play. On the MIT campus alone we have
+seen several independently written shell scripts that permit even the
+most novice of computer users to send forged messages that are
+indistinguishable form the real McCoy.
+
+An additional threat to e-mail is that very few networks are protected
+against eavesdroppers. Recently, bulletins form Carnegie Mellon's
+Computer Emergency Response Team (CERT) [1] have pointed out many
+incidents of computer crackers "sniffing" passwords from the Internet
+[CertSniff]. The same technology that provides for the sniffing of
+passwords can easily read e-mail in flight as well.
+
+Today the only thing protecting e-mail from these prying eyes is the
+sheer boredom that most e- mail represents! However as e-mail is used
+increasingly to discuss confidential corporate plans, commercial
+transactions and even credit card numbers, it will be a target for
+network eavesdroppers.
+
+Another important feature lacking in e-mail is the ability to prove
+after the fact that a message was "signed" by its sender. This ability
+is needed not only for casual proof of origination, but also for formal
+uses of e-mail such as electronic purchase orders, bid documents and
+other commercial interactions. Luckily there is a technology to address
+this requirement. Digital Signatures permit people to electronically
+sign documents in a fashion that allows anyone to prove that a document
+originated from whom it claims to have originated from.
+
+Digital Signatures are provided by Public Key Encryption systems such as
+the RSA [RSA] system. RSA is used by Internet Privacy Enhanced Mail
+[PEM] and by PGP. Its use in PGP will be discussed here.
+
+2. PGP
+
+PGP was written by Phil Zimmermann in 1991 in reaction to a move by the
+U.S. Federal Government to require providers of communication services
+to provide plaintext copies of encrypted information to the government
+upon its request. PGP was designed to make this impossible by providing
+a general purpose cryptographic utility which people can use to protect
+information that they keep for themselves (say in private files) and
+share with others (for example electronic mail). As such the primary
+focus of the development of PGP was on privacy.
+
+PGP provides privacy by using a combination of the IDEA [IDEA] symmetric
+cipher and the RSA public key system. PGP also includes the ability to
+make digital signatures. This makes PGP a complete electronic mail
+security tool. It provides confidentiality, authentication of
+origination and integrity protection for files and messages.
+
+PGP originally had patent difficulties. Because RSA is patented within
+the United States, users require a license from Public Key Partners or
+software from RSA Data Security in order to make use of PGP without the
+threat of legal action being taken against them. In addition,
+cryptographic systems, be they hardware or software, currently may not
+be exported from the United States without a license from the State
+Department Office of Defense Trade Controls.
+
+Version 2 of PGP was coded in Europe and imported into the United
+States. Starting in May, 1994 the Massachusetts Institute of Technology
+(MIT) has been distributing a version of PGP which includes the RSAREF
+software toolkit licensed from RSA Data Security. This release of PGP,
+although not exportable from the United States, provides non-commercial
+users of PGP a legally usable version. The ViaCrypt company [2] sells a
+commercial version that is also licensed from Public Key Partners. The
+effect is that PGP is just about globally available.
+
+2.1. Public Key Cryptography and its use in PGP
+
+Before we continue we should talk a little about Public Key
+Cryptography. Invented in 1976 by Whitfield Diffie and Martin Hellman
+[DiffieHellman], Public Key Encryption is a kind of cipher system where
+instead of the traditional single encryption key, two keys are
+employed. One key is used for encryption while the other is used for
+decryption. Knowing one key does not imply knowledge of the other.
+
+PGP uses the RSA system, named for its three inventors: Ronald Rivest,
+Adi Shamir and Leonard Adleman. Each user of PGP generates a key
+pair. This pair consists of a public key and a private key. As their
+names imply, the public key may be made public while the private key is
+kept secret by its owner. Both the public and private keys are large
+values (not simple words or small numbers that can be memorized) so PGP
+stores them in files. To protect the private key, PGP prompts for a pass
+phrase during key pair generation. This pass phrase is converted into an
+IDEA key which is then used to encrypt (using the IDEA cipher) the file
+that contains the user's RSA private key. A prudent user will protect
+this file against unwanted perusal even though it is also protected by
+the pass phrase. Some people go to the length of storing their private
+key only on a removable floppy which they lock up when not in use.
+
+PGP may be used to encipher a private message between two users if they
+know each others' public keys. A sender can send a message to a
+recipient by encrypting it in the public key of the recipient. The
+recipient can then decrypt the message by making use of her private
+key. This is shown graphically in Figure 1. A private key can also be
+used to construct an unforgeable digital signature which can be affixed
+to any message. The sender would use her own private key to construct
+the digital signature, before encrypting the message, and the recipient
+uses the sender's public key to verify the integrity of a message, after
+first decrypting it.
+
+ Encipherment Decipherment
+ +---------------+ +---------------+
+ | | | |
+ ------->| |---------->| |--------->
+ Message | | Encrypted | | Message
+ +---------------+ Message +---------------+
+ ^ ^
+ | |
+ | |
+ | |
+
+ Public Key Private Key
+
+ Figure 1: Message Flow and Encipherment
+
+Note carefully that all sensitive operations (reading a private message
+or creating the unforgeable signature) make use of the private
+keys. Private keys are never exchanged or disclosed. Public keys are
+never used for these sensitive operations and therefore it is not a
+problem for them to be exchanged unencrypted (or published in a public
+place).
+
+To facilitate the exchange of PGP public keys, a network of key servers
+has arisen that make use of software written by Michael Graff of Iowa
+State University. The key servers are electronic mail based automated
+responders. To fetch someone's public key a user sends an electronic
+message in a particular format requesting the key and the responder
+automatically sends back the requested key via electronic mail. Brian
+LaMacchia of MIT has added a World Wide Web server interfaceto this
+network of servers so keys may be retrieved and stored using popular
+World Wide Web browsing software. [3]
+
+However there is an important issue that needs to be considered. How
+does someone know that a public key that claims to belong to a
+particular person in fact does so? After all anyone can generate a key
+pair and publish the public key along with a claim that the key belongs
+to, say, the President. There needs to be a way to securely associate a
+public key with a name.
+
+PGP addresses this problem by the creation of the PGP Web of Trust. [4]
+The Web of Trust starts by having two people each generate and exchange
+public keys and names. Because this is done in person, and presumably
+between two people who know each other, they can now communicate with
+each other using signed messages and know beyond a shadow of a doubt
+that they are talking with each other. The Web grows from this simple
+one on one association when one of the participants performs a similar
+key exchange with a third person. An example will illustrate this best.
+
+Assume that Alice and Bob meet in person and exchange public keys. Now
+Alice and Toni meet later on and exchange keys. Because Alice securely
+has Bob's key, Alice can provide a "signed" copy of Bob's key to
+Toni. Alice signs Bob's key by computing a digital signature on it using
+PGP (which has built in features for doing exactly this exchange). In
+this example Alice is acting as an Introducer between Bob and
+Toni. Although they have never met, Alice has introduced them digitally
+to each other. Figure 2 illustrates this concept.
+
+ +------------------------------------+
+ | +--------------+ |
+ | |PGP Public Key| |
+ | +--------------+ |
+ | /---+----\
+ | Bob / \
+ | | Digital |
+ +------------------------------+ Signature |
+ | |
+ / \ / \
+ / \--------/ \
+ --- /| | | | \ +-
+ |/ | | | | \|
+ |/\| |/\|
+
+ Signed by: Alice
+
+ Figure 2: Graphical Representation of a Signed Key
+
+PGP permits multiple people to digitally sign an association of a name
+with a public key. If Bob has another friend, Bill, Bob can ask Bill to
+sign his key as well. Now if someone gets Bob's key (either from Bob or
+from a key server) and they trust Bill, they can know that they have
+Bob's key, even if they never heard of Alice. Figure 3 illustrates this,
+Bob's key has two signatures on it now, one from Bill and one from
+Alice.
+
+
+ +------------------------------------+
+ | +--------------+ |
+ | |PGP Public Key| |
+ | +--------------+ |
+ | |
+ |/---+----\ Bob /---+----\
+ / \ / \
+ | Digital | | Digital |
+ | Signature +------------------+ Signature |
+ | | | |
+ / \ / \ / \ / \
+ / \--------/ \ / \--------/ \
+ --- /| | | | \ +- --- /| | | | \ +-
+ |/ | | | | \| |/ | | | | \|
+ |/\| |/\| |/\| |/\|
+
+ Signed by: Bill Signed by: Alice
+
+ Figure 3: Graphical Representation of a Multiply Signed Key
+
+ +---------------------------+ +----------------------------+
+ | +--------------+ | | +--------------+ |
+ | |PGP Public Key| |------>| |PGP Public Key| |
+ | +--------------+ |-+ | +--------------+ |
+ | John Doe <jdoe@mit.edu> |\ \ | Jane Smoot <jsmoot@mit.edu>|
+ +-----------+---------------+ \ \ +----------------------------+
+ | | \
+ v | |
+ +----------------------------+ | | +-----------------------------+
+ | +--------------+ | | | | +--------------+ |
+ | |PGP Public Key| | | | | |PGP Public Key| |
+ | +--------------+ | | \->| +--------------+ |
+ | Joe Admin <jsysadm@mit.edu>| | | Ben Bitdiddl <bitdidl@mit> |
+ +----------------------------+ | +------------------+----------+
+ ^ | |
+ | | |
+ | v |
+ +--+-----------------------+ |
+ | +--------------+ | +
+ | |PGP Public Key| |<---/
+ | +--------------+ |
+ | Bill Clinton@whitehouse> |
+ +--------------------------+
+
+ John Doe vouches for:
+ Jane Smoot
+ Ben Bitdiddl
+ Bill Cliton
+ Joe Admin
+ Joe Admin vouches for:
+ *no one*
+ Bill Clinton vouches for:
+ Joe Admin
+ Ben Bitdiddl vouches for:
+ Bill Clinton
+ Jane Smoot vouches for:
+ *no one*
+
+ Figure 4: A Sample Web of Trust
+
+As more people sign each others' keys, the Web of Trust builds
+up. Figure 4 schematically depicts a more complicated situation. The
+arrows between the keys represent the signatures. So the arrow pointing
+between John Doe and Jane Smoot represents that John has signed Jane's
+key.
+
+The fundamental problem with the Web of Trust is that it depends on
+personal contact between many of the Web participants to build it up. It
+also depends on all of these participants properly verifying the
+identity of people whose keys they sign. It is not reasonable to expect
+a large group of people to be able to perform the necessary
+verifications without some significant number of them cheating. By
+cheating we mean that they sign someone's key without really knowing
+that the key really belongs to them. For example they may sign the key
+of someone who merely sends it by e-mail. Such a key cannot be trusted
+because the authenticity of e-mail is suspect in the absence of PGP,
+which is why we want the Web in the first place!
+
+The Internet's Privacy and Security Research Group was aware of this
+problem when they designed the Internet standard Privacy Enhanced Mail
+(PEM). The PEM solution is to create a strict hierarchy of trust. At the
+root of this hierarchy is the Internet Society which will sign the keys
+of special organizations called Policy Certification Authorities
+(PCAs). In turn PCAs will sign the keys of organizations which finally
+will sign the keys of individuals.
+
+Although this rigid hierarchical approach scales better then the PGP Web
+of Trust, it requires a fair amount of infrastructure to be in place
+before two people may use PEM to secure their e-mail. With PGP, if Alice
+and Bob wish to exchange secure messages and they have no common
+associates to Web their keys together, they can still meet in person and
+manually exchange keys. To use PEM, on the other hand, Alice's company
+will have to be registered with a PCA and be in a position to issue key
+signatures (called Certificates in the PEM terminology) to Alice. Bob's
+company will also have to be part of the game. Very few organizations
+are currently setup to use PEM. Most likely Alice and Bob are out of
+luck!
+
+2.2. A Word on Names
+
+PEM requires the use of X.500 style names. These names are of a special
+form and are not directly printable. By comparison, each PGP name is
+chosen by an end user. This flexibility is another reason why PGP has
+found quick acceptance in the community.
+
+Although the PGP program will happily accept any string as the name for
+a key, Internet users typically use a name that would easily fit in the
+"To:" field of an e-mail message. For example a PGP key may be named:
+
+ John H. Doe <JDoe@xyzzy.com>
+
+where John Doe's e-mail address is JDoe@xyzzy.com. Such a name may be
+provided to most RFC822 e-mail compliant systems without difficulty.
+
+PGP is oriented toward electronic mail. Electronic mail does not have a
+strong performance requirement. Basically PGP processes mail messages
+and needs to be fast enough to run faster then reasonable human
+perception. However many applications require many transactions per
+second. Kerberos is designed to work in such an environment.
+
+3. Kerberos
+
+Kerberos was developed by MIT's Project Athena in 1986. It provides for
+cryptographically based secure real-time authentication of individuals
+and computers. Kerberos users are given tickets when they login which
+they can then present to network services to prove their
+identity. Kerberos was designed for real-time client server
+applications; it is fast and provides protection against replay of
+sessions and other security threats to a real time system.
+
+In order to make Kerberos fast, and to avoid patent issues during its
+design, Kerberos today does not make use of Public Key
+technology. Instead it relies on the U.S. Data Encryption Standard [5]
+(DES) [DES] cipher system.
+
+What this means is that with Kerberos one can prove to a particular
+service that a user is who she claims to be, but one cannot generate a
+digital document that is digitally signed such that anyone, now and in
+the future, can verify it.
+
+Kerberos provides authentication services to a large number of users. A
+Kerberos Realm [6] can support over 100,000 users. At MIT we have
+approximately 25,000 users in our "ATHENA.MIT.EDU" realm and about 7,000
+of them login every day. In general, each organization will have a
+Kerberos realm of its own. Kerberos can also be used to provide
+authentication between realms when a shared key is established by the
+realm administrators.
+
+3.1. A Word on Names
+
+Kerberos names have structure to them. In version 4 (and version 5 as
+provided by MIT) names have the form name.instance@REALM. Typically a
+company will use its Internet Domain name as its Kerberos realm
+name. [7] The instance portion of a name is typically only present in
+the names of computer services and in special circumstances. Most user
+names do not have an instance component. Therefore the John Doe of our
+previous example will likely have a Kerberos name of:
+
+ JDoe@XYZZY.COM
+
+4. Combining Kerberos and PGP
+
+Kerberos is designed for an organization size body of users, but doesn't
+provide digital signatures. PGP on the other hand provides document
+authentication via digital signatures, but its Web of Trust is
+cumbersome to use on an organization level. Below we present the design
+of a service which provides a way to integrate the PGP Web of Trust with
+the Kerberos authentication model. By doing so an organization can use
+Kerberos to leverage its use of PGP.
+
+Our design goal is to provide e-mail and document security across an
+organization the size of MIT [8] and yet make no modifications to the
+basic Kerberos or PGP systems.
+
+We do this by introducing a new Kerberos authentication service. We call
+this service the PGP Signer service. The PGP Signer service appears to
+PGP as just another user who has a public key. To Kerberos it is simply
+another service which makes use of Kerberos authentication.
+
+To use the PGP Signer service, a user invokes the signer service client
+program. This program takes the user's public key (and name) and sends
+this in a Kerberos authenticated transaction to the PGP Signer
+server. The server, upon receipt of the transaction, compares the name
+in the PGP public key with the Kerberos authenticated name. This
+comparison is made using a set of rules that determine if the claimed
+PGP name is congruent with the authenticated Kerberos name. If they are
+not congruent the request is rejected; If the names are congruent, then
+the PGP Signer service signs the PGP public key and name using its
+private key and returns the result.
+
+To take full advantage of the PGP Signer service, each PGP user in the
+organization needs to obtain (usually at the same time as they obtain
+the PGP Signer client program) the PGP Signer's public key and add it to
+their personal PGP keyring as a trusted signer. [9] When this is done,
+the PGP Signer can act as a trusted introducer between people. Each user
+securely meets with the PGP Signer courtesy of Kerberos authentication.
+
+When a group of users wish to exchange e-mail with each other, securing
+it with PGP, they merely need to use the PGP Signer as their
+introducer. As a program, the signer never sleeps and is always
+available to provide service!
+
+4.1. Name Congruency
+
+For PGP names and Kerberos names to be congruent, they need to describe
+the same entity. A simple congruency rule is to require that submitted
+PGP key names have the structure "Real Name <user@realm>" format. The
+PGP Signer may choose to ignore the "Real Name" portion of the PGP name
+and ensure that the portion between the angle brackets is equal to the
+Kerberos name. So:
+
+ John H. Doe <JDoe@xyzzy.com>
+
+would be congruent to:
+
+ JDoe@XYZZY.COM
+
+If the PGP signer has access to it a database mapping Kerberos user
+names to real names, then it can enforce that the supplied real name
+also corresponds to the actual user name. This permits the PGP Signer to
+reject names of the form:
+
+ Chief Executive Officer and King <jdoe@xyzzy.com>
+
+assuming that John isn't the Chief and King!
+
+4.2. The Security of the PGP Key Signer
+
+The PGP Signer service must run on a secure computer system. This is
+because it requires access to the PGP Signer's private RSA key. The PGP
+Signer's Private key is the private key generated along with the PGP
+Signer's public key, which is published. The PGP Signer never has access
+to any user's private key.Whoever obtains this private key may construct
+trusted PGP keys that do not belong to their claimed owner and the
+organization's security can be compromised.
+
+Organizations that operate Kerberos servers are familiar with the
+requirement for a physically secure computer, as Kerberos key
+distribution servers also need to be managed securely. However the PGP
+Key Signer does not have to be as guarded as the Kerberos server because
+recovery from the compromise of the PGP Key Signer is not as disastrous.
+
+4.2.1. Operating a Secure Signer Server
+
+Along with using good host security techniques and providing physical
+security for the PGP Signer, some additional steps taken in advance can
+make recovery from a compromise easier.
+
+The first step is to keep a copy of the PGP Signer private key in a safe
+place off-line. A floppy disk can easily store a PGP private key and
+should suffice for the off-line backup. We recommend that two such
+floppies be created and stored in safe and secure locations.
+
+The PGP Signer should keep a copy of all public keys that it signs. This
+database of public keys should be backed up frequently. Because it
+contains no confidential information, this backup of public keys need
+not be protected against reading, but should be protected against
+unauthorized modification. An off-line periodic tape backup suffices.
+
+4.2.2. If the PGP Signer is Compromised
+
+Unlike Kerberos, where compromise of the server is a disaster, security
+can be restored to a compromised PGP Signer with just a little effort.
+
+The first step is to repair whatever host security or physical security
+problem resulted in the compromise in the first place. Once you are sure
+that the PGP Signer computing environment is safe, destroy the copy of
+the public key database and the file containing the PGP Signer private
+key (these will be "pubring.pgp" and "secring.pgp", the standard PGP
+keyring files). Restore them from a safe backup. Generate a new PGP
+Signer key and use this to sign all the keys that are in the backup
+public key database. Use the old PGP Signer key private key to revoke
+the old PGP Signer public key. Finally distribute the new PGP Signer
+public key and ensure that the key revocation certificate [10] that PGP
+generated for the old key is distributed as well.
+
+Although you will have to "go public" over the compromise of the PGP
+Signer, the steps that end-users will have to take to recover are
+minimal.
+
+In the future it may be possible to store the PGP Signer private key in
+special purpose hardware. BBN manufactures a device that may be used
+for this purpose. Designed for PEM, the BBN Safekeyper(tm) may be
+adaptable for the use with the PGP Signer. The advantage that this
+hardware brings is that the PGP Signer private key can be stored in it
+in a fashion that makes it impossible to read it out. An intruder who
+gains physical access to the PGP Signer server may steal the Safekeyper,
+but a "read only" compromise where she secretly learns the PGP Signer
+private key is not possible.
+
+5. Why not just use Kerberos?
+
+At this point the reader may be wondering why we bother to integrate
+Kerberos and PGP in the fashion that we do here. Wouldn't it make more
+sense to simply extend Kerberos so that it can generate digital
+signatures and provide encrypted e-mail messages?
+
+The answer to this has two parts. The first has to do with creating
+digital signatures.
+
+To create a digital signature that is verifiable to anyone after it is
+created requires the use of Public Key Cryptography. Because Kerberos
+does not make use of Public Key Cryptography it cannot create a digital
+signature. The best that Kerberos can do is prove to one party that a
+message is from another party. However, before you can create the
+equivalent of a digital signature using Kerberos, you need to know the
+identities of the parties who will be verifying the signature. Using
+Public Key Technology one can create a signature that anyone, both known
+and unknown, can verify.
+
+One might consider adding public key cryptographic algorithms to
+Kerberos in order to implement this function. However one of our design
+goals was to not make any modifications to the basic Kerberos system. It
+is also worth noting that if you add public key technology to Kerberos
+to implement digital signatures for messages you ultimately wind up
+re-inventing PGP (or PEM).
+
+The other answer is more philosophical and has to do with
+confidentiality. Because Kerberos does not use Public Key Cryptography,
+a Kerberos "super-user" can always decrypt a message that was encrypted
+from one person to another using Kerberos techniques. Perhaps more
+ominous is that such a "super-user" can be compelled to decrypt messages
+presented to her under court order.
+
+It is our belief that confidential messages should be exactly that:
+messages that are only readable by the parties communicating, which
+usually does not include the government!
+
+6. Project Status
+
+The PGP Signer design is described in this paper. A server is operating
+at MIT on the Internet host RFA.MIT.EDU. A client program exists for
+UNIX( systems. As of the time of the writing of this paper (November
+1994) MIT has not released the signer system code. However, it is our
+intention to do so.
+
+7. Future Work
+
+Today PGP has a significant presence in the Internet community, a
+presence not shared by the standard PEM. However PEM may yet take on an
+important role as the required certificate infrastructure comes into
+existence, as it eventually will. A similar PEM signer can be created
+using most of the functions of the PGP Signer, but this signer will
+issue PEM certificates as well.
+
+8. Conclusion
+
+This paper has described the design of a simple service that permits a
+digital signature/privacy application, PGP, to leverage and bootstrap
+its authentication infrastructure from a real-time authentication
+service, Kerberos. It demonstrates that these technologies are not
+antagonistic to each other but instead are quite synergistic.
+
+9. References
+
+[IDEA] X. Lai, On the Design and Security of Block Ciphers, ETH Series
+in Information Processing, v. 1, Konstanz: Hartung-Gorre Verlag, 1992
+
+[CertSniff] Cert Advisory CA-94:01 Ongoing Network Monitoring Attacks,
+Computer Emergency Response Team, Carnegie Mellon University,
+Pittsburgth, Pennsylvania (Februrary 3, 1994).
+
+[DES] Federal Information Processing Standards Publication (FIPS PUB)
+46-1, Data Encryption Standard, Reaffirmed 1988 January 22 (supersedes
+FIPS PUB 46, 1977 January 15)
+
+[DiffieHellman] W. Diffie and M. E. Hellman, New Directions in
+Cryptography, IEEE Transactions on Information Theory, v. IT-22, n. 6,
+November 1976, pp. 644-654
+
+[Kerb1] J G. Steiner, B. C. Neuman, J. I. Schiller, Kerberos: An
+Authentication Service for Open Network Systems, Usenix Conference
+Proceedings pp191-202, Dallas, Texas (February 1988).
+
+[Kerb2] S. P. Miller, B. C. Neuman, J. I. Schiller, and J. H. Saltzer,
+Project Athena Technical Plan Section E.2.1: Kerberos Authentication and
+Authorization System, M.I.T. Project Athena, Cambridge, Massachusetts
+(December 21, 1987).
+
+[PEM] Linn, J., Privacy Enhancement for Internet Electronic Mail: Part
+I: Message Encryption and Authentication Procedures, RFC 1421, Internet
+Engineering Task Force, (February 1993).
+
+[PGP] P. Zimmermann, PGP User's Guide Volumes I & II, MIT PGP Release
+2.6, Cambridge, Massachusetts (May 1994).
+
+[RSA] R. Rivest, A. Shamir, L. Adleman, A method for obtaining digital
+signatures and public key cryptosystems, CACM, Vol 21 No 2, pp 120-128
+(February 1978).
+
+10. Authors
+
+JEFFREY I. SCHILLER received his S.B. in Electrical Engineering (1979)
+from the Massachusetts Institute of Technology. As MIT Network Manager
+he has managed the MIT Campus Computer Network since its inception in
+1984. Prior to his work in the Network Group he maintained MIT's
+Multics timesharing system during the timeframe of the ArpaNet TCP/IP
+conversion. He is an author of MIT's Kerberos Authentication system.
+Mr. Schiller is the Internet Engineering Steering Group's (IESG) Area
+Director for Security. He is responsible for overseeing security related
+Working Groups of the Internet Engineering Task Force (IETF). He is
+also a member of the Privacy and Security Research Group (PSRG) of the
+Internet Research Task Force His recent efforts have involved work on
+the Internet Privacy Enhanced Mail standards (and implementation) as
+well as releasing a U.S. legal freeware version of the popular PGP
+encryption program. Mr. Schiller is also a founding member of the
+Steering Group of the New England Academic and Research Network
+(NEARnet). NEARnet provides Internet Access to institutions in New
+England.
+
+DEREK ATKINS is currently a graduate student in Media Arts and Sciences
+at MIT. He is studying distributed, secure systems for multimedia data
+distribution. His intrests include, among other things, cryptography,
+flying, and playing guitar. He can be reached at warlord@MIT.EDU.
+
+FootNotes:
+
+[1] CERT was founded after the Internet Worm Incident of November
+1988. Funded by ARPA, it is operated by Carnegie Mellon's Software
+Engineering Institute.
+
+[2] ViaCrypt, 9033 North 24th Avenue, Suite 7, Phoenix, Arizona 85021,
+USA, Phone: (602) 944-0773, viacrypt@acm.org
+
+[3] http://www-swiss.ai.mit.edu/~bal/pks-toplev.html
+
+[4] Not to be confused with the World Wide Web
+
+[5] DES is a U.S. Standard Symmetric cipher. Kerberos uses it instead of
+IDEA simply because IDEA was not around when Kerberos was designed.
+
+[6] A realm is the administrative domain of a set of Kerberos servers
+and the users they authenticate.
+
+[7] Because Kerberos is case sensitive whereas Internet domain names are
+case insensitive, by convention realm names are always in all
+upper-case.
+
+[8] The MIT community is roughly 14,000 people, 4,500 undergraduate
+students, 5,300 graduate students and about 4,000 faculty and staff.
+
+[9] The Signer's key will be provided in a file. When PGP processes this
+file it will automatically recognize that it contains a PGP key and will
+ask the user if she wishes to add the key to her keyring. PGP will also
+ask if the key should be "trusted" to sign other keys.
+
+[10] When PGP is instructed to revoke a key it generates a key
+revocation certificate. It is a datum that instructs any invocation of
+PGP that receives it to consider the revoked key as invalid.
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2
+
+iQCVAwUBLsQQoMUtR20Nv5BtAQHkUgP/ZPVjAyyV4GdvgSrY9n2HXCSEtN9IskQI
+86JiSFOJ6+LFVEJRiF02gkR8rFwliddMpkXPgR9asjVCjLSEgE8WbfSP5HS8H78C
+wmV0jkXI0T6UUjHirppVvgVtNf9QSI+35sO81nqzqdJmT+OO3HR3BNrSB3sFIPmq
+ZsqdkDrzqmw=
+=Jvm/
+-----END PGP SIGNATURE-----
+
diff --git a/Protocol/PGP/Info/stealth b/Protocol/PGP/Info/stealth
new file mode 100644
index 0000000..6383b78
--- /dev/null
+++ b/Protocol/PGP/Info/stealth
@@ -0,0 +1,173 @@
+From andrewk@cst.ca Tue Feb 27 09:49 EST 1996
+Received: from lapis.cst.ca by emerald.cst.ca with SMTP
+ (1.38.193.4/15.6) id AA09225; Tue, 27 Feb 1996 09:49:32 -0500
+Return-Path: <andrewk@cst.ca>
+Received: by lapis.cst.ca
+ (1.38.193.5/15.6) id AA00422; Tue, 27 Feb 1996 10:00:37 -0500
+From: Andrew Kuchling <andrewk@cst.ca>
+Subject: Re: Stealth PGP work (fwd)
+To: develop@emerald.cst.ca
+Date: Tue, 27 Feb 96 10:00:37 EST
+Mailer: Elm [revision: 70.85.2.1]
+
+
+
+(migrating to coderpunks)
+
+Bill Stewart <stewarts@ix.netcom.com> writes on cpunks:
+> Derek wrote:
+> > I'm not familiar with the exact details of what stealth does, which is
+> > why I asked for more details. The problem is that PGP API, when
+> > decrypting a message, keys off the PGP packet types in order to
+> > operate. If stealth can work outside of PGP 2.6.2, then it should be
+> > possible to add it on to PGP 3, theoretically.
+>
+> My assumption was that the request for "stealth" was for the more general
+> feature of stealthiness rather than the specific implementation provided
+> by the Stealth program that "Harry Hastur" wrote to solve it.
+> I suspect that the new toolkits in PGP3 will make it much easier to
+> implement a good stealth program, but it may or may not be perfect.
+>
+> The basic requirement is that you can't tell whether a message is
+> PGP or Random Bits unless it's for you, for applications like steganography;
+
+that's Henry's stealth approach,
+
+> a milder requirement is that you at least can't tell who it's for and
+> also can't verify your guess about the recipient if you guess right.
+
+This could be useful for mail drops to alt.anonymous.messages, it
+would save the necessity of generating a new key, when you don't mind
+the sender knowing the recipients normal key, but don't want anyone
+else to know. Yet you don't care that anyone knows it is a PGP message.
+
+> Sure, most people don't need it, but most people don't need 1024-bit crypto
+> either;
+
+I think PGP should cater for less rosy situations than that in the US
+at present: there are other countries where clandestine use may be
+necessary because of local laws, and the way the NSA is headed you
+can't be too sure of the US future either. (How's the idea future
+odds for mandatory key escrow in the near future?)
+
+I'd vote for both of your suggested modes, I think they would be
+useful to have.
+
+> 512 bits will protect just about everybody from just about every real threat
+> for the next decade or so. One requirement is getting rid of identifiable
+> packet type and length indicators,
+
+separately from the requirement to strip off the keyid? People can
+see it's from you, but they can't tell what length and what packets
+are in there?
+
+> another is getting rid of the key id,
+
+yep.
+
+> and another is the more subtle problem that M**e mod n isn't
+> distributed evenly.
+
+yep. m**e % n not being evenly distrubited would mean that you should
+do the normalising transformation on the RSA block even if you are
+just stripping the keyid and leaving the packet types and lengths; not
+only does it give away that it is a PGP message (which is now obvious
+due to packet type fields), but with enough messages it gives away n,
+and hence the keyid.
+
+> Stealthing the block type and length indicators isn't a requirement for
+> ascii-armored and clearsigned versions (obviously not for clearsigned,
+> and if you don't like your ascii version starting with ----- BEGIN PGP,
+> you can encode the stealth binary with uuencode or MIME instead.)
+
+You'd need to strip the length indicators if you wanted the option to
+pad the message with random junk to a fixed size (eg much like
+mixmaster fixed sized packets).
+
+> [...]
+>
+> I also don't remember if the block with the public-key-encrypted session key
+> has a length indicator or not;
+
+it does:
+
+: RSA public-key-encrypted packet
+: -------------------------------
+:
+: Offset Length Meaning
+: 0 1 CTB for RSA public-key-encrypted packet
+: 1 2 16-bit (or maybe 8-bit) length of packet
+
+> if it doesn't, parts of the job become easier.
+
+> For all the following blocks, you can xor the packet type and length indictor
+> with shared-secret random bits. An obvious source, assuming the API lets
+> you have it,
+> is the random padding that PGP adds to the session key when PK-encrypting,
+> or some PRNG output derived from that, and you can do the xoring quickly
+> without having to open up packets beyond that.
+
+This is an interesting approach to allowing a stealthy operation which
+can deal with multiple blocks, Henry's method will only recover one
+IDEA block.
+
+Another method would be to rely on all outer packets after the RSA
+packet(s) being IDEA encrypted (is this the case?) to reconstruct the
+multiple packet lengths. Literal plaintext blocks have length fields
+also, so the length information in the outer IDEA block which was
+stripped in a stealth operation was redundant anyway. So you could
+modify the IDEA decrypt code to use the length field encoded within it
+if there is no external length field.
+
+(saves arguments about whether revealing some of the padding
+theoretically weakens anything, but may not fit cleanly in to Derek
+and Colins software architecture.)
+
+(It is possible with Henry's existing code to pad data with random
+junk because of the redundant internal length fields: pgp does IDEA
+decrypt the packet (including a meaningless decrypt of trailing junk),
+but the internal packet length means that it then goes on to ignore
+the decrypted padding junk).
+
+> The initial block's types can be played with by an external program;
+> it wouldn't leak too much data to always use a value other than the
+> value a normal binary-flavor PGP program would use, so Stealth can
+> just pass non-stealthed files through to PGP instead of
+> destealthing.
+
+Stealth autodetect, so you could just point PGP at any message,
+steatlhed or not, and have it try to make sense of it? Because it is
+a fairly densely packed format (bit fields etc), the legal CTB values
+cover a fair proportion of the 256 values a byte can take. It would
+break the stealthiness of it to do that.
+
+Just checking the probablities of getting white noise that would make
+it as a valid PGP message:
+
+probability for mistaken RSA public key enc packet = 2 / 256**3
+(CTB fixed, version = 2 or 3, and algorithm byte = 1)
+
+probability for mistaken IDEA encrypted packet = 1 / 256
+(CTB fixed)
+
+So a ~ 1/8,000,000 chance of getting asked for a non existant public
+key, sound ok?
+
+The IDEA encrypted packet is more troublesome, it'll ask for
+conventional key passphrase, it'll notice if it is junk due to the
+check bytes inside the IDEA encrypted packet, but only after giving
+the passphrase.
+
+Due to the IDEA packet thing, it would seem that you have to forgo the
+normal PGP point and go approach, and would have to request unstealthing?
+
+> Can stealthing the PK-encrypted session key be done transparently in
+> a separate program, or does it really gain from integrating with
+> PGP's handling.
+
+I'd argue for integrating, as a core feature so that stego programs,
+and remailer programs can rely on and make use of the features.
+
+Adam
+
+
diff --git a/Protocol/PGP/Makefile b/Protocol/PGP/Makefile
new file mode 100644
index 0000000..447762b
--- /dev/null
+++ b/Protocol/PGP/Makefile
@@ -0,0 +1,7 @@
+
+clean:
+ rm -f *.pyc *~ core *.bak
+
+distrib: clean
+ cd .. ; tar -zcvf ~/public_html/files/py/pypgp.tgz -X pgp/excludefiles pgp
+
diff --git a/Protocol/PGP/README b/Protocol/PGP/README
new file mode 100644
index 0000000..774accf
--- /dev/null
+++ b/Protocol/PGP/README
@@ -0,0 +1,26 @@
+
+The code in this directory is included because my intention is to
+eventually provide support for PGP messaging, compatible with PGP 5.x.
+However, as of the time of writing (January 1998), I haven't even run
+this code in months, and it may not work at all. Once I've finished a
+first version of a Python ssh implementation, I'll then return to
+working on PGP support.
+
+
+ Andrew Kuchling
+ amk@magnet.com
+ http://starship.skyport.net/crew/amk/
+
+
+The original README was:
+========================
+This is version 0.02 of the Python/PGP (PyPGP) distribution. It
+contains Python classes and modules that read and write PGP-format
+files. A PGP binary is not required to encrypt and decrypt PGP
+messages.
+
+The doc/ subdirectory contains the documentation.
+
+Most of the code in version 0.01 was discarded and rewritten afresh,
+starting from new code written by Mark Shuttleworth of Thawte
+Consulting (http://XXX)
diff --git a/Protocol/PGP/TODO b/Protocol/PGP/TODO
new file mode 100644
index 0000000..852e07f
--- /dev/null
+++ b/Protocol/PGP/TODO
@@ -0,0 +1,24 @@
+
+ Things to do:
+
+ * Are all the parse_bin and write_bin methods completely implemented?
+
+ * Documentation : table of packet classes and their public attributes
+
+ * Signatures aren't yet implemented.
+
+ * There's no high-level interface to PGP messaging, with callbacks
+to retrieve keys.
+
+ Medium-term things:
+
+ * I've punted on the problem of random number generation, and
+just read from Linux's /dev/urandom device all the time.
+
+ * Use RSAREF if available, to avoid getting in trouble with RSADSI
+
+ Longer-term, once things have stablized:
+
+ * Add more algorithms: 3DES, SHA, ElGamal, ... (Suggestions?)
+
+ * A GUI interface to PGP encryption written in Tkinter.
diff --git a/Protocol/PGP/config.txt b/Protocol/PGP/config.txt
new file mode 100644
index 0000000..249534a
--- /dev/null
+++ b/Protocol/PGP/config.txt
@@ -0,0 +1,3 @@
+armor=off
+PubRing="./pubring.pgp"
+SecRing="./secring.pgp"
diff --git a/Protocol/PGP/doc/bugreport b/Protocol/PGP/doc/bugreport
new file mode 100644
index 0000000..7bfc992
--- /dev/null
+++ b/Protocol/PGP/doc/bugreport
@@ -0,0 +1,89 @@
+I've come across something that is either a bug in PGP, or a bug in
+the doc/pgformat.doc specification included with PGP. In crypto.c,
+idea_file seems to assume that the length of its input is known; it
+doesn't handle the case where lenfile==-1.
+
+I'm (still) working on a PGP-compatible library, and was testing its
+output versus the output of 'pgp -c'. My code could unpack a
+PGP-generated message, but PGP choked with a 'Bad pass phrase' error
+on processing a file generated by my code. A bit of exploration found
+the problem; it wasn't due to the passphrase at all.
+
+The output of 'pgp -c' is a single ciphered packet, which contains a
+plaintext or compressed packet. 'pgp -c' always generates a ciphered
+packet where the length is explicitly given after the CTB; however, my
+code is attempting to use only one pass at all times, and generates an
+indefinite-length packet, since it doesn't know the length ahead of
+time. This causes the lenfile parameter passed to idea_file to be
+negative, which causes an fread() for a negative number of items. The
+fread() returns zero, and idea_file reports an error. I expect I'll
+run into this again, as my code prefers to create indefinite-length
+packets whenever it can.
+
+So... should idea_file be fixed to handle lenfile==-1? (A *very
+lightly tested* patch to do this is appended--treat it with
+suspicion.) Or is this a specification bug in pgformat.doc?
+
+
+ Andrew Kuchling
+ andrewk@cst.ca
+
+
+*** ../orig-src/crypto.c Fri Feb 23 09:25:30 1996
+--- crypto.c Fri Feb 23 09:50:51 1996
+***************
+*** 530,534 ****
+ /* See if the redundancy is present after the random prefix */
+ count = fread(textbuf,1,RAND_PREFIX_LENGTH+2,f);
+! lenfile -= count;
+ if (count==(RAND_PREFIX_LENGTH+2)) {
+ ideaCfbDecrypt(&cfb, textbuf, textbuf,
+--- 530,534 ----
+ /* See if the redundancy is present after the random prefix */
+ count = fread(textbuf,1,RAND_PREFIX_LENGTH+2,f);
+! if (lenfile!=4294967295) lenfile -= count;
+ if (count==(RAND_PREFIX_LENGTH+2)) {
+ ideaCfbDecrypt(&cfb, textbuf, textbuf,
+***************
+*** 548,558 ****
+
+ /* read and write the whole file in CFB mode... */
+! count = (lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE;
+ while (count && status == 0) {
+! if ((count = fread(textbuf,1,count,f)) <= 0) {
+ status = -3;
+ break;
+ }
+! lenfile -= count;
+ if (decryp)
+ ideaCfbDecrypt(&cfb, textbuf, textbuf, count);
+--- 548,559 ----
+
+ /* read and write the whole file in CFB mode... */
+! count = (lenfile!=4294967295 && lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE;
+ while (count && status == 0) {
+! if ((count = fread(textbuf,1,count,f)) < 0) {
+ status = -3;
+ break;
+ }
+! if (count==0) break;
+! if (lenfile!=4294967295) lenfile -= count;
+ if (decryp)
+ ideaCfbDecrypt(&cfb, textbuf, textbuf, count);
+***************
+*** 560,565 ****
+ ideaCfbEncrypt(&cfb, textbuf, textbuf, count);
+ if (fwrite(textbuf,1,count,g) != count)
+! status = -3;
+! count = (lenfile < DISKBUFSIZE) ? (int)lenfile : DISKBUFSIZE;
+ }
+
+--- 561,567 ----
+ ideaCfbEncrypt(&cfb, textbuf, textbuf, count);
+ if (fwrite(textbuf,1,count,g) != count)
+! status = -3;
+! count = (lenfile!=4294967295 && lenfile < DISKBUFSIZE)
+! ? (int)lenfile : DISKBUFSIZE;
+ }
+
+
diff --git a/Protocol/PGP/doc/pgp.texi b/Protocol/PGP/doc/pgp.texi
new file mode 100644
index 0000000..39a605c
--- /dev/null
+++ b/Protocol/PGP/doc/pgp.texi
@@ -0,0 +1,298 @@
+\input texinfo.tex @c -*-texinfo-*-
+@c %** start of header
+@setfilename pct.info
+@settitle Python/PGP Interfaces
+@syncodeindex fn cp
+@syncodeindex vr cp
+@c %** end of header
+
+@titlepage
+@title Python/PGP Interfaces (OUT OF DATE)
+@subtitle Release 0.0.1
+@subtitle Manual Edition 0.0.1
+@author A.M. Kuchling
+@author 762 Williams Road
+@author Hemmingford, Quebec, Canada
+@author E-mail: @samp{andrewk@@cst.ca}
+@end titlepage
+
+@node Top, Introduction, (dir), (dir)
+@ifinfo
+Certain sections require some familiarity with PGP.
+@menu
+* PGP Compatibility:: Maniuplating PGP keys and messages.
+@end menu
+
+@end ifinfo
+
+@node PGP Compatibility, , , Top
+@chapter PGP Compatibility
+This module is intended to allow you to manipulate files and keyrings
+created by Philip Zimmermann's Pretty Good Privacy program. If you
+aren't familar with PGP, get a copy and read Philip Zimmermann's
+excellent documentation. Otherwise, this chapter will be incomprehensible to you.
+
+Several important disclaimers:
+@itemize @bullet
+@item Currently the module cannot handle encrypted files that use PGP's
+data compression. This will require implementing a data compression
+module for Python, and will not be completed any time in the near future.
+
+@item This Python module should be perfectly
+compatible with PGP 2.6; if you find any incompatibilities, please inform me
+@emph{immediately}, as they are serious bugs.
+
+@item PGP has been used more extensively than this code has; treat
+it with care. Bugs in software are always annoying, but this code will be
+handling irreplaceable private keys. If your private key is lost, there's
+no way to recover it. So back up your key rings before experimenting with
+them, and try to verify that encrypted files you produce can be decrypted by
+PGP. This will also protect you against your own mistakes while learning
+how to use the module.
+
+@item Any flaws in the Python PGP module are due to my error,
+and should not be considered to reflect on the reputations of Philip
+Zimmermann, Guido van Rossum, or the current PGP development team;
+none of them had anything to do with it.
+
+@item The PCT's design makes it easy to change from one algorithm to
+another. This means it would be at most a few hours of work (and more
+likely a few minutes) to create your own hacked PGP module that uses
+triple DES or some other cipher instead of IDEA, or to add new fields
+to PGP packets. This freedom is seductive, and also dangerous; it
+could lead to a twisty maze of PGP versions, all different. That
+would severely damage the usefulness of PGP, and could lead to a
+collapse of PGP's usefulness as a common means of secure
+communication. Please think very carefully before creating strange
+variations of PGP, and don't distribute them.
+
+@item As a corollary to the previous item, this module may not share
+some limitations that PGP possesses; for example, RSA keys can be of
+arbitrary length, while PGP is currently limited to 2048 bits. It may
+seem fun to generate an 8192-bit key, but the resulting key couldn't
+be handled by any program other than this module. Again, think before
+you do something strange...
+@end itemize
+
+@section Basic design
+
+For generality, the basic PGP module does not perform any file
+handling. Instead, all operations are performed on strings of binary
+data. So if you want to read the keys in your @code{secring.pgp}
+file, you must write code to read the file, and then pass a string
+containing the contents of the file to the PGP module. This doesn't
+constrain keys to being present in file-like storage, and gives you
+the freedom to pass keys around in any way you like.
+
+PGP files are broken up into packets. A packet consists of a header,
+and a given length of data. A keyring or message is therefore a
+collection of packets, arranged in some defined order. Packets are
+PGP's fundamental unit of data, but they're a bit too low-level for
+convienient usage. For example, a single key is a collection of
+packets: one for the key itself, one for each user ID for the key, one
+for each signature, and possibly one containing a revocation
+certificate.
+
+The Python PGP module defines a hierarchy of objects. There are two
+basic object classes: @code{Key} and @code{Data}. There
+is a lower-level @code{Packet} class that is used throughout the module.
+with it. @code{Data} has several
+more subclasses: XXX The Data classes have not been designed yet.
+
+The publicly-accessible attributes and methods for the objects are
+documented below. Internal attributes and methods are accessible,
+since Python doesn't yet offer data hiding, but don't use them or rely
+on their existence.
+
+The @code{__init__} functions of objects always require the same
+parameter: a string of binary data that contains the data. If the
+string only contains part of a packet, an exception will be raised.
+The caller can then read in more data and try again.
+The exceptions that can be raised are:
+
+@defcv Exception {PGP module} Exception
+Raised on other, miscellaneous error conditions. The associated value
+is a tuple; the first element is an explanatory string, and the other
+elements are associated data.
+@end defcv
+
+@defcv Exception {PGP module} PossibleEnd
+This is something of an ``optional'' exception, raised if the string of
+data is exactly the right length. If you're reading keys from a file,
+this may mean that the string was too short, and you were just lucky in
+where it ended. Or, you may know you have all the key data, in which
+case this error can be ignored. The associated value is the PGP object
+that would have been returned; if you choose to ignore this error, just
+use that object.
+@end defcv
+
+@defcv Exception {PGP module} TooShort
+Raised when the string of data only contains a portion of a needed
+packet of PGP data.
+The associated value is an integer, giving the number of missing bytes.
+You should obtain that number of bytes, and retry the instantiation.
+@end defcv
+
+@subsection Key objects
+@code{Key} objects contain information about a single key, and
+the User ID's associated with that key. At the packet level, there
+are different packets for the key, user IDs, and signatures. However,
+you don't have to worry about that; there are only public and private
+keys. All information about signatures and user IDs are stored as
+attributes of key objects.
+XXX Doesn't support revocation certificates yet!
+
+@defivar Key ?MPI
+@cindex RSA
+@cindex MPI
+Currently the only public-key algorithm used by PGP is RSA. For RSA
+public keys, the binary data read from the packet is stored in
+@code{eMPI} and @code{nMPI}, @footnote{MPI is an acronym for
+Multi-Precision Integer, the data format which PGP uses to store long
+integers.} but you'll probably never need to use them, since they're
+automatically converted to long integers and kept in the @code{e}, and
+@code{n} attributes. @code{e} is the encryption exponent, and
+@code{n} is the modulus.
+@end defivar
+
+@defivar Key CryptAlg
+An 8-bit integer identifying the algorithm
+ for which this public key is appropriate. Currently the only
+ reasonable value is 1, for the RSA algorithm.
+@end defivar
+
+@defivar Key KeyID
+A 64-bit long integer identifying the key. This can be used as a unique
+index for storing and retrieving keys, if desired.
+@end defivar
+
+@defivar Key TimeStamp
+The time that the key was generated, expressed in the standard Unix
+fashion, as seconds from a reference date.
+@end defivar
+
+@defivar Key UserID
+A list of tuples containing the User IDs for this key. Each tuple is of
+the form @code{(@var{IDpacket}, @var{Signaturelist})}.
+@end defivar
+
+@defivar Key Validity
+Eventually, this attribute will be used to indicate a key's lifetime,
+enabling you to create keys only valid for a given period of time.
+Currently this field is unused, and will always be equal to zero.
+@end defivar
+
+@defivar Key Version
+The version of PGP that generated this key. Possible values are 2 or 3.
+@end defivar
+
+Some functions are only applicable to private keys, and there are
+additional attributes containing the secret key, possibly in encrypted
+form. The @code{Unlock} method must be called to transform the
+encrypted data to a form suitable for use, and requires a password if
+the key is encrypted. The @code{Lock} method simply deletes the
+decrypted key information, and the @code{Relock} method re-encrypts the
+key, thus allowing you to change key data or generate new keys. (XXX
+@code{Relock} is implemented-but is its existence a good idea?
+Carelessness could cost you a secret key, and it might be possible to
+attempt a denial-of-service attack by destroying your key.)
+
+
+@defivar Key ?MPI
+The raw, possibly encrypted data for the private key is kept in the
+@code{dMPI}, @code{pMPI}, @code{qMPI}, and @code{uMPI} attributes.
+While you could manipulate the MPI data yourself, it's probably easiest to use
+the @code{Unlock} method.
+@end defivar
+
+@defivar Key CipherAlg
+8-bit integer giving the secret-key algorithm used to protect the
+secret key. A value of 0 means the key is stored in unencrypted form,
+while 1 signals a key encrypted with IDEA.
+@end defivar
+
+@defivar Key IV
+A string containing an initial block of data, used for starting the
+cipher feedback for an encrypted secret key. You'll want to set this
+to a string containing random data.
+@end defivar
+
+The additional method functions allow access to the data for the
+private key.
+
+@defmethod Key Lock
+Deletes the cleartext secret key data. Currently this simply deletes
+ the @code{d}, @code{p}, @code{q}, and @code{u} attributes,
+since there
+ doesn't seem to be an obvious way of erasing them securely.
+@end defmethod
+
+@defmethod Key Relock password
+Recreates the secret key data by applying @var{password}, and deletes
+the cleartext key data.
+@end defmethod
+
+@defmethod Key Unlock [password]
+Decodes the secret key by applying @var{password}. If the secret key
+data is not encrypted, the value of @var{password} is ignored, but you
+still must call the @code{Unlock} method. After calling this method,
+the key will have four additional attributes: @code{d}, @code{p},
+@code{q}, and @code{u}. All of the new attributes are long integers
+containing the secret key data.
+@end defmethod
+
+An example usage is given in the following example, where the user
+accesses a private key protected with the password ``secret''.
+
+@example
+Python 1.1 (Nov 7 1994)
+Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam
+>>> import pgp
+>>> f=open('secring.pgp')
+>>> binary=f.read() # Read the entire file into a string
+>>> f.close()
+>>> key=pgp.Key(binary) # Read the first private key
+>>> key
+<Key instance at 5ce40>
+>>> key.n # Modulus
+963122082828533347002151137300146220135009078073956904069973
+630338075190337890351958426139975067122956338320608624652745
+4945250019523010908959292342378629L
+>>> key.e # Encryption exponent
+17L
+>>> key.d # Decryption exponent not available
+Traceback (innermost last):
+ File "<stdin>", line 1, in ?
+AttributeError: d
+>>> key.CipherAlg # Algorithm for key data
+1
+>>> key.Unlock('phlezofligle') # Wrong password, so exception raised
+Traceback (innermost last):
+ File "<stdin>", line 1, in ?
+ File "./pgp.py", line 189, in Unlock
+ raise Exception, 'Incorrect password'
+pgp.Exception: Incorrect password
+>>> key.Unlock('secret') # Apply correct password
+>>> key.d # The decryption exponent
+396579681164690201706768115358883737702650796853982254617047
+965433325078374417342219491501744606387578757984207954329749
+1347256349281128383401567984775749L
+>>> ciph=pow(19721015L, key.e, key.n) # RSA encryption
+>>> ciph
+103227991689207176390261587823791277903759628199625167641034
+860240242223522848082032689408309240059530813895260337829589
+84375L
+>>> pow(ciph, key.d, key.n) # RSA decryption
+19721015L
+>>> key.Lock() # Delete sensitive data
+>>> key.d # d no longer exists
+Traceback (innermost last):
+ File "<stdin>", line 1, in ?
+AttributeError: d
+@end example
+
+@node Concept Index, ,Extending the Toolkit, Top
+@unnumbered Concept Index
+@printindex cp
+@contents
+@bye
diff --git a/Protocol/PGP/docerrors.txt b/Protocol/PGP/docerrors.txt
new file mode 100644
index 0000000..97ccdf4
--- /dev/null
+++ b/Protocol/PGP/docerrors.txt
@@ -0,0 +1,5 @@
+
+* Signature packets can only have a 16-bit length. The documentation
+ claims it can be either 8 or 16-bit.
+
+
diff --git a/Protocol/PGP/dump.py b/Protocol/PGP/dump.py
new file mode 100644
index 0000000..34b14cb
--- /dev/null
+++ b/Protocol/PGP/dump.py
@@ -0,0 +1,17 @@
+
+import pgp, sys
+
+indent=0
+def loop(s=None, indent=0):
+ import sys
+ while (1):
+ if s==None: p,dummy=pgp.readPacket(sys.stdin)
+ else: p,s=pgp.readPacket(s)
+ if p==None: break
+ print indent*'\t', p.CTBT, p
+ if p.CTBT==pgp.CTBT_COMPR:
+ loop(p.decompress(),indent+1)
+ if p.CTBT==pgp.CTBT_SIG:
+ print p.__dict__
+
+loop()
diff --git a/Protocol/PGP/excludefiles b/Protocol/PGP/excludefiles
new file mode 100644
index 0000000..c96cbc4
--- /dev/null
+++ b/Protocol/PGP/excludefiles
@@ -0,0 +1,33 @@
+oldpgp
+excludefiles
+*.tgz
+core
+out
+err
+*.toc
+*.aux
+*.log
+*.cp
+*.cps
+*.fn
+*.fns
+*.vr
+*.tp
+*.dvi
+*.kys
+*.pg
+*.pgs
+*.ind
+*.pyc
+*.pgp
+*.ky
+*.html
+*~
+RCS
+Info
+Distrib
+present
+util
+*,v
+#*
+LINUXELF
diff --git a/Protocol/PGP/filepgp b/Protocol/PGP/filepgp
new file mode 100755
index 0000000..d832d15
--- /dev/null
+++ b/Protocol/PGP/filepgp
@@ -0,0 +1,61 @@
+#!/usr/local/bin/python
+# Hey Emacs, this is -*-Python-*- code!
+
+import pgp, sys, md5
+
+if len(sys.argv)==1:
+ print 'Usage: filepgp <filename>'
+ print "If <filename> ends in '.pgp', it will be decrypted."
+ print "Otherwise, it will be encrypted."
+ sys.exit(0)
+
+def raw_input(): return 'test'
+
+filename=sys.argv[1]
+if filename[-4:]=='.pgp':
+ # Decrypt the file
+ f=open(filename, 'r')
+ print 'Enter passphrase:',
+ passphrase=raw_input()
+ idea_key=md5.new(passphrase).digest()
+ p1=pgp.Cipher(f, pgp.UNPACK, DEK=idea_key)
+ p2=pgp.ReadPacket(p1, pgp.UNPACK)
+ if p2.Type==pgp.COMPRESSED:
+ input=pgp.Plaintext(p2, pgp.UNPACK)
+ elif p2.Type==pgp.PLAINTEXT:
+ input=p2
+ else:
+ print 'Unexpected packet type', p2.Type
+ sys.exit(1)
+
+ # Copy the contents to stdout
+ while (1):
+ s=input.read(50)
+ sys.stdout.write(s)
+ if s=="": break
+ f.close()
+
+else:
+
+ def getbytes(N):
+ """Returns N bytes of random data.
+ Here it'll just return a string full of the letter 'a'. """
+ return 'a'*N
+
+ # Encrypt the file
+ f=open(filename, 'r')
+ print 'Enter passphrase:',
+ passphrase=raw_input()
+ idea_key=md5.new(passphrase).digest()
+
+ p3=pgp.Plaintext(f, pgp.PACK) # Create a Plaintext filter...
+# p2=pgp.Compress(p3, pgp.PACK) # ...which feeds a Compress filter...
+ # ... which goes into a Cipher filter.
+ p1=pgp.Cipher(p3, pgp.PACK, DEK=idea_key, randfunc=getbytes)
+ # Copy the contents to an output file
+ output=open(filename+'.pgp', 'w')
+ while (1):
+ s=p1.read(50)
+ output.write(s)
+ if s=="": break
+ f.close()
diff --git a/Protocol/PGP/format.doc b/Protocol/PGP/format.doc
new file mode 100644
index 0000000..cc4905a
--- /dev/null
+++ b/Protocol/PGP/format.doc
@@ -0,0 +1,841 @@
+File Formats Used by PGP 2.x
+============================
+
+***Note: Packets generated with PGP 2.6.3i normally contain a version
+ byte of 3. However, by using the +legal_kludge=off option, you
+ can force PGP to use a version byte of 2 instead. This will
+ make all messages and keys generated with PGP 2.6.3i compatible
+ with any PGP 2.x version.
+
+This appendix describes the file formats used externally by Pretty
+Good Privacy (PGP), the RSA public key cryptography application. The
+intended audience includes software engineers trying to port PGP to
+other hardware environments or trying to implement other PGP-
+compatible cryptography products, or anyone else who is curious.
+
+[To be included: a description of ASCII armor. An ASCII armored
+file is just like a binary file described here, but with an extra
+layer of encoding added, framing lines, and a 24-bit CRC at the end.]
+
+
+Byte Order
+----------
+
+All integer data used by PGP is externally stored most significant byte
+(MSB) first, regardless of the byte order used internally by the host
+CPU architecture. This is for portability of messages and keys between
+hosts. This covers multiprecision RSA integers, bit count prefix
+fields, byte count prefix fields, checksums, key IDs, and timestamps.
+
+The MSB-first byte order for external packet representation was
+chosen only because many other crypto standards use it.
+
+
+Multiprecision Integers
+-----------------------
+
+RSA arithmetic involves a lot of multiprecision integers, often
+having hundreds of bits of precision. PGP externally stores a
+multiprecision integer (MPI) with a 16-bit prefix that gives the
+number of significant bits in the integer that follows. The integer
+that follows this bitcount field is stored in the usual byte order,
+with the MSB padded with zero bits if the bitcount is not a multiple
+of 8. The bitcount always specifies the exact number of significant
+bits. For example, the integer value 5 would be stored as these
+three bytes:
+
+ 00 03 05
+
+An MPI with a value of zero is simply stored with the 16-bit bitcount
+prefix field containing a 0, with no value bytes following it.
+
+
+
+Key ID
+------
+
+Some packets use a "key ID" field. The key ID is the least
+significant 64 bits of the RSA public modulus that was involved in
+creating the packet. For all practical purposes it unique to each
+RSA public key.
+
+
+User ID
+-------
+
+Some packets contain a "user ID", which is an ASCII string that
+contains the user's name. Unlike a C string, the user ID has a
+length byte at the beginning that has a byte count of the rest of the
+string. This length byte does not include itself in the count.
+
+
+Timestamp
+---------
+
+Some packets contain a timestamp, which is a 32-bit unsigned integer
+of the number of seconds elapsed since 1970 Jan 1 00:00:00 GMT. This
+is the standard format used by Unix timestamps. It spans 136 years.
+
+
+
+Cipher Type Byte (CTB)
+----------------------
+
+Many of these data structures begin with a Cipher Type Byte (CTB),
+which specifies the type of data structure that follows it. The CTB
+bit fields have the following meaning (bit 0 is the LSB, bit 7 is the
+MSB):
+
+Bit 7: Always 1, which designates this as a CTB
+Bit 6: Reserved.
+Bits 5-2: CTB type field, specifies type of packet that follows
+ 0001 - public-key-encrypted packet
+ 0010 - secret-key-encrypted (signature) packet
+ 0101 - Secret key certificate
+ 0110 - Public key certificate
+ 1000 - Compressed data packet
+ 1001 - Conventional-Key-Encrypted data
+ 1011 - Raw literal plaintext data, with filename and mode
+ 1100 - Keyring trust packet
+ 1101 - User ID packet, associated with public or secret key
+ 1110 - Comment packet
+ Other CTB packet types are unimplemented.
+Bits 1-0: Length-of-length field:
+ 00 - 1 byte packet length field follows CTB
+ 01 - 2 byte packet length field follows CTB
+ 10 - 4 byte packet length field follows CTB
+ 11 - no length field follows CTB, unknown packet length.
+ The 8-, 16-, or 32-bit packet length field after the CTB
+ gives the length in bytes of the rest of the packet, not
+ counting the CTB and the packet length field.
+
+
+
+RSA public-key-encrypted packet
+-------------------------------
+
+Offset Length Meaning
+0 1 CTB for RSA public-key-encrypted packet
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte, may affect rest of fields that follow.
+ (=2) for PGP versions <= 2.5
+ (=3) for PGP versions >= 2.6
+4 8 64-bit Key ID
+12 1 Algorithm byte for RSA (=1 for RSA).
+ --Algorithm byte affects field definitions that follow.
+13 ? RSA-encrypted integer, encrypted conventional key
+ packet. (MPI with bitcount prefix)
+
+The conventionally-encrypted ciphertext packet begins right after the
+RSA public-key-encrypted packet that contains the conventional key.
+
+
+
+Signature packet
+----------------
+
+Offset Length Meaning
+0 1 CTB for secret-key-encrypted (signed) packet
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte, may affect rest of fields that follow.
+ (=2) for PGP versions <= 2.5
+ (=3) for PGP versions >= 2.6
+4 1 Length of following material that is implicitly included
+ in MD calculation (=5).
+5 1 Signature classification field (see below).
+ Implicitly append this to message for MD calculation.
+6 4 32-bit timestamp of when signature was made.
+ Implicitly append this to message for MD calculation.
+10 8 64-bit Key ID
+18 1 Algorithm byte for public key scheme (RSA=0x01).
+ --Algorithm byte affects field definitions that follow.
+19 1 Algorithm byte for message digest (MD5=0x01).
+20 2 First 2 bytes of the Message Digest inside the
+ RSA-encrypted integer, to help us figure out if we
+ used the right RSA key to check the signature.
+22 ? RSA-encrypted integer, encrypted message digest
+ (MPI with bitcount prefix).
+
+If the plaintext that was signed is included in the same file as the
+signature packet, it begins right after the RSA secret-key-signed
+packet that contains the message digest. The plaintext has a
+"literal" CTB prefix.
+
+The original idea had a variable length field following the length
+of following material byte, before the Key ID. In particular, the
+possibility of a 2-byte validity period was defined, although no
+previous version of PGP ever generated those bytes.
+
+Owing to the way the MD5 is computed for the signature, if that field
+is variable length, it is possible to generate two different messages
+with the same MD5 hash. One would be a file of length N, with a 7-byte
+following section consisting of a signature type byte, 4 bytes of
+timestamp, and 2 of validity period, while the other would be a file of
+length N+2, whose last two bytes would be the siganture type byte and
+the first byte of timestamp, and the last three bytes of timestamp and
+the validity period would instead be interpreted as a signature type
+byte and a timestmap.
+
+It should be emphasized that the messages are barely different and
+special circumstances must arise for this to be possible, so it is
+extremely unlilely that this would be exploitable, but it is a
+potential weakness. It has been plugged by allowing only the currently
+implemented 5-byte option. Validity periods will be added later with
+a different format.
+
+The signature classification field describes what kind of
+signature certificate this is. There are various hex values:
+ 00 - Signature of a message or document, binary image.
+ 01 - Signature of a message or document, canonical text.
+ 10 - Key certification, generic. Only version of key
+ certification supported by PGP 2.5.
+ Material signed is public key pkt and User ID pkt.
+ 11 - Key certification, persona. No attempt made at all
+ to identify the user with a real name.
+ Material signed is public key pkt and User ID pkt.
+ 12 - Key certification, casual identification. Some
+ casual attempt made to identify user with his name.
+ Material signed is public key pkt and User ID pkt.
+ 13 - Key certification, positive ID. Heavy-duty
+ identification efforts, photo ID, direct contact
+ with personal friend, etc.
+ Material signed is public key pkt and User ID pkt.
+ 20 - Key compromise. User signs his own compromise
+ certificate. Independent of user ID associations.
+ Material signed is public key pkt ONLY.
+ 30 - Key/userid revocation. User can sign his own
+ revocation to dissolve an association between a key
+ and a user ID, or certifier may revoke his previous
+ certification of this key/userid pair.
+ Material signed is public key pkt and User ID pkt.
+ 40 - Timestamping a signature certificate made by someone
+ else. Can be used to apply trusted timestamp, and
+ log it in notary's log. Signature of a signature.
+ (Planned, not implemented.)
+
+When a signature is made to certify a key/UserID pair, it is computed
+across two packets-- the public key packet, and the separate User ID
+packet. See below.
+
+The packet headers (CTB and length fields) for the public key packet
+and the user ID packet are both omitted from the signature
+calculation for a key certification.
+
+A key compromise certificate may be issued by someone to revoke his
+own key when his secret key is known to be compromised. If that
+happens, a user would sign his own key compromise certificate with
+the very key that is being revoked. A key revoked by its own
+signature means that this key should never be used or trusted again,
+in any form, associated with any user ID. A key compromise
+certificate issued by the keyholder shall take precedence over any
+other key certifications made by anyone else for that key. A key
+compromise signed by someone other than the key holder is invalid.
+
+Note that a key compromise certificate just includes the key packet
+in its signature calculation, because it kills the whole key without
+regard to any userid associations. It isn't tied to any particular
+userid association. It should be inserted after the key packet,
+before the first userid packet.
+
+When a key compromise certificate is submitted to PGP, PGP will place
+it on the public keyring. A key compromise certificate is always
+accompanied in its travels by the public key and userIDs it affects.
+If the affected key is NOT already on the keyring, the compromise
+certificate (and its key and user ID) is merely added to the keyring
+anywhere. If the affected key IS already on the keyring, the
+compromise certificate is inserted after the affected key packet.
+This assumes that the actual key packet is identical to the one
+already on the key ring, so no duplicate key packet is needed.
+If a key has been revoked, PGP will not allow its use to encipher any
+messages, and if an incoming signature uses it, PGP will display a
+stern warning that this key has been revoked.
+
+NOTE: Key/userid revocation certificates ARE NOT SUPPORTED in
+this version of PGP. But if we ever get around to supporting them,
+here are some ideas on how they should work...
+
+A key/userid revocation certificate may be issued by someone to
+dissolve the association between his own key and a user ID. He would
+sign it with the very key that is being revoked. A key/userid
+revocation certificate issued by the keyholder shall take precedence
+over any other key certifications made by anyone else for that
+key/userid pair. Also, a third party certifier may revoke his own
+previous certification of this key/userid pair by issuing a
+key/userid revocation certificate. Such a revocation should not
+affect the certifications by other third parties for this same
+key/userid pair.
+
+When a key/userid revocation certificate is submitted to PGP, PGP
+will place it on the public keyring. A key/userid revocation
+certificate is always accompanied in its travels by the public key it
+affects (the key packet and user ID packet precedes the revocation
+certificate). If the affected key is NOT already on the keyring, the
+revocation certificate (and its key and user ID) is merely added to
+the keyring anywhere. If the affected key IS already on the keyring,
+the revocation certificate is integrated in with the key's other
+certificates as though it were just another key certification. This
+assumes that the actual key packet is identical to the one already on
+the key ring, so no duplicate key packet is needed.
+
+
+
+Message digest "packet"
+-----------------------
+
+The Message digest has no CTB packet framing. It is stored
+packetless and naked, with padding, encrypted inside the MPI in the
+Signature packet.
+
+PGP versions 2.3 and later use a new format for encoding the message
+digest into the MPI in the signature packet, a format which is
+compatible with RFC1425 (formerly RFC1115). This format is accepted
+but not written by version 2.2. The older format used by versions 2.2
+is acepted by versions up to 2.4, but the RSAREF code in 2.5 is
+not capable of parsing it.
+
+PGP versions 2.2 and earlier encode the MD into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 MD(16 bytes) 0 FF(n bytes) 1
+
+Enough bytes of FF padding are added to make the length of this
+whole string equal to the number of bytes in the modulus.
+
+PGP versions 2.3 and later encode the MD into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 FF(n bytes) 0 ASN(18 bytes) MD(16 bytes)
+
+See RFC1423 for an explanation of the meaning of the ASN string.
+It is the following 18 byte long hex value:
+
+ 3020300c06082a864886f70d020505000410
+
+Enough bytes of FF padding are added to make the length of this
+whole string equal to the number of bytes in the modulus.
+
+All this mainly affects the rsa_private_encrypt() and rsa_public_decrypt()
+functions in rsaglue.c.
+
+There is no checksum included. The padding serves to verify that the
+correct RSA key was used.
+
+
+Conventional Data Encryption Key (DEK) "packet"
+-----------------------------------------------
+
+The DEK has no CTB packet framing. The DEK is stored packetless and
+naked, with padding, encrypted inside the MPI in the RSA
+public-key-encrypted packet.
+
+PGP versions 2.3 and later use a new format for encoding the message
+digest into the MPI in the signature packet. (This format is not
+presently based on any RFCs due to the use of the IDEA encryption
+system.) This format is accepted but not written by version 2.2. The
+older format used by versions 2.2 and earlier is also accepted by
+versions up to 2.4, but the RSAREF code in 2.5 is unable to cope
+with it.
+
+PGP versions 2.2 and earlier encode the DEK into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
+
+CSUM refers to a 16-bit checksum appended to the high end of the DEK.
+RND is a string of NONZERO pseudorandom bytes, enough to make the length
+of this whole string equal to the number of bytes in the modulus.
+
+PGP versions 2.3 and later encode the DEK into the MPI as follows:
+
+ MSB . . . LSB
+
+ 0 2 RND(n bytes) 0 1 DEK(16 bytes) CSUM(2 bytes)
+
+CSUM refers to a 16-bit checksum appended to the high end of the DEK.
+RND is a string of NONZERO pseudorandom bytes, enough to make the length
+of this whole string equal to the number of bytes in the modulus.
+
+For both versions, the 16-bit checksum is computed on the rest of the
+bytes in the DEK key material, and does not include any other material
+in the calculation. In the above MSB-first representation, the
+checksum is also stored MSB-first. The checksum is there to help us
+determine if we used the right RSA secret key for decryption.
+
+
+All this mainly affects the rsa_public_encrypt() and rsa_private_decrypt()
+functions in rsaglue.c.
+
+
+
+Conventional Key Encrypted data packet
+--------------------------------------
+
+Offset Length Meaning
+0 1 CTB for Conventional-Key-Encrypted data packet
+1 4 32-bit (or maybe 16-bit) length of packet
+5 ? conventionally-encrypted data.
+ plaintext has 64 bits of random data prepended,
+ plus 16 bits prepended for "key check" purposes
+
+The decrypted ciphertext may contain a compressed data packet or a
+literal plaintext packet.
+
+After decrypting the conventionally-encrypted data, a special 8-byte
+random prefix and 2 "key check" bytes are revealed. The random prefix
+and key check prefix are inserted before encryption and discarded after
+decryption. This prefix group is visible after decrypting the
+ciphertext in the packet.
+
+The random prefix serves to start off the cipher feedback chaining
+process with 64 bits of random material. It may be discarded after
+decryption. The first 8 bytes is the random prefix material, followed
+by the 2-byte "key-check" prefix.
+
+The key-check prefix is composed of two identical copies of the last
+2 random bytes in the random prefix, in the same order. During
+decryption, the 9th and 10th bytes of decrypted plaintext are checked
+to see if they match the 7th and 8th bytes, respectively. If these
+key-check bytes meet this criterion, then the conventional key is
+assumed to be correct.
+
+One unusual point about the way encryption is done. Using the IDEA
+cipher in CFB mode, the first 10 bytes are decrypted normally,
+but bytes 10 to 17, the first 8 bytes of the data proper, are
+encrypted using bytes 2 to 9 (the last 8 bytes of the key check
+prefix) as the IV. This is essentially using CFB-16 for one
+part of the encryption, while CFB-64 is used elsewhere.
+
+
+Compressed data packet
+----------------------
+
+Offset Length Meaning
+0 1 CTB for Compressed data packet
+1 1 Compression algorithm selector byte (1=ZIP)
+2 ? compressed data
+
+The compressed data begins right after the algorithm selector byte.
+The compressed data may decompress into a raw literal plaintext data
+packet with its own CTB. Currently, compressed data packets
+are always the last ones in their enclosing object, and the decompressor
+knows when to stop, so the length field is omitted. The low two bits
+of the CTB are set to 11. This is the only case in PGP where this
+is currently done.
+
+
+Literal data packet, with filename and mode
+-------------------------------------------
+
+Offset Length Meaning
+0 1 CTB for raw literal data packet
+1 4 32-bit (or maybe 16-bit) length of packet
+5 1 mode byte, 'b'= binary or 't'= canonical text
+6 ? filename, with leading string length byte
+? 4 Timestamp of last-modified date, or 0, or right now
+? ? raw literal plaintext data
+
+The timestamp may be have to be derived in a system dependent manner.
+ANSI C functions should be used to get it if available, otherwise
+store the current time in it. Or maybe store 0 if it's somehow not
+applicable.
+
+Whne calculating a signature on a literal packet, the signature
+calculation only includes the raw literal plaintext data that begins
+AFTER the header fields in the literal packet-- after the CTB, the
+length, the mode byte, the filename, and the timestamp. The reason
+for this is to guarantee that detached signatures are exactly the
+same as attached signatures prefixed to the message. Detached
+signatures are calculated on a separate file that has no packet
+encapsulation.
+
+
+
+Comment packet
+--------------
+
+A comment packet is generally just skipped over by PGP, although it
+may be displayed to the user when processed. It can be put in a
+keyring, or anywhere else.
+
+Offset Length Meaning
+0 1 CTB for Comment packet
+1 1 8-bit length of packet
+2 ? ASCII comment, size is as in preceding length byte
+
+Comment packets are currently not generated by PGP.
+
+
+
+Secret key certificate
+----------------------
+
+Offset Length Meaning
+0 1 CTB for secret key certificate
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte, may affect rest of fields that follow.
+ (=2) for PGP versions <= 2.5
+ (=3) for PGP versions >= 2.6
+4 4 Timestamp
+8 2 Validity period, in number of DAYS (0 means forever)
+10 1 Algorithm byte for RSA (=1 for RSA).
+ --Algorithm byte affects field definitions that follow.
+? ? MPI of RSA public modulus n
+? ? MPI of RSA public encryption exponent e
+
+? 1 Algorithm byte for cipher that protects following
+ secret components (0=unencrypted, 1=IDEA cipher)
+? 8 Cipher Feedback IV for cipher that protects secret
+ components (not present if unencrypted)
+? ? MPI of RSA secret decryption exponent d
+? ? MPI of RSA secret factor p
+? ? MPI of RSA secret factor q
+? ? MPI of RSA secret multiplicative inverse u
+ (All MPI's have bitcount prefixes)
+? 2 16-bit checksum of all preceding secret component bytes
+
+All secret fields in the secret key certificate may be password-
+encrypted, including the checksum. The checksum is calculated from
+all of the bytes of the unenciphered secret components. The public
+fields are not encrypted. The encrypted fields are done in CFB mode,
+and the checksum is used to tell if the password was good. The CFB
+IV field is just encrypted random data, assuming the "true" IV was
+zero.
+
+NOTE: The secret key packet does not contain a User ID field. The
+User ID is enclosed in a separate packet that always follows the secret
+key packet on a keyring or in any other context.
+
+
+Public key certificate
+----------------------
+
+Offset Length Meaning
+0 1 CTB for public key certificate
+1 2 16-bit (or maybe 8-bit) length of packet
+3 1 Version byte, may affect rest of fields that follow.
+ (=2) for PGP versions <= 2.5
+ (=3) for PGP versions >= 2.6
+4 4 Timestamp of key creation
+8 2 Validity period, in number of DAYS (0 means forever)
+10 1 Algorithm byte for RSA (=1 for RSA).
+ --Algorithm byte affects field definitions that follow.
+? ? MPI of RSA public modulus n
+? ? MPI of RSA public encryption exponent e
+ (All MPI's have bitcount prefixes)
+
+NOTE: The public key packet does not contain a User ID field. The
+User ID is enclosed in a separate packet that always follows
+somewhere after the public key packet on a keyring or in any other
+context.
+
+The validity period is currently always set to 0.
+
+
+
+User ID packet
+--------------
+
+Offset Length Meaning
+0 1 CTB for User ID packet
+1 1 8-bit length of packet
+2 ? User ID string, size is as in preceding length byte
+
+The User ID packet follows a public key on a public key ring. It
+also follows a secret key on a secret key ring.
+
+When a key is certified by a signature, the signature covers both the
+public key packet and the User ID packet. The signature certificate
+thereby logically "binds" together the user ID with the key. The
+user ID packet is always associated with the most recently occurring
+public key on the key ring, regardless of whether there are other
+packet types appearing between the public key packet and the
+associated user ID packet.
+
+There may be more than one User ID packet after a public key packet.
+They all would be associated with the preceding public key packet.
+
+
+Keyring trust packet
+--------------------
+
+The three different forms of this packet each come after: a public key
+packet, a user ID packet, or a signature packet on the public key
+ring. They exist only on a public key ring, and are never extracted
+with a key. Don't copy this separate trust byte packet from keyring,
+and do add it in back in when adding to keyring.
+
+The meaning of the keyring trust packet is context sensitive. The
+trust byte has three different definitions depending on whether it
+follows a key packet on the ring, or follows a user ID packet on the
+ring, or follows a signature on the ring.
+
+Offset Length Meaning
+0 1 CTB for Keyring trust packet
+1 1 8-bit length of packet (always 1 for now)
+2 1 Trust flag byte, with context-sensitive bit
+ definitions given below.
+
+
+For trust bytes that apply to the preceding key packet, the following
+bit definitions apply:
+
+ Bits 0-2 - OWNERTRUST bits - Trust bits for this key owner. Values are:
+ 000 - undefined, or uninitialized trust.
+ 001 - unknown, we don't know the owner of this key.
+ 010 - We usually do not trust this key owner to sign other keys.
+ 011 - reserved
+ 100 - reserved
+ 101 - We usually do trust this key owner to sign other keys.
+ 110 - We always trust this key owner to sign other keys.
+ 111 - This key is also present in the secret keyring.
+ Bits 3-4 - Reserved.
+ Bit 5 - DISABLED bit - Means that this key is disabled, and
+ should not be used.
+ Bit 6 - Reserved
+ Bit 7 - BUCKSTOP bit - Means this key also appears in secret key ring.
+ Signifies the ultimately-trusted "keyring owner".
+ "The buck stops here". This bit computed from looking
+ at secret key ring. If this bit is set, then all the
+ KEYLEGIT fields are set to maximum for all the user IDs for
+ this key, and OWNERTRUST is also set to ultimate trust.
+
+For trust bytes that apply to the preceding user ID packet, the
+following bit definitions apply:
+
+ Bit 0-1 - KEYLEGIT bits - Validity bits for this key.
+ Set if we believe the preceding key is legitimately owned by
+ who it appears to belong to, specified by the preceding user
+ ID. Computed from various signature trust packets that
+ follow. Also, always fully set if BUCKSTOP is set.
+ To define the KEYLEGIT byte does not require that
+ OWNERTRUST be nonzero, but OWNERTRUST nonzero does require
+ that KEYLEGIT be fully set to maximum trust.
+ 00 - unknown, undefined, or uninitialized trust.
+ 01 - We do not trust this key's ownership.
+ 10 - We have marginal confidence of this key's ownership.
+ Totally useless for certifying other keys, but may be useful
+ for checking message signatures with an advisory warning
+ to the user.
+ 11 - We completely trust this key's ownership.
+ This requires either:
+ - 1 ultimately trusted signature (a signature from
+ yourself, SIGTRUST=111)
+ - COMPLETES_NEEDED completely trusted signatures
+ (SIGTRUST=110)
+ - MARGINALS_NEEDED marginally trusted signatures
+ (SIGTRUST=101)
+ COMPLETES_NEEDED and MARGINALS_NEEDED are configurable
+ constants.
+ Bit 7 - WARNONLY bit - If the user wants to use a not fully validated
+ key for encryption, he is asked if he really wants to use this
+ key. If the user answers 'yes', the WARNONLY bit gets set,
+ and the next time he uses this key, only a warning will be
+ printed. This bit gets cleared during the maintenance pass.
+
+For a trust byte that applies to the preceding signature, the
+following bit definitions apply:
+
+ Bits 0-2 - SIGTRUST bits - Trust bits for this signature. Value is
+ copied directly from OWNERTRUST bits of signer:
+ 000 - undefined, or uninitialized trust.
+ 001 - unknown
+ 010 - We do not trust this signature.
+ 011 - reserved
+ 100 - reserved
+ 101 - We reasonably trust this signature.
+ 110 - We completely trust this signature.
+ 111 - ultimately trusted signature (from the owner of the ring)
+ Bits 3-6 - Reserved.
+ Bit 6 - CHECKED bit - This means that the key checking pass (pgp -kc,
+ also invoked automatically whenever keys are added to the
+ keyring) has tested this signature and found it good. If
+ this bit is not set, the maintenance pass considers this
+ signature untrustworthy.
+ Bit 7 - CONTIG bit - Means this signature leads up a contiguous trusted
+ certification path all the way back to the ultimately-
+ trusted keyring owner, where the buck stops. This bit is derived
+ from other trust packets. It is currently not used for anything
+ in PGP.
+
+The OWNERTRUST bits are set by the user. PGP does not modify them.
+PGP computes the BUCKSTOP bit by checking to see if the key is on the
+secret key ring. If it is, it was created by this user, and thus
+controlled by him.
+
+All other trust is derived from the BUCKSTOP keys in a special
+maintenance pass over the keyring. Any good signature made by a given
+key has its SIGTRUST equal to the key's OWNERTRUST. Based on
+COMPLETES_NEEDED and MARGINALS_NEEDED, if enough trusted signatures are
+on a key/userID pair, the key/userid association is considered
+legitimate.
+
+To be precise, an ultimately trusted key has weight 1, a completely
+trusted key has weight 1/COMPLETES_NEEDED (or 0 if COMPLETES_NEEDED
+is 0), and a marginally trsuted key has weight 1/MARGINALS_NEEDED.
+Other trust values have weight 0. If the total weight of the signatures
+on a key/userid pair is 1 or more, the userid is considered legitimate.
+
+When a key has a legitimate userid, the user is asked to set the
+OWNERTRUST for the corresponding key. Ths idea is that the userid
+identifies someone the user knows, at least by reputation, so once it
+has been established who holds the secret key, that person's
+trustworthiness as an introducer can be established and assigned to the
+key.
+
+Once that is done, the key's signatures then have weight establishing
+other key/userid associations.
+
+There is a limit to the depth to which this can go. Keys on the secret
+keyring are at depth 0. Keys signed by those keys are at depth 1.
+Keys which are fully certified using only signatures from keys at depth
+1 or less are at depth 2. Keys which are fully certified using only
+signatures from keys at depth 2 or less are at depth 3, and so on.
+
+If you know all of your trusted introducers personally, and have signed
+their keys, then you will never have a key at a depth of greater than 2.
+The maximum depth is limited my MAX_CERT_DPETH. It never gets very large
+in a well-connected "web of trust".
+
+This redundant and decentralized method of determining public key
+legitimacy is one of the principal strengths of PGP's key management
+architecture, as compared with PEM, when used in social structures
+that are not miltiary-style rigid hierarchies.
+
+The trust of a key owner (OWNERTRUST) does not just reflect our
+estimation of their personal integrity, it also reflects how competent
+we think they are at understanding key management and using good
+judgement in signing keys. The OWNERTRUST bits are not computed from
+anything -- it requires asking the user for his opinion.
+
+To define the OWNERTRUST bits for a key owner, ask:
+ Would you always trust "Oliver North"
+ to certify other public keys?
+ (1=Yes, 2=No, 3=Usually, 4=I don't know) ? _
+
+When a key is added to the key ring the trust bytes are initialized
+to zero (undefined).
+
+
+[--manual setting of SIGTRUST/OWNERTRUST not implemented]
+Normally, we derive the value of the SIGTRUST field by copying it
+directly from the signer key's OWNERTRUST field. Under special
+circumstances, if the user explicitly requests it with a special PGP
+command, we may let the user override the copied value for SIGTRUST
+by displaying an advisory to him and asking him for ratification,
+like so:
+ This key is signed by "Oliver North",
+ whom you usually trust to sign keys.
+ Do you trust "Oliver North"
+ to certify the key for "Daniel Ellsberg"?
+ (1=Yes, 2=No, 3=Somewhat, 4=I don't know) ? _ <default is yes>
+
+Or:
+ This key is signed by "Oliver North",
+ whom you usually do not trust to sign keys.
+ Do you trust "Oliver North"
+ to certify the key for "Daniel Ellsberg"?
+ (1=Yes, 2=No, 3=Somewhat, 4=I don't know) ? _ <default is no>
+
+An "I don't know" response to this question would have the same
+effect as a response of "no".
+
+If we had no information about the trustworthiness of the signer (the
+OWNERTRUST field was uninitialized), we would leave the advisory note
+off.
+
+
+Certifying a public key is a serious matter, essentially promising to
+the world that you vouch for this key's ownership. But sometimes I
+just want to make a "working assumption" of trust for someone's
+public key, for my own purposes on my own keyring, without taking the
+serious step of actually certifying it for the rest of the world. In
+that case, we can use a special PGP keyring management command to
+manually set the KEYLEGIT field, without relying on it being computed
+during a maintenance pass. Later, if a maintenance pass discovers a
+KEYLEGIT bit set that would not have been otherwise computed as set
+by the maintenance pass logic, it alerts me and asks me to confirm
+that I really want it set.
+
+[--end of not implemented section]
+
+
+During routine use of the public keyring, we don't actually check the
+associated signatures certifying a public key. Rather, we always
+rely on trust bytes to tell us whether to trust the key in question.
+We depend on a separate checking pass (pgp -kc) to actually check the key
+signature certificates against the associated keys, and to set the
+trust bytes accordingly. This pass checks signatures, and if a
+signature fails to verify, obnoxiously alerts the user and drops it from
+the key ring. Then it tuns a maintenance pass to calculate the
+ring-wide effects of this.
+
+A failed signature should be exceedingly rare, and it may not even
+result in a KEYLEGIT field being downgraded. Having several signatures
+certifying each key should prevent damage from spreading too far from a
+failed certificate. But if dominoes do keep falling from this, it may
+indicate the discovery of an important elaborate attack.
+
+The maintenance pass is run every time the keyring changes, and
+operates in a top-of-pyramid-down manner as follows.
+
+If at any time during any of these steps the KEYLEGIT field goes from
+not fully set to fully set, and the OWNERTRUST bits are still undefined,
+the user is asked a question to define the OWNERTRUST bits. First, for
+all keys with BUCKSTOP set, check if they are really present in the
+secret keyring, if not, the BUCKSTOP bit is cleared. SIGTRUST and
+KEYLEGIT is initialized to zero for non-buckstop keys.
+
+The real maintenance pass is done in a recursive scan: Start with
+BUCKSTOP keys, find all userid/key pairs signed by a key and update
+the trust value of these signatures by copying the OWNERTRUST of the
+signer to the SIGTRUST of the signature. If this makes a key fully
+validated, start looking for signatures made by this key, and update
+the trust value for them. Repeat until everything has settled down.
+
+
+
+
+Public Key Ring Overall Structure
+=================================
+
+A public key ring is comprised of a series of public key packets,
+keyring trust packets, user ID packets, and signature certificates.
+
+Here is an example of an ordered collection of packets on a ring:
+
+--------------------------------------------------------------------
+ Public key packet
+ Keyring trust packet for preceding key
+ User ID packet for preceding key
+ Keyring trust packet for preceding user ID/key association
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+
+ Public key packet
+ Keyring trust packet for preceding key
+ User ID packet for preceding key
+ Keyring trust packet for preceding user ID/key association
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+ User ID packet for preceding key
+ Keyring trust packet for preceding user ID/key association
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+
+ Public key packet
+ Keyring trust packet for preceding key
+ Compromise certificate for preceding key
+ User ID packet for preceding key
+ Keyring trust packet for preceding user ID/key association
+ Signature certificate to bind preceding User ID and key pkt
+ Keyring trust packet for preceding signature certificate
+--------------------------------------------------------------------
diff --git a/Protocol/PGP/keyring.shelve b/Protocol/PGP/keyring.shelve
new file mode 100644
index 0000000..718839c
--- /dev/null
+++ b/Protocol/PGP/keyring.shelve
Binary files differ
diff --git a/Protocol/PGP/parsepgp b/Protocol/PGP/parsepgp
new file mode 100755
index 0000000..2c6822a
--- /dev/null
+++ b/Protocol/PGP/parsepgp
@@ -0,0 +1,39 @@
+#!/usr/local/bin/python
+# -*- Python -*-
+import pgp, sys
+
+PacketType={1:'PKEncrypted', 2:'Signature', 5:'PrivKey', 6:'PubKey',
+ 8:'Compressed', 9:'Ciphered', 11:'Plaintext', 12:'Trust',
+ 13:'UserID', 14:'Comment'}
+
+def ParseString(s, packet={}):
+ try:
+ while (s!=""):
+ p=pgp.Packet(s)
+ s=s[p.PacketLength:]
+ packet[p.Type]=p
+ if PacketType.has_key(p.Type): typename=PacketType[p.Type]
+ else: typename='Unknown type'
+ print p.Type, typename
+ except pgp.PossibleEnd, message:
+ pass
+
+import md5
+DEK=md5.new('test').digest()
+
+def DumpPacket(p, indent=0):
+ if indent>20: return
+ while (1):
+ packet=pgp.ReadPacket(p, DEK=DEK)
+ if packet==None: break
+ if PacketType.has_key(packet.Type): typename=PacketType[packet.Type]
+ else: typename=''
+ sys.stderr.write(' '*indent+str(packet.Type)+' '+typename+'\n')
+ if packet.Type in [pgp.CIPHERED, pgp.COMPRESSED]:
+ DumpPacket(packet, indent+4)
+
+DumpPacket(sys.stdin)
+
+
+
+
diff --git a/Protocol/PGP/pgp-api.txt b/Protocol/PGP/pgp-api.txt
new file mode 100644
index 0000000..99fe9e4
--- /dev/null
+++ b/Protocol/PGP/pgp-api.txt
@@ -0,0 +1,74 @@
+Over a year ago, I started work on a PGP library for the Python
+programming language, but it never really got finished. All of the
+pieces are present--cryptographic modules for MD5, IDEA and RSA, a
+zlib module for data compression, and Python code to read the packets
+that make up PGP keyrings and messages--but the pieces were never
+assembled into a coherent high-level interface. Recently a few people
+have expressed interest in the project, so I've revived it.
+
+So... here's a proposal for an interface:
+
+ASCII armoring:
+===============
+
+ ArmorFile( <file1 object> [ , output=<file2 object> ])
+
+Read from file1 and ASCII-armor its contents. If file2 is provided,
+the output will be written to file2; otherwise it will return a string
+containing the data instead.)
+
+ UnarmorFile( <file1 object> [ , output=<file2 object> ])
+Read from file1 and remove ASCII armor from its contents. If file2 is
+provided, the output will be written to file2; otherwise it will be
+written to sys.stdout. An exception will be raised if the CRC check
+is failed or the file is incomplete.
+
+(XXX Do we need versions of the above that operate on strings? One
+ could simply do ArmorFile( StringIO.StringIO(s) ), at the cost of
+ some speed.)
+
+Keyring operations:
+===================
+
+class PGPKey(RSA.key):
+ def __init__(self, file=None, string=""):
+ Create a PGPKey object; the key data will either be
+ taken from the given string or read from the given file
+ object.
+
+ Only zero or one of file, string can be given--not both.
+
+XXX Annoyingly, if the data is being read from a file,
+we have to read PGP packets until we either hit EOF or another key.
+If it's another key, then we've read one packet too far, and have to
+seek back to reset the file pointer. Maybe instead we should have a
+
+
+PGPKey objects have the following methods:
+
+ unlock(password)
+Decrypt the RSA private key (if present), using the provided password.
+
+ lock()
+Discard the decoded RSA key data, if present.
+
+ relock(password)
+Re-encrypt the RSA private key data using the provided password.
+
+ encrypt(string)
+ RSA-encrypt the given string with the key; if string is too
+big, raise an exception.
+
+ decrypt(packet)
+ RSA-decrypt the given packet with the key.
+
+Messages:
+=========
+
+EncryptMessage(recipients= <list of keys>, # Who the message will be encrypted for
+ signer=<unlocked key>, # Key used to sign the message
+ compress=<Boolean> # Compression on/off
+ )
+
+
+
diff --git a/Protocol/PGP/pgp.py b/Protocol/PGP/pgp.py
new file mode 100644
index 0000000..e5a6fae
--- /dev/null
+++ b/Protocol/PGP/pgp.py
@@ -0,0 +1,1061 @@
+#
+# PGP PACKET CLASSES and KEYRING MANAGER
+#
+#
+
+from pgpconst import *
+import md5
+
+# Find a big number library
+try:
+ import gmp ; bignum=gmp.mpz
+except ImportError:
+ try:
+ import mpz ; bignum=mpz.mpz
+ except ImportError: bignum=long
+
+Error = 'PGPError'
+
+#
+#
+# UTILITY FUNCTIONS
+#
+#
+
+def get_hash_module(v, module_dict={}):
+ "Return the module for a given hash algorithm"
+ if module_dict.has_key(v): return module_dict[v]
+ if v==HASH_MD5: import md5 ; mod=md5
+ else: raise Error, 'Unknown hash algorithm '+str(v)
+ module_dict[v]=mod ; return mod
+
+def get_cipher_module(v, module_dict={}):
+ "Return the module for a given private-key encryption algorithm"
+ if module_dict.has_key(v): return module_dict[v]
+ if v==CIPHER_IDEA: import idea ; mod=idea
+ else: raise Error, 'Unknown cipher algorithm '+str(v)
+ module_dict[v]=mod ; return mod
+
+def get_random_bytes(N):
+ "Return N bytes of random data"
+ if N<0:
+ raise ValueError, 'Attempt to retrieve infinite amount of random data'
+ f=open('/dev/urandom', 'r')
+ data=f.read(N)
+ f.close()
+ return data[0:N]
+
+def Str2Int(astr):
+ "Convert a string into a long integer"
+ curr = bignum(0)
+ for char in astr: curr = (curr<<8) + ord(char)
+ return curr
+
+def Int2Str(i, bits=0):
+ "Convert a long integer into a big-endian string, padding if desired."
+ if (i==0): res='\0'
+ elif i<0: raise Error, 'Cannot convert negative INT to string.'
+ else:
+ res = ''
+ while i > 0:
+ res = chr(int(i&255)) + res
+ i = i>>8
+ if bits!=0:
+ bytes=bits/8
+ if len(res)<bytes: res=('\0'*(bytes-len(res)))+res
+ return res
+
+def MPILen(str):
+ "Extract the length of an MPI from the string encoding"
+ length=ord(str[0])*256+ord(str[1])
+ length, remainder = divmod(length, 8)
+ if remainder!=0: length=length+1
+ return length
+
+def MPI2Int(str):
+ "Turn a string-encoded MPI into a long integer"
+ length=MPILen(str)
+ return (Str2Int(str[2:2+length]), (2+length))
+
+def Int2MPI(i):
+ "Turn a long integer into an MPI string"
+ s=Int2Str(i)
+# while (ord(s[0])==0): s=s[1:] # XXX why is this required?
+ if (s==''): return '\000\000'
+ first=ord(s[0])
+ bits= 1+(len(s)-1) *8
+ mask=1
+ while (mask<first and mask <256):
+ first = first & (255-mask)
+ mask=mask << 1
+ bits=bits+1
+ s=chr(bits/256)+chr(bits & 255)+s
+ return s
+
+def Checksum(data, cksum=0):
+ "Compute a simple checksum, which is just the sum of the bytes."
+ for i in range(0,len(data)):
+ cksum= ( cksum + ord(data[i]) ) & 65535
+ return cksum
+
+def getLen(CTB, pgpstring):
+ "Return a length-of-length, and the length, from the CTB and length string"
+ LEN = (CTB&3)
+ if not PACKET_LENGTH.has_key(LEN):
+ raise Error, "Unknown length of length"
+ lenlen=PACKET_LENGTH[LEN]
+ if lenlen!=0:
+ length=int(Str2Int(pgpstring[:lenlen]))
+ else: length=None
+ return lenlen, length
+
+#
+#
+# CLASSES
+#
+#
+
+#
+# Base class for PGP packets
+#
+
+class Packet:
+ def __init__(self, input=None):
+ self.CTBT = 0
+
+ def binary(self, CTBT=0):
+ "Convert object to its string representation, preceded by the packet header."
+ data=self.write_bin()
+ header=self.mkHeader(len(data), bits=0, CTBT=CTBT)
+ return header+data
+
+ def mkHeader(self, length, bits=0, CTBT=0):
+ "Return a packet header from the type and the length"
+
+ # To allow PrivateKey objects to be written either as
+ # public or private objects, there has to be a way to
+ # override the object's CTBT.
+ if CTBT==0: packet_type=self.CTBT
+
+ # Check for a constraint on the length-of-length field
+ if bits==0 and PACKET_SIZES.has_key(packet_type):
+ bits=PACKET_SIZES[packet_type]
+
+ if packet_type<1 or packet_type>14:
+ raise Error, 'Invalid packettype '+str(packet_type)
+ CTB = 128 | (packet_type<<2)
+ if length==None: return chr(CTB|3)
+ elif length<256 and (bits==0 or bits==8):
+ bits=8
+ elif length<65536 and (bits==0 or bits==16):
+ bits=16 ; CTB = CTB|1
+ elif length<4294967296 and (bits==0 or bits==32):
+ bits=32 ; CTB = CTB|2
+ else: raise Error, 'Packet too long.'
+ return chr(CTB)+Int2Str(length, bits)
+
+ def parse_bin(self, binstr):
+ """Parse a string containing a PGP packet, into the 'self' object."""
+ raise Error, 'Called unimplemented method parse_bin.'
+
+ def write_bin(self):
+ "Convert object to its string representation, without the packet header."
+ raise Error, 'Called unimplemented method write_bin.'
+
+
+class PKEncrypted(Packet):
+ def __init__(self, version=2):
+ Packet.__init__(self)
+ self.CTBT=CTBT_PKEP
+ self.Version = version
+ self.KeyID=bignum(0)
+ self.PubkeyAlg=PK_NONE
+ self.Data=bignum(0)
+
+ def parse_bin(self, binstring):
+ pos=0
+ self.Version=ord(binstring[pos])
+ if self.Version<>2: raise Error, 'Unsupported packet version '+str(version)
+ pos=pos+1
+ self.KeyID=Str2Int(binstring[pos:pos+8])
+ pos=pos+8
+ self.PubkeyAlg=ord(binstring[pos])
+ pos=pos+1
+ if self.PubkeyAlg==PK_RSA:
+ self.Data, mpilen = MPI2Int(binstring[pos:])
+ pos=pos+mpilen
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+ if pos<>len(binstring):
+ print 'WARNING: length mismatch in PK-encrypted packet.'
+ def write_bin(self):
+ data = (chr(self.Version) +
+ Int2Str( self.KeyID, 64) +chr(self.PubkeyAlg) )
+ if self.PubkeyAlg==PK_RSA:
+ d=self.Data
+ if type(d)==type(''): d=Str2Int(d)
+ data=data+Int2MPI(d)
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+ return data
+
+class Compressed(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.CompressAlg=COMPRESS_NONE
+ self.CTBT=CTBT_COMPR
+ self.Data=""
+ def compress(self, data):
+ if self.CompressAlg==COMPRESS_ZLIB:
+ import zlib
+ compr_obj=zlib.compressobj(5, 8, -15)
+ self.Data=compr_obj.compress(data)
+ self.Data=self.Data+compr_obj.flush()
+ else:
+ raise Error, 'Unknown compression algorithm'
+
+ def decompress(self):
+ if self.CompressAlg==COMPRESS_ZLIB:
+ import zlib
+ decompr_obj=zlib.decompressobj(-15)
+ data=decompr_obj.decompress(self.Data)
+ data=data+decompr_obj.flush()
+ return data
+ else:
+ raise Error, 'Unknown compression algorithm'
+
+ def parse_bin(self, binstring):
+ pos=0
+ self.CompressAlg=ord(binstring[pos])
+ pos=pos+1
+ if self.CompressAlg==COMPRESS_ZLIB:
+ self.Data=binstring[pos:]
+ else:
+ raise Error, 'Unknown compression algorithm'
+ def write_bin(self):
+ return chr(self.CompressAlg)+self.Data
+
+class ConvEncrypted(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.Data="" ; self.CTBT = CTBT_CKEP
+ def encrypt(self, key, data, cipheralg=CIPHER_IDEA):
+ if cipheralg==CIPHER_IDEA:
+ import idea
+ IV=get_random_bytes(idea.blocksize)
+ cipherobj=idea.new(key, idea.PGP, '\000'*idea.blocksize)
+ output=cipherobj.encrypt(IV+IV[-2:])
+ cipherobj.sync()
+ self.Data=output+cipherobj.encrypt(data)
+ else: raise Error, 'Unsupported cipher algorithm '+str(cipheralg)
+ def decrypt(self, key, cipheralg):
+ if cipheralg==CIPHER_IDEA:
+ import idea
+ cipherobj=idea.new(key, idea.PGP, '\000'*idea.blocksize)
+ data=cipherobj.decrypt(self.Data[:10])
+ if data[6:8]!=data[8:10]:
+ raise Error, 'Error during conventional decryption'
+ cipherobj.sync()
+ else: raise Error, 'Unsupported cipher algorithm '+str(cipheralg)
+ return cipherobj.decrypt(self.Data[10:])
+ def parse_bin(self, binstring):
+ self.Data=binstring
+ def write_bin(self):
+ return self.Data
+
+class Plaintext(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.CTBT = CTBT_PLAIN
+ self.Mode='b'
+ self.Filename=""
+ self.Timestamp=0
+ self.Data=""
+ def isBinary(self):
+ if self.Mode in 'bB': return 1
+ elif self.Mode in 'tT': return 0
+ else: raise Error, 'Unknown Plaintext mode byte'
+ def parse_bin(self, binstring):
+ pos=0
+ self.Mode=binstring[pos] ; pos=pos+1
+ if self.Mode not in 'bBtT':
+ raise Error, 'Unknown Plaintext mode byte'
+ filename_len=ord(binstring[pos]) ; pos=pos+1
+ self.Filename=binstring[pos:pos+filename_len]
+ pos=pos+filename_len
+ self.Timestamp=Str2Int(binstring[pos:pos+4])
+ pos=pos+4
+ self.Data=binstring[pos:]
+ def write_bin(self):
+ if len(self.Filename)>256:
+ raise Error, "Filename is too long...256 chars maximum"
+ return (self.Mode +
+ chr(len(self.Filename)) + self.Filename +
+ Int2Str(self.Timestamp, 32) + self.Data )
+
+class Comment(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.CTBT = CTBT_COMMENT
+ self.Comment=None
+ def parse_bin(self, binstring):
+ self.Comment=binstring
+ def write_bin(self, binstring):
+ return self.Comment
+ def __str__(self): return self.Comment
+
+#
+# Base class for Keys (private and public)
+#
+class Key(Packet):
+ def __init__(self, version=3):
+ Packet.__init__(self)
+ self.ModulusSize = 0
+ self.Version = version
+ self.KeyID = bignum(0)
+ self.Timestamp = 0
+ self.Validity = 0
+ self.PubkeyAlg = PK_RSA
+ self.IDList = []
+ self.Trust = None
+
+ def padEncryptionKey(self, M):
+ "Given a Data Encryption Key (DEK), pad it suitably for PK encryption"
+ if type(M)!=type(''): M=Int2Str(M)
+ L=len(M)
+ if L>=384/8:
+ # We'll assume that anything larger than 384 bits doesn't
+ # need padding.
+ return M
+
+ if self.Version==2:
+ pad=self.ModulusSize/8-L-6
+ csum=Int2Str(Checksum(M), 16)
+ randbytes=get_random_bytes(pad)
+ M='\000\001'+M+csum+'\000'+randbytes+'\002'
+ return M
+ elif self.Version==3:
+ pad=self.ModulusSize/8-L-6
+ csum=Int2Str(Checksum(M), 16)
+ randbytes=get_random_bytes(pad)
+ M='\000\002'+randbytes+'\000\001'+M+csum
+ return M
+ else:
+ raise Error, 'Unsupported packet version '+str(self.Version)
+
+ def unpadEncryptionKey(self, M):
+ "Return the DEK, by removing the padding."
+ if type(M)!=type(''): M=Int2Str(M)
+ import string
+ if self.Version==2:
+ start=string.find(M, '\001')
+ if start==-1 or M[0]!='\001' or M[-1]!='\002':
+ raise Error, "Can't undo v2.2 key padding"
+ DEK, csum = M[start:start+16], M[start+16:start+18]
+ # XXX check csum!
+ return DEK
+ elif self.Version==3:
+ if M[0]!='\002' or M[-20:-18]!='\000\001':
+ raise Error, "Can't undo v2.3 key padding"
+ DEK, csum = M[-18:-2], M[-2:]
+ # XXX check csum!
+ return DEK
+ else:
+ raise Error, 'Unsupported packet version '+str(self.Version)
+
+ def padMessageDigest(self, M):
+ "Pad a message digest appropriately."
+ L=len(M)
+ if L>=384/8:
+ # We'll assume that anything larger than 384 bits doesn't
+ # need padding.
+ return M
+ if self.PubkeyAlg==PK_RSA:
+ # RSA encryption
+ if L<self.ModulusSize/8:
+ if self.Version==2:
+ # PGP 2.2 padding
+ pad=self.ModulusSize/8-L-4
+ M='\000\001'+M+'\000'+('\377'*pad)+'\001'
+ return M
+ elif self.Version==3:
+ pad=self.ModulusSize/8-L-21
+ M='\000\001'+('\377'*pad)+'\000'+ASN_STRING+M
+ return M
+ else:
+ raise Error, 'Unsupported packet version '+str(self.Version)
+ else: raise Error, "Unknown public-key algorithm "+str(PubkeyAlg)
+
+ def unpadMessageDigest(self, M):
+ "Return the message digest, after removing the padding"
+ import string
+ if self.PubkeyAlg==PK_RSA:
+ if self.Version==2:
+ end=string.rfind(M, '\000')
+ start=string.find(M, '\001')
+ if start==-1 or end==-1:
+ raise Error, "Can't undo v2.2 digest padding"
+ return M[start+1:end]
+ elif self.Version==3:
+ start=string.find(M, ASN_STRING)
+ if start==-1:
+ raise Error, "Can't undo v2.3 digest padding"
+ return M[start+len(ASN_STRING):]
+ else: raise Error, "Unknown public-key algorithm "+str(PubkeyAlg)
+
+ def isPrivate(self): return 0
+ def isUnlocked(self): return 0
+
+#
+# Public Keys
+#
+
+class PublicKey(Key):
+ def __init__(self, version=3):
+ Key.__init__(self, version)
+ self.CTBT = CTBT_PKCERT
+ if (version==2) or (version==3):
+ self.PubkeyAlg = PK_RSA
+ self.KeyCompromise = None
+ self.n = 0
+ self.e = 0
+ else: raise Error, 'Unsupported packet version '+str(version)
+
+ def __repr__(self):
+ return '<Public '+hex(self.KeyID)+'>'
+
+ def encrypt(self, M):
+ "Encrypt a message with this key object. Padding the caller's responsibility."
+ if type(M)==type(''): M=Str2Int(M)
+ if self.PubkeyAlg==PK_RSA:
+ result=pow(M, self.e, self.n)
+# Mt=pow(result, self.d, self.n)
+# if M!=Mt: print 'Encryption mismatch'
+ return Int2Str(result)
+ else:
+ raise Error, "Unknown public-key algorithm "+str(self.PubkeyAlg)
+
+ def decrypt(self, M):
+ "Decrypt with this key object"
+ if not self.isPrivate():
+ raise Error, "Cannot decrypt with public key"
+ elif not self.isUnlocked():
+ raise Error, "Private key is not unlocked."
+ if type(M)==type(''): M=Str2Int(M)
+ if self.PubkeyAlg==PK_RSA:
+ result=pow(M, self.d, self.n)
+ # XXX remove the following check
+ Mt=pow(result, self.e, self.n)
+ if M!=Mt: print 'Decryption mismatch'
+ return Int2Str(result)
+ else:
+ raise Error, "Unknown public-key algorithm "+str(self.PubkeyAlg)
+
+ def sign(self, data, hashAlg=HASH_MD5):
+ import time
+ hash=get_hash_module(hashAlg)
+ hash_obj=hash.new(data)
+ sig=Signature()
+ sig.Timestamp = long(time.time())
+ sig.SigClass=0 ; sig.HashAlg=hashAlg
+ sig.SigKeyID, sig.PubkeyAlg=self.KeyID, self.PubkeyAlg
+ hash_obj.update(chr(sig.SigClass) +
+ Int2Str(sig.Timestamp, 32))
+ print `chr(sig.SigClass) + Int2Str(sig.Timestamp, 32)`
+ MD=hash_obj.digest()
+ sig.HashClue=MD[0:2]
+ MD=self.padMessageDigest(MD)
+ sig.signature=Str2Int(self.decrypt(MD))
+ print sig.__dict__
+ return sig
+
+ def is_self_signed(self):
+ "Test if a key is self-signed, returning a Boolean value"
+ for item in self.IDList:
+ for sig in item.SigList:
+ if (sig.SigKeyID==self.KeyID and
+ sig.verify_key_sig(self, self, item)):
+ return 1
+ return 0
+
+ def measureModulus(self):
+ "Determine the maximum message size that this key can handle"
+ if self.PubkeyAlg==PK_RSA:
+ t,bits=1L,0
+ while t<self.n: t,bits = t<<1L, bits+1
+ self.ModulusSize=bits
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+
+ def parse_bin(self, binstring):
+ pos = 0
+ self.Version = ord(binstring[pos])
+ if self.Version not in [2, 3]: raise Error, 'Unknown Public Key version '+str(self.Version)
+ pos = pos + 1
+ self.Timestamp = Str2Int(binstring[pos:pos+4])
+ pos = pos + 4
+ self.Validity = Str2Int(binstring[pos:pos+2])
+ pos = pos + 2
+ self.PubkeyAlg = ord(binstring[pos])
+ if self.PubkeyAlg not in PK_LIST:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+ pos = pos + 1
+ self.n, mpilen = MPI2Int(binstring[pos:])
+ self.KeyID = Str2Int(binstring[pos+mpilen-8:pos+mpilen])
+ pos = pos + mpilen
+ self.e, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ if pos<>len(binstring):
+ print 'WARNING: length mismatch in Public Key packet.'
+ self.measureModulus()
+
+ def write_bin(self):
+ data = (chr(self.Version) + Int2Str(self.Timestamp, 32) +
+ Int2Str(self.Validity, 16) + chr(self.PubkeyAlg) )
+ if self.PubkeyAlg==PK_RSA:
+ data=data+Int2MPI(self.n)+Int2MPI(self.e)
+ else: raise Error, "Unknown public-key algorithm "+str(self.PubkeyAlg)
+ return data
+
+
+#
+# Private Keys
+#
+
+class PrivateKey(PublicKey):
+ def __init__(self, version=3):
+ Key.__init__(self, version)
+ self.CTBT = CTBT_SKCERT ; self.CipherAlg=CIPHER_NONE
+ self.PubkeyAlg = PK_RSA
+
+ def __repr__(self):
+ return '<Secret key '+hex(self.KeyID)+'>'
+
+ def isPrivate(self): return 1
+ def isUnlocked(self):
+ if self.PubkeyAlg==PK_RSA:
+ return hasattr(self, 'd')
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+
+ def Unlock(self, passphrase = ""):
+ "Decrypt the private key data, given a passphrase."
+ binstring=self.Data ; pos=0
+ if (self.CipherAlg==CIPHER_NONE):
+ # Unencrypted private key, so just unpack
+ self.d, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ self.p, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ self.q, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ self.u, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ checksum=Str2Int(binstring[pos:pos+2])
+ pos = pos + 2
+ elif self.CipherAlg==CIPHER_IDEA:
+ cipher_mod=get_cipher_module(CIPHER_IDEA)
+ hash_mod=get_hash_module(HASH_MD5)
+ key=hash_mod.new(passphrase).digest()
+ cipherobj=cipher_mod.new(key, cipher_mod.PGP,
+ cipher_mod.blocksize*'\000')
+
+ IV=binstring[pos:pos+8] ; pos=pos+8
+ s=cipherobj.decrypt(IV)
+ cipherobj.sync()
+
+ if (self.PubkeyAlg==PK_RSA):
+ d={}
+ cksum=Checksum("")
+ for i in 'dpqu':
+ dummy, mpilen = MPI2Int(binstring[pos:])
+ MPI=binstring[pos:pos+mpilen]
+ pos = pos + mpilen
+
+ plain=MPI[:2]+cipherobj.decrypt(MPI[2:])
+ cipherobj.sync()
+ cksum=Checksum(plain,cksum)
+ value, dummy = MPI2Int(plain)
+ setattr(self, i, value)
+
+ checksum=Str2Int(binstring[pos:pos+2])
+ pos = pos + 2
+
+ # If the checksum doesn't match, the passphrase must be wrong
+ if (cksum!=checksum):
+ raise Error, 'Incorrect passphrase'
+
+ else:
+ raise Error, "Unknown public-key algorithm "+str(self.PubkeyAlg)
+
+ def Lock(self, passphrase=None):
+ """Reencipher a PGP private key with a new passphrase, or with
+ the previous passphrase implied. Note that once a key's private
+ data has been encrypted, this interface will never let you
+ revert to having no password, even though PGP permits this.
+ It's probably not a big loss."""
+
+ if passphrase!=None:
+ # Transform passphrase to a 128-bit IDEA key
+ import md5
+ key=md5.new(passphrase).digest()
+
+ # Create encryption object
+ if self.CipherAlg==CIPHER_NONE: self.CipherAlg=CIPHER_IDEA
+ cipher_mod=get_cipher_module(self.CipherAlg)
+ cipherobj=cipher_mod.new(key, cipher_mod.PGP,
+ '\000'*cipher_mod.blocksize)
+ data=IV=get_random_bytes(cipher_mod.blocksize)
+ cipherobj.decrypt(IV)
+ cksum=Checksum("")
+ for i in 'dpqu':
+ cipherobj.sync()
+ MPI=Int2MPI(getattr(self, i))
+ cksum=Checksum(MPI, cksum)
+ MPI=MPI[:2]+cipherobj.encrypt(MPI[2:])
+ data=data+MPI
+ self.Data=data+Int2Str(cksum, 16)
+ elif not hasattr(self, 'Data'):
+ raise Error, "Can't lock a generated key without a passphrase"
+ # Delete the secret attributes
+ for i in 'dpqu': delattr(self, i)
+
+ def public_binary(self):
+ "Return the string representation of this key as a public certificate"
+ data=PublicKey.write_bin(self)
+ header=self.mkHeader(len(data), CTBT=CTBT_PKCERT)
+ return header+data
+
+ def generate(self, PKalg=PK_RSA, *args):
+ "Generate a new public/private key pair"
+ self.PubkeyAlg=PKalg
+ if PKalg==PK_RSA: self.generateRSA(args)
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+
+ def generateRSA(self, args):
+ "Generate a new RSA public/private key pair"
+ # XXX Comment this section!
+ import pubkey
+ if len(args)==1: bits, = args ; ebits=5
+ elif len(args)==2: bits, ebits = args
+ bits=(bits+7)/8
+ if bits%2==1: bits=bits+1 # Ensure that an odd number of bytes are required
+ p=Str2Int(get_random_bytes(bits/2)) | pow(2L, bits*8/2-1) | 3
+ q=Str2Int(get_random_bytes(bits-bits/2)) | pow(2L, bits*8/2) | 3
+ p=pubkey.findPrime(p) ; q=pubkey.findPrime(q)
+ if p>q: p,q=q,p
+ phi=(p-1)*(q-1)
+ ebits=(ebits+7)/8
+ exp= Str2Int(get_random_bytes(ebits))|1
+ exp = exp & (pow(bignum(2), ebits+1) - 1)
+ while pubkey.GCD(exp, phi)!=1: exp=exp+2
+ self.p, self.q, self.n = p, q, p*q
+ self.e, self.d = exp, pubkey.Inverse(exp, phi)
+ self.u = pubkey.Inverse(p, q)
+
+ import time
+ self.Timestamp=int(time.time())
+ self.KeyID = self.n & 0xFFFFffffL
+ self.measureModulus()
+
+ print hex(self.p),hex(self.q)
+ print hex(self.n)
+ print hex(self.e),hex(self.d)
+## M=1972L
+## C=pow(M, self.e, self.n)
+## M=pow(C, self.d, self.n)
+## print M
+
+ def parse_bin(self, binstring):
+ pos = 0
+ self.Version = ord(binstring[pos])
+ if self.Version not in [2, 3]: raise Error, 'Unknown Private Key version '+str(self.Version)
+ pos = pos + 1
+ self.Timestamp = Str2Int(binstring[pos:pos+4])
+ pos = pos + 4
+ self.Validity = Str2Int(binstring[pos:pos+2])
+ pos = pos + 2
+ self.PubkeyAlg = ord(binstring[pos])
+ if self.PubkeyAlg==PK_RSA:
+ pos = pos + 1
+ self.n, mpilen = MPI2Int(binstring[pos:])
+ self.KeyID = Str2Int(binstring[pos+mpilen-8:pos+mpilen])
+ pos = pos + mpilen
+ self.e, mpilen = MPI2Int(binstring[pos:])
+ pos = pos + mpilen
+ self.CipherAlg=ord(binstring[pos])
+ pos = pos + 1
+ if self.CipherAlg in [CIPHER_NONE, CIPHER_IDEA]:
+ self.Data=binstring[pos:]
+ pos=len(binstring)
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+ self.measureModulus()
+ if pos<>len(binstring):
+ print 'WARNING: length mismatch in Private Key packet.'
+
+ def write_bin(self):
+ data=(chr(self.Version)+Int2Str(self.Timestamp, 32)+
+ Int2Str(self.Validity, 16)+chr(self.PubkeyAlg))
+ if self.PubkeyAlg==PK_RSA:
+ data=data+Int2MPI(self.n)+Int2MPI(self.e)+self.Data
+ else:
+ raise Error, 'Unknown PK Algorithm '+str(self.PubkeyAlg)
+ return data
+
+#
+# User ID's
+#
+class UserID(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.CTBT=CTBT_USERID
+ self.UserID = ""
+ self.SigList = []
+ self.Trust = None
+ def __repr__(self): return '< User ID "'+str(self.UserID)+'" >'
+ def parse_bin(self, binstring):
+ self.UserID = binstring
+ def write_bin(self):
+ return self.UserID
+
+
+#
+# Signatures
+#
+class Signature(Packet):
+ def __init__(self, version=3):
+ Packet.__init__(self)
+ self.CTBT = CTBT_SIG
+ self.Version = version
+ if (version==2) or (version==3):
+ self.SigClass = None
+ self.SigKeyID = 0
+ self.Timestamp = 0
+ self.PubkeyAlg = PK_RSA
+
+#
+# Verify that key was used to sign target. Target is:
+#
+# - a binary string for sig classes 0x0 and 0x1
+# - a tuple (pubkey, uid) for a key certification signature
+# - None for key compromise signature (since it should be self-signed)
+# - a signature for a timestamp signature
+
+ def verify(self, key, target):
+ if self.SigClass == None: raise Error, "Can't verify uninitialised signature."
+ elif (self.SigClass==0 or self.SigClass==1):
+ raise Error, "We don't yet check document signatures."
+ elif (self.SigClass==0x10 or self.SigClass==0x11 or self.SigClass==0x12 or self.SigClass==0x13):
+ return self.verify_key_sig(self, key, target[0], target[1])
+ elif (self.SigClass==0x20):
+ raise Error, "We don't yet do key compromise signatures."
+ elif (self.SigClass==0x30):
+ raise Error, "We don't yet do certificate revokation."
+ elif (self.SigClass==0x40):
+ raise Error, "We don't yet do timestamps."
+ else: raise Error, 'Unknown signature class '+str(hex(self.SigClass))
+
+ def verify_key_sig(self, signerkey, signedkey, userid):
+ if (self.SigClass<0x10) or (self.SigClass>0x13):
+ raise Error, "Can't verify key signature on non key signature."
+ hash_mod=get_hash_module(self.HashAlg)
+ hash_obj=hash_mod.new()
+ if signerkey.KeyID!=self.SigKeyID:
+ raise Error, "Incorrect signator key"
+ if signedkey.CTBT!=CTBT_PKCERT:
+ raise Error, "Can only verify signatures on a public key cert"
+ data=signedkey.write_bin()
+ data=signedkey.mkHeader(len(data),16) + data
+ hash_obj.update (data)
+ hash_obj.update (userid.UserID)
+ hash_obj.update (chr(self.SigClass))
+ hash_obj.update (Int2Str(self.Timestamp, 32))
+ hash = hash_obj.digest()
+ signature = signerkey.encrypt(self.signature)
+ sighash = signerkey.unpadMessageDigest(signature)
+ if self.HashClue!=sighash[0:2]:
+ raise Error, 'Signature checking failed--message digest mismatch'
+ return sighash==hash
+
+ def parse_bin(self, binstring):
+ pos = 0
+ self.Version = ord(binstring[pos])
+ if self.Version not in [2, 3]: raise Error, 'Unknown signature version '+str(self.Version)
+ pos = pos + 1
+ if ord(binstring[pos]) <> 5: raise Error, 'Variable-length signature material <> 5.'
+ pos = pos + 1
+ self.SigClass = ord(binstring[pos])
+ pos = pos + 1
+ self.Timestamp = Str2Int(binstring[pos:pos+4])
+ pos = pos + 4
+ self.SigKeyID = Str2Int(binstring[pos:pos+8])
+ pos = pos + 8
+ self.PubkeyAlg = ord(binstring[pos])
+ pos = pos + 1
+ if self.PubkeyAlg not in PK_LIST:
+ raise Error, 'Unknown signature PK Algorithm.'
+ self.HashAlg = ord(binstring[pos])
+ pos = pos + 1
+ if self.HashAlg not in HASH_LIST:
+ raise Error, 'Unknown hashing Algorithm.'
+ self.HashClue = binstring[pos:pos+2]
+ pos = pos + 2
+ self.signature, siglen = MPI2Int(binstring[pos:])
+ if (pos + siglen) <> len(binstring):
+ print 'WARNING: length mismatch in signature packet.'
+ def write_bin(self):
+ data = (chr(self.Version) + chr(5) + chr(self.SigClass) +
+ Int2Str(self.Timestamp, 32) +
+ Int2Str(self.SigKeyID, 64) +
+ chr(self.PubkeyAlg))
+ if self.PubkeyAlg==PK_RSA:
+ data=data+ chr(self.HashAlg) + self.HashClue
+ if type(self.signature)==type(''): data=data+Int2MPI(Str2Int(self.signature))
+ else: data=data+Int2MPI(self.signature)
+ return data
+ else: raise Error, "Unknown public-key algorithm "+str(PubkeyAlg)
+
+#
+# Trust packet
+#
+class Trust(Packet):
+ def __init__(self):
+ Packet.__init__(self)
+ self.CTBT=CTBT_TRUST
+ self.Trust = 0 ; self.Disabled = 0 ; self.Ultimate=0
+
+
+ def parse_bin(self, binstring):
+ pos = 0
+ trust = ord(binstring[pos])
+ self.Trust = trust & 7
+ self.Disabled = ((trust & 32) != 0)
+ self.Ultimate = ((trust & 128) != 0)
+
+ def write_bin(self):
+ trust=(self.Trust & 7)
+ if self.Disabled: trust=trust | 32
+ if self.Ultimate: trust=trust | 128
+ return chr(trust)
+
+
+#
+#
+# KeyRing class
+#
+#
+
+class KeyRing:
+ def __init__(self):
+ self.keyring = {}
+
+ # The following 6 methods simulate a dictionary's interface
+ def __getitem__(self, key):
+ return self.keyring[key]
+ def __delitem__(self, key):
+ del self.keyring[key]
+ def __setitem__(self, key, value):
+ self.keyring[key]=value
+ def values(self): return self.keyring.values()
+ def items(self): return self.keyring.items()
+ def keys(self): return self.keyring.keys()
+
+#
+# Parse a binary PGP key string into a keyring
+#
+ def parseKeyRing(self, input):
+ curr_key = None
+ curr_uid = None
+ while 1:
+ p, dummy = readPacket(input)
+ if p==None: break
+ elif p.CTBT==CTBT_PKCERT or p.CTBT==CTBT_SKCERT:
+ self[p.KeyID]=p
+ self[p.KeyID & 0xffffFFFFL]=p
+ curr_key = p
+ curr_uid = None
+ elif p.CTBT==CTBT_USERID:
+ if curr_key: curr_key.IDList.append(p)
+ else: print 'WARNING: dangling USERID packet.'
+ curr_uid = p
+ elif p.CTBT==CTBT_TRUST:
+ if curr_key:
+ if curr_key.Trust: pass#print 'WARNING: multiple Trusts for Key.'
+ else: curr_key.Trust = p
+ elif curr_uid:
+ if curr_uid.Trust: print 'WARNING: multiple Trusts for USERID.'
+ else: curr_uid.Trust = p
+ else: print 'WARNING: dangling Trust packet.'
+ elif p.CTBT==CTBT_SIG:
+ if not curr_uid: print 'WARNING: dangling signature.'
+ else:
+ curr_uid.SigList.append(p)
+ else: raise Error, 'Unknown KeyRing Packet type: '+str(p.CTBT)
+
+
+class ShelfKeyRing(KeyRing):
+ def __init__(self, filename):
+ import shelve
+ self.__shelf=shelve.open(filename)
+
+ # The following 6 methods simulate a dictionary's interface
+ def __getitem__(self, key):
+ key=repr(key)
+ return self.__shelf[key]
+ def __delitem__(self, key):
+ key=repr(key)
+ del self.__shelf[key]
+ def __setitem__(self, key, value):
+ key=repr(key)
+ self.__shelf[key]=value
+ def values(self): return self.__shelf.values()
+ def items(self): return self.__shelf.items()
+ def keys(self): return self.__shelf.keys()
+ def __del__(self):
+ self.__shelf.close()
+
+def readPacket(input):
+ if input=="": return None, ""
+ retval=""
+ import types
+ if type(input)==types.StringType:
+ CTB=ord(input[0])
+ lenlen, length=getLen(CTB, input[1:])
+ if length!=None:
+ s=input[1+lenlen:1+lenlen+length]
+ retval=input[1+lenlen+length:]
+ else: s=input[1+lenlen:]
+ elif type(input)==types.FileType:
+ CTB=input.read(1)
+ if CTB=="": return None, ""
+ CTB=ord(CTB)
+ lenlen=PACKET_LENGTH[CTB & 3]
+ if lenlen==0:
+ s=input.read()
+ else:
+ lenstr=input.read(lenlen)
+ length=Str2Int(lenstr)
+ s=input.read(length)
+
+ if (CTB&128) <> 128: raise Error, 'Keystring contains format error.'
+ CTBT = (CTB&60)>>2
+ if CTBT==CTBT_PKEP: packet=PKEncrypted()
+ elif CTBT==CTBT_SIG: packet = Signature()
+ elif CTBT==CTBT_SKCERT: packet = PrivateKey()
+ elif CTBT==CTBT_PKCERT: packet = PublicKey()
+ elif CTBT==CTBT_COMPR: packet = Compressed()
+ elif CTBT==CTBT_CKEP: packet = ConvEncrypted()
+ elif CTBT==CTBT_PLAIN: packet = Plaintext()
+ elif CTBT==CTBT_USERID: packet = UserID()
+ elif CTBT==CTBT_TRUST: packet = Trust()
+ elif CTBT==CTBT_COMMENT: packet = Comment()
+ else: raise Error, 'Unknown KeyRing Packet type: '+str(CTBT)
+ packet.CTBT=CTBT
+ packet.parse_bin(s)
+ return packet, retval
+
+def EncryptMessage(message, signer=None,
+ recipients=None, DEK=None,
+ compression=COMPRESS_ZLIB,
+ cipherAlg=CIPHER_IDEA, hashAlg=HASH_MD5):
+ p=Plaintext() ; p.Data=message ; data=p.binary()
+
+ if signer!=None:
+ sig=signer.sign(message, hashAlg=hashAlg)
+ data=sig.binary() + data
+
+ if compression!=COMPRESS_NONE:
+ p=Compressed() ; p.CompressAlg=compression
+ p.compress(data) ; data=p.binary()
+
+ output=data
+ cipher_mod=get_cipher_module(cipherAlg)
+ if DEK==None: DEK=get_random_bytes(cipher_mod.keysize)
+ if recipients!=None and recipients!=[]:
+ if cipherAlg!=CIPHER_NONE:
+ p=ConvEncrypted() ; p.encrypt(DEK, data, cipherAlg)
+ output=data=p.binary()
+
+ if type(recipients)!=type([]): recipients=[recipients]
+ for rec in recipients:
+ c = PKEncrypted()
+ c.KeyID, c.PubkeyAlg = rec.KeyID, rec.PubkeyAlg
+ paddedKey=rec.padEncryptionKey(DEK)
+ c.Data = rec.encrypt(paddedKey)
+ output=c.binary()+output
+ return output
+
+#
+# Tools to handle PGP Armoring and DeArmoring
+#
+
+import regex, string
+import binascii
+import zlib
+
+MAX_LINE_SIZE=80
+LINE_LEN=48
+
+begin_whole_pat = regex.compile("^[-]+BEGIN[ \t]+PGP")
+end_whole_pat = regex.compile("^[-]+END[ \t]+PGP")
+
+begin_partial_pat = regex.compile("^[-]+BEGIN[ \t]+PGP[ \t]+MESSAGE,[ \t]+PART[ \t]+\([0-9]+\)/\([0-9]+\)[-]+[ \t\n]+$")
+end_partial_pat = regex.compile("^[-]+END[ \t]+PGP[ \t]+MESSAGE,[ \t]+PART[ \t]+\([0-9]+\)/\([0-9]+\)[-]+[ \t\n]+$")
+
+def ArmorFile(input, output, blocktype="MESSAGE"):
+ s=[]
+ output.write("-----BEGIN PGP "+blocktype+"-----\n")
+ output.write("Version: "+pgp.Version+'\n')
+ data=""
+ crc=zlib.pgp24("")
+ while (1):
+ data=input.read(LINE_LEN)
+ if data=="": break
+ output.write(binascii.b2a_base64(data))
+ crc=zlib.pgp24(data, crc)
+ crc=chr((crc >> 16) & 0xff) + chr((crc >> 8) & 0xff) + chr(crc & 0xff)
+ output.write("="+binascii.b2a_base64(crc))
+ output.write("-----END PGP "+blocktype+"-----\n")
+
+def UnarmorFile(input, output):
+ s=[]
+ started = 0
+ busy = 0
+ crc=zlib.pgp24("")
+ while (1):
+ data=input.readline()
+ if not started:
+ if begin_whole_pat.match(data)>=0: started = 1
+ if data=="": break
+ else: continue
+ if not busy:
+ if len(string.strip(data))<>0: continue
+ busy = 1
+ if data=="" or end_whole_pat.match(data)!=-1: break
+ if data[0]=='=':
+ # The CRC line begins with a padding character
+ chkcrc=binascii.a2b_base64(data[1:])
+ break
+ else:
+ data=binascii.a2b_base64(data)
+ output.write(data)
+ crc=zlib.pgp24(data, crc)
+ crc=chr((crc >> 16) & 0xff) + chr((crc >> 8) & 0xff) + chr(crc & 0xff)
+ if chkcrc!=crc: raise Error, "CRC checksums don't match"
+
+def armor(binstr):
+ import StringIO
+ i = StringIO.StringIO(ascstr)
+ o = StringIO.StringIO()
+ ArmorFile(i,o)
+ return o.getvalue()
+
+def unarmor(ascstr):
+ import StringIO
+ i = StringIO.StringIO(ascstr)
+ o = StringIO.StringIO()
+ UnarmorFile(i, o)
+ return o.getvalue()
+
diff --git a/Protocol/PGP/pgpapi.html b/Protocol/PGP/pgpapi.html
new file mode 100644
index 0000000..0ee142a
--- /dev/null
+++ b/Protocol/PGP/pgpapi.html
@@ -0,0 +1,191 @@
+<HTML>
+<HEAD><TITLE>A Proposed PGP API for Python</TITLE></HEAD>
+<BODY>
+
+<H1>A Proposed PGP API for Python</H1>
+
+<P>This document resides at <A
+HREF="http://www.magnet.com/%7Eamk/python/pgpapi.html">http://www.magnet.com/%7Eamk/python/pgpapi.html</A>.
+
+<P>Comments on this proposed API are welcomed; please write me at <A
+HREF="mailto:amk@magnet.com"><CODE>amk@magnet.com</CODE></A>.
+
+<P>I would like to write a collection of modules and classes for the
+Python programming language to perform PGP en/decryption. The code
+would not execute a PGP subprocess, but would be a complete
+re-implementation of PGP's format. Currently all the low-level pieces
+are in place; there are interfaces to a compression library, IDEA,
+MD5, and other crypto algorithms that might be in PGP 3.0 (SHA, 3DES,
+Blowfish); reading of PGP packets is implemented; the Key objects are
+implemented to a significant degree, etc. However, the high-level
+interface is the tricky part. Suggestions are welcomed at <A
+HREF="mailto:amk@magnet.com"><CODE>amk@magnet.com</CODE></A>.
+
+<P>The following tasks must be supported:
+<OL>
+<LI> Reading keys from keyrings, and writing them out.
+<LI> Verifying signatures on keys
+<LI> Encrypting messages for recipients, optionally signing them.
+<LI> Decrypting messages, and finding out whether the signature was valid or not.
+<LI> Encoding and decoding ASCII armor. Should this be integrated with
+encryption and decryption, or will the caller have to do that ahead of
+time when decoding, and afterwards when encoding?
+</OL>
+
+<H2>PGP Keys</H2>
+
+<P>Keys are produced by <CODE>pgp.KeyRing</CODE> objects, which are
+passed a file object. <CODE>KeyRing</CODE> objects support a
+dictionary-style interface, where the key is a 64-bit or 32-bit long
+integer corresponding to the key's ID. (PGP uses the 64-bit form
+internally, though the 32-bit form is what's printed in the output of
+pgp -kv.)
+
+<P>Keys have various methods:
+
+<DL>
+<DT><CODE>isPrivate()</CODE>
+<DD>Returns a Boolean (true if it's a secret key).
+<DT><CODE>isUnlocked()</CODE>
+<DD>Returns a Boolean (true if the secret key data is available).
+<dt><CODE>Unlock(<EM>passphrase</EM>)</CODE>
+<dd>Decrypt the private key info, using the given passphrase.
+<dt><CODE>Lock(<EM>passphrase</EM>=None)</CODE>
+<dd>Encrypt the private key info, using the given passphrase; if the
+passphrase is <CODE>None</CODE>, the secret key info is simply
+deleted, without reencrypting the key data.
+</DL>
+
+<P>There will also be various private methods to perform RSA
+operations; I can't think of a reason to expose these operations to
+the caller. Keys also have various attributes: <CODE>PKalgorithm, Version, KeyID,
+IDList (a list of User ID packets), Trust, ...</CODE>
+
+<H2>Encrypting/decrypting messages</H2>
+<P>Encrypting messages is fairly simple; there's one function call,
+<CODE>pgp.Encrypt()</CODE>:
+<PRE>
+Encrypt(input, # File object
+ output, # File object
+ recipients=[], # List of recipients
+ cipher_alg={one of pgp.IDEA, pgp.DES3, ...},
+ hash_alg={one of pgp.MD5, pgp.SHA, ...},
+ compression= true/false,
+ signer=&lt;key to sign message with&gt;,
+ passphrase=&lt;conventional passphrase&gt;
+ ) </PRE>
+
+<P>That's a lot of options! However, usually callers will only be
+guaranteed to include the first two, and then the other options would
+be set using keyword arguments; otherwise, sensible defaults would be
+assumed. It doesn't make sense to specify all the above arguments, so
+you wouldn't have to include them all, or remember their order.
+
+<P>(Note that the above interface doesn't provide for clearsigning
+files. Should that be an extra parameter, or a separate function?)
+
+<PRE>
+Decrypt(input, output,
+ recipient # The recipient's key
+ )
+</PRE>
+
+If it succeeds, <CODE>Decrypt()</CODE> returns a
+<CODE>Signature</CODE> object, whose methods are:
+
+<DL>
+<DT><CODE>isEncrypted(), isSigned()</CODE>
+<DD>Both these methods return Booleans.
+<DT><CODE>signerID()</CODE>
+<DD>The 64-bit Key ID of the signer's key; <CODE>None</CODE> if the
+message isn't signed. It would be the caller's responsibility to retrieve
+the ID, somehow retrieve a <CODE>pgp.Key</CODE> object corresponding
+to that ID, and pass it to the next function.
+<DT><CODE>verifySignature(<EM>K</EM>)</CODE>
+<DD>Verify the signature on the message with the key K; an exception
+is raised if the message wasn't signed with K, or if the signature
+verification failed.
+</DL>
+
+<H3>Sample usages</H3>
+
+<P>In all the following examples, <CODE>input</CODE> and
+<CODE>output</CODE> are two file objects, or two objects that imitate
+file objects; should the API require that these objects be seekable?
+(That would rule out using sockets as the input or the output.
+Strings can be used by passing them to the <CODE>StringIO</CODE>
+module first, which simulates a file on a string. The functions could
+check the type of their parameters and perform this conversion
+automatically, if desired.) <P><CODE>RK</CODE> is a
+<CODE>pgp.Key</CODE> instance for the recipient's keys, and
+<CODE>SK</CODE> is the sender's key, a <CODE>pgp.PrivateKey</CODE>
+instance.
+
+<P>To conventionally encrypt a message with just IDEA, using the
+password "TomServo":
+
+<PRE>pgp.Encrypt(input, output, passphrase="TomServo")
+</PRE>
+<P>To encrypt (but not sign) a message, with IDEA, MD5, and compression:
+<PRE>pgp.Encrypt(input, output, recipient=RK)
+ or
+pgp.Encrypt(input, output, recipient=[RK])
+</PRE>
+
+<P>To encrypt and sign a message, with IDEA, MD5, and no compression:
+(SK must be a private key instance, and must be unlocked.
+
+<PRE>pgp.Encrypt(input, output, recipient=[RK], signer=SK, compression=0)
+</PRE>
+
+<P>To decrypt a message:
+<PRE>pgp.Decrypt(input, output, recipient=RK)
+</PRE>
+
+<H2>ASCII armoring and dearmoring</H2>
+I'm not sure what the interface to this should look like; assuming
+that it's a separate function (and not part of <CODE>Encrypt()</CODE> and <CODE>Decrypt()</CODE>, how about the following?
+
+<PRE>
+pgp.Enarmor(input, output) # These functions assume one single file
+pgp.Dearmor(input, output) # and return nothing
+</PRE>
+
+<P>Multipart encoding and decoding will be the caller's problem with
+this interface. The "PART 01/05" notation in the armor headers means
+that you have to know how large the file will be before you can write
+the headers. Perhaps the input file will simply have to be seekable, to allow
+measuring the file's size before processing.
+
+<H2>Unanswered Questions</H2>
+
+<UL>
+<LI>Should the API require that the input and output objects be
+seekable?
+<LI>Should ASCII armoring and dearmoring be integrated into encryption
+and decryption, or should that be the responsibility of the caller?
+(In the latter case, the API would then always expect binary data.)
+<LI>Should everything be done in memory, or in temporary files? (Possible
+clever idea: generate a random IDEA key, and encrypt all the temp
+files with it in ECB or OFB mode.)
+<LI>Should the caller be able to select a random number generation
+function to be used?
+<LI>Clear-signed messages could be generated by an additional option
+to <CODE>Encrypt()</CODE>; how should clearsigned messages be read?
+(Probably a utility function that calls <CODE>Decrypt()</CODE> for
+you, after assembling the clearsigned text.)
+<LI>Is the above API useful for various applications? Applications I
+can think of:
+<UL><LI>A PGP clone<LI>A GUI PGP clone<LI>Remailer software
+<LI>Writing an app that run under Grail or the Python plug-in for
+Netscape.
+</UL>
+</UL>
+
+<P>This document resides at <A
+HREF="http://www.magnet.com/%7Eamk/python/pgpapi.html">http://www.magnet.com/%7Eamk/python/pgpapi.html</A>.
+
+<P>Comments on this proposed API are welcomed; please write me at <A
+HREF="mailto:amk@magnet.com"><CODE>amk@magnet.com</CODE></A>.
+
+</BODY></HTML>
diff --git a/Protocol/PGP/pgpconst.py b/Protocol/PGP/pgpconst.py
new file mode 100644
index 0000000..5061206
--- /dev/null
+++ b/Protocol/PGP/pgpconst.py
@@ -0,0 +1,81 @@
+#
+# PGP CONSTANTS
+#
+
+#
+# Cipher Type Byte Types
+#
+CTBT_PKEP = 0x1
+CTBT_SIG = 0x2
+CTBT_SKCERT = 0x5
+CTBT_PKCERT = 0x6
+CTBT_COMPR = 0x8
+CTBT_CKEP = 0x9
+CTBT_PLAIN = 0xB
+CTBT_TRUST = 0xC
+CTBT_USERID = 0xD
+CTBT_COMMENT = 0xE
+
+
+#
+# Length Types
+#
+LEN_1 = 0x0
+LEN_2 = 0x1
+LEN_4 = 0x2
+LEN_UNKNOWN = 0x3
+PACKET_LENGTH={LEN_1:1, LEN_2: 2, LEN_4: 4, LEN_UNKNOWN: 0}
+
+#
+# Signature Types
+#
+SIG_BIN = 0x0
+SIG_TXT = 0x1
+SIG_KEY = 0x10
+SIG_KEY1 = 0x11
+SIG_KEY2 = 0x12
+SIG_KEY3 = 0x13
+SIG_COMP = 0x20
+SIG_REVOKE = 0x30
+SIG_TIME = 0x40
+
+# Ciphering algorithms
+CIPHER_NONE = 0
+CIPHER_IDEA = 1
+
+# List of the supported ciphering algorithms
+CIPHER_LIST = [CIPHER_NONE, CIPHER_IDEA]
+
+# PK algorithms
+PK_NONE = 0
+PK_RSA = 1
+
+# List of the supported PK algorithms
+PK_LIST = [PK_RSA]
+
+# Hashing algorithms
+HASH_MD5=1
+
+# List of the supported hashing algorithms
+HASH_LIST = [HASH_MD5]
+
+# Compression algorithms
+COMPRESS_NONE = 0
+COMPRESS_ZLIB = 1
+
+# List of the supported compression algorithms
+COMPRESS_LIST = [COMPRESS_ZLIB]
+
+# ASN.1 identifier string that precedes v2.3 message digests
+ASN_STRING='0 0\014\006\010*\206H\206\367\015\002\005\005\000\004\020'
+
+# Packet sizes: despite the flexibility of PGP's packet structure,
+# much code assumes things about the size of the field giving
+# the packet's length. For example, secret and public key
+# certificates are assumed to have a 16-bit length field.
+# The following dictionary maps packet types to the expected size.
+# If the type isn't here, then PGP doesn't have any expectation
+# of its size.
+
+PACKET_SIZES={CTBT_SKCERT:16, CTBT_PKCERT:16, CTBT_SIG:16}
+
diff --git a/Protocol/PGP/pgpdoc1.txt b/Protocol/PGP/pgpdoc1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Protocol/PGP/pgpdoc1.txt
diff --git a/Protocol/PGP/pgpdoc2.txt b/Protocol/PGP/pgpdoc2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Protocol/PGP/pgpdoc2.txt
diff --git a/Protocol/PGP/pgpops.py b/Protocol/PGP/pgpops.py
new file mode 100644
index 0000000..3187cbf
--- /dev/null
+++ b/Protocol/PGP/pgpops.py
@@ -0,0 +1,350 @@
+
+# pgpops.py : Various low-level operations related to PGP packets.
+#
+# To speed things up, this module could be rewritten as a C extension.
+#
+# Copyright (C) 1995, 1996, A.M. Kuchling
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence.
+#
+
+import idea, md5
+
+def MPILength(str):
+ length=ord(str[0])*256+ord(str[1])
+ length, remainder = divmod(length, 8)
+ if remainder!=0: length=length+1
+ return length
+
+def MPI2Integer(str):
+ length=MPILength(str)
+ return (String2Int(str[2:2+length]), str[2+length:])
+
+def Integer2MPI(i):
+ s=Int2String(i)
+ while (ord(s[0])==0): s=s[1:]
+ if (s==''): return '\000\000'
+ first=ord(s[0])
+ bits= 1+(len(s)-1) *8
+ mask=1
+ while (mask<first and mask <256):
+ first = first & (255-mask)
+ mask=mask << 1
+ bits=bits+1
+ s=chr(bits/256)+chr(bits & 255)+s
+ return s
+
+def String2Int(str):
+ value=0L
+ for i in range(0, len(str)):
+ value=value*256+ord(str[i])
+ return(value)
+
+def Int2String(i):
+ str=''
+ if (i==0): return '\000'
+ while(i>0):
+ str= chr(int(i & 255)) +str
+ i=i >> 8
+ return str
+
+# The following two routines read and write PGP packets. Originally,
+# I wrote a huge set of if...elif...else statements to handle different
+# packet types and versions. This was simple to write, but lengthy and
+# repetitive. Implementing the writing of packets would require another
+# long if statement, and would result in two separate sections of code that
+# would have to be kept consistent. So, I decided to create a single
+# description that would be used for both reading and writing packets.
+# The actual description (current up to PGP 2.6.2) can be found below.
+#
+# A PGP packet is described as a list of tuples. A tuple can be in
+# one of two forms:
+# 1) (DataFormat, Variable) : Reads a piece of data and stores it in the
+# attribute named 'Variable' of the packet object. DataFormat must be
+# one of 'Byte', 'U16', 'U32', 'U64', 'String', 'SizedString', 'MPI',
+# or 'Error'.
+# 2) (Condition, Sublist) : Evaluates the condition string; if it is true,
+# the sublist is used for further parsing.
+
+def ReadPacket(object, Type):
+ templist=Format[Type]
+ while (len(templist)!=0):
+ data=""
+ s1, s2 = templist[0]
+ templist = templist[1:]
+ if s1=='Byte':
+ data=object._input.read(1)
+ setattr(object, s2, ord(data[0]))
+ elif s1=='U16':
+ data=object._input.read(2)
+ setattr(object, s2, ord(data[0])*256+ord(data[1]))
+ elif s1=='U32':
+ data=object._input.read(4)
+ value=0L
+ for j in range(0, 4): value = value * 256 + ord(data[j])
+ setattr(object, s2, value)
+ elif s1=='U64':
+ data=object._input.read(8)
+ value=0L
+ for j in range(0, 8):
+ value = value * 256 + ord(data[j])
+ setattr(object, s2, value)
+ elif s1[0:6]=='String':
+ if (s1=='String'):
+ if object.LengthType==3: setattr(object, s2, "")
+ else:
+ data=object._input.read(object._length)
+ setattr(object, s2, data)
+ else:
+ import string
+ v=string.atoi(s1[6:])
+ data=object._input.read(v)
+ setattr(object, s2, data)
+ elif s1=='SizedString':
+ data=object._input.read(1)
+ length=ord(data[0])
+ data=data+object._input.read(length)
+ setattr(object, s2, data[1:])
+ elif s1=='MPI':
+ data=object._input.read(2)
+ length=ord(data[0])*256+ord(data[1])
+ if ((length % 8)==0): length=length/8
+ else: length=(length-(length%8))/8+1
+ data=data+object._input.read(length)
+ setattr(object, s2, data)
+ elif s1=='Error':
+ raise 'pgp.Exception', s2
+ else:
+ if eval(s1, vars(), object.__dict__):
+ templist=s2+templist
+ object._length=object._length-len(data)
+
+def WritePacket(object):
+ print `object`
+ output=''
+ templist=Format[object.Type]
+ while (len(templist)!=0):
+ s1, s2 = templist[0]
+ templist = templist[1:]
+ if (type(s2)!=type([])):
+ v=getattr(object, s2)
+ if s1=='Byte':
+ output=output+chr(v)
+ elif s1=='U16':
+ output=output+chr(v/256)
+ output=output+chr(v & 255)
+ elif s1=='U32':
+ s=''
+ for j in range(0, 4):
+ s=chr(v & 255)+s
+ v=v/256
+ output=output+s
+ elif s1=='U64':
+ s=''
+ for j in range(0, 8):
+ s=chr(v & 255)+s
+ v=v/256
+ output=output+s
+ elif s1[0:6]=='String':
+ if s1=='String':
+ if object.LengthType==3: pass
+ else:
+ output=output+v
+ else:
+ length=string.atoi(s1[6:])
+ output=output+v
+ elif s1=='SizedString':
+ output=output+chr(len(v))
+ output=output+v
+ elif s1=='MPI':
+ output=output+v
+ elif s1=='Error':
+ raise 'pgp.Exception', s2
+ else:
+ if eval(s1, vars(), object.__dict__): templist=s2+templist
+ l=long(len(output))
+ if object.LengthType==3: lengthType=object.LengthType
+ else:
+ bytes, lengthType = 4,2
+ if object.PacketLength!=None:
+ if l<65536: bytes,lengthType=2,1
+ if l<256: bytes,lengthType=1,0
+ # XXX For key ring packets, it seems that the length *must* be
+ # two bytes, or PGP 2.6.2 won't read it. This is broken
+ # behaviour on PGP's part.
+ if object.Type==5 or object.Type==6: bytes,lengthType=2,1
+ for i in range(0,bytes):
+ output=chr( int(l & 255) ) + output
+ l=l>>8
+ output=chr(128 + (object.Type<<2)+ lengthType)+output
+ return output
+
+
+# The master description of PGP packets (current up to 2.6.2)
+
+# Packet constants (this table is duplicated in pgp.py)
+
+PK_ENCRYPTED = 1
+SIGNATURE = 2
+PRIVKEY = 5
+PUBKEY = 6
+COMPRESSED = 8
+CIPHERED = 9
+PLAINTEXT = 11
+TRUST = 12
+USERID = 13
+COMMENT = 14
+
+# Values in CTB for the length of the length of the following packet.
+Lengths = {0:1, 1:2, 2:4, 3:-1}
+
+#
+# Here comes a gigantic dictionary from hell!
+#
+
+Format = {
+PK_ENCRYPTED:[
+ ('Byte', 'Version'),
+ ('U64', 'KeyID'),
+ ('Byte', 'PKCalg'),
+ ('PKCalg==1',
+ [
+ ('MPI', 'IntegerMPI')
+ ]
+ ),
+ ('PKCalg!=1',
+ [
+ ('Error', 'Unknown encryption algorithm in PK-encrypted packet')
+ ]
+ )
+ ],
+SIGNATURE: [
+ ('Byte', 'Version'),
+ ('Version==2 or Version==3',
+ [
+ ('Byte', 'MatLength'),
+ ('MatLength==5',
+ [
+ ('Byte', 'SecClass'),
+ ('U32', 'TimeStamp'),
+ ('U64', 'KeyID'),
+ ('Byte', 'PKCalg'),
+ ('PKCalg==1',
+ [
+ ('Byte', 'DigestAlg'),
+ ('U16', 'Checksum'),
+ ('MPI', 'IntegerMPI')
+ ]
+ ),
+ ('PKCalg!=1',
+ [
+ ('Error', 'Unknown encryption algorithm in signature packet')
+ ]
+ )
+ ]
+ ),
+ ('MatLength!=5',
+ [
+ ('Error', 'Unknown length of material in signature packet')
+ ]
+ )
+ ]
+ ),
+ ('Version!=2 and Version!=3',
+ [
+ ('Error', 'Unknown version number in signature packet')
+ ]
+ )
+ ],
+PRIVKEY: [
+ ('Byte', 'Version'),
+ ('U32', 'TimeStamp'),
+ ('U16', 'Validity'),
+ ('Byte', 'PKCalg'),
+ ('PKCalg==1',
+ [
+ ('MPI', 'nMPI'),
+ ('MPI', 'eMPI'),
+ ('Byte', 'CipherAlg'),
+ ('CipherAlg==0',
+ [
+ ('MPI', 'dMPI'),
+ ('MPI', 'pMPI'),
+ ('MPI', 'qMPI'),
+ ('MPI', 'uMPI')
+ ]
+ ),
+ ('CipherAlg==1',
+ [
+ ('String+8', 'IV'),
+ ('MPI', 'dMPI'),
+ ('MPI', 'pMPI'),
+ ('MPI', 'qMPI'),
+ ('MPI', 'uMPI')
+ ]
+ ),
+ ('CipherAlg!=0 and CipherAlg!=1',
+ [
+ ('Error', 'Unknown ciphering algorithm in public key')
+ ]
+ ),
+ ('U16', 'CkSum')
+ ]
+ ),
+ ('PKCalg!=1',
+ [
+ ('Error', 'Unknown encryption algorithm in private key')
+ ]
+ )
+ ],
+PUBKEY: [
+ ('Byte', 'Version'),
+ ('Version==2 or Version==3',
+ [
+ ('U32', 'TimeStamp'),
+ ('U16', 'Validity'),
+ ('Byte', 'PKCalg'),
+ ('PKCalg==1',
+ [
+ ('MPI', 'nMPI'),
+ ('MPI', 'eMPI')
+ ]
+ ),
+ ('PKCalg!=1',
+ [
+ ('Error', 'Unknown encryption algorithm in Public Key packet')
+ ]
+ )
+ ]
+ ),
+ ('Version!=2 and Version!=3',
+ [
+ ('Error', 'Unknown version in Public Key packet')
+ ]
+ )
+ ],
+CIPHERED: [
+ ('String', 'Ciphertext')
+ ],
+PLAINTEXT: [
+ ('Byte', 'TextMode'),
+ ('SizedString', 'Filename'),
+ ('U32', 'TimeStamp'),
+ ('String', 'Plaintext')
+ ],
+COMPRESSED: [
+ ('Byte', 'CompressAlg'),
+ ('String', 'CompressedData')
+ ],
+TRUST: [
+ ('Byte', 'Trust')
+ ],
+USERID: [
+ ('String', 'UserID')
+ ],
+COMMENT: [
+ ('String', 'Comment')
+ ]
+}
diff --git a/Protocol/PGP/pgpsort.py b/Protocol/PGP/pgpsort.py
new file mode 100755
index 0000000..cb92cff
--- /dev/null
+++ b/Protocol/PGP/pgpsort.py
@@ -0,0 +1,51 @@
+#!/usr/local/bin/python
+
+# PGP keyring sorter:
+# Usage: pgpsort <keyring file>
+
+import os, pgp, string, sys
+if len(sys.argv)!=2:
+ print 'Usage: pgpsort keyring'
+ sys.exit(1)
+
+filename=sys.argv[1]
+if filename[-4:]!='.pgp': filename=filename+'.pgp'
+
+try:
+ keyfile=open(sys.argv[1], 'r')
+except IOError, value:
+ print value
+ print "pgpsort: Can't open "+filename
+ sys.exit(1)
+
+sys.stderr.write('Reading...\n')
+
+keylist=[]
+while (1):
+ key=pgp.Key(keyfile)
+ sys.stderr.write('['+key.UserID[0][0].UserID+']\n')
+ data=data[key.PacketLength:]
+ keylist.append(key)
+
+def Compare(key1, key2):
+ id1=string.upper(key1.UserID[0][0].UserID)
+ id2=string.upper(key2.UserID[0][0].UserID)
+ if id1<id2: return -1
+ elif id1>id2: return 1
+ else: return 0
+
+backup=filename[:-4]+'.bak'
+try:
+ os.unlink(backup)
+except os.error, (value, message):
+ if value!=2: raise os.error, (value, message)
+os.rename(filename, backup)
+
+sys.stderr.write('Sorting...')
+keylist.sort(Compare)
+sys.stderr.write('Writing...\n')
+f=open(filename, 'wb')
+for i in keylist:
+ f.write(i.Write())
+f.close()
+
diff --git a/Protocol/PGP/prof.py b/Protocol/PGP/prof.py
new file mode 100644
index 0000000..edb38e5
--- /dev/null
+++ b/Protocol/PGP/prof.py
@@ -0,0 +1,3 @@
+import pstats
+p = pstats.Stats('read.profile')
+p.sort_stats('cumulative').print_stats()
diff --git a/Protocol/PGP/pubkey.py b/Protocol/PGP/pubkey.py
new file mode 100644
index 0000000..1c85188
--- /dev/null
+++ b/Protocol/PGP/pubkey.py
@@ -0,0 +1,39 @@
+
+ITER=50
+
+def isPrime(N):
+ N1=N-1 ; exp=N1/2
+ minusOneSeen=0
+ for i in range(2, ITER+2):
+ r=pow(i, exp, N)
+ if r==N1: minusOneSeen=1
+ elif r!=1: return 0
+ return minusOneSeen
+
+def findPrime(N):
+ while not isPrime(N): N=N+2
+ return N
+
+def GCD(x,y):
+ if x<0: x=-x
+ if y<0: y=-y
+ while x>0: x,y = y%x, x
+ return y
+
+def Inverse(u, v):
+ u3, v3 = long(u), long(v)
+ u1, v1 = 1L, 0L
+ while v3>0:
+ q=u3/v3
+ u1, v1 = v1, u1-v1*q
+ u3, v3 = v3, u3-v3*q
+ return u1 % v
+
+
+
+
+
+
+
+
+
diff --git a/Protocol/PGP/pubring.pgp b/Protocol/PGP/pubring.pgp
new file mode 100644
index 0000000..a775023
--- /dev/null
+++ b/Protocol/PGP/pubring.pgp
Binary files differ
diff --git a/Protocol/PGP/secring.pgp b/Protocol/PGP/secring.pgp
new file mode 100644
index 0000000..bde5625
--- /dev/null
+++ b/Protocol/PGP/secring.pgp
Binary files differ
diff --git a/Protocol/PGP/shelvepgp b/Protocol/PGP/shelvepgp
new file mode 100755
index 0000000..74cd2c4
--- /dev/null
+++ b/Protocol/PGP/shelvepgp
@@ -0,0 +1,35 @@
+#!/usr/local/bin/python
+# Hey Emacs, this is -*-Python-*- code!
+
+# Places PGP keys into a shelved file, where they can be instantly
+# retrieved with the KeyID.
+
+# Usage: shelvepgp <keyring file>
+
+import pgp, sys
+if len(sys.argv)!=2:
+ print 'Usage: shelvepgp keyring'
+ sys.exit(1)
+
+input=pgp.KeyRing()
+input.parseKeyRing(open(sys.argv[1], 'r'))
+
+output=pgp.ShelfKeyRing('keyring.shelve')
+for i in input.keys():
+ output[i]=input[i]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Protocol/PGP/test.pgp b/Protocol/PGP/test.pgp
new file mode 100644
index 0000000..4a698a6
--- /dev/null
+++ b/Protocol/PGP/test.pgp
Binary files differ
diff --git a/Protocol/PGP/test.py b/Protocol/PGP/test.py
new file mode 100644
index 0000000..4109d4a
--- /dev/null
+++ b/Protocol/PGP/test.py
@@ -0,0 +1,79 @@
+#!/usr/local/bin/python
+
+import sys, pgp
+
+abcID=0x57FBBFB1L ; amkID=0x0E304991L
+abcPass='secret' ; amkPass='super secret'
+
+def testKeyGeneration():
+ key=pgp.PrivateKey()
+ key.generate(pgp.PK_RSA, 1024)
+ key.Lock('super')
+ newID=pgp.UserID()
+ newID.UserID='Python'
+ key.IDList.append(newID)
+ trust=pgp.Trust()
+ # Write the secret keyring
+ f=open('secring.pgp', 'a')
+ f.write(key.binary())
+ f.write(newID.binary())
+ f.close()
+ # Write the public keyring, with trust packets
+ f=open('pubring.pgp', 'a')
+ f.write(key.public_binary())
+ f.write(trust.binary())
+ f.write(newID.binary())
+ f.write(trust.binary())
+ f.close()
+
+def testMessaging():
+ pass
+
+def getpubkeys():
+ pubring=pgp.KeyRing()
+ pubring.parseKeyRing(open('./pubring.pgp', 'r'))
+ pub_abc=pubring[abcID]
+ pub_amk=pubring[amkID]
+ return pub_abc, pub_amk
+
+def getseckeys():
+ secring=pgp.KeyRing()
+ secring.parseKeyRing(open('./secring.pgp', 'r'))
+ sec_abc=secring[abcID]
+ sec_amk=secring[amkID]
+ return sec_abc, sec_amk
+
+sec_abc, sec_amk = getseckeys()
+pub_abc, pub_amk = getpubkeys()
+
+print 'amk=', hex(sec_amk.KeyID)
+print 'abc=', hex(sec_abc.KeyID)
+
+f=open('books.txt', 'r') ; message=f.read() ; f.close()
+
+import md5
+DEK=md5.new('testp').digest()
+sec_amk.Unlock(amkPass)
+output=pgp.EncryptMessage(message, recipients=[pub_amk,pub_abc],
+ signer=sec_amk )
+
+f=open('books.txt.pgp', 'w') ; f.write(output) ; f.close()
+
+sec_amk.Unlock(amkPass)
+sec_abc.Unlock(abcPass)
+for sig in pub_abc.IDList[0].SigList:
+ if sig.SigKeyID==pub_amk.KeyID:
+ print sig.verify_key_sig(pub_amk, pub_abc, u)
+
+print "abc's key is self signed:", pub_abc.is_self_signed()
+print "amk's key is self signed:", pub_amk.is_self_signed()
+
+# Test the Lock() method of key objects
+L=[] ; L2=[]
+for i in 'ednpqu': L.append(getattr(sec_amk, i))
+sec_amk.Lock(amkPass)
+sec_amk.Unlock(amkPass)
+for i in 'ednpqu': L2.append(getattr(sec_amk, i))
+if L!=L2:
+ print "ERROR: key data doesn't match after Lock() and Unlock()"
+print L==L2
diff --git a/Protocol/PGP/testpub.pgp b/Protocol/PGP/testpub.pgp
new file mode 100644
index 0000000..1cbcc66
--- /dev/null
+++ b/Protocol/PGP/testpub.pgp
Binary files differ
diff --git a/Protocol/PGP/testsec.pgp b/Protocol/PGP/testsec.pgp
new file mode 100644
index 0000000..2139b5a
--- /dev/null
+++ b/Protocol/PGP/testsec.pgp
Binary files differ
diff --git a/Protocol/__init__.py b/Protocol/__init__.py
new file mode 100644
index 0000000..1d027cd
--- /dev/null
+++ b/Protocol/__init__.py
@@ -0,0 +1,2 @@
+
+__all__ = ['AllOrNothing', 'Chaffing', 'Winnow']
diff --git a/PublicKey/DSA.py b/PublicKey/DSA.py
new file mode 100644
index 0000000..ff364a3
--- /dev/null
+++ b/PublicKey/DSA.py
@@ -0,0 +1,132 @@
+
+#
+# DSA.py : Digital Signature Algorithm
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+from pubkey import *
+from Crypto.Hash import SHA
+
+error = 'DSA module'
+
+def generateQ(randfunc):
+ S=randfunc(20)
+ hash1=SHA.new(S).digest()
+ hash2=SHA.new(longtobytes(bytestolong(S)+1)).digest()
+ q = bignum(0)
+ for i in range(0,20):
+ c=ord(hash1[i])^ord(hash2[i])
+ if i==0: c=c | 128
+ if i==19: c= c | 1
+ q=q*256+c
+ while (not isPrime(q)):
+ q=q+2
+ if pow(2,159L)<q<pow(2,160L): return S, q
+ raise error, 'Bad q value generated'
+
+# Generate a DSA modulus with L bits
+def generate(bits, randfunc, progress_func=None):
+ if bits<160: raise error, 'Key length <160 bits'
+ obj=DSAobj()
+ # Generate string S and prime q
+ if progress_func: apply(progress_func, ('p,q\n',))
+ while (1):
+ S, obj.q = generateQ(randfunc)
+ n=(bits-1)/160
+ C, N, V = 0, 2, {}
+ b=(obj.q >> 5) & 15
+ powb=pow(bignum(2), b)
+ powL1=pow(bignum(2), bits-1)
+ while C<4096:
+ for k in range(0, n+1):
+ V[k]=bytestolong(SHA.new(S+str(N)+str(k)).digest())
+ W=V[n] % powb
+ for k in range(n-1, -1, -1): W=(W<<160L)+V[k]
+ X=W+powL1
+ p=X-(X%(2*obj.q)-1)
+ if powL1<=p and isPrime(p): break
+ C, N = C+1, N+n+1
+ if C<4096: break
+ if progress_func: apply(progress_func, ('4096 multiples failed\n',) )
+ obj.p = p
+ power=(p-1)/obj.q
+ if progress_func: apply(progress_func, ('h,g\n',))
+ while (1):
+ h=bytestolong(randfunc(bits)) % (p-1)
+ g=pow(h, power, p)
+ if 1<h<p-1 and g>1: break
+ obj.g=g
+ if progress_func: apply(progress_func, ('x,y\n',))
+ while (1):
+ x=bytestolong(randfunc(20))
+ if 0<x<obj.q: break
+ obj.x, obj.y=x, pow(g, x, p)
+ return obj
+
+def construct(tuple):
+ obj=DSAobj()
+ if len(tuple) not in [4,5]:
+ raise error, 'argument for construct() wrong length'
+ for i in range(len(tuple)):
+ field = obj.keydata[i]
+ setattr(obj, field, tuple[i])
+ return obj
+
+class DSAobj(pubkey):
+ keydata=['y', 'g', 'p', 'q', 'x']
+
+ def _encrypt(self, s, Kstr):
+ raise error, 'Algorithm cannot en/decrypt data'
+ def _decrypt(self, s):
+ raise error, 'Algorithm cannot en/decrypt data'
+ def _sign(self, M, K):
+ if (K<2 or self.q<=K): raise error, 'K is not between 2 and q'
+ r=pow(self.g, K, self.p) % self.q
+ s=(inverse(K, self.q)*(M+self.x*r)) % self.q
+ return (r,s)
+
+ def _verify(self, M, sig):
+ r, s = sig
+ if r<=0 or r>=self.q or s<=0 or s>=self.q: return 0
+ w=inverse(s, self.q)
+ u1, u2 = (M*w) % self.q, (r*w) % self.q
+ v1=pow(self.g, u1, self.p)
+ v2=pow(self.y, u2, self.p)
+ v=((v1*v2) % self.p)
+ v=v % self.q
+ if v==r: return 1
+ return 0
+
+ def size(self):
+ "Return the maximum number of bits that can be handled by this key."
+ bits, power = 0,1L
+ while (power<self.p): bits, power = bits+1, power<<1
+ return bits-1
+
+ def hasprivate(self):
+ """Return a Boolean denoting whether the object contains
+ private components."""
+ if hasattr(self, 'x'): return 1
+ else: return 0
+
+ def cansign(self):
+ """Return a Boolean value recording whether this algorithm can generate signatures."""
+ return 1
+ def canencrypt(self):
+ """Return a Boolean value recording whether this algorithm can encrypt data."""
+ return 0
+
+ def publickey(self):
+ """Return a new key object containing only the public information."""
+ return construct((self.y, self.g, self.p, self.q))
+
+object=DSAobj
+
+
diff --git a/PublicKey/ElGamal.py b/PublicKey/ElGamal.py
new file mode 100644
index 0000000..1802b4a
--- /dev/null
+++ b/PublicKey/ElGamal.py
@@ -0,0 +1,103 @@
+#
+# ElGamal.py : ElGamal encryption/decryption and signatures
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+from pubkey import *
+
+error = 'ElGamal module'
+
+# Generate an ElGamal key with N bits
+def generate(bits, randfunc, progress_func=None):
+ obj=ElGamalobj()
+ # Generate prime p
+ if progress_func: apply(progress_func, ('p\n',))
+ obj.p=bignum(getPrime(bits, randfunc))
+ # Generate random number g
+ if progress_func: apply(progress_func, ('g\n',))
+ size=bits-1-(ord(randfunc(1)) & 63) # g will be from 1--64 bits smaller than p
+ if size<1: size=bits-1
+ while (1):
+ obj.g=bignum(getPrime(size, randfunc))
+ if obj.g<obj.p: break
+ size=(size+1) % bits
+ if size==0: size=4
+ # Generate random number x
+ if progress_func: apply(progress_func, ('x\n',))
+ while (1):
+ size=bits-1-ord(randfunc(1)) # x will be from 1 to 256 bits smaller than p
+ if size>2: break
+ while (1):
+ obj.x=bignum(getPrime(size, randfunc))
+ if obj.x<obj.p: break
+ size=(size+1) % bits
+ if size==0: size=4
+ if progress_func: apply(progress_func, ('y\n',))
+ obj.y=pow(obj.g, obj.x, obj.p)
+ return obj
+
+def construct(tuple):
+ obj=ElGamalobj()
+ if len(tuple) not in [3,4]:
+ raise error, 'argument for construct() wrong length'
+ for i in range(len(tuple)):
+ field = obj.keydata[i]
+ setattr(obj, field, tuple[i])
+ return obj
+
+class ElGamalobj(pubkey):
+ keydata=['p', 'g', 'y', 'x']
+
+ def _encrypt(self, M, K):
+ a=pow(self.g, K, self.p)
+ b=( M*pow(self.y, K, self.p) ) % self.p
+ return ( a,b )
+ def _decrypt(self, M):
+ if (not hasattr(self, 'x')):
+ raise error, 'Private key not available in this object'
+ ax=pow(M[0], self.x, self.p)
+ plaintext=(M[1] * inverse(ax, self.p ) ) % self.p
+ return plaintext
+ def _sign(self, M, K):
+ if (not hasattr(self, 'x')):
+ raise error, 'Private key not available in this object'
+ p1=self.p-1
+ if (GCD(K, p1)!=1):
+ raise error, 'Bad K value: GCD(K,p-1)!=1'
+ a=pow(self.g, K, self.p)
+ t=(M-self.x*a) % p1
+ while t<0: t=t+p1
+ b=(t*inverse(K, p1)) % p1
+ return (a, b)
+ def _verify(self, M, sig):
+ v1=pow(self.y, sig[0], self.p)
+ v1=(v1*pow(sig[0], sig[1], self.p)) % self.p
+ v2=pow(self.g, M, self.p)
+ if v1==v2: return 1
+ return 0
+
+ def size(self):
+ "Return the maximum number of bits that can be handled by this key."
+ bits, power = 0,1L
+ while (power<self.p): bits, power = bits+1, power<<1
+ return bits-1
+
+ def hasprivate(self):
+ """Return a Boolean denoting whether the object contains
+ private components."""
+ if hasattr(self, 'x'): return 1
+ else: return 0
+
+ def publickey(self):
+ """Return a new key object containing only the public information."""
+ return construct((self.p, self.g, self.y))
+
+
+object=ElGamalobj
diff --git a/PublicKey/RSA.py b/PublicKey/RSA.py
new file mode 100644
index 0000000..f1532df
--- /dev/null
+++ b/PublicKey/RSA.py
@@ -0,0 +1,85 @@
+#
+# RSA.py : RSA encryption/decryption
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+import pubkey
+
+error = 'RSA module'
+
+# Generate an RSA key with N bits
+def generate(bits, randfunc, progress_func=None):
+ obj=RSAobj()
+ # Generate random number from 0 to 7
+ difference=ord(randfunc(1)) & 7
+ # Generate the prime factors of n
+ if progress_func: apply(progress_func, ('p\n',))
+ obj.p=pubkey.getPrime(bits/2, randfunc)
+ if progress_func: apply(progress_func, ('q\n',))
+ obj.q=pubkey.getPrime((bits/2)+difference, randfunc)
+ obj.n=obj.p*obj.q
+ # Generate encryption exponent
+ if progress_func: apply(progress_func, ('e\n',))
+ obj.e=pubkey.getPrime(17, randfunc)
+ if progress_func: apply(progress_func, ('d\n',))
+ obj.d=pubkey.inverse(obj.e, (obj.p-1)*(obj.q-1))
+ return obj
+
+# Construct an RSA object
+def construct(tuple):
+ obj=RSAobj()
+ if len(tuple) not in [2,3,5]:
+ raise error, 'argument for construct() wrong length'
+ for i in range(len(tuple)):
+ field = obj.keydata[i]
+ setattr(obj, field, tuple[i])
+ return obj
+
+class RSAobj(pubkey.pubkey):
+ keydata=['n', 'e', 'd', 'p','q']
+ def _encrypt(self, plaintext, K=''):
+ if self.n<=plaintext:
+ raise error, 'Plaintext too large'
+ return (pow(plaintext, self.e, self.n),)
+
+ def _decrypt(self, ciphertext):
+ if (not hasattr(self, 'd')):
+ raise error, 'Private key not available in this object'
+ if self.n<=ciphertext[0]:
+ raise error, 'Ciphertext too large'
+ return pow(ciphertext[0], self.d, self.n)
+
+ def _sign(self, M, K=''):
+ return (self._decrypt((M,)),)
+ def _verify(self, M, sig):
+ m2=self._encrypt(sig[0])
+ if m2[0]==M: return 1
+ else: return 0
+
+ def size(self):
+ "Return the maximum number of bits that can be handled by this key."
+ bits, power = 0,1L
+ while (power<self.n): bits, power = bits+1, power<<1
+ return bits-1
+
+ def hasprivate(self):
+ """Return a Boolean denoting whether the object contains
+ private components."""
+ if hasattr(self, 'd'): return 1
+ else: return 0
+
+ def publickey(self):
+ """Return a new key object containing only the public information."""
+ return construct((self.n, self.e))
+
+
+object = RSAobj
+
+
diff --git a/PublicKey/__init__.py b/PublicKey/__init__.py
new file mode 100644
index 0000000..0556e26
--- /dev/null
+++ b/PublicKey/__init__.py
@@ -0,0 +1,3 @@
+
+__all__ = ['RSA', 'DSA', 'ElGamal', 'qNEW']
+
diff --git a/PublicKey/pubkey.py b/PublicKey/pubkey.py
new file mode 100644
index 0000000..dba131c
--- /dev/null
+++ b/PublicKey/pubkey.py
@@ -0,0 +1,103 @@
+#
+# pubkey.py : Internal functions for public key operations
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+from Crypto.Util.number import *
+
+# Basic public key class
+import types
+class pubkey:
+ def __init__(self):
+ pass
+ def __getstate__(self):
+ """To keep key objects platform-independent, the key data is
+ converted to standard Python long integers before being
+ written out. It will then be reconverted as necessary on
+ restoration."""
+ d=self.__dict__
+ for key in self.keydata:
+ if d.has_key(key): d[key]=long(d[key])
+ return d
+
+ def __setstate__(self, d):
+ """On unpickling a key object, the key data is converted to the big
+number representation being used, whether that is Python long
+integers, MPZ objects, or whatever."""
+ for key in self.keydata:
+ if d.has_key(key): self.__dict__[key]=bignum(d[key])
+
+ def encrypt(self, plaintext, K):
+ """Encrypt the string or integer plaintext. K is a random
+ parameter required by some algorithms."""
+ wasString=0
+ if type(plaintext)==types.StringType:
+ plaintext=bytestolong(plaintext) ; wasString=1
+ if type(K)==types.StringType:
+ K=bytestolong(K)
+ ciphertext=self._encrypt(plaintext, K)
+ if wasString: return tuple(map(longtobytes, ciphertext))
+ else: return ciphertext
+
+ def decrypt(self, ciphertext):
+ """Decrypt the string or integer ciphertext."""
+ wasString=0
+ if type(ciphertext)!=types.TupleType:
+ ciphertext=(ciphertext,)
+ if types.StringType in map(type, ciphertext):
+ ciphertext=tuple(map(bytestolong, ciphertext)) ; wasString=1
+ plaintext=self._decrypt(ciphertext)
+ if wasString: return longtobytes(plaintext)
+ else: return plaintext
+
+ def sign(self, M, K):
+ """Return a tuple containing the signature for the message M. K is a random
+ parameter required by some algorithms."""
+ if (not self.hasprivate()):
+ raise error, 'Private key not available in this object'
+ if type(M)==types.StringType: M=bytestolong(M)
+ if type(K)==types.StringType: K=bytestolong(K)
+ return self._sign(M, K)
+
+ def verify(self, M, signature):
+ """Verify that the signature is valid for the message M;
+ returns true if the signature checks out."""
+ if type(M)==types.StringType: M=bytestolong(M)
+ return self._verify(M, signature)
+
+ validate = verify # alias to compensate for the old validate() name
+
+ # The following methods will usually be left alone, except for
+ # signature-only algorithms. They both return Boolean values
+ # recording whether this key's algorithm can sign and encrypt.
+ def cansign(self):
+ """Return a Boolean value recording whether this algorithm can generate signatures."""
+ return 1
+ def canencrypt(self):
+ """Return a Boolean value recording whether this algorithm can encrypt data."""
+ return 1
+
+ # The following methods will certainly be overridden by
+ # subclasses.
+
+ def size(self):
+ "Return the maximum number of bits that can be handled by this key."
+ return 0
+
+ def hasprivate(self):
+ """Return a Boolean denoting whether the object contains
+ private components."""
+ return 0
+
+ def publickey(self):
+ """Return a new key object containing only the public information."""
+ return self
+
+
diff --git a/PublicKey/qNEW.py b/PublicKey/qNEW.py
new file mode 100644
index 0000000..dc89153
--- /dev/null
+++ b/PublicKey/qNEW.py
@@ -0,0 +1,146 @@
+#
+# qNEW.py : The q-NEW signature algorithm.
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+import pubkey
+from Crypto.Util.number import *
+import Crypto.Hash.SHA
+
+error = 'qNEW module'
+HASHBITS = 160 # Size of SHA digests
+
+# Generate an qNEW key with N bits
+def generate(bits, randfunc, progress_func=None):
+ obj=qNEWobj()
+
+ # Generate prime numbers p and q. q is a 160-bit prime
+ # number. p is another prime number (the modulus) whose bit
+ # size is chosen by the caller, and is generated so that p-1
+ # is a multiple of q.
+ #
+ # Note that only a single seed is used to
+ # generate p and q; if someone generates a key for you, you can
+ # use the seed to duplicate the key generation. This can
+ # protect you from someone generating values of p,q that have
+ # some special form that's easy to break.
+ if progress_func: progress_func('p,q\n')
+ while (1):
+ obj.q = getPrime(160, randfunc)
+ # assert pow(2, 159L)<obj.q<pow(2, 160L)
+ obj.seed = S = longtobytes(obj.q)
+ C, N, V = 0, 2, {}
+ # Compute b and n such that bits-1 = b + n*HASHBITS
+ n= (bits-1) / HASHBITS
+ b= (bits-1) % HASHBITS ; powb=pow(long(2), b)
+ powL1=pow(long(2), bits-1)
+ while C<4096:
+ # The V array will contain (bits-1) bits of random
+ # data, that are assembled to produce a candidate
+ # value for p.
+ for k in range(0, n+1):
+ V[k]=bytestolong(Crypto.Hash.SHA.new(S+str(N)+str(k)).digest())
+ p = V[n] % powb
+ for k in range(n-1, -1, -1):
+ p= (p << long(HASHBITS) )+V[k]
+ p = p+powL1 # Ensure the high bit is set
+
+ # Ensure that p-1 is a multiple of q
+ p = p - (p % (2*obj.q)-1)
+
+ # If p is still the right size, and it's prime, we're done!
+ if powL1<=p and isPrime(p): break
+
+ # Otherwise, increment the counter and try again
+ C, N = C+1, N+n+1
+ if C<4096: break # Ended early, so exit the while loop
+ if progress_func: progress_func('4096 values of p tried\n')
+
+ obj.p = p
+ power=(p-1)/obj.q
+
+ # Next parameter: g = h**((p-1)/q) mod p, such that h is any
+ # number <p-1, and g>1. g is kept; h can be discarded.
+ if progress_func: progress_func('h,g\n')
+ while (1):
+ h=bytestolong(randfunc(bits)) % (p-1)
+ g=pow(h, power, p)
+ if 1<h<p-1 and g>1: break
+ obj.g=g
+
+ # x is the private key information, and is
+ # just a random number between 0 and q.
+ # y=g**x mod p, and is part of the public information.
+ if progress_func: progress_func('x,y\n')
+ while (1):
+ x=bytestolong(randfunc(20))
+ if 0<x<obj.q: break
+ obj.x, obj.y=x, pow(g, x, p)
+
+ return obj
+
+# Construct an qNEW object
+def construct(tuple):
+ obj=qNEWobj()
+ if len(tuple) not in [4,5]:
+ raise error, 'argument for construct() wrong length'
+ for i in range(len(tuple)):
+ field = obj.keydata[i]
+ setattr(obj, field, tuple[i])
+ return obj
+
+class qNEWobj(pubkey.pubkey):
+ keydata=['p', 'q', 'g', 'y', 'x']
+
+ def _sign(self, M, K=''):
+ if (self.q<=K):
+ raise error, 'K is greater than q'
+ if M<0:
+ raise error, 'Illegal value of M (<0)'
+ if M>=pow(2,161L):
+ raise error, 'Illegal value of M (too large)'
+ r=pow(self.g, K, self.p) % self.q
+ s=(K- (r*M*self.x % self.q)) % self.q
+ return (r,s)
+ def _verify(self, M, sig):
+ r, s = sig
+ if r<=0 or r>=self.q or s<=0 or s>=self.q: return 0
+ if M<0:
+ raise error, 'Illegal value of M (<0)'
+ if M<=0 or M>=pow(2,161L): return 0
+ v1=pow(self.g, s, self.p)
+ v2=pow(self.y, M*r, self.p)
+ v=((v1*v2) % self.p)
+ v=v % self.q
+ if v==r: return 1
+ return 0
+
+ def size(self):
+ "Return the maximum number of bits that can be handled by this key."
+ return 160
+
+ def hasprivate(self):
+ """Return a Boolean denoting whether the object contains
+ private components."""
+ return hasattr(self, 'x')
+
+ def cansign(self):
+ """Return a Boolean value recording whether this algorithm can generate signatures."""
+ return 1
+ def canencrypt(self):
+ """Return a Boolean value recording whether this algorithm can encrypt data."""
+ return 0
+
+ def publickey(self):
+ """Return a new key object containing only the public information."""
+ return construct((self.p, self.q, self.g, self.y))
+
+object = qNEWobj
+
diff --git a/README b/README
new file mode 100644
index 0000000..960cf55
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+
+ This is version 1.1 of the Python cryptography modules, a
+collection of cryptographic code for the Python programming language.
+
+ This is a collection of both secure hash functions (such as MD5
+and SHA), and various encryption algorithms (IDEA, DES, RSA, ElGamal,
+etc.). The package is structured to make adding new modules easy. I
+consider this section to be essentially complete, and the software
+interface will almost certainly not change in an incompatible way in
+the future; all that remains to be done is to fix any bugs that show
+up. If you encounter a bug, please inform me immediately. If you
+implement a new algorithm, please send me a copy.
+
+ A sample usage of the MD5 module is:
+>>> from Crypto.Hash import MD5
+>>> hash=MD5.new()
+>>> hash.update(message)
+>>> hash.digest()
+'\235\361\034\357\217MX\2246\226\367\366Ebx\326'
+
+ A sample use of an encryption algorithm (IDEA, in this case) is:
+>>> from Crypto.Cipher import IDEA
+>>> obj=IDEA.new('This is a key456', IDEA.ECB)
+>>> message="The answer is no"
+>>> ciphertext=obj.encrypt(message)
+>>> ciphertext
+'\2325$\343=)d\341^\025<\344\013\204 T'
+>>> obj.decrypt(ciphertext)
+'The answer is no'
+
+ One possible application of the modules is writing secure
+administration tools. Another application is in writing daemons and
+servers. Clients and servers can encrypt the data being exchanged and
+mutually authenticate themselves; daemons can encrypt private data for
+added security. Python also provides a pleasant framework for
+prototyping and experimentation with cryptographic algorithms; thanks
+to its arbitrary-length integers, public key algorithms are easily
+implemented.
+
+ For discussion about using Python for cryptography-related
+tasks, join the python-crypto mailing list. Point your Web browser to
+<URL:http://www.findmail.com/list/python-crypto/> and fill out the
+form, or send a message with "subscribe" in the Subject: line to
+python-crypto-request@makelist.com .
+
+TO INSTALL:
+
+ You must already have Python installed to build the
+cryptography modules since the buildkit script (which the Makefile
+uses) is written in Python. Be sure you ran the "libainstall" and
+"inclinstall" targets when you built Python, which install various
+libraries and *.h files needed to compile modified versions of the
+Python interpreter.
+
+ Once Python has been built and installed, this package can be
+compiled. Simply run "make" in the same directory as this file. The
+default setup is to compile the modules so they can be dynamically
+linked into the Python interpreter when they're imported; edit
+Setup.in and/or Makefile.pre.in if desired. If you installed Python
+in a non-standard location, you might want to call make like so:
+
+ make -k installdir=/path/to/exec/prefix/when/i/installed/Python
+
+ To verify that everything is in order, run "make test". It
+will test all the cryptographic modules, skipping ones that aren't
+available. If the test script reports an error on your machine,
+please inform me immediately, because that means there's a serious bug
+somewhere in the cryptographic routines. (Alternatively, track down
+the bug and send me a patch.)
+
+ Running test.py without the --quiet argument will let you see
+what it's doing, and will also run a crude benchmark to give you an
+impression of the comparative speeds of the algorithms and feedback
+modes.
+
+ To install the package under the site-packages directory of
+your Python installation, run "make install" once you've run "make
+test" successfully.
+
+ If you have any comments, corrections, or improvements for
+this package, please e-mail me at the address below, or send it to the
+python-crypto mailing list at python-crypto@makelist.com . Good luck!
+
+
+ Andrew Kuchling
+ akuchling@acm.org
diff --git a/Setup.in b/Setup.in
new file mode 100644
index 0000000..cd2d941
--- /dev/null
+++ b/Setup.in
@@ -0,0 +1,30 @@
+
+*shared*
+
+# Hash algorithms
+
+MD2 MD2module.c # MD2
+MD4 MD4module.c # MD4
+MD5 MD5module.c # MD5
+RIPEMD RIPEMDmodule.c # RIPEMD
+SHA SHAmodule.c # SHA
+HAVAL HAVALmodule.c # HAVAL
+
+# Block encryption algorithms
+ARC2 ARC2module.c
+Blowfish Blowfishmodule.c
+CAST CASTmodule.c
+DES DESmodule.c
+DES3 DES3module.c
+Diamond Diamondmodule.c
+IDEA IDEAmodule.c
+RC5 RC5module.c
+Skipjack Skipjackmodule.c
+
+# Stream encryption algorithms
+
+ARC4 ARC4module.c
+Sapphire Sapphiremodule.c
+
+
+
diff --git a/Setup.in-export b/Setup.in-export
new file mode 100644
index 0000000..4c2eca4
--- /dev/null
+++ b/Setup.in-export
@@ -0,0 +1,15 @@
+
+*shared*
+
+# Hash algorithms
+
+MD2 MD2module.c # MD2
+MD4 MD4module.c # MD4
+MD5 MD5module.c # MD5
+RIPEMD RIPEMDmodule.c # RIPEMD
+SHA SHAmodule.c # SHA
+HAVAL HAVALmodule.c # HAVAL
+
+
+
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..e6a44f8
--- /dev/null
+++ b/TODO
@@ -0,0 +1,23 @@
+
+Core algorithms:
+ Elliptic-curve algs should be added; they're not a priority for now.
+ A secret sharing module should be added to Util or Protocols.
+
+Protocols:
+ Implement ssh
+ Add PGP modules to the package, rearranging them to fit.
+
+Generic cryptographic stuff:
+ Optimize the feedback modes a bit
+
+Demo programs:
+ Shadowing of files into X parts
+ Secure talk or telnet
+
+Documentation:
+ Document chaff/winnow better
+ Add docstrings everywhere.
+
+Config stuff:
+ Smarter distribution building
+
diff --git a/Util/RFC1751.py b/Util/RFC1751.py
new file mode 100644
index 0000000..e3b059b
--- /dev/null
+++ b/Util/RFC1751.py
@@ -0,0 +1,340 @@
+#!/usr/local/bin/python
+# rfc1751.py : Converts between 128-bit strings and a human-readable
+# sequence of words, as defined in RFC1751: "A Convention for
+# Human-Readable 128-bit Keys", by Daniel L. McDonald.
+
+error = 'rfc1751 error'
+import string
+
+binary={0:'0000', 1:'0001', 2:'0010', 3:'0011', 4:'0100', 5:'0101',
+ 6:'0110', 7:'0111', 8:'1000', 9:'1001', 10:'1010', 11:'1011',
+ 12:'1100', 13:'1101', 14:'1110', 15:'1111'}
+
+def key2bin(s):
+ "Convert a key into a string of binary digits"
+ kl=map(lambda x: ord(x), s)
+ kl=map(lambda x: binary[x/16]+binary[x&15], kl)
+ return reduce(lambda x,y: x+y, kl, '')
+
+def extract(key, start, length):
+ """Extract a bitstring from a string of binary digits, and return its
+ numeric value."""
+ k=key[start:start+length]
+ return reduce(lambda x,y: x*2+ord(y)-48, k, 0)
+
+def Key2English(key):
+ """Transform an arbitrary key into a string containing English words.
+ The key length must be a multiple of 8."""
+ english=''
+ for index in range(0, len(key), 8): # Loop over 8-byte subkeys
+ subkey=key[index:index+8]
+ # Compute the parity of the key
+ skbin=key2bin(subkey) ; p=0
+ for i in range(0, 64, 2): p=p+extract(skbin, i, 2)
+ # Append parity bits to the subkey
+ skbin=key2bin(subkey+chr((p<<6) & 255))
+ for i in range(0, 64, 11):
+ english=english+wordlist[extract(skbin, i, 11)]+' '
+ return english[:-1] # Remove the trailing space
+
+def English2Key(seq):
+ """Transform a string into a corresponding key.
+ The string must contain words separated by whitespace; the number
+ of words must be a multiple of 6."""
+ L=string.split(string.upper(seq)) ; key=''
+ for index in range(0, len(L), 6):
+ sublist=L[index:index+6] ; char=9*[0] ; bits=0
+ for i in sublist:
+ index=wordlist.index(i)
+ shift=(8-(bits+11)%8) %8
+ y=index<<shift
+ cl, cc, cr = (y>>16), (y>>8)&0xff, y & 0xff
+ if (shift>5):
+ char[bits/8] = char[bits/8] | cl
+ char[bits/8+1] = char[bits/8+1] | cc
+ char[bits/8+2] = char[bits/8+2] | cr
+ elif shift>-3:
+ char[bits/8] = char[bits/8] | cc
+ char[bits/8+1] = char[bits/8+1] | cr
+ else: char[bits/8] = char[bits/8] | cr
+ bits=bits+11
+ subkey=reduce(lambda x,y:x+chr(y), char, '')
+
+ # Check the parity of the resulting key
+ skbin=key2bin(subkey)
+ p=0
+ for i in range(0, 64, 2): p=p+extract(skbin, i, 2)
+ if (p&3) != extract(skbin, 64, 2):
+ raise error, "Parity error in resulting key"
+ key=key+subkey[0:8]
+ return key
+
+wordlist=[ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
+ "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
+ "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
+ "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
+ "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
+ "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
+ "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
+ "BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
+ "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
+ "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
+ "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
+ "DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
+ "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
+ "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
+ "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
+ "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
+ "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
+ "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
+ "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
+ "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
+ "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
+ "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
+ "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
+ "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
+ "INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
+ "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET",
+ "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT",
+ "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB",
+ "LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
+ "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT",
+ "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG",
+ "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW",
+ "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
+ "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG",
+ "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED",
+ "NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD",
+ "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
+ "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL",
+ "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT",
+ "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD",
+ "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
+ "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT",
+ "PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB",
+ "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT",
+ "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
+ "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB",
+ "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM",
+ "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET",
+ "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
+ "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY",
+ "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN",
+ "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE",
+ "TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
+ "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP",
+ "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS",
+ "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT",
+ "WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
+ "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT",
+ "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS",
+ "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE",
+ "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA",
+ "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN",
+ "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW",
+ "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA",
+ "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM",
+ "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
+ "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL",
+ "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM",
+ "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK",
+ "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH",
+ "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT",
+ "BEAU", "BECK", "BEEF", "BEEN", "BEER",
+ "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN",
+ "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE",
+ "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE",
+ "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT",
+ "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK",
+ "BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT",
+ "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK",
+ "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS",
+ "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
+ "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD",
+ "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG",
+ "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST",
+ "BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF",
+ "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL",
+ "CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL",
+ "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF",
+ "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG",
+ "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
+ "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA",
+ "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN",
+ "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK",
+ "COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST",
+ "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB",
+ "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY",
+ "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE",
+ "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN",
+ "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
+ "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED",
+ "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK",
+ "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT",
+ "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES",
+ "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA",
+ "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG",
+ "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK",
+ "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK",
+ "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
+ "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT",
+ "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT",
+ "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED",
+ "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL",
+ "FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT",
+ "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST",
+ "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE",
+ "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE",
+ "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
+ "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM",
+ "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL",
+ "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL",
+ "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY",
+ "FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY",
+ "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA",
+ "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH",
+ "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE",
+ "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
+ "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN",
+ "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD",
+ "GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG",
+ "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB",
+ "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN",
+ "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH",
+ "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR",
+ "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK",
+ "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
+ "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR",
+ "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL",
+ "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN",
+ "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT",
+ "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE",
+ "HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK",
+ "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL",
+ "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK",
+ "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
+ "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH",
+ "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE",
+ "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE",
+ "JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL",
+ "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN",
+ "JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY",
+ "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST",
+ "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL",
+ "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
+ "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW",
+ "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD",
+ "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN",
+ "LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD",
+ "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS",
+ "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER",
+ "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST",
+ "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU",
+ "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
+ "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST",
+ "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE",
+ "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD",
+ "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK",
+ "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE",
+ "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE",
+ "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI",
+ "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK",
+ "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
+ "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK",
+ "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH",
+ "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT",
+ "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS",
+ "MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD",
+ "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON",
+ "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH",
+ "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK",
+ "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
+ "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR",
+ "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS",
+ "NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA",
+ "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON",
+ "NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB",
+ "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY",
+ "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE",
+ "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS",
+ "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
+ "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT",
+ "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE",
+ "RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR",
+ "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA",
+ "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT",
+ "RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD",
+ "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME",
+ "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS",
+ "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
+ "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE",
+ "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE",
+ "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE",
+ "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR",
+ "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK",
+ "SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS",
+ "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN",
+ "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE",
+ "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
+ "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW",
+ "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY",
+ "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT",
+ "SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB",
+ "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA",
+ "SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE",
+ "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR",
+ "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH",
+ "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
+ "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM",
+ "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK",
+ "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM",
+ "TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS",
+ "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN",
+ "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER",
+ "TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY",
+ "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG",
+ "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
+ "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG",
+ "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE",
+ "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK",
+ "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER",
+ "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST",
+ "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY",
+ "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE",
+ "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK",
+ "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
+ "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY",
+ "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR",
+ "WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM",
+ "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE",
+ "WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE",
+ "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD",
+ "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE",
+ "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR",
+ "YELL", "YOGA", "YOKE" ]
+
+if __name__=='__main__':
+ def hex2str(s):
+ s2=''
+ for i in range(0, len(s), 2):
+ s2=s2+chr(string.atoi(s[i:i+2], 16))
+ return s2
+
+ data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'),
+ ('CCAC2AED591056BE4F90FD441C534766',
+ 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'),
+ ('EFF81F9BFBC65350920CDD7416DE8009',
+ 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL')
+ ]
+
+ for key, words in data:
+ print 'Trying key', key
+ key=hex2str(key)
+ w2=Key2English(key)
+ if w2!=words:
+ print 'Key2English fails on key', repr(key), ', producing', str(w2)
+ k2=English2Key(words)
+ if k2!=key:
+ print 'English2Key fails on key', repr(key), ', producing', repr(k2)
+
+
diff --git a/Util/__init__.py b/Util/__init__.py
new file mode 100644
index 0000000..f88e88e
--- /dev/null
+++ b/Util/__init__.py
@@ -0,0 +1,3 @@
+
+__all__ = ['randpool', 'RFC1751', 'number']
+
diff --git a/Util/number.py b/Util/number.py
new file mode 100644
index 0000000..2be1c35
--- /dev/null
+++ b/Util/number.py
@@ -0,0 +1,156 @@
+#
+# number.py : Number-theoretic functions
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+
+bignum = long
+try:
+ import gmp
+except ImportError:
+ try:
+ import mpz
+ #bignum=mpz.mpz # Temporarily disabled; the 'outrageous exponent'
+ # error messes things up.
+ except ImportError:
+ pass
+
+# Commented out and replaced with faster versions below
+## def long2str(n):
+## s=''
+## while n>0:
+## s=chr(n & 255)+s
+## n=n>>8
+## return s
+
+## import types
+## def str2long(s):
+## if type(s)!=types.StringType: return s # Integers will be left alone
+## return reduce(lambda x,y : x*256+ord(y), s, 0L)
+
+def getRandomNumber(N, randfunc):
+ "Return an N-bit random number."
+ str=randfunc(N/8)
+ char=ord(randfunc(1))>>(8-(N%8))
+ return str2long(chr(char)+str)
+
+def GCD(x,y):
+ "Return the GCD of x and y."
+ if x<0: x=-x
+ if y<0: y=-y
+ while x>0: x,y = y%x, x
+ return y
+
+def inverse(u, v):
+ "Return the inverse of u mod v."
+ u3, v3 = long(u), long(v)
+ u1, v1 = 1L, 0L
+ while v3>0:
+ q=u3/v3
+ u1, v1 = v1, u1-v1*q
+ u3, v3 = v3, u3-v3*q
+ print u1,u3,v1,v3
+ while u1<0: u1=u1+v
+ return u1
+
+# Given a number of bits to generate and a random generation function,
+# find a prime number of the appropriate size.
+
+def getPrime(N, randfunc):
+ "Return a random N-bit prime number."
+ number=getRandomNumber(N, randfunc) | 1
+ while (not isPrime(number)):
+ number=number+2
+ return number
+
+def isPrime(N):
+ "Return true if N is prime."
+ if N in sieve: return 1
+ for i in sieve:
+ if (N % i)==0: return 0
+
+ # Compute the highest bit that's set in N
+ N1=N - 1L ; n=1L
+ while (n<N): n=n<<1L
+ n = n >> 1L
+
+ # Rabin-Miller test
+ for c in sieve[:7]:
+ a=long(c) ; d=1L ; t=n
+ while (t): # Iterate over the bits in N1
+ x=(d*d) % N
+ if x==1L and d!=1L and d!=N1: return 0 # Square root of 1 found
+ if N1 & t: d=(x*a) % N
+ else: d=x
+ t = t >> 1L
+ if d!=1L: return 0
+ return 1
+
+# Small primes used for checking primality; these are all the primes
+# less than 256. This should be enough to eliminate most of the odd
+# numbers before needing to do a Rabin-Miller test at all.
+
+sieve=[2, 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]
+
+
+# Improved conversion functions contributed by Barry Warsaw, after
+# careful benchmarking
+
+import struct
+
+def longtobytes(n, blocksize=0):
+ """Convert a long integer to a byte string
+
+ If optional blocksize is given and greater than zero, pad the front of the
+ byte string with binary zeros so that the length is a multiple of
+ blocksize.
+ """
+ # after much testing, this algorithm was deemed to be the fastest
+ s = ''
+ pack = struct.pack
+ while n > 0:
+ s = pack('>I', n & 0xffffffffL) + s
+ n = n >> 32
+ # strip off leading zeros
+ for i in range(len(s)):
+ if s[i] <> '\000':
+ break
+ else:
+ # only happens when n == 0
+ s = '\000'
+ i = 0
+ s = s[i:]
+ # add back some pad bytes. this could be done more efficiently w.r.t. the
+ # de-padding being done above, but sigh...
+ if blocksize > 0 and len(s) % blocksize:
+ s = (blocksize - len(s) % blocksize) * '\000' + s
+ return s
+
+def bytestolong(s):
+ """Convert a byte string to a long integer.
+
+ This is (essentially) the inverse of longtobytes().
+ """
+ acc = 0L
+ unpack = struct.unpack
+ length = len(s)
+ if length % 4:
+ extra = (4 - length % 4)
+ s = '\000' * extra + s
+ length = length + extra
+ for i in range(0, length, 4):
+ acc = (acc << 32) + unpack('>I', s[i:i+4])[0]
+ return acc
+
+# For backwards compatibility...
+long2str = longtobytes
+str2long = bytestolong
diff --git a/Util/randpool.py b/Util/randpool.py
new file mode 100644
index 0000000..71710d1
--- /dev/null
+++ b/Util/randpool.py
@@ -0,0 +1,223 @@
+#
+# randpool.py : Cryptographically strong random number generation
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+
+"""randpool.py : Cryptographically strong random number generation.
+
+The implementation here is similar to the one in PGP. To be
+cryptographically strong, it must be difficult to determine the RNG's
+output, whether in the future or the past. This is done by using
+encryption algorithms to "stir" the random data.
+
+Entropy is gathered in the same fashion as PGP; the highest-resolution
+clock around is read and the data is added to the random number pool.
+A conservative estimate of the entropy is then kept.
+"""
+
+import time, array
+
+from Crypto.Util.number import longtobytes
+
+class RandomPool:
+ def __init__(self, numbytes = 160, cipher=None, hash='SHA'):
+ # The cipher argument is vestigial; it was removed from
+ # version 1.1 so RandomPool would work even in the limited
+ # exportable subset of the code
+
+ if type(hash) == type(''):
+ # ugly hack to force __import__ to give us the end-path module
+ hash = __import__('Crypto.Hash.'+hash,
+ None, None, ['new'])
+
+ self.entropy, self._addPos = 0,0
+ self._event1, self._event2 = 0,0
+ self._addPos, self._getPos = 0,hash.digestsize
+ self.bytes, self.hash=numbytes, hash
+ self.bits=self.bytes*8
+ self.__counter = 0
+
+ # Construct an array to hold the random pool
+ a = []
+ while len(a) < self.bytes:
+ a = a + range( min(256, self.bytes-len(a)) )
+ self._randpool = array.array('B', a)
+
+ # Linux supports a /dev/urandom device; soon other OSes will, too.
+ # We'll grab some randomness from it.
+ try:
+ f=open('/dev/urandom')
+ data=f.read(self.bytes)
+ f.close()
+ self._addBytes(data)
+ # Conservative entropy estimate: The number of bits of
+ # data obtained from /dev/urandom, divided by 4.
+ self.entropy = self.entropy + (8/2)*len(data)
+ except IOError, (num, msg):
+ if num!=2: raise IOError, (num, msg)
+ # If the file wasn't found, ignore the error
+
+ def stir(self):
+ entropy=self.entropy
+ self.addEvent(time.time())
+
+ for i in range( self.bytes / self.hash.digestsize):
+ h = self.hash.new(self._randpool)
+ h.update(str(self.__counter) + str(i) + str(self._addPos) )
+ self._addBytes( h.digest() )
+ self.__counter = (self.__counter + 1) & 0xFFFFffff
+
+ self._addPos, self._getPos = 0, self.hash.digestsize
+ self.addEvent(time.time())
+
+ # Paranoia is a Good Thing in cryptographic applications.
+ # While the call to addEvent() may be adding entropy to the
+ # pool, we won't take that into account.
+ self.entropy=entropy
+
+ def getBytes(self, N):
+ "Return num bytes of random data"
+ s=''
+ i, pool = self._getPos, self._randpool
+ h=self.hash.new()
+ dsize = self.hash.digestsize
+ num = N
+ while num>0:
+ h.update( self._randpool[i:i+dsize] )
+ s = s + h.digest()
+ num = num - dsize
+ i = (i + dsize) % self.bytes
+ if i<dsize:
+ self.stir()
+ i=self._getPos
+
+ self._getPos = i
+ self.entropy=self.entropy-8*num
+ if self.entropy<0: self.entropy=0
+ return s[:N]
+
+ def addEvent(self, event, s=''):
+ event=long(event*1000)
+ delta=self._noise()
+ s=s+longtobytes(event)+4*chr(0xaa)+longtobytes(long(delta))
+ self._addBytes(s)
+ if event==self._event1 and event==self._event2:
+ bits=0
+ else:
+ bits=0
+ while (delta): delta, bits = delta>>1, bits+1
+ if (bits>8): bits=8
+ self._event1, self._event2 = event, self._event1
+ self.entropy=self.entropy+bits
+ if self.entropy>self.bytes*8:
+ self.entropy=self.bytes*8
+ return self.entropy
+
+ # Private functions
+ def _noise(self):
+ if not self.__dict__.has_key('_lastcounter'):
+ self._lastcounter=time.time()
+ if not self.__dict__.has_key('_ticksize'):
+ self._noiseTickSize()
+ t=time.time()
+ delta = (t - self._lastcounter)/self._ticksize*1e6
+ self._lastcounter = t
+ self._addBytes(longtobytes(long(1000*time.time())))
+ self._addBytes(longtobytes(long(1000*time.clock())))
+ self._addBytes(longtobytes(long(1000*time.time())))
+ self._addBytes(longtobytes(long(delta)))
+ delta=delta % 0x1000000 # Reduce delta so it fits into an int
+ return int(delta)
+
+ def _noiseTickSize(self):
+ interval=[]
+ t=time.time()
+ for i in range(0,100):
+ t2=time.time()
+ delta=int((t2-t)*1e6)
+ t=t2
+ if delta: interval.append(delta)
+ interval.sort()
+ self._ticksize=interval[len(interval)/2]
+
+ def _addBytes(self, s):
+ "XOR the contents of the string S into the random pool"
+ i, pool = self._addPos, self._randpool
+ for j in range(0, len(s)):
+ pool[i]=pool[i] ^ ord(s[j])
+ i=(i+1) % self.bytes
+ self._addPos = i
+
+
+class KeyboardRandomPool(RandomPool):
+ def __init__(self, filename='', numbytes = 384, cipher=None, hash='MD5'):
+ self.filename=filename
+ if filename:
+ try:
+ import pickle
+ f=open(filename, 'r')
+ temp=pickle.load(f)
+ for key in temp.__dict__.keys():
+ self.__dict__[key]=temp.__dict__[key]
+ f.close()
+ self.stir()
+ except IOError:
+ RandomPool.__init__(self, numbytes, cipher, hash)
+ else:
+ RandomPool.__init__(self, numbytes, cipher, hash)
+
+ self.stir() # Wash the random pool
+ self.stir()
+ self.stir()
+
+ def save(self):
+ import pickle
+ if self.filename == "":
+ raise ValueError, "No filename set for this object"
+ self.stir() # Wash the random pool
+ self.stir()
+ self.stir()
+ f=open(self.filename, 'w')
+ pickle.dump(self, f)
+ f.close()
+
+ def randomize(self):
+ import os, string, termios, TERMIOS, time
+ bits=self.bits-self.entropy
+ if bits==0: return # No entropy required, so we exit.
+ print bits,'bits of entropy are now required. Please type on the keyboard'
+ print 'until enough randomness has been accumulated.'
+ fd=0
+ old=termios.tcgetattr(fd)
+ new=termios.tcgetattr(fd)
+ new[3]=new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
+ termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
+ s='' # We'll save the characters typed and add them to the pool.
+ hash = self.hash
+ try:
+ while (self.entropy<self.bits):
+ temp=string.rjust(str(self.bits-self.entropy), 6)
+ os.write(1, temp)
+ termios.tcflush(0, TERMIOS.TCIFLUSH) # XXX Leave this in?
+ s=s+os.read(0, 1)
+ self.addEvent(time.time())
+ os.write(1, 6*chr(8))
+ self.addEvent(time.time(), s+hash.new(s).digest() )
+ finally:
+ termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
+ print '\n\007 Enough.\n'
+ time.sleep(3)
+ termios.tcflush(0, TERMIOS.TCIFLUSH)
+
+
+if __name__ == '__main__':
+ pool = RandomPool()
+ print `pool.getBytes(100)`
diff --git a/Util/test.py b/Util/test.py
new file mode 100644
index 0000000..83bfc2e
--- /dev/null
+++ b/Util/test.py
@@ -0,0 +1,803 @@
+#
+# test.py : Functions used for testing the modules
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+def die(string):
+ import sys
+ print '***ERROR: ', string
+# sys.exit(0) # Will default to continuing onward...
+
+def hex2str(str):
+ s=''
+ for i in range(0,len(str),2):
+ s=s+chr(string.atoi(str[i:i+2], 16))
+ return s
+
+def exerciseBlockCipher(cipher, verbose):
+ import string, time
+ try:
+ from Crypto.Cipher import * ; ciph = eval(cipher, locals() )
+ except ImportError:
+ print cipher, 'module not available'
+ return None
+ print cipher+ ':'
+ str='1' # Build 128K of test data
+ for i in xrange(0, 17):
+ str=str+str
+ if ciph.keysize==0: ciph.keysize=16
+ password = 'password12345678Extra text for password'[0:ciph.keysize]
+ IV = 'Test IV Test IV Test IV Test'[0:ciph.blocksize]
+
+ if verbose: print ' Testing ECB mode with key '+ `password`
+ obj=ciph.new(password, ciph.ECB)
+ if verbose: print ' Sanity check'
+ if obj.blocksize != ciph.blocksize:
+ die("Module and cipher object blocksize don't match")
+
+ text='1234567812345678'[0:ciph.blocksize]
+ c=obj.encrypt(text)
+ if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+ text='KuchlingKuchling'[0:ciph.blocksize]
+ c=obj.encrypt(text)
+ if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+ text='NotTodayNotEver!'[0:ciph.blocksize]
+ c=obj.encrypt(text)
+ if (obj.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+
+ start=time.time()
+ s=obj.encrypt(str)
+ s2=obj.decrypt(s)
+ end=time.time()
+ if (str!=s2):
+ die('Error in resulting plaintext from ECB mode')
+ if verbose: print ' Benchmark for 256K: ', 256/(end-start), 'K/sec'
+ del obj
+
+ if verbose: print ' Testing CFB mode with key ' + `password`+ ' IV "Test IV@"'
+ obj1=ciph.new(password, ciph.CFB, IV)
+ obj2=ciph.new(password, ciph.CFB, IV)
+ start=time.time()
+ ciphertext=obj1.encrypt(str[0:65536])
+ plaintext=obj2.decrypt(ciphertext)
+ end=time.time()
+ if (plaintext!=str[0:65536]):
+ die('Error in resulting plaintext from CFB mode')
+ if verbose: print ' Benchmark for 64K: ', 64/(end-start), 'K/sec'
+ del obj1, obj2
+
+ if verbose: print ' Testing CBC mode with key ' + `password`+ ' IV "Test IV@"'
+ obj1=ciph.new(password, ciph.CBC, IV)
+ obj2=ciph.new(password, ciph.CBC, IV)
+ start=time.time()
+ ciphertext=obj1.encrypt(str)
+ plaintext=obj2.decrypt(ciphertext)
+ end=time.time()
+ if (plaintext!=str):
+ die('Error in resulting plaintext from CBC mode')
+ if verbose: print ' Benchmark for 256K: ', 256/(end-start), 'K/sec'
+ del obj1, obj2
+
+ if verbose: print ' Testing PGP mode with key ' + `password`+ ' IV "Test IV@"'
+ obj1=ciph.new(password, ciph.PGP, IV)
+ obj2=ciph.new(password, ciph.PGP, IV)
+ start=time.time()
+ ciphertext=obj1.encrypt(str)
+ plaintext=obj2.decrypt(ciphertext)
+ end=time.time()
+ if (plaintext!=str):
+ die('Error in resulting plaintext from PGP mode')
+ if verbose: print ' Benchmark for 256K: ', 256/(end-start), 'K/sec'
+ del obj1, obj2
+
+ # Test the IV handling
+ if verbose: print ' Testing IV handling'
+ obj1=ciph.new(password, ciph.CBC, IV)
+ plaintext='Test'*(ciph.blocksize/4)*3
+ ciphertext1=obj1.encrypt(plaintext)
+ obj1.IV=IV
+ ciphertext2=obj1.encrypt(plaintext)
+ if ciphertext1!=ciphertext2:
+ die('Error in setting IV')
+
+ # Test keyword arguments
+ obj1=ciph.new(key=password)
+ obj1=ciph.new(password, mode=ciph.CBC)
+ obj1=ciph.new(mode=ciph.CBC, key=password)
+ obj1=ciph.new(IV=IV, mode=ciph.CBC, key=password)
+
+ return ciph
+
+def exerciseStreamCipher(cipher, verbose):
+ import string, time
+ try:
+ from Crypto.Cipher import * ; ciph = eval(cipher, locals() )
+ except (ImportError):
+ print cipher, 'module not available'
+ return None
+ print cipher + ':'
+ str='1' # Build 128K of test data
+ for i in xrange(0, 17):
+ str=str+str
+ if ciph.keysize==0: ciph.keysize=16
+ password = 'password12345678Extra text for password'[0:ciph.keysize]
+
+ obj1=ciph.new(password)
+ obj2=ciph.new(password)
+ if verbose: print ' Sanity check'
+ if obj1.blocksize != ciph.blocksize:
+ die("Module and cipher object blocksize don't match")
+ if obj1.keysize != ciph.keysize:
+ die("Module and cipher object keysize don't match")
+
+ text='1234567812345678Python'
+ c=obj1.encrypt(text)
+ if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+ text='B1FF I2 A R3A11Y |<00L D00D!!!!!'
+ c=obj1.encrypt(text)
+ if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+ text='SpamSpamSpamSpamSpamSpamSpamSpamSpam'
+ c=obj1.encrypt(text)
+ if (obj2.decrypt(c)!=text): die('Error encrypting "'+text+'"')
+
+ start=time.time()
+ s=obj1.encrypt(str)
+ str=obj2.decrypt(s)
+ end=time.time()
+ if verbose: print ' Benchmark for 256K: ', 256/(end-start), 'K/sec'
+ del obj1, obj2
+
+ return ciph
+
+def exercisePublicKey(randfunc, module, verbose):
+ N=256 # Key size, measured in bits
+
+ if verbose: print ' Generating', N, 'bit key'
+ import sys
+ import Crypto.Util.number
+ def write(s):
+ import sys ; sys.stdout.write(' '+s)
+ if verbose: key=module.generate(N, randfunc, write)
+ else: key=module.generate(N, randfunc)
+
+ if verbose:
+ print ' Key data:'
+ for field in key.keydata:
+ print " ", field, ':', hex(getattr(key,field))
+
+ def testkey(key, randfunc, verbose):
+ plaintext="Hello"
+
+ if key.canencrypt():
+ if verbose: print ' Encryption/decryption test'
+ K=Crypto.Util.number.getPrime(10, randfunc)
+ ciphertext=key.encrypt(plaintext, K)
+ if key.decrypt(ciphertext)!=plaintext:
+ print '***ERROR: Mismatch decrypting plaintext'
+
+ if key.cansign():
+ if verbose: print ' Signature test'
+ K=Crypto.Util.number.getPrime(30, randfunc)
+ signature=key.sign(plaintext, K)
+ result=key.verify(plaintext, signature)
+ if not result:
+ print "***ERROR 1: Sig. verification failed when it should have succeeded"
+ result=key.verify(plaintext[:-1], signature)
+ if result:
+ print "***ERROR 2: Sig. verification succeeded when it should have failed"
+ # Change a single bit in the plaintext
+ badtext=plaintext[:-3]+chr( 1 ^ ord(plaintext[-3]) )+plaintext[-3:]
+ result=key.verify(badtext, signature)
+ if result:
+ print "***ERROR 3: Sig. verification succeeded when it should have failed"
+ if verbose: print ' Removing private key data'
+ pubonly=key.publickey()
+ result=pubonly.verify(plaintext, signature)
+ if not result:
+ print "***ERROR 4: Sig. verification failed when it should have succeeded"
+
+ if verbose: print " Testing newly generated key"
+ testkey(key, randfunc, verbose)
+ if verbose: print " Testing pickled/unpickled key"
+ import pickle
+ s = pickle.dumps(key) ; key2 = pickle.loads(s)
+ testkey(key2, randfunc, verbose)
+
+ if verbose: print " Testing cPickled key"
+ import cPickle
+ s = cPickle.dumps(key) ; key2 = cPickle.loads(s)
+ testkey(key2, randfunc, verbose)
+ if verbose: print
+
+import string
+def compareHashResult(hash, strg, result):
+ obj=hash.new(strg)
+ s=obj.digest()
+ s1=s
+ temp=0L
+ while (s!=''):
+ temp=temp*256+ord(s[0])
+ s=s[1:]
+
+ # Check that the right hash result is produced
+ if (result!=temp):
+ die(`hash`+' produces incorrect result on string "'+strg+'"')
+ return
+
+ # Check that .hexdigest() produces the same output
+ hex_result = string.lower( hex(result)[2:-1] )
+ if len(hex_result) % 2: hex_result = '0'+hex_result
+ if hex_result != obj.hexdigest():
+ die(`hash`+' produces incorrect result on string "'+strg+'" using hexdigest()')
+ return
+
+ # Test second hashing, and copying of a hashing object
+ s2=obj.digest()
+ if s2!=s1: die(`hash`+' produces incorrect result on second hashing')
+ s3=obj.copy().digest()
+ if s3!=s1: die(`hash`+' produces incorrect result after copying')
+
+ del temp, s
+
+
+import Crypto.Util.testdata
+
+def TestHashModules(args=['ripemd', 'md2', 'md4', 'md5', 'sha', 'haval'],
+ verbose=1):
+ import string
+ args=map(string.lower, args)
+
+ teststr='1' # Build 128K of test data
+ for i in xrange(0, 17):
+ teststr=teststr+teststr
+
+ if 'ripemd' in args:
+ # Test/benchmark RIPEMD hash algorithm ; the test data is taken from
+ # the README in rmd.zip
+ try:
+ from Crypto.Hash import RIPEMD
+ except ImportError:
+ print 'RIPEMD module not available'
+ else:
+ print 'RIPEMD:'
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for text, hash in Crypto.Util.testdata.ripemd:
+ compareHashResult(RIPEMD, text, hash)
+ # Compute value for 1 megabyte of a's...
+ obj, astring=RIPEMD.new(), 1000*'a'
+ for i in range(0,1000): obj.update(astring)
+ result=obj.digest()
+ if result!=hex2str("52783243c1697bdbe16d37f97f68f08325dc1528"):
+ die('RIPEMD produces incorrect result on 1E6*"a"')
+
+ if verbose: print ' Completed'
+ import time
+ obj=RIPEMD.new()
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj
+
+ if 'md2' in args:
+ # Test/benchmark MD2 hash algorithm ; the test data is taken from
+ # RFC1319, "The MD2 Message-Digest Algorithm"
+ try:
+ from Crypto.Hash import MD2
+ except ImportError:
+ print 'MD2 module not available'
+ else:
+ print 'MD2:'
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for text, hash in Crypto.Util.testdata.md2:
+ compareHashResult(MD2, text, hash)
+ if verbose: print ' Completed'
+ import time
+ obj=MD2.new()
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj
+
+ if 'md4' in args:
+ # Test/benchmark MD4 hash algorithm ; the test data is taken from
+ # RFC1186B, "The MD4 Message-Digest Algorithm"
+ try:
+ from Crypto.Hash import MD4
+ except ImportError:
+ print 'MD4 module not available'
+ else:
+ print 'MD4:'
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for text, hash in Crypto.Util.testdata.md4:
+ compareHashResult(MD4, text, hash)
+ if verbose: print ' Completed'
+ import time
+ obj=MD4.new()
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj
+
+ if 'md5' in args:
+ # Test/benchmark MD5 hash algorithm ; the test data is taken from
+ # RFC1321, "The MD5 Message-Digest Algorithm"
+ try:
+ from Crypto.Hash import MD5
+ except ImportError:
+ print 'MD5 module not available'
+ else:
+ print 'MD5:'
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for text, hash in Crypto.Util.testdata.md5:
+ compareHashResult(MD5, text, hash)
+ if verbose: print ' Completed'
+ import time
+ obj=MD5.new()
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj
+
+ if 'haval' in args:
+ # Test/benchmark HAVAL
+ try:
+ from Crypto.Hash import HAVAL
+ except ImportError:
+ print 'HAVAL module not available'
+ else:
+ print 'HAVAL:'
+ try:
+ import Crypto.Util.testdata
+ if verbose: print ' Verifying against test suite...'
+ for (passes, length, text, hash) in Crypto.Util.testdata.haval:
+ ID=str(passes)+'-pass, '+str(length)+'-bit HAVAL '
+ obj=HAVAL.new('', rounds=passes, digestsize=length)
+ obj.update(text)
+ s1=obj.digest()
+ if (s1!=hex2str(hash)):
+ die(ID+'produces incorrect result on string "'+text+'"')
+ s2=obj.digest()
+ if s2!=s1: die(ID+'produces incorrect result on second hashing')
+ s3=obj.copy().digest()
+ if s3!=s1: die(ID+'produces incorrect result after copying')
+ if verbose: print ' Completed'
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ obj=HAVAL.new()
+ import time
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj
+
+ if 'sha' in args:
+ # Test/benchmark SHA hash algorithm
+ try:
+ from Crypto.Hash import SHA
+ except ImportError:
+ print 'SHA module not available'
+ else:
+ print 'SHA:'
+ if verbose: print ' Verifying against test suite...'
+ for text, hash in Crypto.Util.testdata.sha:
+ compareHashResult(SHA, text, hash)
+ # Compute value for 1 megabyte of a's...
+ obj, astring=SHA.new(), 1000*'a'
+ for i in range(0,1000): obj.update(astring)
+ result=obj.digest()
+ if result!=hex2str('34AA973CD4C4DAA4F61EEB2BDBAD27316534016F'):
+ die('SHA produces incorrect result on 1E6*"a"')
+ if verbose: print ' Completed'
+ obj=SHA.new()
+ start=time.time()
+ s=obj.update(teststr)
+ end=time.time()
+ if verbose: print ' Benchmark for 128K: ', 128/(end-start), 'K/sec'
+ del obj, astring
+
+def TestStreamModules(args=['arc4', 'sapphire', 'XOR'], verbose=1):
+ import sys, string
+ args=map(string.lower, args)
+
+ if 'arc4' in args:
+ # Test ARC4 stream cipher
+ arc4=exerciseStreamCipher('ARC4', verbose)
+ if (arc4!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ for entry in Crypto.Util.testdata.arc4:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=arc4.new(key)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('ARC4 failed on entry '+`entry`)
+ if verbose: print ' ARC4 test suite completed'
+
+ if 'sapphire' in args:
+ # Test Sapphire stream cipher
+ sapphire=exerciseStreamCipher('Sapphire', verbose)
+ if (sapphire!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ result=hex2str(Crypto.Util.testdata.sapphire)
+ obj=sapphire.new('testSapphirekey')
+ s=''
+ for i in range(0,256):
+ s=s+chr(i)
+ s=obj.encrypt(s)
+ if (s!=result):
+ die('Sapphire fails verification test')
+ if verbose: print ' Sapphire test suite completed'
+
+ print args
+ if 'xor' in args:
+ # Test XOR stream cipher
+ XOR=exerciseStreamCipher('XOR', verbose)
+ if (XOR!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ for entry in Crypto.Util.testdata.XOR:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=XOR.new(key)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('XOR failed on entry '+`entry`)
+ if verbose: print ' XOR test suite completed'
+
+
+def TestBlockModules(args=['arc2', 'blowfish', 'cast', 'des', 'des3',
+ 'diamond', 'idea', 'rc5', 'skipjack'],
+ verbose=1):
+ import string
+ args=map(string.lower, args)
+
+ if 'arc2' in args:
+ ciph=exerciseBlockCipher('ARC2', verbose) # Alleged RC2
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.arc2:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('ARC2 failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ print
+ if verbose: print ' Completed'
+
+ if 'blowfish' in args:
+ ciph=exerciseBlockCipher('Blowfish',verbose)# Bruce Schneier's Blowfish cipher
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.blowfish:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('Blowfish failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ if verbose: print
+ if verbose: print ' Completed'
+
+ if 'cast' in args:
+ ciph=exerciseBlockCipher('CAST', verbose) # CAST-128
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.cast:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('CAST failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ if verbose: print
+
+ if 0:
+ # The full-maintenance test; it requires 4 million encryptions,
+ # and correspondingly is quite time-consuming. I've disabled
+ # it; it's faster to compile block/cast.c with -DTEST and run
+ # the resulting program.
+ a = b = '\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45\x67\x89\x34\x56\x78\x9A'
+
+ for i in range(0, 1000000):
+ obj = cast.new(b, cast.ECB)
+ a = obj.encrypt(a[:8]) + obj.encrypt(a[-8:])
+ obj = cast.new(a, cast.ECB)
+ b = obj.encrypt(b[:8]) + obj.encrypt(b[-8:])
+
+ if a!="\xEE\xA9\xD0\xA2\x49\xFD\x3B\xA6\xB3\x43\x6F\xB8\x9D\x6D\xCA\x92":
+ if verbose: print 'CAST test failed: value of "a" doesn\'t match'
+ if b!="\xB2\xC9\x5E\xB0\x0C\x31\xAD\x71\x80\xAC\x05\xB8\xE8\x3D\x69\x6E":
+ if verbose: print 'CAST test failed: value of "b" doesn\'t match'
+ if verbose: print ' Completed'
+
+ if 'des' in args:
+ # Test/benchmark DES block cipher
+ des=exerciseBlockCipher('DES', verbose)
+ if (des!=None):
+ # Various tests taken from the DES library packaged with Kerberos V4
+ obj=des.new(hex2str('0123456789abcdef'), des.ECB)
+ s=obj.encrypt('Now is t')
+ if (s!=hex2str('3fa40e8a984d4815')):
+ die('DES fails test 1')
+ obj=des.new(hex2str('08192a3b4c5d6e7f'), des.ECB)
+ s=obj.encrypt('\000\000\000\000\000\000\000\000')
+ if (s!=hex2str('25ddac3e96176467')):
+ die('DES fails test 2')
+ obj=des.new(hex2str('0123456789abcdef'), des.CBC,
+ hex2str('1234567890abcdef'))
+ s=obj.encrypt("Now is the time for all ")
+ if (s!=hex2str('e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6')):
+ die('DES fails test 3')
+ obj=des.new(hex2str('0123456789abcdef'), des.CBC,
+ hex2str('fedcba9876543210'))
+ s=obj.encrypt("7654321 Now is the time for \000\000\000\000")
+ if (s!=hex2str("ccd173ffab2039f4acd8aefddfd8a1eb468e91157888ba681d269397f7fe62b4")):
+ die('DES fails test 4')
+ del obj,s
+
+ # R. Rivest's test: see http://theory.lcs.mit.edu/~rivest/destest.txt
+ x=hex2str('9474B8E8C73BCA7D')
+ for i in range(0, 16):
+ obj=des.new(x, des.ECB)
+ if (i & 1): x=obj.decrypt(x)
+ else: x=obj.encrypt(x)
+ if x!=hex2str('1B1A2DDB4C642438'):
+ die("DES fails Rivest's test")
+
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.des:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=des.new(key, des.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('DES failed on entry '+`entry`)
+ for entry in Crypto.Util.testdata.des_cbc:
+ key, iv, plain, cipher=entry
+ key, iv, cipher=hex2str(key),hex2str(iv),hex2str(cipher)
+ obj1=des.new(key, des.CBC, iv)
+ obj2=des.new(key, des.CBC, iv)
+ ciphertext=obj1.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('DES CBC mode failed on entry '+`entry`)
+ if verbose: print ' Completed'
+
+ if 'des3' in args:
+ ciph=exerciseBlockCipher('DES3', verbose) # Triple DES
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.des3:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('DES3 failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ if verbose: print
+ for entry in Crypto.Util.testdata.des3_cbc:
+ key, iv, plain, cipher=entry
+ key, iv, cipher=hex2str(key),hex2str(iv),hex2str(cipher)
+ obj1=ciph.new(key, ciph.CBC, iv)
+ obj2=ciph.new(key, ciph.CBC, iv)
+ ciphertext=obj1.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('DES3 CBC mode failed on entry '+`entry`)
+ if verbose: print ' Completed'
+
+ if 'diamond' in args:
+ ciph=exerciseBlockCipher('Diamond', verbose) # M.P. Johnson's Diamond
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.diamond:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key[1:], ciph.ECB, rounds = ord(key[0]) )
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('Diamond failed on entry '+`entry`)
+ if verbose: print ' Completed'
+
+
+ if 'idea' in args:
+ ciph=exerciseBlockCipher('IDEA', verbose) # IDEA block cipher
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.idea:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('IDEA failed on entry '+`entry`)
+ if verbose: print ' Completed'
+
+ if 'rc5' in args:
+ # Ronald Rivest's RC5 algorithm
+ ciph=exerciseBlockCipher('RC5', verbose)
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.rc5:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key[4:], ciph.ECB,
+ version =ord(key[0]),
+ wordsize=ord(key[1]),
+ rounds =ord(key[2]) )
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('RC5 failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ if verbose: print
+ if verbose: print ' Completed'
+
+ if 'skipjack' in args:
+ ciph=exerciseBlockCipher('Skipjack', verbose) # Skipjack
+ if (ciph!=None):
+ try:
+ import Crypto.Util.testdata
+ except ImportError:
+ if verbose: print ' Test suite data not available'
+ else:
+ if verbose: print ' Verifying against test suite...'
+ for entry in Crypto.Util.testdata.skipjack:
+ key,plain,cipher=entry
+ key=hex2str(key)
+ plain=hex2str(plain)
+ cipher=hex2str(cipher)
+ obj=ciph.new(key, ciph.ECB)
+ ciphertext=obj.encrypt(plain)
+ if (ciphertext!=cipher):
+ die('Skipjack failed on entry '+`entry`)
+ for i in ciphertext:
+ if verbose: print hex(ord(i)),
+ print
+ if verbose: print ' Completed'
+
+
+def TestPKModules(args=['rsa', 'dsa', 'elgamal', 'qnew'], verbose=1):
+ # Set up a random pool; we won't bother to actually fill it with
+ # entropy from the keyboard
+ if verbose: print ' Initializing random pool'
+ from Crypto.Util.randpool import RandomPool
+ r=RandomPool(384)
+ r.stir()
+ randfunc=r.getBytes
+
+ if 'rsa' in args:
+ print 'RSA:'
+ from Crypto.PublicKey import RSA
+ exercisePublicKey(randfunc, RSA, verbose)
+ r.stir()
+
+ if 'dsa' in args:
+ print 'DSA:'
+ from Crypto.PublicKey import DSA
+ exercisePublicKey(randfunc, DSA, verbose)
+ r.stir()
+
+ if 'elgamal' in args:
+ print 'ElGamal'
+ from Crypto.PublicKey import ElGamal
+ exercisePublicKey(randfunc, ElGamal, verbose)
+ r.stir()
+
+ if 'qnew' in args:
+ print 'qNEW'
+ from Crypto.PublicKey import qNEW
+ exercisePublicKey(randfunc, qNEW, verbose)
+ r.stir()
+
+
diff --git a/Util/testdata.py b/Util/testdata.py
new file mode 100644
index 0000000..1ff7600
--- /dev/null
+++ b/Util/testdata.py
@@ -0,0 +1,860 @@
+#
+# testdata.py : Test data for the various algorithms
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence. This software is provided "as is" without
+# warranty of fitness for use or suitability for any purpose, express
+# or implied. Use at your own risk or not at all.
+#
+
+# Data for encryption algorithms is saved as (key, plaintext,
+# ciphertext) tuples. Hashing algorithm test data is simply
+# (text, hashvalue) pairs.
+
+# MD2 validation data
+
+md2= [
+ ("", 0x8350e5a3e24c153df2275c9f80692773L),
+ ("a", 0x32ec01ec4a6dac72c0ab96fb34c0b5d1L),
+ ("abc", 0xda853b0d3f88d99b30283a69e6ded6bbL),
+ ("message digest", 0xab4f496bfb2a530b219ff33031fe06b0L),
+ ("abcdefghijklmnopqrstuvwxyz", 0x4e8ddff3650292ab5a4108c3aa47940bL),
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ 0xda33def2a42df13975352846c30338cdL),
+ ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ 0xd5976f79d83d3a0dc9806c3c66f3efd8L)
+ ]
+
+# MD4 validation data
+
+md4= [
+ ('', 0x31d6cfe0d16ae931b73c59d7e0c089c0L),
+ ("a", 0xbde52cb31de33e46245e05fbdbd6fb24L),
+ ("abc", 0xa448017aaf21d8525fc10ae87aa6729dL),
+ ("message digest", 0xd9130a8164549fe818874806e1c7014bL),
+ ("abcdefghijklmnopqrstuvwxyz", 0xd79e1c308aa5bbcdeea8ed63df412da9L),
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ 0x043f8582f241db351ce627e153e7f0e4L),
+ ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ 0xe33b4ddc9c38f2199c3e7b164fcc0536L),
+ ]
+
+# MD5 validation data
+
+md5= [
+ ('', 0xd41d8cd98f00b204e9800998ecf8427eL),
+ ('a', 0x0cc175b9c0f1b6a831c399e269772661L),
+ ('abc', 0x900150983cd24fb0d6963f7d28e17f72L),
+ ('message digest', 0xf96b697d7cb7938d525a2f31aaf161d0L),
+ ('abcdefghijklmnopqrstuvwxyz', 0xc3fcd3d76192e4007dfb496cca67e13bL),
+ ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
+ 0xd174ab98d277d9f5a5611c2c9f419d9fL),
+ ('12345678901234567890123456789012345678901234567890123456789'
+ '012345678901234567890', 0x57edf4a22be3c955ac49da2e2107b67aL)
+ ]
+
+# Test data for SHA, the Secure Hash Algorithm.
+
+sha = [
+ ('abc', 0xA9993E364706816ABA3E25717850C26C9CD0D89DL),
+ ('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq',
+ 0x84983E441C3BD26EBAAE4AA1F95129E5E54670F1L)
+ ]
+
+# Test data for HAVAL (passes, length, text, value)
+haval = [(3, 128, '', '1BDC556B29AD02EC09AF8C66477F2A87'),
+ (3, 128, 'a', '24D2BC955A219E3E06462C91B555CFA1'),
+ (3, 128, 'HAVAL', '16C743E5EEFD3266ED50DEAC6C30313E'),
+ (3, 128, '0123456789', '82D163440F6E853229A97007EC4AF0E5'),
+ (3, 128, 'abcdefghijklmnopqrstuvwxyz', '92E8EC9AD7FD209D97E9CE21B50440E9'),
+ (3, 128, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '4AE2F37CEF9275CCE0D73F6A1EB9CDD8'),
+ (3, 160, '', 'FE79D0A044FFB75D5354668D664E4F4B9CC33477'),
+ (3, 160, 'a', '5E1610FCED1D3ADB0BB18E92AC2B11F0BD99D8ED'),
+ (3, 160, 'HAVAL', '8E568AD6CCD58D17E0A11E92183232E0D1D2E9BF'),
+ (3, 160, '0123456789', '700D43A9B5E38300303FD4E25A6A326BEB4A2241'),
+ (3, 160, 'abcdefghijklmnopqrstuvwxyz', '1DD40AEAB9610585FCAE7492FF3B893C2A018F4E'),
+ (3, 160, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '485ABB76ED2F5AC8BB86DDEB8CB4C54CF5BB077B'),
+ (3, 192, '', '5E05A29CA2DB5DABE05A36BEED1D9F23A62E24714E74E2FF'),
+ (3, 192, 'a', '53FD81208C51EBC807ED5A6596A2897BD8211975F10CC46E'),
+ (3, 192, 'HAVAL', '365F46AF04836A174C7F17E0A364E77FB613DC54990649D5'),
+ (3, 192, '0123456789', '241210926D574FAFB89CA187D51BDD78209DB46410660DF2'),
+ (3, 192, 'abcdefghijklmnopqrstuvwxyz', '91FF2A2BE448D2C4301E27AC664FC6BDE5B98BF275967DDC'),
+ (3, 192, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'F9658C8807D791F3A7F364E17B8771E85BE7BD539A1957A6'),
+ (3, 224, '', 'F3D390AF42356F1D32CBD3B6F26B16FAB3771AAE92E7B48D32DED172'),
+ (3, 224, 'a', 'C0ADA85221F054D8266370225C36765A4E337615C987703391D0A06F'),
+ (3, 224, 'HAVAL', 'A728355187983BBF110DC6EA263995F57D56B08A063FB2750D58648A'),
+ (3, 224, '0123456789', 'FD47F2202811C889A45C19E334249F52A23670843B6B4682636E5B14'),
+ (3, 224, 'abcdefghijklmnopqrstuvwxyz', '558832025C6B71DF1CA043905CE6199A031B4ED2DCAA820B2E27F122'),
+ (3, 224, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '5311AADA23AF4F8993448B53C2994186F181E9D80D821A6A7F58386A'),
+ (3, 256, '', '839786AC4F89EE6AE87F2065AC681097D7276A9903B7E972E992566D0DE38E0C'),
+ (3, 256, 'a', '5BCB16472639B8E63CA1E2B347D9038F7A808D8B317CBE4F202DFB9C0529B0FD'),
+ (3, 256, 'HAVAL', '7208A60270D70EE998F942B03D5D3ACF5B3AA4A841F21360896948D0B78CACD2'),
+ (3, 256, '0123456789', 'CC2CE6F921AA5423E1EEAB178AE0FFD293972C2530DCE9C7FE8A7EA77C8ACEAC'),
+ (3, 256, 'abcdefghijklmnopqrstuvwxyz', 'DB9CEDB76576C2BFF4345F3D17C241CB1B4D29B0DBBE8F263E463BFFD260AC89'),
+ (3, 256, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '8FB83BFDA5F8324DFBA078B3DB48A95B7C7C4023F8FB70045EF875425AF83868'),
+ (4, 128, '', 'A0E12BA547C3F7724B97BEB2B2466825'),
+ (4, 128, 'a', '9D576BED5A29B47100157FDBF7AF4B34'),
+ (4, 128, 'HAVAL', '3BF0CE4A6C375AD2C5FC954242B68219'),
+ (4, 128, '0123456789', '361F885D16277A4686558A0B694EE215'),
+ (4, 128, 'abcdefghijklmnopqrstuvwxyz', '198504C9CD40D1938396CE81F5F64BD0'),
+ (4, 128, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '50F905D51FB69C2B8CA5D15F13C099CB'),
+ (4, 160, '', 'D4093169135AA22DAD562993D362F79BA23B5F10'),
+ (4, 160, 'a', 'F00666EFE778E269F149371FA9FABFC98C07B7BE'),
+ (4, 160, 'HAVAL', 'EB6E692476720867737523ECE547FF027839B84F'),
+ (4, 160, '0123456789', '0FB6575C829528FE5345E528E084AC814C1A88DA'),
+ (4, 160, 'abcdefghijklmnopqrstuvwxyz', '1BB37E16413FAE67FD39973C943A719C44F2855A'),
+ (4, 160, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '1AC51AE99A8915BA8A651370C2B96037BC53496F'),
+ (4, 192, '', '51FA9E28C96865207ED6DAE2EAA1D8AF6E7DE2783EBEC4B4'),
+ (4, 192, 'a', 'A1446E6CEDB4B28BC6E13D4D1D2694E9CE4A3D942C73589E'),
+ (4, 192, 'HAVAL', '74AA31182FF09BCCE453A7F71B5A7C5E80872FA90CD93AE4'),
+ (4, 192, '0123456789', 'CA05546FFA4B69DAFA7C04424CC10802A2523EFCB8BEBB61'),
+ (4, 192, 'abcdefghijklmnopqrstuvwxyz', '5A238735D9E902E16CAD81229CC981A763508C73F4A52DD0'),
+ (4, 192, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'D51D73EB03B0D841C24F2007AA9159F0F70A971CBFBED33C'),
+ (4, 224, '', 'AACD8950B239B05E8A40A0419AFD3BBED206623913D8A6DFE71D174B'),
+ (4, 224, 'a', '54A26096C951725228D34A1B55C2DB5C28446E6B243FE2AE78623A4B'),
+ (4, 224, 'HAVAL', 'F9040EEBAE11709245501BEFFB5FB849F88A9086F24DF3A55A03A01A'),
+ (4, 224, '0123456789',
+ '144CB2DE11F05DF7C356282A3B485796DA653F6B702868C7DCF4AE76'),
+ (4, 224, 'abcdefghijklmnopqrstuvwxyz', 'FBB63F06592FB9AA4F59652B99BC53C1FF72675726C71326C682DABC'),
+ (4, 224, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '1120B26105044DF0B4E5B904705F3B8CBBC14A52B73301C300BAFF8A'),
+ (4, 256, '', '75128F15B3DAADD15D3C1D85F88A8B7E39948BABA7B2F4EA3D7B8E9A75A710E7'),
+ (4, 256, 'a', 'D710C33A848E8138CCE2C3D8B4DE2252A55C75FD60B6B4E2D6C39EBBAB215EBF'),
+ (4, 256, 'HAVAL', '0D25D9903F37C840250179821DB66353CC490DF2B90A45A5E20060D5F2D67593'),
+ (4, 256, '0123456789', 'AEEF777C84664C3D07A939815E45DEF9C1750A6505DD24BF7FCEB88282A33DD2'),
+ (4, 256, 'abcdefghijklmnopqrstuvwxyz', 'CB8C4E5C74AD38DB97031A51C0125CDF466E396C16674479DDF57D5A7E5DB55B'),
+ (4, 256, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '5A1910C4F800FF94B2D56403EF6371452EB50275896EFD57B4E2E716E955D6D1'),
+ (5, 128, '', '03FD808CAC90089E43B62B1C522953F8'),
+ (5, 128, 'a', '50FA56EAF75E634D63F2CDB6409125BA'),
+ (5, 128, 'HAVAL', 'C91CDFB768369566270A5E7F4B20E3B9'),
+ (5, 128, '0123456789', '29C0AAB1F6D03E11DFC1CF2B9E4DE91A'),
+ (5, 128, 'abcdefghijklmnopqrstuvwxyz', '6994C3F53914D42E736EA81427A408EC'),
+ (5, 128, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '54E55ECCAC0BF7C7BBA47A49B3D27422'),
+ (5, 160, '', 'A8213CACD787CEBF23F416049540AAFB637D34F2'),
+ (5, 160, 'a', 'B960F55EADD6091ADEC094827455584131F3C62C'),
+ (5, 160, 'HAVAL', 'F9E24DD43FD5D3EA5B45D046529C7DDB93937F8B'),
+ (5, 160, '0123456789', 'A7C539EA79EAAF856089FA6DED81F60374E95A96'),
+ (5, 160, 'abcdefghijklmnopqrstuvwxyz', '40B8769D3C555E43DCF235C4F1E5E130EEE2CAC7'),
+ (5, 160, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'F4E246BC33D04DA73B0D0EDDF94CFA5824CF2063'),
+ (5, 192, '', 'A352EF5FC2004ECE93BACC1C7429B8DD66ED270FD7EE5B0D'),
+ (5, 192, 'a', 'FAF3158553F717992FFB29595FBC23E93AF632A5A2782C57'),
+ (5, 192, 'HAVAL', 'BED2A1EBD9CB2F89F65FE33254E460E5019275191589A739'),
+ (5, 192, '0123456789', '56048B23FAEEFBC90174B8238F1D8BB92FAEDAA6D73C8A93'),
+ (5, 192, 'abcdefghijklmnopqrstuvwxyz', 'D8D531F3872B42A23899A2057A503F15D8DCB19DB2361AE1'),
+ (5, 192, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', '20F3BA5DF1971041D4D2EC4724DCBC090A9BBB07151B9FE0'),
+ (5, 224, '', 'E84C8F723F431282E88B9D3F0AD44504769402D07E46F8F8B326438D'),
+ (5, 224, 'a', '23AD516F08E024A1C0976A25DDB161797E8EE2E4B657D725704216D6'),
+ (5, 224, 'HAVAL', 'A23B187B07B8F7A1B2DE0AE5408EF3CBA8830565355FF59D53CAB0E1'),
+ (5, 224, '0123456789', '9A050B4386E51F72E0F0088AF1917E737E66036F8561CFC25CDDB8DB'),
+ (5, 224, 'abcdefghijklmnopqrstuvwxyz', 'B917D5FB2637AEEF80EFC747CCD44E31B08726AA5890C20FD7757045'),
+ (5, 224, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'B70ADBC1504075689EBB71BF9B7D7A849805B77D37C5E1C209AA4E71'),
+ (5, 256, '', '5981D3F8CCE7F5674752595F4AD24C184BA1C738C986D4D2EDDF2BD86C3F8679'),
+ (5, 256, 'a', '166F2218E0994A78EBAD3FEAB0211B612B14E93E5CCEB60E6F143DF0FA166D39'),
+ (5, 256, 'HAVAL', '217BFDF84F5C775596C2F13CEEA7417CD4E198D53CA24902F9717585EC5789AC'),
+ (5, 256, '0123456789', 'A6828EEB82D5A9CBFC7C522AD4B3C38A42753DECEB20FB3A6FABC0DA8CCD6A1A'),
+ (5, 256, "abcdefghijklmnopqrstuvwxyz",
+ '1A1DC8099BDAA7F35B4DA4E805F1A28FEE909D8DEE920198185CBCAED8A10A8D'),
+ (5, 256,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ 'C5647FC6C1877FFF96742F27E9266B6874894F41A08F5913033D9D532AEDDB39')
+ ]
+
+ripemd = [ ("", 0x9c1185a5c5e9fc54612808977ee8f548b2258d31L),
+ ("a", 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffeL),
+ ("abc", 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfcL),
+ ("message digest", 0x5d0689ef49d2fae572b881b123a85ffa21595f36L),
+ ("abcdefghijklmnopqrstuvwxyz",
+ 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbcL),
+ ("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 0x12a053384a9c0c88e405a06c27dcf49ada62eb2bL),
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ 0xb0e20b6e3116640286ed3a87a5713079b21f5189L),
+ (8 *"1234567890", 0x9b752e45573d4b39f4dbd3323cab82bf63326bfbL)
+]
+
+
+# DES validation data
+
+# Key, IV, plaintext, ciphertext
+des_cbc= [('0123456789abcdef', 'fedcba9876543210',
+ "7654321 Now is the time for \000\000\000\000", 'ccd173ffab2039f4acd8aefddfd8a1eb468e91157888ba681d269397f7fe62b4')]
+
+des = [ ('0000000000000000', '0000000000000000', '8CA64DE9C1B123A7'),
+ ('FFFFFFFFFFFFFFFF', 'FFFFFFFFFFFFFFFF', '7359B2163E4EDC58'),
+ ('3000000000000000', '1000000000000001', '958E6E627A05557B'),
+ ('1111111111111111', '1111111111111111', 'F40379AB9E0EC533'),
+ ('0123456789ABCDEF', '1111111111111111', '17668DFC7292532D'),
+ ('1111111111111111', '0123456789ABCDEF', '8A5AE1F81AB8F2DD'),
+ ('0000000000000000', '0000000000000000', '8CA64DE9C1B123A7'),
+ ('FEDCBA9876543210', '0123456789ABCDEF', 'ED39D950FA74BCC4'),
+ ('7CA110454A1A6E57', '01A1D6D039776742', '690F5B0D9A26939B'),
+ ('0131D9619DC1376E', '5CD54CA83DEF57DA', '7A389D10354BD271'),
+ ('07A1133E4A0B2686', '0248D43806F67172', '868EBB51CAB4599A'),
+ ('3849674C2602319E', '51454B582DDF440A', '7178876E01F19B2A'),
+ ('04B915BA43FEB5B6', '42FD443059577FA2', 'AF37FB421F8C4095'),
+ ('0113B970FD34F2CE', '059B5E0851CF143A', '86A560F10EC6D85B'),
+ ('0170F175468FB5E6', '0756D8E0774761D2', '0CD3DA020021DC09'),
+ ('43297FAD38E373FE', '762514B829BF486A', 'EA676B2CB7DB2B7A'),
+ ('07A7137045DA2A16', '3BDD119049372802', 'DFD64A815CAF1A0F'),
+ ('04689104C2FD3B2F', '26955F6835AF609A', '5C513C9C4886C088'),
+ ('37D06BB516CB7546', '164D5E404F275232', '0A2AEEAE3FF4AB77'),
+ ('1F08260D1AC2465E', '6B056E18759F5CCA', 'EF1BF03E5DFA575A'),
+ ('584023641ABA6176', '004BD6EF09176062', '88BF0DB6D70DEE56'),
+ ('025816164629B007', '480D39006EE762F2', 'A1F9915541020B56'),
+ ('49793EBC79B3258F', '437540C8698F3CFA', '6FBF1CAFCFFD0556'),
+ ('4FB05E1515AB73A7', '072D43A077075292', '2F22E49BAB7CA1AC'),
+ ('49E95D6D4CA229BF', '02FE55778117F12A', '5A6B612CC26CCE4A'),
+ ('018310DC409B26D6', '1D9D5C5018F728C2', '5F4C038ED12B2E41'),
+ ('1C587F1C13924FEF', '305532286D6F295A', '63FAC0D034D9F793'),
+ ('0101010101010101', '0123456789ABCDEF', '617B3A0CE8F07100'),
+ ('1F1F1F1F0E0E0E0E', '0123456789ABCDEF', 'DB958605F8C8C606'),
+ ('E0FEE0FEF1FEF1FE', '0123456789ABCDEF', 'EDBFD1C66C29CCC7'),
+ ('0000000000000000', 'FFFFFFFFFFFFFFFF', '355550B2150E2451'),
+ ('FFFFFFFFFFFFFFFF', '0000000000000000', 'CAAAAF4DEAF1DBAE'),
+ ('0123456789ABCDEF', '0000000000000000', 'D5D44FF720683D0D'),
+ ('FEDCBA9876543210', 'FFFFFFFFFFFFFFFF', '2A2BB008DF97C2F2'),
+ ('0101010101010101', '95F8A5E5DD31D900', '8000000000000000'),
+ ('0101010101010101', 'DD7F121CA5015619', '4000000000000000'),
+ ('0101010101010101', '2E8653104F3834EA', '2000000000000000'),
+ ('0101010101010101', '4BD388FF6CD81D4F', '1000000000000000'),
+ ('0101010101010101', '20B9E767B2FB1456', '0800000000000000'),
+ ('0101010101010101', '55579380D77138EF', '0400000000000000'),
+ ('0101010101010101', '6CC5DEFAAF04512F', '0200000000000000'),
+ ('0101010101010101', '0D9F279BA5D87260', '0100000000000000'),
+ ('0101010101010101', 'D9031B0271BD5A0A', '0080000000000000'),
+ ('0101010101010101', '424250B37C3DD951', '0040000000000000'),
+ ('0101010101010101', 'B8061B7ECD9A21E5', '0020000000000000'),
+ ('0101010101010101', 'F15D0F286B65BD28', '0010000000000000'),
+ ('0101010101010101', 'ADD0CC8D6E5DEBA1', '0008000000000000'),
+ ('0101010101010101', 'E6D5F82752AD63D1', '0004000000000000'),
+ ('0101010101010101', 'ECBFE3BD3F591A5E', '0002000000000000'),
+ ('0101010101010101', 'F356834379D165CD', '0001000000000000'),
+ ('0101010101010101', '2B9F982F20037FA9', '0000800000000000'),
+ ('0101010101010101', '889DE068A16F0BE6', '0000400000000000'),
+ ('0101010101010101', 'E19E275D846A1298', '0000200000000000'),
+ ('0101010101010101', '329A8ED523D71AEC', '0000100000000000'),
+ ('0101010101010101', 'E7FCE22557D23C97', '0000080000000000'),
+ ('0101010101010101', '12A9F5817FF2D65D', '0000040000000000'),
+ ('0101010101010101', 'A484C3AD38DC9C19', '0000020000000000'),
+ ('0101010101010101', 'FBE00A8A1EF8AD72', '0000010000000000'),
+ ('0101010101010101', '750D079407521363', '0000008000000000'),
+ ('0101010101010101', '64FEED9C724C2FAF', '0000004000000000'),
+ ('0101010101010101', 'F02B263B328E2B60', '0000002000000000'),
+ ('0101010101010101', '9D64555A9A10B852', '0000001000000000'),
+ ('0101010101010101', 'D106FF0BED5255D7', '0000000800000000'),
+ ('0101010101010101', 'E1652C6B138C64A5', '0000000400000000'),
+ ('0101010101010101', 'E428581186EC8F46', '0000000200000000'),
+ ('0101010101010101', 'AEB5F5EDE22D1A36', '0000000100000000'),
+ ('0101010101010101', 'E943D7568AEC0C5C', '0000000080000000'),
+ ('0101010101010101', 'DF98C8276F54B04B', '0000000040000000'),
+ ('0101010101010101', 'B160E4680F6C696F', '0000000020000000'),
+ ('0101010101010101', 'FA0752B07D9C4AB8', '0000000010000000'),
+ ('0101010101010101', 'CA3A2B036DBC8502', '0000000008000000'),
+ ('0101010101010101', '5E0905517BB59BCF', '0000000004000000'),
+ ('0101010101010101', '814EEB3B91D90726', '0000000002000000'),
+ ('0101010101010101', '4D49DB1532919C9F', '0000000001000000'),
+ ('0101010101010101', '25EB5FC3F8CF0621', '0000000000800000'),
+ ('0101010101010101', 'AB6A20C0620D1C6F', '0000000000400000'),
+ ('0101010101010101', '79E90DBC98F92CCA', '0000000000200000'),
+ ('0101010101010101', '866ECEDD8072BB0E', '0000000000100000'),
+ ('0101010101010101', '8B54536F2F3E64A8', '0000000000080000'),
+ ('0101010101010101', 'EA51D3975595B86B', '0000000000040000'),
+ ('0101010101010101', 'CAFFC6AC4542DE31', '0000000000020000'),
+ ('0101010101010101', '8DD45A2DDF90796C', '0000000000010000'),
+ ('0101010101010101', '1029D55E880EC2D0', '0000000000008000'),
+ ('0101010101010101', '5D86CB23639DBEA9', '0000000000004000'),
+ ('0101010101010101', '1D1CA853AE7C0C5F', '0000000000002000'),
+ ('0101010101010101', 'CE332329248F3228', '0000000000001000'),
+ ('0101010101010101', '8405D1ABE24FB942', '0000000000000800'),
+ ('0101010101010101', 'E643D78090CA4207', '0000000000000400'),
+ ('0101010101010101', '48221B9937748A23', '0000000000000200'),
+ ('0101010101010101', 'DD7C0BBD61FAFD54', '0000000000000100'),
+ ('0101010101010101', '2FBC291A570DB5C4', '0000000000000080'),
+ ('0101010101010101', 'E07C30D7E4E26E12', '0000000000000040'),
+ ('0101010101010101', '0953E2258E8E90A1', '0000000000000020'),
+ ('0101010101010101', '5B711BC4CEEBF2EE', '0000000000000010'),
+ ('0101010101010101', 'CC083F1E6D9E85F6', '0000000000000008'),
+ ('0101010101010101', 'D2FD8867D50D2DFE', '0000000000000004'),
+ ('0101010101010101', '06E7EA22CE92708F', '0000000000000002'),
+ ('0101010101010101', '166B40B44ABA4BD6', '0000000000000001'),
+ ('8001010101010101', '0000000000000000', '95A8D72813DAA94D'),
+ ('4001010101010101', '0000000000000000', '0EEC1487DD8C26D5'),
+ ('2001010101010101', '0000000000000000', '7AD16FFB79C45926'),
+ ('1001010101010101', '0000000000000000', 'D3746294CA6A6CF3'),
+ ('0801010101010101', '0000000000000000', '809F5F873C1FD761'),
+ ('0401010101010101', '0000000000000000', 'C02FAFFEC989D1FC'),
+ ('0201010101010101', '0000000000000000', '4615AA1D33E72F10'),
+ ('0180010101010101', '0000000000000000', '2055123350C00858'),
+ ('0140010101010101', '0000000000000000', 'DF3B99D6577397C8'),
+ ('0120010101010101', '0000000000000000', '31FE17369B5288C9'),
+ ('0110010101010101', '0000000000000000', 'DFDD3CC64DAE1642'),
+ ('0108010101010101', '0000000000000000', '178C83CE2B399D94'),
+ ('0104010101010101', '0000000000000000', '50F636324A9B7F80'),
+ ('0102010101010101', '0000000000000000', 'A8468EE3BC18F06D'),
+ ('0101800101010101', '0000000000000000', 'A2DC9E92FD3CDE92'),
+ ('0101400101010101', '0000000000000000', 'CAC09F797D031287'),
+ ('0101200101010101', '0000000000000000', '90BA680B22AEB525'),
+ ('0101100101010101', '0000000000000000', 'CE7A24F350E280B6'),
+ ('0101080101010101', '0000000000000000', '882BFF0AA01A0B87'),
+ ('0101040101010101', '0000000000000000', '25610288924511C2'),
+ ('0101020101010101', '0000000000000000', 'C71516C29C75D170'),
+ ('0101018001010101', '0000000000000000', '5199C29A52C9F059'),
+ ('0101014001010101', '0000000000000000', 'C22F0A294A71F29F'),
+ ('0101012001010101', '0000000000000000', 'EE371483714C02EA'),
+ ('0101011001010101', '0000000000000000', 'A81FBD448F9E522F'),
+ ('0101010801010101', '0000000000000000', '4F644C92E192DFED'),
+ ('0101010401010101', '0000000000000000', '1AFA9A66A6DF92AE'),
+ ('0101010201010101', '0000000000000000', 'B3C1CC715CB879D8'),
+ ('0101010180010101', '0000000000000000', '19D032E64AB0BD8B'),
+ ('0101010140010101', '0000000000000000', '3CFAA7A7DC8720DC'),
+ ('0101010120010101', '0000000000000000', 'B7265F7F447AC6F3'),
+ ('0101010110010101', '0000000000000000', '9DB73B3C0D163F54'),
+ ('0101010108010101', '0000000000000000', '8181B65BABF4A975'),
+ ('0101010104010101', '0000000000000000', '93C9B64042EAA240'),
+ ('0101010102010101', '0000000000000000', '5570530829705592'),
+ ('0101010101800101', '0000000000000000', '8638809E878787A0'),
+ ('0101010101400101', '0000000000000000', '41B9A79AF79AC208'),
+ ('0101010101200101', '0000000000000000', '7A9BE42F2009A892'),
+ ('0101010101100101', '0000000000000000', '29038D56BA6D2745'),
+ ('0101010101080101', '0000000000000000', '5495C6ABF1E5DF51'),
+ ('0101010101040101', '0000000000000000', 'AE13DBD561488933'),
+ ('0101010101020101', '0000000000000000', '024D1FFA8904E389'),
+ ('0101010101018001', '0000000000000000', 'D1399712F99BF02E'),
+ ('0101010101014001', '0000000000000000', '14C1D7C1CFFEC79E'),
+ ('0101010101012001', '0000000000000000', '1DE5279DAE3BED6F'),
+ ('0101010101011001', '0000000000000000', 'E941A33F85501303'),
+ ('0101010101010801', '0000000000000000', 'DA99DBBC9A03F379'),
+ ('0101010101010401', '0000000000000000', 'B7FC92F91D8E92E9'),
+ ('0101010101010201', '0000000000000000', 'AE8E5CAA3CA04E85'),
+ ('0101010101010180', '0000000000000000', '9CC62DF43B6EED74'),
+ ('0101010101010140', '0000000000000000', 'D863DBB5C59A91A0'),
+ ('0101010101010120', '0000000000000000', 'A1AB2190545B91D7'),
+ ('0101010101010110', '0000000000000000', '0875041E64C570F7'),
+ ('0101010101010108', '0000000000000000', '5A594528BEBEF1CC'),
+ ('0101010101010104', '0000000000000000', 'FCDB3291DE21F0C0'),
+ ('0101010101010102', '0000000000000000', '869EFD7F9F265A09'),
+ ('1046913489980131', '0000000000000000', '88D55E54F54C97B4'),
+ ('1007103489988020', '0000000000000000', '0C0CC00C83EA48FD'),
+ ('10071034C8980120', '0000000000000000', '83BC8EF3A6570183'),
+ ('1046103489988020', '0000000000000000', 'DF725DCAD94EA2E9'),
+ ('1086911519190101', '0000000000000000', 'E652B53B550BE8B0'),
+ ('1086911519580101', '0000000000000000', 'AF527120C485CBB0'),
+ ('5107B01519580101', '0000000000000000', '0F04CE393DB926D5'),
+ ('1007B01519190101', '0000000000000000', 'C9F00FFC74079067'),
+ ('3107915498080101', '0000000000000000', '7CFD82A593252B4E'),
+ ('3107919498080101', '0000000000000000', 'CB49A2F9E91363E3'),
+ ('10079115B9080140', '0000000000000000', '00B588BE70D23F56'),
+ ('3107911598080140', '0000000000000000', '406A9A6AB43399AE'),
+ ('1007D01589980101', '0000000000000000', '6CB773611DCA9ADA'),
+ ('9107911589980101', '0000000000000000', '67FD21C17DBB5D70'),
+ ('9107D01589190101', '0000000000000000', '9592CB4110430787'),
+ ('1007D01598980120', '0000000000000000', 'A6B7FF68A318DDD3'),
+ ('1007940498190101', '0000000000000000', '4D102196C914CA16'),
+ ('0107910491190401', '0000000000000000', '2DFA9F4573594965'),
+ ('0107910491190101', '0000000000000000', 'B46604816C0E0774'),
+ ('0107940491190401', '0000000000000000', '6E7E6221A4F34E87'),
+ ('19079210981A0101', '0000000000000000', 'AA85E74643233199'),
+ ('1007911998190801', '0000000000000000', '2E5A19DB4D1962D6'),
+ ('10079119981A0801', '0000000000000000', '23A866A809D30894'),
+ ('1007921098190101', '0000000000000000', 'D812D961F017D320'),
+ ('100791159819010B', '0000000000000000', '055605816E58608F'),
+ ('1004801598190101', '0000000000000000', 'ABD88E8B1B7716F1'),
+ ('1004801598190102', '0000000000000000', '537AC95BE69DA1E1'),
+ ('1004801598190108', '0000000000000000', 'AED0F6AE3C25CDD8'),
+ ('1002911598100104', '0000000000000000', 'B3E35A5EE53E7B8D'),
+ ('1002911598190104', '0000000000000000', '61C79C71921A2EF8'),
+ ('1002911598100201', '0000000000000000', 'E2F5728F0995013C'),
+ ('1002911698100101', '0000000000000000', '1AEAC39A61F0A464'),
+ ('7CA110454A1A6E57', '01A1D6D039776742', '690F5B0D9A26939B'),
+ ('0131D9619DC1376E', '5CD54CA83DEF57DA', '7A389D10354BD271'),
+ ('07A1133E4A0B2686', '0248D43806F67172', '868EBB51CAB4599A'),
+ ('3849674C2602319E', '51454B582DDF440A', '7178876E01F19B2A'),
+ ('04B915BA43FEB5B6', '42FD443059577FA2', 'AF37FB421F8C4095'),
+ ('0113B970FD34F2CE', '059B5E0851CF143A', '86A560F10EC6D85B'),
+ ('0170F175468FB5E6', '0756D8E0774761D2', '0CD3DA020021DC09'),
+ ('43297FAD38E373FE', '762514B829BF486A', 'EA676B2CB7DB2B7A'),
+ ('07A7137045DA2A16', '3BDD119049372802', 'DFD64A815CAF1A0F'),
+ ('04689104C2FD3B2F', '26955F6835AF609A', '5C513C9C4886C088'),
+ ('37D06BB516CB7546', '164D5E404F275232', '0A2AEEAE3FF4AB77'),
+ ('1F08260D1AC2465E', '6B056E18759F5CCA', 'EF1BF03E5DFA575A'),
+ ('584023641ABA6176', '004BD6EF09176062', '88BF0DB6D70DEE56'),
+ ('025816164629B007', '480D39006EE762F2', 'A1F9915541020B56'),
+ ('49793EBC79B3258F', '437540C8698F3CFA', '6FBF1CAFCFFD0556'),
+ ('4FB05E1515AB73A7', '072D43A077075292', '2F22E49BAB7CA1AC'),
+ ('49E95D6D4CA229BF', '02FE55778117F12A', '5A6B612CC26CCE4A'),
+ ('018310DC409B26D6', '1D9D5C5018F728C2', '5F4C038ED12B2E41'),
+ ('1C587F1C13924FEF', '305532286D6F295A', '63FAC0D034D9F793') ]
+
+
+# LOKI91 Validation Data Suite
+loki91 = [
+# List of weak and semi-weak keys
+#
+# Weak Keys
+#
+('0000000000000000', '0000000000000000', 'bd84a2085ef609c7'),
+('0000000000000000', 'bd84a2085ef609c7', '0000000000000000'),
+('ffffffffffffffff', '0000000000000000', '5c77e002d1991c4d'),
+('ffffffffffffffff', '5c77e002d1991c4d', '0000000000000000'),
+('55555555aaaaaaaa', '0000000000000000', '71fd6dc44bf4e881'),
+('55555555aaaaaaaa', '71fd6dc44bf4e881', '0000000000000000'),
+('aaaaaaaa55555555', '0000000000000000', '65b38fdc551b2576'),
+('aaaaaaaa55555555', '65b38fdc551b2576', '0000000000000000'),
+#
+# Semi-Weak Keys
+#
+('0000000055555555', '0000000000000000', '85d84cad08342044'),
+('0000000055555555', '8621ccb894705f8f', '0000000000000000'),
+('aaaaaaaa00000000', '0000000000000000', '8621ccb894705f8f'),
+('aaaaaaaa00000000', '85d84cad08342044', '0000000000000000'),
+#
+('00000000aaaaaaaa', '0000000000000000', '971fe23b8904399b'),
+('00000000aaaaaaaa', 'e10c4efc9d4c9b52', '0000000000000000'),
+('5555555500000000', '0000000000000000', 'e10c4efc9d4c9b52'),
+('5555555500000000', '971fe23b8904399b', '0000000000000000'),
+#
+('00000000ffffffff', '0000000000000000', 'ca30a526e3bf6fe9'),
+('00000000ffffffff', '9cc24ace4d477f39', '0000000000000000'),
+('ffffffff00000000', '0000000000000000', '9cc24ace4d477f39'),
+('ffffffff00000000', 'ca30a526e3bf6fe9', '0000000000000000'),
+#
+('5555555555555555', '0000000000000000', 'bc85de5e486d7ddb'),
+('5555555555555555', '504d4c4fea439b63', '0000000000000000'),
+('aaaaaaaaaaaaaaaa', '0000000000000000', '504d4c4fea439b63'),
+('aaaaaaaaaaaaaaaa', 'bc85de5e486d7ddb', '0000000000000000'),
+#
+('55555555ffffffff', '0000000000000000', '0bef28021cd23fcb'),
+('55555555ffffffff', 'baa5521bd8ff9f75', '0000000000000000'),
+('ffffffffaaaaaaaa', '0000000000000000', 'baa5521bd8ff9f75'),
+('ffffffffaaaaaaaa', '0bef28021cd23fcb', '0000000000000000'),
+#
+('aaaaaaaaffffffff', '0000000000000000', 'a78c6f84509c4d9a'),
+('aaaaaaaaffffffff', '05dac4a04d83c0ab', '0000000000000000'),
+('ffffffff55555555', '0000000000000000', '05dac4a04d83c0ab'),
+('ffffffff55555555', 'a78c6f84509c4d9a', '0000000000000000'),
+#
+# Inversion of all the key and plaintext bits results
+# in the inversion of all the ciphertext bits
+#
+('0123456789abcdef', '0000000000000000', 'd26de3321aaa29f6'),
+('0123456789abcdef', 'fcf597b7da5a3a3d', '0000000000000000'),
+('fedcba9876543210', 'ffffffffffffffff', '2d921ccde555d609'),
+('fedcba9876543210', '030a684825a5c5c2', 'ffffffffffffffff'),
+#
+# Other assorted values
+#
+('0000000000000000', '0000000000000000', 'bd84a2085ef609c7'),
+('0000000000000000', 'bd84a2085ef609c7', '0000000000000000'),
+('0000000000000000', '355550b2150e2451', '3644dd20d5ba5d10'),
+('0000000000000000', '3644dd20d5ba5d10', '355550b2150e2451'),
+('0000000000000000', '35a7bae825c0d73b', '826ff28db7edf0a3'),
+('0000000000000000', '826ff28db7edf0a3', '35a7bae825c0d73b'),
+('0000000000000000', '8ca64de9c1b123a7', 'fb3038a35a93646b'),
+('0000000000000000', 'fb3038a35a93646b', '8ca64de9c1b123a7'),
+('0000000000000000', '8e2a251b94704c69', '4829a2faf34973e8'),
+('0000000000000000', '4829a2faf34973e8', '8e2a251b94704c69'),
+('0000000000000000', 'ffffffffffffffff', 'a3881ffd2e66e3b2'),
+('0000000000000000', 'a3881ffd2e66e3b2', 'ffffffffffffffff'),
+('0101010101010101', '0123456789abcdef', '7935b683eada00f4'),
+('0101010101010101', 'ec5960c9d3bf1e1e', '0123456789abcdef'),
+('0101010101010101', '617b3a0ce8f07100', 'a6090c5f651d84ff'),
+('0101010101010101', '8eeb7798a291b0b3', '617b3a0ce8f07100'),
+('0101010101010101', '9b38f6ce85aab9c3', '2165fc9b5a4430d4'),
+('0101010101010101', '2143badadbd4f539', '9b38f6ce85aab9c3'),
+('0113b970fd34f2ce', '059b5e0851cf143a', 'f1f6daa4368d32c0'),
+('0113b970fd34f2ce', '313b8c589bcf2955', '059b5e0851cf143a'),
+('0113b970fd34f2ce', '7514cdb961b6760d', 'a2f3f0e425f6cd30'),
+('0113b970fd34f2ce', '31b8050defd959ce', '7514cdb961b6760d'),
+('0113b970fd34f2ce', '86a560f10ec6d85b', 'a27506525cf66e5c'),
+('0113b970fd34f2ce', '6566f294daf82c26', '86a560f10ec6d85b'),
+('0123456789abcdef', '0000000000000000', 'd26de3321aaa29f6'),
+('0123456789abcdef', 'fcf597b7da5a3a3d', '0000000000000000'),
+('0123456789abcdef', '1111111111111111', 'e1dd3b59134f32ab'),
+('0123456789abcdef', 'c7c0ea4a6a9d3360', '1111111111111111'),
+('0123456789abcdef', '17668dfc7292532d', '7aab3b9a42feceb2'),
+('0123456789abcdef', '0a9462fa8fee7f4a', '17668dfc7292532d'),
+('0123456789abcdef', '23c086665917b8e1', '9fbc1a193dcee02d'),
+('0123456789abcdef', '1cb728f0c1b26f75', '23c086665917b8e1'),
+('0123456789abcdef', 'd5d44ff720683d0d', '621f20a1884677f3'),
+('0123456789abcdef', 'c8c9a1ace8cf89dc', 'd5d44ff720683d0d'),
+('0123456789abcdef', 'fce30226576320bd', '5da683da7e9fd159'),
+('0123456789abcdef', '5edf1c8466ce6cca', 'fce30226576320bd'),
+('0131d9619dc1376e', '5cd54ca83def57da', '018781deb9ea97cc'),
+('0131d9619dc1376e', 'bd1084a4b6d1ab38', '5cd54ca83def57da'),
+('0131d9619dc1376e', '65e160aed7b773a9', '57e3c651e72c6d99'),
+('0131d9619dc1376e', 'aeab88168e9c0e3e', '65e160aed7b773a9'),
+('0131d9619dc1376e', '7a389d10354bd271', '5520951007ac3123'),
+('0131d9619dc1376e', '78eaddbfcb1ca8f2', '7a389d10354bd271'),
+('0170f175468fb5e6', '0756d8e0774761d2', 'ab786040f925d13e'),
+('0170f175468fb5e6', 'b7c1284ca7043dcb', '0756d8e0774761d2'),
+('0170f175468fb5e6', '0cd3da020021dc09', '77ce52c63517b689'),
+('0170f175468fb5e6', '802191063dd8ff06', '0cd3da020021dc09'),
+('0170f175468fb5e6', '914c1806fccbce33', 'dd546f5263780633'),
+('0170f175468fb5e6', '5356fadab9832b2c', '914c1806fccbce33'),
+('018310dc409b26d6', '1d9d5c5018f728c2', '80d1106e854f7296'),
+('018310dc409b26d6', '0eb06d867b7034b3', '1d9d5c5018f728c2'),
+('018310dc409b26d6', '5a0bf934fd6009f8', 'f67c664125809846'),
+('018310dc409b26d6', '9c1edf390e47f09a', '5a0bf934fd6009f8'),
+('018310dc409b26d6', '5f4c038ed12b2e41', '20a61c3bc186b0b2'),
+('018310dc409b26d6', 'e93ae52452b20098', '5f4c038ed12b2e41'),
+('025816164629b007', '480d39006ee762f2', '8197cc96e066f971'),
+('025816164629b007', '8e67efe514fa5985', '480d39006ee762f2'),
+('025816164629b007', 'a1f9915541020b56', '0e1b15aa45daad23'),
+('025816164629b007', '7b1bd88c59347ee4', 'a1f9915541020b56'),
+('025816164629b007', 'ec92e65da168b46f', 'fd5d36553cc7cdad'),
+('025816164629b007', '10f09ce8ec84f207', 'ec92e65da168b46f'),
+('04689104c2fd3b2f', '26955f6835af609a', '082133fd6bfa1e88'),
+('04689104c2fd3b2f', '36153da8e8e4a67a', '26955f6835af609a'),
+('04689104c2fd3b2f', '5265227fe08a28ec', '1b03084901b20c14'),
+('04689104c2fd3b2f', 'f2e7e1a4678d10a7', '5265227fe08a28ec'),
+('04689104c2fd3b2f', '5c513c9c4886c088', 'db8e496a8aa4eae8'),
+('04689104c2fd3b2f', '49a2827db6293c72', '5c513c9c4886c088'),
+('04b915ba43feb5b6', '42fd443059577fa2', 'b794c8fec41d93fd'),
+('04b915ba43feb5b6', '688762c5782c8d46', '42fd443059577fa2'),
+('04b915ba43feb5b6', 'a483ea7ccf2e0e5a', '1319804d5e6477fb'),
+('04b915ba43feb5b6', 'a4407673e0289704', 'a483ea7ccf2e0e5a'),
+('04b915ba43feb5b6', 'af37fb421f8c4095', '5e1fbeca6d3dd240'),
+('04b915ba43feb5b6', '76f8a9d3d646b45a', 'af37fb421f8c4095'),
+('07a1133e4a0b2686', '0248d43806f67172', 'bdc50f07265f98bb'),
+('07a1133e4a0b2686', '5352ea74d4f98d17', '0248d43806f67172'),
+('07a1133e4a0b2686', '624f2e2dfa008142', '43966fba71697d9e'),
+('07a1133e4a0b2686', '94e8f64562868d44', '624f2e2dfa008142'),
+('07a1133e4a0b2686', '868ebb51cab4599a', '2bc4d7ac9f09e2cf'),
+('07a1133e4a0b2686', '38df7d98c5841cb1', '868ebb51cab4599a'),
+('07a7137045da2a16', '28e686668c3bd6d9', '5ddb3c7fc1c8ce22'),
+('07a7137045da2a16', 'a725d943d567693c', '28e686668c3bd6d9'),
+('07a7137045da2a16', '3bdd119049372802', '3f0db5539d36d6ff'),
+('07a7137045da2a16', 'e617587ef5ec4992', '3bdd119049372802'),
+('07a7137045da2a16', 'dfd64a815caf1a0f', 'a4af3b0773dad9be'),
+('07a7137045da2a16', '3000a06acca1e95c', 'dfd64a815caf1a0f'),
+('1111111111111111', '0123456789abcdef', '75f0c8bc2bafd309'),
+('1111111111111111', '46b19d48d8569e55', '0123456789abcdef'),
+('1111111111111111', '1111111111111111', 'cc8a79bccae0bb7e'),
+('1111111111111111', 'd96e387165e701bc', '1111111111111111'),
+('1111111111111111', '24900548c21a3567', '93f5dbd7f154b9ba'),
+('1111111111111111', '66b41b7d36c436de', '24900548c21a3567'),
+('1111111111111111', '8a5ae1f81ab8f2dd', '20f677bebabe1775'),
+('1111111111111111', 'd96faf34f9f90454', '8a5ae1f81ab8f2dd'),
+('1111111111111111', 'a273d7cb7d390531', '70ab8b1bc85a3535'),
+('1111111111111111', '44260ee8c8eeb426', 'a273d7cb7d390531'),
+('1111111111111111', 'f40379ab9e0ec533', '06f8080ae1393c2f'),
+('1111111111111111', '9ae34de86300215f', 'f40379ab9e0ec533'),
+('1c587f1c13924fef', '305532286d6f295a', '2fc181b0cb6b30b7'),
+('1c587f1c13924fef', 'e9eef1eb68e8c676', '305532286d6f295a'),
+('1c587f1c13924fef', '63fac0d034d9f793', 'e3f0d7afe60812b2'),
+('1c587f1c13924fef', '7409d13ab01f25f6', '63fac0d034d9f793'),
+('1c587f1c13924fef', 'f63de067f58c38ed', '3f4913280d2793fc'),
+('1c587f1c13924fef', '0109eccd8a9c40dd', 'f63de067f58c38ed'),
+('1f08260d1ac2465e', '2c0a241eb9f05999', 'e86f92ac2ec186f3'),
+('1f08260d1ac2465e', '2dbafaaf1eb7b072', '2c0a241eb9f05999'),
+('1f08260d1ac2465e', '6b056e18759f5cca', '02dd8970249255f1'),
+('1f08260d1ac2465e', '377f235592b45ca9', '6b056e18759f5cca'),
+('1f08260d1ac2465e', 'ef1bf03e5dfa575a', '98e1e5771c4a9455'),
+('1f08260d1ac2465e', 'f489970bb6e8a94e', 'ef1bf03e5dfa575a'),
+('1f1f1f1f0e0e0e0e', '0123456789abcdef', '1998d96b0bb0add6'),
+('1f1f1f1f0e0e0e0e', '7454d8d7c56be016', '0123456789abcdef'),
+('1f1f1f1f0e0e0e0e', '322f206b2d39d65d', '0b636eb981e987c0'),
+('1f1f1f1f0e0e0e0e', '0b926c6049361bff', '322f206b2d39d65d'),
+('1f1f1f1f0e0e0e0e', 'db958605f8c8c606', '5a153aea62bdd0cb'),
+('1f1f1f1f0e0e0e0e', '2c7bf241aa0b2c97', 'db958605f8c8c606'),
+('3000000000000000', '1000000000000001', '12f2d0471de69a16'),
+('3000000000000000', 'b0ef21ad8b82dd0a', '1000000000000001'),
+('3000000000000000', '958e6e627a05557b', '4be1b16ef2c9524a'),
+('3000000000000000', '437b3ac6a2a027c8', '958e6e627a05557b'),
+('3000000000000000', 'd3c4539579b96231', 'bbfcaf9cc8cd9e46'),
+('3000000000000000', '7b8b6b2e19e13c69', 'd3c4539579b96231'),
+('37d06bb516cb7546', '0a2aeeae3ff4ab77', '32a65f25341d17f0'),
+('37d06bb516cb7546', '90d6dcee0f2f8d62', '0a2aeeae3ff4ab77'),
+('37d06bb516cb7546', '164d5e404f275232', '782a69ec6256c642'),
+('37d06bb516cb7546', '1dabf24c62f0fd89', '164d5e404f275232'),
+('37d06bb516cb7546', '19acae3136c0bc7c', '9cd87a6a8ea4c562'),
+('37d06bb516cb7546', 'f8bf4d34438681a2', '19acae3136c0bc7c'),
+('3849674c2602319e', '126898d55e911500', 'c86caec1e3b7b17e'),
+('3849674c2602319e', 'd8d28161851ed6d6', '126898d55e911500'),
+('3849674c2602319e', '51454b582ddf440a', '8904c12a608bac74'),
+('3849674c2602319e', '562de7a88b1f4877', '51454b582ddf440a'),
+('3849674c2602319e', '7178876e01f19b2a', 'ba940cd1789e92fd'),
+('3849674c2602319e', '295ece9867b10e95', '7178876e01f19b2a'),
+('43297fad38e373fe', '4c974f1caa59f5d4', '71a64728851d6e14'),
+('43297fad38e373fe', 'f386803c5a434216', '4c974f1caa59f5d4'),
+('43297fad38e373fe', '762514b829bf486a', '6684fb847e1283c0'),
+('43297fad38e373fe', 'bf8e6fbf6c48ec44', '762514b829bf486a'),
+('43297fad38e373fe', 'ea676b2cb7db2b7a', '5a2d250d39eb8fc1'),
+('43297fad38e373fe', '6d42d3b3b5a9abcc', 'ea676b2cb7db2b7a'),
+('49793ebc79b3258f', '437540c8698f3cfa', '0b46e6cd65118775'),
+('49793ebc79b3258f', 'b9d425d544c1ce71', '437540c8698f3cfa'),
+('49793ebc79b3258f', '6fbf1cafcffd0556', '50bfa6e233cef0af'),
+('49793ebc79b3258f', '000c45276715001d', '6fbf1cafcffd0556'),
+('49793ebc79b3258f', 'a0cb2871752053f0', 'af27090a887c7e3e'),
+('49793ebc79b3258f', '51fc08afec3c8f1a', 'a0cb2871752053f0'),
+('49e95d6d4ca229bf', '00b0024eaac70ae3', '6f2421dc83df9ba2'),
+('49e95d6d4ca229bf', '82537ce99e3476de', '00b0024eaac70ae3'),
+('49e95d6d4ca229bf', '02fe55778117f12a', 'bd6bb416626be321'),
+('49e95d6d4ca229bf', '417b8cdd1c64b3e7', '02fe55778117f12a'),
+('49e95d6d4ca229bf', '5a6b612cc26cce4a', '73cb63595026b590'),
+('49e95d6d4ca229bf', 'a90f566d8f4e3e41', '5a6b612cc26cce4a'),
+('4fb05e1515ab73a7', '072d43a077075292', 'ac6174b535bcad69'),
+('4fb05e1515ab73a7', '2d139d3801a19346', '072d43a077075292'),
+('4fb05e1515ab73a7', '2f22e49bab7ca1ac', '86019dd993c46cbe'),
+('4fb05e1515ab73a7', '44fef33e6971a69b', '2f22e49bab7ca1ac'),
+('4fb05e1515ab73a7', 'ad87789bc00718c2', '733b12f600953a98'),
+('4fb05e1515ab73a7', '8341990d8ba44544', 'ad87789bc00718c2'),
+('584023641aba6176', '004bd6ef09176062', '6ceca0e2d5351cd1'),
+('584023641aba6176', '9c6aedffd92b1cca', '004bd6ef09176062'),
+('584023641aba6176', '88bf0db6d70dee56', 'b3a4719eca678ecc'),
+('584023641aba6176', 'bb39bb8bdf9db594', '88bf0db6d70dee56'),
+('584023641aba6176', 'c7d2845ea6d01c70', '2932e00da18db422'),
+('584023641aba6176', '2217a63228e547c1', 'c7d2845ea6d01c70'),
+('5b5a57676a56676e', '974affbf86022d1f', '6b6413098aaa7f2b'),
+('5b5a57676a56676e', 'daabfab98dea5e78', '974affbf86022d1f'),
+('7ca110454a1a6e57', '01a1d6d039776742', '0200c0b643578183'),
+('7ca110454a1a6e57', '1405433e91265b1b', '01a1d6d039776742'),
+('7ca110454a1a6e57', '690f5b0d9a26939b', 'd6173b3a2f754508'),
+('7ca110454a1a6e57', '9f7c523c7bfe7586', '690f5b0d9a26939b'),
+('7ca110454a1a6e57', 'ecd1c2f929f33ced', 'a5d38784ef7973ee'),
+('7ca110454a1a6e57', 'c6642999c37b99b3', 'ecd1c2f929f33ced'),
+('e0fee0fef1fef1fe', '0123456789abcdef', 'e09ca157c6dfe236'),
+('e0fee0fef1fef1fe', '20bc4d004e45c048', '0123456789abcdef'),
+('e0fee0fef1fef1fe', 'b7687facf9b1a656', 'eb2c523be4dedd8a'),
+('e0fee0fef1fef1fe', 'c21c42ef608f5ae6', 'b7687facf9b1a656'),
+('e0fee0fef1fef1fe', 'edbfd1c66c29ccc7', 'd7a84a5234f98995'),
+('e0fee0fef1fef1fe', 'cb3f0e23d4ad3760', 'edbfd1c66c29ccc7'),
+('fedcba9876543210', '0123456789abcdef', '480f0eac8d4c6cbc'),
+('fedcba9876543210', '25d00012f501adaf', '0123456789abcdef'),
+('fedcba9876543210', '2a2bb008df97c2f2', '9de0df5e77b9880c'),
+('fedcba9876543210', '37365e5317307623', '2a2bb008df97c2f2'),
+('fedcba9876543210', '7f46aa73f7fcde02', 'f6b3c639d4588687'),
+('fedcba9876543210', '286334c90fc54d99', '7f46aa73f7fcde02'),
+('fedcba9876543210', 'c44c1b3668a0f2cf', 'f1fbe0db72af2072'),
+('fedcba9876543210', '4da710ea766dddb4', 'c44c1b3668a0f2cf'),
+('fedcba9876543210', 'ed39d950fa74bcc4', '1529a5409e492728'),
+('fedcba9876543210', 'ba2fcbdf566d6b40', 'ed39d950fa74bcc4'),
+('fedcba9876543210', 'ffffffffffffffff', '2d921ccde555d609'),
+('fedcba9876543210', '030a684825a5c5c2', 'ffffffffffffffff'),
+('ffffffffffffffff', '0000000000000000', '5c77e002d1991c4d'),
+('ffffffffffffffff', '5c77e002d1991c4d', '0000000000000000'),
+('ffffffffffffffff', '16b15028f06a5ab8', 'c594d15528f44560'),
+('ffffffffffffffff', 'c594d15528f44560', '16b15028f06a5ab8'),
+('ffffffffffffffff', '3c7188775253884d', 'ac490aef39a87b61'),
+('ffffffffffffffff', 'ac490aef39a87b61', '3c7188775253884d'),
+('ffffffffffffffff', '7359b2163e4edc58', '04cfc75ca56c9b94'),
+('ffffffffffffffff', '04cfc75ca56c9b94', '7359b2163e4edc58'),
+('ffffffffffffffff', 'caaaaf4deaf1dbae', 'c9bb22df2a45a2ef'),
+('ffffffffffffffff', 'c9bb22df2a45a2ef', 'caaaaf4deaf1dbae'),
+('ffffffffffffffff', 'ffffffffffffffff', '427b5df7a109f638'),
+('ffffffffffffffff', '427b5df7a109f638', 'ffffffffffffffff') ]
+
+# Test data for Alleged RC4
+
+arc4 = [ ('0000000000000000', '0000000000000000', 'de188941a3375d3a'),
+ ('0123456789abcdef', '0123456789abcdef', '75b7878099e0c596'),
+ ('0123456789abcdef', '0000000000000000', '7494c2e7104b0879'),
+ ('ef012345', '00000000000000000000', 'd6a141a7ec3c38dfbd61') ]
+
+# Test data for Sapphire : Ciphertext of characters 0 through 255, with
+# key "testSapphirekey"
+
+sapphire = ('0cf45580c5b2490830e0f90d5cc5970316e63d52f8cef4b88bace'
+ '96257aa39c3c5a9156c9cf2f3ee7fb9d659dd27928b8bc7fff555'
+ '593b0b27fb65180c21e2b1f1a121ecd2654ff274d6c5b1ed35eef'
+ 'f89f64b7e7dd55cdd5ba1a7f1516453fc648aa7926e359eb1ad26'
+ '341cb53074960d033887a7473724b743ef4f706c88c4f6ee17652'
+ '6e0c869089dc71225337b6c773c308f5b174e668b27b2f7c75cb3'
+ '169a985c85e29c6dfa9def1b461cb9684105c55dfd6ed8701b19f'
+ '1d05fe8ee8dad4062749ae87c4cb5f943607257024585af956171'
+ '9758b578aecbd9cd863b2ff50218650fecca0ca9f6aed52be36ce'
+ '39c4fa610b485dc3981ada313c0f02ba562'
+ )
+
+# Test data for IDEA
+
+idea = [('00010002000300040005000600070008', '0000000100020003', '11fbed2b01986de5'),
+ ('00010002000300040005000600070008', '0102030405060708', '540E5FEA18C2F8B1'),
+ ('00010002000300040005000600070008', '0019324B647D96AF', '9F0A0AB6E10CED78'),
+ ('00010002000300040005000600070008', 'F5202D5B9C671B08', 'CF18FD7355E2C5C5'),
+ ('00010002000300040005000600070008', 'FAE6D2BEAA96826E', '85DF52005608193D'),
+ ('00010002000300040005000600070008', '0A141E28323C4650', '2F7DE750212FB734'),
+ ('00010002000300040005000600070008', '050A0F14191E2328', '7B7314925DE59C09'),
+ ('0005000A000F00140019001E00230028', '0102030405060708', '3EC04780BEFF6E20'),
+ ('3A984E2000195DB32EE501C8C47CEA60', '0102030405060708', '97BCD8200780DA86'),
+ ('006400C8012C019001F4025802BC0320', '05320A6414C819FA', '65BE87E7A2538AED'),
+ ('9D4075C103BC322AFB03E7BE6AB30006', '0808080808080808', 'F5DB1AC45E5EF9F9')
+ ];
+
+# Diamond validation data
+
+diamond= [
+('0FE834FDB933C502923D92BC9E14368E70D41C66CBDF36155033A66E07E6CC6D8D',
+ '5A8D872D31EEDDE63FC46F6C36456D8E', '7345025F0802112D5575FC86C12DE34D'),
+('0C07CFCB83B4BED44F6E253C5CFA36367A195E4D0D54843692856729A3542288',
+ '407D166413286727B6694F63F2E53517', 'DDC1BB703FFCF63936833A375745A481'),
+('095310E1AAAD0E4BB0EC167B770239A1BAFB7BA009C0986CFF5DCED2B9A708',
+ '6AAABA305E9D60E437FADB7730883744', '4E8E8A32804C2DA248DD1621A2DF5A59'),
+('06351601558986E3CB295E26D0B575E8A60226561CB098B91E9E48D0A421',
+ '621127720D127F14AB021095257F6C9D', '8099EC7AA94A31E7A602C59B73EE53C4'),
+('0E29D0C2E84D8954AE30F96D8080BA260B5D5485D36A4E4DF7C3B48E85',
+ '23A6FCF704C04FBF19FDF983EDC39127', '7B86739B5F742871B53AD8916CBDC6B0'),
+('0B2DF793534BE688C016711B05BF9DFFD4C74A1B33524FC494D3DA3E',
+ 'F1C964CDE2032DB0BC27B4BE0F3D9D0F', '1463F77F39BDC235EA5E8A5B081F9CE1'),
+('089358CD27EF176094C635CACCD66234249E12137D65618533911A',
+ 'ECDA4CBE89F74DBF79EBE9B9F4F6CF2C', '4C333A87CDBC5F8EDD568A08ACD22D2E'),
+('05031058F338D421B5EC460694B432ADD824708B6FBFC1E8E5BE',
+ '1D0D3F08D8487FB6B68E762973FD2152', 'F9BE7970B1A6689FBA1D1B83DBDC1346'),
+('0DA5C3BE04CDD35306F442817EAB347B9344D7E5C68BF3AE0C',
+ '2ED35B01A830E3FCC46C1989C6F4D3DE', '1DA5D794C98F0937B32C355F9448B0A7'),
+('0A4C748F1B820D90EF4E4487930184D83A975079258F3E4C',
+ '607CF038557E4F47BF698C167B57591E', '48065D489BC746D6A75DC5DCC6E4F50B'),
+('0728C4C94EB27C184197F02B75630D65DF00E5F6ADE5FE',
+ 'D5C77CD3F9A7EDF2EDB958F4DAF45FF9', '33F7E9DF813EBE5C58244C8F3E85EBB4'),
+('0FC973FE155E072F4D59E8DC50F75E731C32FAC65986',
+ '4574FF5B256C18928E2B9DF241825863', '687754F76CBDE753BAD5EDDF7A903715'),
+('0C4AF410A88AC1E99CCB6E06588F53576D5E4F9D1A',
+ 'E4890AD4BD722A84A6C8BB3AB02C5FBD', '60291771D5810238C0459E0DE3A07725'),
+('094F7102C1649E097A9259628C2F2711348FCBBD',
+ '6917AF1266EBC9C7E901753973A06E82', '5BB024216B9314BA550085190A1509BE'),
+('069502CA455398A07296669DC55B67756EC554',
+ 'E292CAF38755D561CF7035DFBD554ADB', 'A13380C10591BEBD8DEBFF63E22D219E'),
+('0E56BF070CEC71301616A85980DADC37FBAE',
+ '34F51EFDC20D06845853BAF2CE2727D9', '42B9F6F6A57E0F939FC40399FD3B3A4A'),
+('0B1B81208A65F6DD6E9D75CA64B6DE9102',
+ '28D471B93D593959D0828FD1DA9B876D', '188C3C40455E49E1716FF2B00D3B4852'),
+('084B00E05A8A31EDD4491705399571A5',
+ '8AF72EED4716980112A8EB3BF4A6BF0E', 'F197A1681AFD1F6B97EB46491722CDCD'),
+('059CC4EB1BEE4A8C36D62AD1117D2C',
+ 'CB3DF13AA5C9A4B0CEA489C22D941127', 'CA635CB32EBA76EA6A263DC5B63E4462'),
+('0DB3E4E9AAFEAA07657FE500DA49',
+ '840506BFFE845A9D573A7014D915389A', '34066FB8EC127674DEA47682F48ED6A0'),
+('0A0E91DC60AE757379CC07078C',
+ 'C940AE7EC343183C01D9A435E1DA1675', '38E8C4B858CFF14B425CF6ADF9C4E05D'),
+('0718DB219F364817F8EA38E9',
+ '4BDD132F3E7D215E5CAE53D033956989', '3FB1DDE1F10CA1813B71BDF51C9D0C4B'),
+('0FB46C3A84C229322F38E0',
+ 'B05B9B1923A5154F901016264497FC10', '1A8F6CF4526045AFCC95AD377593797D'),
+('0C5F7C6DE608F961490C',
+ 'EB4AEE30F3937A85D6DA4FE53E232333', '5005F10F2CDC39DA5D3A2B821E8AFAA7'),
+('091C5D3EF1DAA3C5C8',
+ 'F329EF6A9492BCF8EA471B605DEE2718', '6C4C87C3C745FD514842A6CA979D26E3')
+ ]
+
+# Test data for RC5
+
+rc5 = [('10200c1000000000000000000000000000000000', '0000000000000000',
+ '21A5DBEE154B8F6D'),
+ ('10200c10915F4619BE41B2516355A50110A9CE91', '21A5DBEE154B8F6D',
+ 'F7C013AC5B2B8952'),
+ ('10200c10783348E75AEB0F2FD7B169BB8DC16787', 'F7C013AC5B2B8952',
+ '2F42B3B70369FC92'),
+ ('10200c10DC49DB1375A5584F6485B413B5F12BAF', '2F42B3B70369FC92',
+ '65C178B284D197CC'),
+ ('10200c105269F149D41BA0152497574D7F153125', '65C178B284D197CC',
+ 'EB44E415DA319824')
+ ]
+
+# Test data for ARC2
+arc2 = [
+('5068696c6970476c617373', '0000000000000000', '624fb3e887419e48'),
+('5068696c6970476c617373', 'ffffffffffffffff', '79cadef44c4a5a85'),
+('5068696c6970476c617373', '0001020304050607', '90411525b34e4c2c'),
+('5068696c6970476c617373', '0011223344556677', '078656aaba61cbfb'),
+('ffffffffffffffff', '0000000000000000', 'd7bcc5dbb4d6e56a'),
+('ffffffffffffffff', 'ffffffffffffffff', '7259018ec557b357'),
+('ffffffffffffffff', '0001020304050607', '93d20a497f2ccb62'),
+('ffffffffffffffff', '0011223344556677', 'cb15a7f819c0014d'),
+('ffffffffffffffff5065746572477265656e6177617953e5ffe553', '0000000000000000', '63ac98cdf3843a7a'),
+('ffffffffffffffff5065746572477265656e6177617953e5ffe553', 'ffffffffffffffff', '3fb49e2fa12371dd'),
+('ffffffffffffffff5065746572477265656e6177617953e5ffe553', '0001020304050607', '46414781ab387d5f'),
+('ffffffffffffffff5065746572477265656e6177617953e5ffe553', '0011223344556677', 'be09dc81feaca271'),
+('53e5ffe553', '0000000000000000', 'e64221e608be30ab'),
+('53e5ffe553', 'ffffffffffffffff', '862bc60fdcd4d9a9'),
+('53e5ffe553', '0001020304050607', '6a34da50fa5e47de'),
+('53e5ffe553', '0011223344556677', '584644c34503122c'),
+]
+
+# Test data for Blowfish
+
+blowfish = [('6162636465666768696a6b6c6d6e6f707172737475767778797a',
+ '424c4f5746495348', '324ed0fef413a203'),
+ ('57686f206973204a6f686e2047616c743f', 'fedcba9876543210',
+ 'cc91732b8022f684')
+ ]
+
+# Test data for DES3
+
+des3_cbc=[]
+
+des3= [('0123456789abcdeffedcba9876543210', '0123456789abcde7',
+ '7f1d0a77826b8aff')
+ ]
+
+# Test data for CAST
+
+_castkey = '0123456712345678234567893456789A'
+_castdata = '0123456789ABCDEF'
+
+cast = [(_castkey, _castdata, '238B4FE5847E44B2'),
+ (_castkey[:10*2], _castdata, 'EB6A711A2C02271B'),
+ (_castkey[: 5*2], _castdata, '7AC816D16E9B302E'),
+ ]
+
+# Test data for Skipjack
+
+skipjack = [ ('00998877665544332211', '33221100ddccbbaa',
+ '2587cae27a12d300'),
+('f8da02647722f7103adf', '1ddf39abf5cd711e', 'c92d22324c6b31ae'),
+('82760ac137948821eee4', 'dd6c6cce8f83e69e', 'e32877c1d9527fff'),
+('843c1687d3cdca5fc5c3', 'beaacf177fa41a11', '4745783f75b8861a'),
+('ae870cd7ff33a995f7e5', 'c4c09f216c1bc60a', '5c101636b8a57a72'),
+('5ccbd913ea8b73bd6391', 'd3f814b000245856', 'b4fc0f8e54728f91'),
+('f65e74cd599c68a40cc7', '356ec7d93832329c', '93b750608f5701f8'),
+('aa106e46d7087c4e93dc', '209ecf1c537ad56c', 'd823d45510099e61'),
+('a93f9789a20c3cc34fea', '892eea9d64e17d66', '0959e231b275d95f'),
+('88b163cbd61616888899', '991390fd760fc91b', 'e7700209886767ae'),
+('fb6cd1ff70487561df10', 'daebc947ddca9c9e', 'e7cc49a56bd6a322'),
+('5edc1ac0c4e7ef5f002c', '6419ddefe2cd8f2e', 'e48a05cf26e242fd'),
+('8e3090c19aa32f94496a', '322998ecbd068112', '62c0e537b14df2c1'),
+('b96e3fd46fa4263f9092', '3aae2aee20da93cc', '54d1e58a6b624d71'),
+('9e6635baee28c5bce2bc', '14311112ca11f727', '5d0f235a9d221ce0'),
+('04127ce16dc1b1726a66', '300e4313e7ad6796', '8e5b03522e68cbeb'),
+('f0b89d75e979ccc9b172', '09cd1c1accbe7797', '572c9b4025a9134b'),
+('f9bfc78798cbf1bcd4b5', '31b30ca354af3cd8', '8c959c904789fbda'),
+('f43a51b4273bde27d2b0', '08c59b0db99ec267', 'b7d7f5fa342988fb'),
+('cd51f0a75aa73c48edd2', '9784b1e3e7e60e60', '763aa8ee109397b3'),
+('b3319a3f6622aa726bb3', 'f65216373d4b43c7', '0325600337b8ad3c'),
+('493254c9596e993f5f9c', 'cba4c1215d5d36ce', '68e1c551c59108c0'),
+('76150c2c3ced1c7ca021', '82294851288e75cb', '7eb6325d82a2096c'),
+('7140d6c5486305872df6', 'c3a7b7e4a52e407b', '2483f385a42ee3c6'),
+('3c2c3901f0ee9a3b2b0e', '1bfde32ab559e13a', 'd6fa9db8685fd88a'),
+('606a8b4bdfaae8a0ba51', 'd205f7486c782838', '0330489170b85293'),
+('7847a47a0fe79ab770ce', 'd96ff1f7c7fc60e0', '1f9b3301c9b2708c'),
+('73b9ab0c36c99e91a891', '241d4bde19a75f8f', '2b86c57ffe168895'),
+('a37f2ad5a85e170741f5', '7be1b8d58321c619', '5af7ceb3eed9dca1'),
+('f7b0c2a8170e3c4e48b3', 'c9214ea01ec14948', '1b587736e116c04b'),
+('a1fc67e44eacacf4a902', 'e2a3091feb581588', 'f3ecf0f1789a3923'),
+('f14430affc5fe82a9ae9', '3cb466d301b60854', 'e8d114c20ffa1c79'),
+('fd26df50486a4cd96d9b', 'b0684f8a5e63d935', '222903994d64fe3a'),
+('a6d46d46ca287e1a332a', 'ba1f37e88edec55f', '91f2baad6fa0de55'),
+('83c3f1cb8d06efc6196b', 'e9fed8501b7a6579', '83f9f08f89a854ee'),
+('0edfa44c7d4a4ef0725e', 'eb5ca8b3fa1fcdbb', '2b1b6670a6be0324'),
+('b8edcf167d99a711ccee', 'b8b525c6382af277', '211a695da473766f'),
+('4f639e0d5a5d2ad7e9a4', '9162e781ff683853', 'eb2976370d22ef22'),
+('37e006256a4ae6d320c4', 'c9f23a20a39ded11', 'dba4c0ef0ea098c0'),
+('e41d0bd25f931ba1d85c', '5a6f12f32f7eefdf', '923daee8000709f9'),
+('fdf65bbc5fe600f3cd68', 'cad5414c1c64f194', 'd5771e78b6f1fe1e'),
+('1c269af2ff166acb27ef', '063a58a20b45378f', '634f7a3861af97a1'),
+('1179f64acb6122ccf649', '08fbf42b4313347b', '3a803a4bd0e8c3e6'),
+('078c87265eb8da323e90', '6d4ed0e9930532d1', 'f4fa372e7e1441a1'),
+('2fff35f8eb774c843bb0', '40b699812345661d', '63a9197f7b75f53f'),
+('09f77346a4393ce99856', '22ed54626a51e505', 'e91a050a7481b3dd'),
+('5b878e0b22a705acf8fb', '0c489b66e2da531b', '6e9370a91b994878'),
+('9d72c1ab2092c1b10877', 'c64b10f8b191bc2c', '5bdecded96d656c9'),
+('72865f289725e1b55502', '91fdf7236f85bdd6', '1a5680e51736026f'),
+('06e3c0e541f4aae6fe93', '40009f8a465a9feb', '0e7aace421bc79d8'),
+('2ea09f1cc89e064f09bc', '543208b05bfa3858', 'a95d87fad12c3593')
+]
+
+# Test data for XOR
+
+XOR = []
+
diff --git a/__init__.py b/__init__.py
new file mode 100644
index 0000000..3d71101
--- /dev/null
+++ b/__init__.py
@@ -0,0 +1,3 @@
+
+__all__ = ['Cipher', 'Hash', 'PublicKey', 'Util', 'Protocol', 'Winnow']
+
diff --git a/_checkversion.py b/_checkversion.py
new file mode 100644
index 0000000..a783341
--- /dev/null
+++ b/_checkversion.py
@@ -0,0 +1,16 @@
+"""This file (which is sourced, not imported) checks the version of the
+"versioncheck" package. It is also an example of how to format your own
+_checkversion.py file"""
+
+import pyversioncheck
+
+_PACKAGE="Crypto"
+_VERSION="1.1a2"
+_URL="http://starship.skyport.net/crew/amk/versions/pct.txt"
+
+try:
+ _myverbose=VERBOSE
+except NameError:
+ _myverbose=1
+
+pyversioncheck.versioncheck(_PACKAGE, _URL, _VERSION, verbose=_myverbose)
diff --git a/block/ARC2.c b/block/ARC2.c
new file mode 100644
index 0000000..77b59c9
--- /dev/null
+++ b/block/ARC2.c
@@ -0,0 +1,186 @@
+
+/*
+ * rc2.c : Source code for the RC2 block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+
+typedef unsigned int U32;
+typedef unsigned short U16;
+typedef unsigned char U8;
+
+typedef struct
+{
+ PCTObject_HEAD
+ U16 xkey[64];
+} ARC2object;
+
+static inline void
+ARC2encrypt(self, block)
+ ARC2object *self;
+ U8 *block;
+{
+ U16 x76, x54, x32, x10;
+ int i;
+
+ x76 = (block[7] << 8) + block[6];
+ x54 = (block[5] << 8) + block[4];
+ x32 = (block[3] << 8) + block[2];
+ x10 = (block[1] << 8) + block[0];
+
+ for (i = 0; i < 16; i++)
+ {
+ x10 += (x32 & ~x76) + (x54 & x76) + self->xkey[4*i+0];
+ x10 = (x10 << 1) + (x10 >> 15 & 1);
+
+ x32 += (x54 & ~x10) + (x76 & x10) + self->xkey[4*i+1];
+ x32 = (x32 << 2) + (x32 >> 14 & 3);
+
+ x54 += (x76 & ~x32) + (x10 & x32) + self->xkey[4*i+2];
+ x54 = (x54 << 3) + (x54 >> 13 & 7);
+
+ x76 += (x10 & ~x54) + (x32 & x54) + self->xkey[4*i+3];
+ x76 = (x76 << 5) + (x76 >> 11 & 31);
+
+ if (i == 4 || i == 10) {
+ x10 += self->xkey[x76 & 63];
+ x32 += self->xkey[x10 & 63];
+ x54 += self->xkey[x32 & 63];
+ x76 += self->xkey[x54 & 63];
+ }
+ }
+
+ block[0] = (U8)x10;
+ block[1] = (U8)(x10 >> 8);
+ block[2] = (U8)x32;
+ block[3] = (U8)(x32 >> 8);
+ block[4] = (U8)x54;
+ block[5] = (U8)(x54 >> 8);
+ block[6] = (U8)x76;
+ block[7] = (U8)(x76 >> 8);
+}
+
+
+static inline void
+ARC2decrypt(self, block)
+ ARC2object *self;
+ U8 *block;
+{
+ U16 x76, x54, x32, x10;
+ int i;
+
+ x76 = (block[7] << 8) + block[6];
+ x54 = (block[5] << 8) + block[4];
+ x32 = (block[3] << 8) + block[2];
+ x10 = (block[1] << 8) + block[0];
+
+ i = 15;
+ do {
+ x76 &= 65535;
+ x76 = (x76 << 11) + (x76 >> 5);
+ x76 -= (x10 & ~x54) + (x32 & x54) + self->xkey[4*i+3];
+
+ x54 &= 65535;
+ x54 = (x54 << 13) + (x54 >> 3);
+ x54 -= (x76 & ~x32) + (x10 & x32) + self->xkey[4*i+2];
+
+ x32 &= 65535;
+ x32 = (x32 << 14) + (x32 >> 2);
+ x32 -= (x54 & ~x10) + (x76 & x10) + self->xkey[4*i+1];
+
+ x10 &= 65535;
+ x10 = (x10 << 15) + (x10 >> 1);
+ x10 -= (x32 & ~x76) + (x54 & x76) + self->xkey[4*i+0];
+
+ if (i == 5 || i == 11) {
+ x76 -= self->xkey[x54 & 63];
+ x54 -= self->xkey[x32 & 63];
+ x32 -= self->xkey[x10 & 63];
+ x10 -= self->xkey[x76 & 63];
+ }
+ } while (i--);
+
+ block[0] = (U8)x10;
+ block[1] = (U8)(x10 >> 8);
+ block[2] = (U8)x32;
+ block[3] = (U8)(x32 >> 8);
+ block[4] = (U8)x54;
+ block[5] = (U8)(x54 >> 8);
+ block[6] = (U8)x76;
+ block[7] = (U8)(x76 >> 8);
+}
+
+
+static inline void
+ARC2init(self, key, keylength)
+ ARC2object *self;
+ U8 *key;
+ int keylength;
+{
+ U8 x;
+ U16 i;
+ /* 256-entry permutation table, probably derived somehow from pi */
+ static const U8 permute[256] = {
+ 217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157,
+ 198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162,
+ 23,154, 89,245,135,179, 79, 19, 97, 69,109,141, 9,129,125, 50,
+ 189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130,
+ 84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220,
+ 18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38,
+ 111,191, 14,218, 70,105, 7, 87, 39,242, 29,155,188,148, 67, 3,
+ 248, 17,199,246,144,239, 62,231, 6,195,213, 47,200,102, 30,215,
+ 8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42,
+ 150, 26,210,113, 90, 21, 73,116, 75,159,208, 94, 4, 24,164,236,
+ 194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57,
+ 153,124, 58,133, 35,184,180,122,252, 2, 54, 91, 37, 85,151, 49,
+ 45, 93,250,152,227,138,146,174, 5,223, 41, 16,103,108,186,201,
+ 211, 0,230,207,225,158,168, 44, 99, 22, 1, 63, 88,226,137,169,
+ 13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46,
+ 197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173
+ };
+
+ /* The "bits" value may be some sort of export control weakening.
+ We'll hardwire it to 1024. */
+#define bits 1024
+
+ memcpy(self->xkey, key, keylength);
+
+ /* Phase 1: Expand input key to 128 bytes */
+ if (keylength < 128) {
+ i = 0;
+ x = ((U8 *)self->xkey)[keylength-1];
+ do {
+ x = permute[(x + ((U8 *)self->xkey)[i++]) & 255];
+ ((U8 *)self->xkey)[keylength++] = x;
+ } while (keylength < 128);
+ }
+
+ /* Phase 2 - reduce effective key size to "bits" */
+ keylength = (bits+7) >> 3;
+ i = 128-keylength;
+ x = permute[((U8 *)self->xkey)[i] & (255 >>
+ (7 &
+ ((bits %8 ) ? 8-(bits%8): 0))
+ )];
+ ((U8 *)self->xkey)[i] = x;
+
+ while (i--) {
+ x = permute[ x ^ ((U8 *)self->xkey)[i+keylength] ];
+ ((U8 *)self->xkey)[i] = x;
+ }
+
+ /* Phase 3 - copy to self->xkey in little-endian order */
+ i = 63;
+ do {
+ self->xkey[i] = ((U8 *)self->xkey)[2*i] +
+ (((U8 *)self->xkey)[2*i+1] << 8);
+ } while (i--);
+}
+
+#undef bits
diff --git a/block/Blowfish.c b/block/Blowfish.c
new file mode 100644
index 0000000..a6840b5
--- /dev/null
+++ b/block/Blowfish.c
@@ -0,0 +1,506 @@
+
+/*
+ * blowfish.c : Source code for the Blowfish block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+/*************************************************************************/
+/* File: bf.c
+ Blowfish cipher by Bruce Schneier,
+ Code by Bryan Olson, based partly on Schneier's.
+*/
+
+/* Define IntU32 to be an unsigned in 32 bits long */
+typedef unsigned int IntU32 ;
+typedef unsigned char IntU8 ;
+#define NROUNDS 16
+
+
+
+/* Define IntP to be an integer which
+ is the same size as a pointer. */
+typedef unsigned long IntP ;
+
+
+typedef struct
+{
+ IntU32 p[2][NROUNDS+2],
+ sbox[4][256] ;
+} BFkey_type ;
+
+typedef struct
+{
+ PCTObject_HEAD
+ BFkey_type bfkey;
+} Blowfishobject;
+
+/* File bfinit.h
+ Data to initialize P and S in BlowFish.
+*/
+
+static IntU32 p_init[NROUNDS+2] =
+{
+ 608135816UL, 2242054355UL, 320440878UL, 57701188UL,
+ 2752067618UL, 698298832UL, 137296536UL, 3964562569UL,
+ 1160258022UL, 953160567UL, 3193202383UL, 887688300UL,
+ 3232508343UL, 3380367581UL, 1065670069UL, 3041331479UL,
+ 2450970073UL, 2306472731UL
+} ;
+
+static IntU32 s_init[4][256] = {
+ {3509652390UL, 2564797868UL, 805139163UL, 3491422135UL,
+ 3101798381UL, 1780907670UL, 3128725573UL, 4046225305UL,
+ 614570311UL, 3012652279UL, 134345442UL, 2240740374UL,
+ 1667834072UL, 1901547113UL, 2757295779UL, 4103290238UL,
+ 227898511UL, 1921955416UL, 1904987480UL, 2182433518UL,
+ 2069144605UL, 3260701109UL, 2620446009UL, 720527379UL,
+ 3318853667UL, 677414384UL, 3393288472UL, 3101374703UL,
+ 2390351024UL, 1614419982UL, 1822297739UL, 2954791486UL,
+ 3608508353UL, 3174124327UL, 2024746970UL, 1432378464UL,
+ 3864339955UL, 2857741204UL, 1464375394UL, 1676153920UL,
+ 1439316330UL, 715854006UL, 3033291828UL, 289532110UL,
+ 2706671279UL, 2087905683UL, 3018724369UL, 1668267050UL,
+ 732546397UL, 1947742710UL, 3462151702UL, 2609353502UL,
+ 2950085171UL, 1814351708UL, 2050118529UL, 680887927UL,
+ 999245976UL, 1800124847UL, 3300911131UL, 1713906067UL,
+ 1641548236UL, 4213287313UL, 1216130144UL, 1575780402UL,
+ 4018429277UL, 3917837745UL, 3693486850UL, 3949271944UL,
+ 596196993UL, 3549867205UL, 258830323UL, 2213823033UL,
+ 772490370UL, 2760122372UL, 1774776394UL, 2652871518UL,
+ 566650946UL, 4142492826UL, 1728879713UL, 2882767088UL,
+ 1783734482UL, 3629395816UL, 2517608232UL, 2874225571UL,
+ 1861159788UL, 326777828UL, 3124490320UL, 2130389656UL,
+ 2716951837UL, 967770486UL, 1724537150UL, 2185432712UL,
+ 2364442137UL, 1164943284UL, 2105845187UL, 998989502UL,
+ 3765401048UL, 2244026483UL, 1075463327UL, 1455516326UL,
+ 1322494562UL, 910128902UL, 469688178UL, 1117454909UL,
+ 936433444UL, 3490320968UL, 3675253459UL, 1240580251UL,
+ 122909385UL, 2157517691UL, 634681816UL, 4142456567UL,
+ 3825094682UL, 3061402683UL, 2540495037UL, 79693498UL,
+ 3249098678UL, 1084186820UL, 1583128258UL, 426386531UL,
+ 1761308591UL, 1047286709UL, 322548459UL, 995290223UL,
+ 1845252383UL, 2603652396UL, 3431023940UL, 2942221577UL,
+ 3202600964UL, 3727903485UL, 1712269319UL, 422464435UL,
+ 3234572375UL, 1170764815UL, 3523960633UL, 3117677531UL,
+ 1434042557UL, 442511882UL, 3600875718UL, 1076654713UL,
+ 1738483198UL, 4213154764UL, 2393238008UL, 3677496056UL,
+ 1014306527UL, 4251020053UL, 793779912UL, 2902807211UL,
+ 842905082UL, 4246964064UL, 1395751752UL, 1040244610UL,
+ 2656851899UL, 3396308128UL, 445077038UL, 3742853595UL,
+ 3577915638UL, 679411651UL, 2892444358UL, 2354009459UL,
+ 1767581616UL, 3150600392UL, 3791627101UL, 3102740896UL,
+ 284835224UL, 4246832056UL, 1258075500UL, 768725851UL,
+ 2589189241UL, 3069724005UL, 3532540348UL, 1274779536UL,
+ 3789419226UL, 2764799539UL, 1660621633UL, 3471099624UL,
+ 4011903706UL, 913787905UL, 3497959166UL, 737222580UL,
+ 2514213453UL, 2928710040UL, 3937242737UL, 1804850592UL,
+ 3499020752UL, 2949064160UL, 2386320175UL, 2390070455UL,
+ 2415321851UL, 4061277028UL, 2290661394UL, 2416832540UL,
+ 1336762016UL, 1754252060UL, 3520065937UL, 3014181293UL,
+ 791618072UL, 3188594551UL, 3933548030UL, 2332172193UL,
+ 3852520463UL, 3043980520UL, 413987798UL, 3465142937UL,
+ 3030929376UL, 4245938359UL, 2093235073UL, 3534596313UL,
+ 375366246UL, 2157278981UL, 2479649556UL, 555357303UL,
+ 3870105701UL, 2008414854UL, 3344188149UL, 4221384143UL,
+ 3956125452UL, 2067696032UL, 3594591187UL, 2921233993UL,
+ 2428461UL, 544322398UL, 577241275UL, 1471733935UL,
+ 610547355UL, 4027169054UL, 1432588573UL, 1507829418UL,
+ 2025931657UL, 3646575487UL, 545086370UL, 48609733UL,
+ 2200306550UL, 1653985193UL, 298326376UL, 1316178497UL,
+ 3007786442UL, 2064951626UL, 458293330UL, 2589141269UL,
+ 3591329599UL, 3164325604UL, 727753846UL, 2179363840UL,
+ 146436021UL, 1461446943UL, 4069977195UL, 705550613UL,
+ 3059967265UL, 3887724982UL, 4281599278UL, 3313849956UL,
+ 1404054877UL, 2845806497UL, 146425753UL, 1854211946UL},
+
+{ 1266315497UL, 3048417604UL, 3681880366UL, 3289982499UL,
+ 2909710000UL, 1235738493UL, 2632868024UL, 2414719590UL,
+ 3970600049UL, 1771706367UL, 1449415276UL, 3266420449UL,
+ 422970021UL, 1963543593UL, 2690192192UL, 3826793022UL,
+ 1062508698UL, 1531092325UL, 1804592342UL, 2583117782UL,
+ 2714934279UL, 4024971509UL, 1294809318UL, 4028980673UL,
+ 1289560198UL, 2221992742UL, 1669523910UL, 35572830UL,
+ 157838143UL, 1052438473UL, 1016535060UL, 1802137761UL,
+ 1753167236UL, 1386275462UL, 3080475397UL, 2857371447UL,
+ 1040679964UL, 2145300060UL, 2390574316UL, 1461121720UL,
+ 2956646967UL, 4031777805UL, 4028374788UL, 33600511UL,
+ 2920084762UL, 1018524850UL, 629373528UL, 3691585981UL,
+ 3515945977UL, 2091462646UL, 2486323059UL, 586499841UL,
+ 988145025UL, 935516892UL, 3367335476UL, 2599673255UL,
+ 2839830854UL, 265290510UL, 3972581182UL, 2759138881UL,
+ 3795373465UL, 1005194799UL, 847297441UL, 406762289UL,
+ 1314163512UL, 1332590856UL, 1866599683UL, 4127851711UL,
+ 750260880UL, 613907577UL, 1450815602UL, 3165620655UL,
+ 3734664991UL, 3650291728UL, 3012275730UL, 3704569646UL,
+ 1427272223UL, 778793252UL, 1343938022UL, 2676280711UL,
+ 2052605720UL, 1946737175UL, 3164576444UL, 3914038668UL,
+ 3967478842UL, 3682934266UL, 1661551462UL, 3294938066UL,
+ 4011595847UL, 840292616UL, 3712170807UL, 616741398UL,
+ 312560963UL, 711312465UL, 1351876610UL, 322626781UL,
+ 1910503582UL, 271666773UL, 2175563734UL, 1594956187UL,
+ 70604529UL, 3617834859UL, 1007753275UL, 1495573769UL,
+ 4069517037UL, 2549218298UL, 2663038764UL, 504708206UL,
+ 2263041392UL, 3941167025UL, 2249088522UL, 1514023603UL,
+ 1998579484UL, 1312622330UL, 694541497UL, 2582060303UL,
+ 2151582166UL, 1382467621UL, 776784248UL, 2618340202UL,
+ 3323268794UL, 2497899128UL, 2784771155UL, 503983604UL,
+ 4076293799UL, 907881277UL, 423175695UL, 432175456UL,
+ 1378068232UL, 4145222326UL, 3954048622UL, 3938656102UL,
+ 3820766613UL, 2793130115UL, 2977904593UL, 26017576UL,
+ 3274890735UL, 3194772133UL, 1700274565UL, 1756076034UL,
+ 4006520079UL, 3677328699UL, 720338349UL, 1533947780UL,
+ 354530856UL, 688349552UL, 3973924725UL, 1637815568UL,
+ 332179504UL, 3949051286UL, 53804574UL, 2852348879UL,
+ 3044236432UL, 1282449977UL, 3583942155UL, 3416972820UL,
+ 4006381244UL, 1617046695UL, 2628476075UL, 3002303598UL,
+ 1686838959UL, 431878346UL, 2686675385UL, 1700445008UL,
+ 1080580658UL, 1009431731UL, 832498133UL, 3223435511UL,
+ 2605976345UL, 2271191193UL, 2516031870UL, 1648197032UL,
+ 4164389018UL, 2548247927UL, 300782431UL, 375919233UL,
+ 238389289UL, 3353747414UL, 2531188641UL, 2019080857UL,
+ 1475708069UL, 455242339UL, 2609103871UL, 448939670UL,
+ 3451063019UL, 1395535956UL, 2413381860UL, 1841049896UL,
+ 1491858159UL, 885456874UL, 4264095073UL, 4001119347UL,
+ 1565136089UL, 3898914787UL, 1108368660UL, 540939232UL,
+ 1173283510UL, 2745871338UL, 3681308437UL, 4207628240UL,
+ 3343053890UL, 4016749493UL, 1699691293UL, 1103962373UL,
+ 3625875870UL, 2256883143UL, 3830138730UL, 1031889488UL,
+ 3479347698UL, 1535977030UL, 4236805024UL, 3251091107UL,
+ 2132092099UL, 1774941330UL, 1199868427UL, 1452454533UL,
+ 157007616UL, 2904115357UL, 342012276UL, 595725824UL,
+ 1480756522UL, 206960106UL, 497939518UL, 591360097UL,
+ 863170706UL, 2375253569UL, 3596610801UL, 1814182875UL,
+ 2094937945UL, 3421402208UL, 1082520231UL, 3463918190UL,
+ 2785509508UL, 435703966UL, 3908032597UL, 1641649973UL,
+ 2842273706UL, 3305899714UL, 1510255612UL, 2148256476UL,
+ 2655287854UL, 3276092548UL, 4258621189UL, 236887753UL,
+ 3681803219UL, 274041037UL, 1734335097UL, 3815195456UL,
+ 3317970021UL, 1899903192UL, 1026095262UL, 4050517792UL,
+ 356393447UL, 2410691914UL, 3873677099UL, 3682840055UL},
+
+{ 3913112168UL, 2491498743UL, 4132185628UL, 2489919796UL,
+ 1091903735UL, 1979897079UL, 3170134830UL, 3567386728UL,
+ 3557303409UL, 857797738UL, 1136121015UL, 1342202287UL,
+ 507115054UL, 2535736646UL, 337727348UL, 3213592640UL,
+ 1301675037UL, 2528481711UL, 1895095763UL, 1721773893UL,
+ 3216771564UL, 62756741UL, 2142006736UL, 835421444UL,
+ 2531993523UL, 1442658625UL, 3659876326UL, 2882144922UL,
+ 676362277UL, 1392781812UL, 170690266UL, 3921047035UL,
+ 1759253602UL, 3611846912UL, 1745797284UL, 664899054UL,
+ 1329594018UL, 3901205900UL, 3045908486UL, 2062866102UL,
+ 2865634940UL, 3543621612UL, 3464012697UL, 1080764994UL,
+ 553557557UL, 3656615353UL, 3996768171UL, 991055499UL,
+ 499776247UL, 1265440854UL, 648242737UL, 3940784050UL,
+ 980351604UL, 3713745714UL, 1749149687UL, 3396870395UL,
+ 4211799374UL, 3640570775UL, 1161844396UL, 3125318951UL,
+ 1431517754UL, 545492359UL, 4268468663UL, 3499529547UL,
+ 1437099964UL, 2702547544UL, 3433638243UL, 2581715763UL,
+ 2787789398UL, 1060185593UL, 1593081372UL, 2418618748UL,
+ 4260947970UL, 69676912UL, 2159744348UL, 86519011UL,
+ 2512459080UL, 3838209314UL, 1220612927UL, 3339683548UL,
+ 133810670UL, 1090789135UL, 1078426020UL, 1569222167UL,
+ 845107691UL, 3583754449UL, 4072456591UL, 1091646820UL,
+ 628848692UL, 1613405280UL, 3757631651UL, 526609435UL,
+ 236106946UL, 48312990UL, 2942717905UL, 3402727701UL,
+ 1797494240UL, 859738849UL, 992217954UL, 4005476642UL,
+ 2243076622UL, 3870952857UL, 3732016268UL, 765654824UL,
+ 3490871365UL, 2511836413UL, 1685915746UL, 3888969200UL,
+ 1414112111UL, 2273134842UL, 3281911079UL, 4080962846UL,
+ 172450625UL, 2569994100UL, 980381355UL, 4109958455UL,
+ 2819808352UL, 2716589560UL, 2568741196UL, 3681446669UL,
+ 3329971472UL, 1835478071UL, 660984891UL, 3704678404UL,
+ 4045999559UL, 3422617507UL, 3040415634UL, 1762651403UL,
+ 1719377915UL, 3470491036UL, 2693910283UL, 3642056355UL,
+ 3138596744UL, 1364962596UL, 2073328063UL, 1983633131UL,
+ 926494387UL, 3423689081UL, 2150032023UL, 4096667949UL,
+ 1749200295UL, 3328846651UL, 309677260UL, 2016342300UL,
+ 1779581495UL, 3079819751UL, 111262694UL, 1274766160UL,
+ 443224088UL, 298511866UL, 1025883608UL, 3806446537UL,
+ 1145181785UL, 168956806UL, 3641502830UL, 3584813610UL,
+ 1689216846UL, 3666258015UL, 3200248200UL, 1692713982UL,
+ 2646376535UL, 4042768518UL, 1618508792UL, 1610833997UL,
+ 3523052358UL, 4130873264UL, 2001055236UL, 3610705100UL,
+ 2202168115UL, 4028541809UL, 2961195399UL, 1006657119UL,
+ 2006996926UL, 3186142756UL, 1430667929UL, 3210227297UL,
+ 1314452623UL, 4074634658UL, 4101304120UL, 2273951170UL,
+ 1399257539UL, 3367210612UL, 3027628629UL, 1190975929UL,
+ 2062231137UL, 2333990788UL, 2221543033UL, 2438960610UL,
+ 1181637006UL, 548689776UL, 2362791313UL, 3372408396UL,
+ 3104550113UL, 3145860560UL, 296247880UL, 1970579870UL,
+ 3078560182UL, 3769228297UL, 1714227617UL, 3291629107UL,
+ 3898220290UL, 166772364UL, 1251581989UL, 493813264UL,
+ 448347421UL, 195405023UL, 2709975567UL, 677966185UL,
+ 3703036547UL, 1463355134UL, 2715995803UL, 1338867538UL,
+ 1343315457UL, 2802222074UL, 2684532164UL, 233230375UL,
+ 2599980071UL, 2000651841UL, 3277868038UL, 1638401717UL,
+ 4028070440UL, 3237316320UL, 6314154UL, 819756386UL,
+ 300326615UL, 590932579UL, 1405279636UL, 3267499572UL,
+ 3150704214UL, 2428286686UL, 3959192993UL, 3461946742UL,
+ 1862657033UL, 1266418056UL, 963775037UL, 2089974820UL,
+ 2263052895UL, 1917689273UL, 448879540UL, 3550394620UL,
+ 3981727096UL, 150775221UL, 3627908307UL, 1303187396UL,
+ 508620638UL, 2975983352UL, 2726630617UL, 1817252668UL,
+ 1876281319UL, 1457606340UL, 908771278UL, 3720792119UL,
+ 3617206836UL, 2455994898UL, 1729034894UL, 1080033504UL},
+
+{ 976866871UL, 3556439503UL, 2881648439UL, 1522871579UL,
+ 1555064734UL, 1336096578UL, 3548522304UL, 2579274686UL,
+ 3574697629UL, 3205460757UL, 3593280638UL, 3338716283UL,
+ 3079412587UL, 564236357UL, 2993598910UL, 1781952180UL,
+ 1464380207UL, 3163844217UL, 3332601554UL, 1699332808UL,
+ 1393555694UL, 1183702653UL, 3581086237UL, 1288719814UL,
+ 691649499UL, 2847557200UL, 2895455976UL, 3193889540UL,
+ 2717570544UL, 1781354906UL, 1676643554UL, 2592534050UL,
+ 3230253752UL, 1126444790UL, 2770207658UL, 2633158820UL,
+ 2210423226UL, 2615765581UL, 2414155088UL, 3127139286UL,
+ 673620729UL, 2805611233UL, 1269405062UL, 4015350505UL,
+ 3341807571UL, 4149409754UL, 1057255273UL, 2012875353UL,
+ 2162469141UL, 2276492801UL, 2601117357UL, 993977747UL,
+ 3918593370UL, 2654263191UL, 753973209UL, 36408145UL,
+ 2530585658UL, 25011837UL, 3520020182UL, 2088578344UL,
+ 530523599UL, 2918365339UL, 1524020338UL, 1518925132UL,
+ 3760827505UL, 3759777254UL, 1202760957UL, 3985898139UL,
+ 3906192525UL, 674977740UL, 4174734889UL, 2031300136UL,
+ 2019492241UL, 3983892565UL, 4153806404UL, 3822280332UL,
+ 352677332UL, 2297720250UL, 60907813UL, 90501309UL,
+ 3286998549UL, 1016092578UL, 2535922412UL, 2839152426UL,
+ 457141659UL, 509813237UL, 4120667899UL, 652014361UL,
+ 1966332200UL, 2975202805UL, 55981186UL, 2327461051UL,
+ 676427537UL, 3255491064UL, 2882294119UL, 3433927263UL,
+ 1307055953UL, 942726286UL, 933058658UL, 2468411793UL,
+ 3933900994UL, 4215176142UL, 1361170020UL, 2001714738UL,
+ 2830558078UL, 3274259782UL, 1222529897UL, 1679025792UL,
+ 2729314320UL, 3714953764UL, 1770335741UL, 151462246UL,
+ 3013232138UL, 1682292957UL, 1483529935UL, 471910574UL,
+ 1539241949UL, 458788160UL, 3436315007UL, 1807016891UL,
+ 3718408830UL, 978976581UL, 1043663428UL, 3165965781UL,
+ 1927990952UL, 4200891579UL, 2372276910UL, 3208408903UL,
+ 3533431907UL, 1412390302UL, 2931980059UL, 4132332400UL,
+ 1947078029UL, 3881505623UL, 4168226417UL, 2941484381UL,
+ 1077988104UL, 1320477388UL, 886195818UL, 18198404UL,
+ 3786409000UL, 2509781533UL, 112762804UL, 3463356488UL,
+ 1866414978UL, 891333506UL, 18488651UL, 661792760UL,
+ 1628790961UL, 3885187036UL, 3141171499UL, 876946877UL,
+ 2693282273UL, 1372485963UL, 791857591UL, 2686433993UL,
+ 3759982718UL, 3167212022UL, 3472953795UL, 2716379847UL,
+ 445679433UL, 3561995674UL, 3504004811UL, 3574258232UL,
+ 54117162UL, 3331405415UL, 2381918588UL, 3769707343UL,
+ 4154350007UL, 1140177722UL, 4074052095UL, 668550556UL,
+ 3214352940UL, 367459370UL, 261225585UL, 2610173221UL,
+ 4209349473UL, 3468074219UL, 3265815641UL, 314222801UL,
+ 3066103646UL, 3808782860UL, 282218597UL, 3406013506UL,
+ 3773591054UL, 379116347UL, 1285071038UL, 846784868UL,
+ 2669647154UL, 3771962079UL, 3550491691UL, 2305946142UL,
+ 453669953UL, 1268987020UL, 3317592352UL, 3279303384UL,
+ 3744833421UL, 2610507566UL, 3859509063UL, 266596637UL,
+ 3847019092UL, 517658769UL, 3462560207UL, 3443424879UL,
+ 370717030UL, 4247526661UL, 2224018117UL, 4143653529UL,
+ 4112773975UL, 2788324899UL, 2477274417UL, 1456262402UL,
+ 2901442914UL, 1517677493UL, 1846949527UL, 2295493580UL,
+ 3734397586UL, 2176403920UL, 1280348187UL, 1908823572UL,
+ 3871786941UL, 846861322UL, 1172426758UL, 3287448474UL,
+ 3383383037UL, 1655181056UL, 3139813346UL, 901632758UL,
+ 1897031941UL, 2986607138UL, 3066810236UL, 3447102507UL,
+ 1393639104UL, 373351379UL, 950779232UL, 625454576UL,
+ 3124240540UL, 4148612726UL, 2007998917UL, 544563296UL,
+ 2244738638UL, 2330496472UL, 2058025392UL, 1291430526UL,
+ 424198748UL, 50039436UL, 29584100UL, 3605783033UL,
+ 2429876329UL, 2791104160UL, 1057563949UL, 3255363231UL,
+ 3075367218UL, 3463963227UL, 1469046755UL, 985887462UL}
+} ;
+
+/* sLb(s,n) allows us to subsript s by byte offsets, which
+ allows us to avoid a subscript scaling.
+*/
+#define sub(s,n) *((IntU32 *)((IntP)s+(n)))
+
+/* Below is one BlowFish round including the F function
+*/
+#define round(l,r,n) \
+ l ^= P[n]; \
+ r ^= ( (sub(S[0],l>>22 & 0x3fc) + sub(S[1],l>>14 & 0x3fc)) \
+ ^ sub(S[2],l>>6 & 0x3fc) ) +S[3][l & 0xff]
+
+
+
+/* This function requires the block to be two 32 bit integers, in
+whatever endian form the machine uses. On little endian machines
+use crypt_8bytes() on user data. make_bfkey should call crypt_block
+on either endian machine. Pass direction 0 to encrypt, 1 to decrypt.
+*/
+static void crypt_block(block, bfkey, direction)
+ IntU32 block[2];
+ BFkey_type *bfkey;
+ short direction;
+{
+ register IntU32 left, right,
+ (*S)[256],
+ *P ;
+
+ left = block[0] ; right = block[1] ;
+
+ S = bfkey->sbox ;
+ P = bfkey->p[direction] ;
+
+ round( left, right, 0 ) ; round( right, left, 1 ) ;
+ round( left, right, 2 ) ; round( right, left, 3 ) ;
+ round( left, right, 4 ) ; round( right, left, 5 ) ;
+ round( left, right, 6 ) ; round( right, left, 7 ) ;
+ round( left, right, 8 ) ; round( right, left, 9 ) ;
+ round( left, right, 10 ) ; round( right, left, 11 ) ;
+ round( left, right, 12 ) ; round( right, left, 13 ) ;
+ round( left, right, 14 ) ; round( right, left, 15 ) ;
+
+ left = left ^ P[NROUNDS] ;
+ right = right ^ P[NROUNDS+1] ;
+ block[0] = right ;
+ block[1] = left ;
+}
+
+/* The following should be allignment and endian independent.
+ I have not tested it on a little-endian machine.
+ It takes the input block from source, and puts the output
+ in dest. They can be the same. It takes the same direction
+ parameter as crypt_block().
+*/
+static void crypt_8bytes(source, dest, bfkey, direction)
+ IntU8 *source, *dest;
+ BFkey_type *bfkey;
+ short direction;
+{
+ IntU32 block[2] ;
+
+ block[0] = source[3] | source[2]<<8 | source[1]<<16 | source[0]<<24 ;
+ block[1] = source[7] | source[6]<<8 | source[5]<<16 | source[4]<<24 ;
+
+ crypt_block( block, bfkey, direction ) ;
+
+ dest[0]= block[0]>>24 ;
+ dest[1]= block[0]>>16 & 0xff ;
+ dest[2]= block[0]>>8 & 0xff ;
+ dest[3]= block[0] & 0xff ;
+ dest[4]= block[1]>>24 ;
+ dest[5]= block[1]>>16 & 0xff ;
+ dest[6]= block[1]>> 8 & 0xff ;
+ dest[7]= block[1] & 0xff ;
+}
+
+/* make_bfkey() takes the address of the key data as a char*,
+ and the length of the key in bytes. It generates and returns
+ a pointer to an object of BFkey_type, which can be passed
+ to the crypt functions. It does some simple testing of the
+ init data and crypt routine, and returns 0 on error.
+*/
+static void make_bfkey(key_string, keylength, bfkey)
+ unsigned char *key_string;
+ int keylength;
+ BFkey_type *bfkey;
+{
+ int i, j, k ;
+ IntU32 dspace[2],
+ checksum=0 ;
+
+ /* Copy constant initial data to P vector */
+ for( i=0 ; i<NROUNDS+2 ; ++i )
+ {
+ bfkey->p[0][i] = p_init[i] ;
+ bfkey->p[1][NROUNDS+1-i] = p_init[i] ;
+ checksum = (checksum<<1 | checksum>>31)+p_init[i] ;
+ }
+
+ /* Copy constant initial data to sboxes */
+ for( i=0 ; i<4 ; ++i )
+ for( j=0 ; j<256 ; ++j )
+ {
+ bfkey->sbox[i][j] = s_init[i][j] ;
+ checksum = ((checksum*13)<<11 | (checksum*13)>>21)
+ + s_init[i][j] ;
+ }
+
+ /* Test init data. */
+ if( checksum != 0x55861a61 )
+ {
+ PyErr_SetString(PyExc_SystemError,
+ "Blowfish: Bad initialization data");
+ return;
+ }
+
+ dspace[0] = 0 ;
+ dspace[1] = 0 ;
+
+ /* Test the crypt_block() routine. */
+ for( i=0 ; i<10 ; ++i )
+ crypt_block( dspace, bfkey, 0 ) ;
+ checksum = dspace[0] ;
+ for( i=0 ; i<10 ; ++i )
+ crypt_block( dspace, bfkey, 1 ) ;
+ if( (checksum!=0xaafe4ebd) || dspace[0] || dspace[1] )
+ {
+ PyErr_SetString(PyExc_SystemError,
+ "Blowfish: Error in crypt_block routine");
+ return;
+ }
+
+
+ /* Xor key string into encryption key vector */
+ j = 0 ;
+ for (i=0 ; i<NROUNDS+2 ; ++i)
+ {
+ IntU32 data;
+ data = 0 ;
+ for (k=0 ; k<4 ; ++k )
+ data = (data << 8) | key_string[j++ % keylength];
+ (bfkey->p)[0][i] ^= data;
+ }
+
+
+ for (i = 0 ; i<NROUNDS+2 ; i+=2)
+ {
+ crypt_block( dspace, bfkey, 0 ) ;
+ bfkey->p[0][i] = dspace[0] ;
+ bfkey->p[1][NROUNDS+1-i] = dspace[0] ;
+ bfkey->p[0][i+1] = dspace[1] ;
+ bfkey->p[1][NROUNDS-i] = dspace[1] ;
+ }
+
+ for ( i=0 ; i<4 ; ++i )
+ for ( j=0 ; j<256 ; j+=2 )
+ {
+ crypt_block( dspace, bfkey, 0 ) ;
+ bfkey->sbox[i][j] = dspace[0] ;
+ bfkey->sbox[i][j+1] = dspace[1] ;
+ }
+}
+
+
+static inline void
+Blowfishencrypt(self, block)
+ Blowfishobject *self;
+ unsigned char *block;
+{
+ crypt_8bytes(block, block, &(self->bfkey), 0);
+}
+
+
+static inline void
+Blowfishdecrypt(self, block)
+ Blowfishobject *self;
+ unsigned char *block;
+{
+ crypt_8bytes(block, block, &(self->bfkey), 1);
+}
+
+static inline void
+Blowfishinit(self, key, keylength)
+ Blowfishobject *self;
+ unsigned char *key;
+ int keylength;
+{
+ make_bfkey(key, keylength, &(self->bfkey));
+}
diff --git a/block/CAST.c b/block/CAST.c
new file mode 100644
index 0000000..7062f3e
--- /dev/null
+++ b/block/CAST.c
@@ -0,0 +1,466 @@
+/*
+ cast.c -- implementation of CAST-128 (aka CAST5) as described in RFC2144
+
+ compile -DPCT for use in the Python Cryptography Toolkit
+ (this should work automatically)
+ compile -DTEST to include main() which performs the tests
+ specified in RFC2144
+
+ Written by Wim Lewis <wiml@hhhh.org> based entirely on RFC2144. This code
+ is in the public domain. Consult your local laws for possible restrictions
+ on use, distribution, and import/export. RFC2144 states that this
+ algorithm "is available worldwide on a royalty-free basis for commercial
+ and non-commercial uses".
+
+ This code is a pretty straightforward transliteration of the RFC into C.
+ It has not been optimized much at all: byte-order-independent arithmetic
+ operations are used where order-dependent pointer ops or unions might be
+ faster; the code could be rearranged to give the optimizer a better
+ chance to speed things up; etc.
+
+ This code requires a vaguely ANSI-ish compiler.
+
+ Tested with gcc 2.5.8 on i486, i586, i686, hp pa-risc, mc68040, sparc;
+ also with gcc 2.7.2 and (with minor changes) native Sun compiler on sparc
+
+ History:
+ 21 Jul 1997: wiml : first working version & Python module
+*/
+
+
+/* adjust these according to your compiler/platform. On some machines
+ uint32 will have to be a long. It's OK if uint32 is more than 32 bits. */
+typedef unsigned int uint32;
+typedef unsigned char uint8;
+
+#ifdef PCTObject_HEAD
+#define PCT
+#endif
+
+#ifdef PCT
+#define PCTstatic static
+#else
+#define PCTstatic
+#endif
+
+/* this struct probably belongs in cast.h */
+typedef struct {
+ /* masking and rotate keys */
+ uint32 Km[16];
+ uint8 Kr[16];
+ /* number of rounds (depends on original unpadded keylength) */
+ int rounds;
+} cast_keyschedule;
+
+/* these are the eight 32*256 S-boxes */
+#include "../block/cast5.c"
+
+/* fetch a uint32 from an array of uint8s (with a given offset) */
+#define fetch(ptr, base) (((((( ptr[base]<< 8 ) | ptr[base+1] )<< 8 ) | ptr[base+2] )<< 8 ) | ptr[base+3])
+
+/* this is the round function f(D, Km, Kr) */
+static inline uint32 castfunc(D, Kmi, Kri, type)
+ uint32 D, Kmi;
+ uint8 Kri;
+ int type;
+{
+ uint32 I, f;
+ short Ia, Ib, Ic, Id;
+
+ switch(type) {
+ case 0:
+ I = (Kmi + D) ;
+ break;
+ case 1:
+ I = (Kmi ^ D) ;
+ break;
+ default:
+ case 2:
+ I = (Kmi - D) ;
+ break;
+ }
+
+ I &= 0xFFFFFFFF;
+ I = ( I << Kri ) | ( I >> ( 32-Kri ) );
+ Ia = ( I >> 24 ) & 0xFF;
+ Ib = ( I >> 16 ) & 0xFF;
+ Ic = ( I >> 8 ) & 0xFF;
+ Id = ( I ) & 0xFF;
+
+ switch(type) {
+ case 0:
+ f = ((S1[Ia] ^ S2[Ib]) - S3[Ic]) + S4[Id];
+ break;
+ case 1:
+ f = ((S1[Ia] - S2[Ib]) + S3[Ic]) ^ S4[Id];
+ break;
+ default:
+ case 2:
+ f = ((S1[Ia] + S2[Ib]) ^ S3[Ic]) - S4[Id];
+ break;
+ }
+
+ return f;
+}
+
+/* encrypts/decrypts one block of data according to the key schedule
+ pointed to by `key'. Encrypts if decrypt=0, otherwise decrypts. */
+PCTstatic void castcrypt(key, block, decrypt)
+ cast_keyschedule *key;
+ uint8 *block;
+ int decrypt;
+{
+ uint32 L, R, tmp, f;
+ uint32 Kmi;
+ uint8 Kri;
+ short functype, round;
+
+ L = fetch(block, 0);
+ R = fetch(block, 4);
+
+/* printf("L0 = %08x R0 = %08x\n", L, R); */
+
+ for(round = 0; round < key->rounds; round ++) {
+
+ if (!decrypt) {
+ Kmi = key->Km[round];
+ Kri = key->Kr[round];
+ functype = round % 3;
+ } else {
+ Kmi = key->Km[(key->rounds) - round - 1];
+ Kri = key->Kr[(key->rounds) - round - 1];
+ functype = (((key->rounds) - round - 1) % 3);
+ }
+
+ f = castfunc(R, Kmi, Kri, functype);
+
+ tmp = L;
+ L = R;
+ R = tmp ^ f;
+
+/* printf("L%d = %08x R%d = %08x\n", round+1, L, round+1, R); */
+ }
+
+ block[0] = ( R & 0xFF000000 ) >> 24;
+ block[1] = ( R & 0x00FF0000 ) >> 16;
+ block[2] = ( R & 0x0000FF00 ) >> 8;
+ block[3] = ( R & 0x000000FF );
+ block[4] = ( L & 0xFF000000 ) >> 24;
+ block[5] = ( L & 0x00FF0000 ) >> 16;
+ block[6] = ( L & 0x0000FF00 ) >> 8;
+ block[7] = ( L & 0x000000FF );
+}
+
+/* fetch a uint8 from an array of uint32s */
+#define b(a,n) (((a)[n/4] >> (24-((n&3)*8))) & 0xFF)
+
+/* key schedule round functions */
+
+#define XZRound(T, F, ki1, ki2, ki3, ki4, \
+ si11, si12, si13, si14, si15,\
+ si25,\
+ si35,\
+ si45 ) \
+ T[0] = F[ki1] ^ S5[si11 ] ^ S6[si12 ] ^ S7[si13 ] ^ S8[si14 ] ^ S7[si15];\
+ T[1] = F[ki2] ^ S5[b(T, 0)] ^ S6[b(T,2)] ^ S7[b(T, 1)] ^ S8[b(T,3)] ^ S8[si25];\
+ T[2] = F[ki3] ^ S5[b(T, 7)] ^ S6[b(T,6)] ^ S7[b(T, 5)] ^ S8[b(T,4)] ^ S5[si35];\
+ T[3] = F[ki4] ^ S5[b(T,10)] ^ S6[b(T,9)] ^ S7[b(T,11)] ^ S8[b(T,8)] ^ S6[si45];
+
+#define zxround() XZRound(z, x, 0, 2, 3, 1, \
+ b(x,13), b(x,15), b(x,12), b(x,14),\
+ b(x, 8), b(x,10), b(x, 9), b(x,11))
+
+#define xzround() XZRound(x, z, 2, 0, 1, 3, \
+ b(z,5), b(z,7), b(z,4), b(z,6), \
+ b(z,0), b(z,2), b(z,1), b(z,3))
+
+#define Kround(T, base, F,\
+ i11, i12, i13, i14, i15,\
+ i21, i22, i23, i24, i25,\
+ i31, i32, i33, i34, i35,\
+ i41, i42, i43, i44, i45)\
+ T[base+0] = S5[b(F,i11)] ^ S6[b(F,i12)] ^ S7[b(F,i13)] ^ S8[b(F,i14)] ^ S5[b(F,i15)];\
+ T[base+1] = S5[b(F,i21)] ^ S6[b(F,i22)] ^ S7[b(F,i23)] ^ S8[b(F,i24)] ^ S6[b(F,i25)];\
+ T[base+2] = S5[b(F,i31)] ^ S6[b(F,i32)] ^ S7[b(F,i33)] ^ S8[b(F,i34)] ^ S7[b(F,i35)];\
+ T[base+3] = S5[b(F,i41)] ^ S6[b(F,i42)] ^ S7[b(F,i43)] ^ S8[b(F,i44)] ^ S8[b(F,i45)];
+
+/* generates sixteen 32-bit subkeys based on a 4x32-bit input key;
+ modifies the input key *in as well. */
+static void schedulekeys_half(in, keys)
+ uint32 *in;
+ uint32 *keys;
+{
+ uint32 x[4], z[4];
+
+ x[0] = in[0];
+ x[1] = in[1];
+ x[2] = in[2];
+ x[3] = in[3];
+
+ zxround();
+ Kround(keys, 0, z,
+ 8, 9, 7, 6, 2,
+ 10, 11, 5, 4, 6,
+ 12, 13, 3, 2, 9,
+ 14, 15, 1, 0, 12);
+ xzround();
+ Kround(keys, 4, x,
+ 3, 2, 12, 13, 8,
+ 1, 0, 14, 15, 13,
+ 7, 6, 8, 9, 3,
+ 5, 4, 10, 11, 7);
+ zxround();
+ Kround(keys, 8, z,
+ 3, 2, 12, 13, 9,
+ 1, 0, 14, 15, 12,
+ 7, 6, 8, 9, 2,
+ 5, 4, 10, 11, 6);
+ xzround();
+ Kround(keys, 12, x,
+ 8, 9, 7, 6, 3,
+ 10, 11, 5, 4, 7,
+ 12, 13, 3, 2, 8,
+ 14, 15, 1, 0, 13);
+
+ in[0] = x[0];
+ in[1] = x[1];
+ in[2] = x[2];
+ in[3] = x[3];
+}
+
+/* generates a key schedule from an input key */
+PCTstatic void castschedulekeys(schedule, key, keybytes)
+ cast_keyschedule *schedule;
+ uint8 *key;
+ int keybytes;
+{
+ uint32 x[4];
+ uint8 paddedkey[16];
+ uint32 Kr_wide[16];
+ int i;
+
+ for(i = 0; i < keybytes; i++)
+ paddedkey[i] = key[i];
+ for( ; i < 16 ; i++)
+ paddedkey[i] = 0;
+
+ if (keybytes <= 10)
+ schedule->rounds = 12;
+ else
+ schedule->rounds = 16;
+
+ x[0] = fetch(paddedkey, 0);
+ x[1] = fetch(paddedkey, 4);
+ x[2] = fetch(paddedkey, 8);
+ x[3] = fetch(paddedkey, 12);
+
+ schedulekeys_half(x, schedule->Km);
+ schedulekeys_half(x, Kr_wide);
+
+ for(i = 0; i < 16; i ++) {
+ /* The Kr[] subkeys are used for 32-bit circular shifts,
+ so we only need to keep them modulo 32 */
+ schedule->Kr[i] = (uint8)(Kr_wide[i] & 0x1F);
+ }
+}
+
+#ifdef TEST
+
+/* This performs a variety of encryptions and verifies that the results
+ match those specified in RFC2144 appendix B. Also verifies that
+ decryption restores the original data. */
+
+#include <stdio.h>
+
+static cast_keyschedule sched;
+
+void encrypt(key, keylen, in, out)
+ uint8 *key;
+ int keylen;
+ uint8 *in, *out;
+{
+ int i;
+ uint8 k[16];
+
+ castschedulekeys(&sched, key, keylen);
+
+ for(i = 0; i < 8; i++)
+ out[i] = in[i];
+ castcrypt(&sched, out, 0);
+}
+
+void tst(key, keylen, data, result)
+ uint8 *key;
+ int keylen;
+ uint8 *data, *result;
+{
+ uint8 d[8];
+ int i;
+
+ encrypt(key, keylen, data, d);
+
+ for(i = 0; i < 8; i++)
+ if (d[i] != result[i])
+ break;
+
+ if (i == 8) {
+ printf("-- test ok (encrypt)\n");
+ } else {
+ for(i = 0; i < 8; i++)
+ printf(" %02x", d[i]);
+ printf(" (computed)\n");
+ for(i = 0; i < 8; i++)
+ printf(" %02x", result[i]);
+ printf(" (expected)\n");
+ }
+
+ /* uses key schedule already set up */
+ castcrypt(&sched, d, 1);
+ if (bcmp(d, data, 8))
+ printf(" test FAILED (decrypt)\n");
+ else
+ printf(" test ok (decrypt)\n");
+
+}
+
+uint8 key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+ 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A };
+uint8 data[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
+
+/* expected results of encrypting the above with 128, 80, and 40
+ bits of key length */
+uint8 out1[8] = { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
+uint8 out2[8] = { 0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B };
+uint8 out3[8] = { 0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E };
+
+/* expected results of the "full maintenance test" */
+uint8 afinal[16] = { 0xEE, 0xA9, 0xD0, 0xA2, 0x49, 0xFD, 0x3B, 0xA6,
+ 0xB3, 0x43, 0x6F, 0xB8, 0x9D, 0x6D, 0xCA, 0x92 };
+uint8 bfinal[16] = { 0xB2, 0xC9, 0x5E, 0xB0, 0x0C, 0x31, 0xAD, 0x71,
+ 0x80, 0xAC, 0x05, 0xB8, 0xE8, 0x3D, 0x69, 0x6E };
+
+main()
+{
+ /* Appendix B.1 : Single Plaintext-Key-Ciphertext Sets */
+ tst(key, 16, data, out1);
+ tst(key, 10, data, out2);
+ tst(key, 5, data, out3);
+
+ /* Appendix B.2 : Full Maintenance Test */
+ {
+ uint8 abuf[16];
+ uint8 bbuf[16];
+ int i;
+
+ bcopy(key, abuf, 16);
+ bcopy(key, bbuf, 16);
+
+ printf("\nrunning full maintenance test...\n");
+
+ for(i = 0; i < 1000000; i++) {
+ castschedulekeys(&sched, bbuf, 16);
+ castcrypt(&sched, abuf, 0);
+ castcrypt(&sched, abuf+8, 0);
+
+ castschedulekeys(&sched, abuf, 16);
+ castcrypt(&sched, bbuf, 0);
+ castcrypt(&sched, bbuf+8, 0);
+
+ if (!(i % 10000)) {
+ fprintf(stdout, "\r%d%% ", i / 10000);
+ fflush(stdout);
+ }
+ }
+
+ printf("\r \r");
+
+ for(i = 0; i < 16; i ++)
+ if (abuf[i] != afinal[i] || bbuf[i] != bfinal[i])
+ break;
+
+ if(i == 16) {
+ printf("-- full maintenance test ok\n");
+ } else {
+ for(i = 0; i < 16; i++)
+ printf(" %02x", abuf[i]);
+ printf("\n");
+ for(i = 0; i < 16; i++)
+ printf(" %02x", bbuf[i]);
+ printf("\n");
+ }
+
+ printf("running maintenance test in reverse...\n");
+ for(i = 0; i < 1000000; i++) {
+ castschedulekeys(&sched, abuf, 16);
+ castcrypt(&sched, bbuf+8, 1);
+ castcrypt(&sched, bbuf, 1);
+
+ castschedulekeys(&sched, bbuf, 16);
+ castcrypt(&sched, abuf+8, 1);
+ castcrypt(&sched, abuf, 1);
+
+ if (!(i % 10000)) {
+ fprintf(stdout, "\r%d%% ", i / 10000);
+ fflush(stdout);
+ }
+ }
+
+ printf("\r \r");
+ if (bcmp(abuf, key, 16) || bcmp(bbuf, key, 16))
+ printf("-- reverse maintenance test FAILED\n");
+ else
+ printf("-- reverse maintenance test ok\n");
+ }
+}
+
+#endif
+
+#ifdef PCT
+
+/* code to interface with the Python Cryptography Toolkit */
+
+typedef struct
+{
+ PCTObject_HEAD
+ cast_keyschedule schedule;
+} CASTobject;
+
+static void
+CASTinit(self, key, keylength)
+ CASTobject *self;
+ unsigned char *key;
+ int keylength;
+{
+ /* presumably this will optimize out */
+ if (sizeof(uint32) < 4 || sizeof(uint8) != 1) {
+ PyErr_SetString(PyExc_SystemError,
+ "CAST module compiled with bad typedefs!");
+ }
+
+ /* make sure the key length is within bounds */
+ if (keylength < 5 || keylength > 16) {
+ PyErr_SetString(PyExc_ValueError, "CAST key must be "
+ "at least 5 bytes and no more than 16 bytes long");
+ return;
+ }
+
+ /* do the actual key schedule setup */
+ castschedulekeys(&(self->schedule), key, keylength);
+}
+
+static void
+CASTencrypt(self, block)
+ CASTobject *self;
+ unsigned char *block;
+{
+ castcrypt(&(self->schedule), block, 0);
+}
+
+static void CASTdecrypt(self, block)
+ CASTobject *self;
+ unsigned char *block;
+{
+ castcrypt(&(self->schedule), block, 1);
+}
+
+#endif
diff --git a/block/DES.c b/block/DES.c
new file mode 100644
index 0000000..c79fa62
--- /dev/null
+++ b/block/DES.c
@@ -0,0 +1,678 @@
+
+/*
+ * des.c : Source code for the DES block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+/* des.c */
+/* Copyright (C) 1993 Eric Young */
+/* Integrated into the PCT by A.M. Kuchling, November 1994 */
+
+typedef unsigned char des_cblock[8];
+
+/* ecb_enc.c */
+/* Copyright (C) 1993 Eric Young - see README for more details */
+
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<<24)
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2|=((unsigned long)(*(--(c))))<<24; \
+ case 7: l2|=((unsigned long)(*(--(c))))<<16; \
+ case 6: l2|=((unsigned long)(*(--(c))))<< 8; \
+ case 5: l2|=((unsigned long)(*(--(c)))); \
+ case 4: l1|=((unsigned long)(*(--(c))))<<24; \
+ case 3: l1|=((unsigned long)(*(--(c))))<<16; \
+ case 2: l1|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l1|=((unsigned long)(*(--(c)))); \
+ } \
+ }
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+/* replacements for htonl and ntohl since I have no idea what to do
+ * when faced with machines with 8 byte longs. */
+#define HDRSIZE 4
+
+#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++))))
+
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+#define D_ENCRYPT(L,R,S) \
+ u=(R^s[S ]); \
+ t=R^s[S+1]; \
+ t=((t>>4)+(t<<28)); \
+ L^= des_SPtrans[1][(t )&0x3f]| \
+ des_SPtrans[3][(t>> 8)&0x3f]| \
+ des_SPtrans[5][(t>>16)&0x3f]| \
+ des_SPtrans[7][(t>>24)&0x3f]| \
+ des_SPtrans[0][(u )&0x3f]| \
+ des_SPtrans[2][(u>> 8)&0x3f]| \
+ des_SPtrans[4][(u>>16)&0x3f]| \
+ des_SPtrans[6][(u>>24)&0x3f];
+
+ /* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+ The output has been subject to swaps of the form
+ 0 1 -> 3 1 but the odd and even bits have been put into
+ 2 3 2 0
+ different words. The main trick is to remember that
+ t=((l>>size)^r)&(mask);
+ r^=t;
+ l^=(t<<size);
+ can be used to swap and move bits between words.
+
+ So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+ becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+ Thanks for hints from Richard Outerbridge - he told me IP&FP
+ could be done in 15 xor, 10 shifts and 5 ands.
+ When I finally started to think of the problem in 2D
+ I first got ~42 operations without xors. When I remembered
+ how to use xors :-) I got it to its final state.
+ */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+
+
+/* spr.h */
+/* Copyright (C) 1993 Eric Young - see README for more details */
+static unsigned long des_SPtrans[8][64]={
+/* nibble 0 */
+{0x00820200, 0x00020000, 0x80800000, 0x80820200,
+0x00800000, 0x80020200, 0x80020000, 0x80800000,
+0x80020200, 0x00820200, 0x00820000, 0x80000200,
+0x80800200, 0x00800000, 0x00000000, 0x80020000,
+0x00020000, 0x80000000, 0x00800200, 0x00020200,
+0x80820200, 0x00820000, 0x80000200, 0x00800200,
+0x80000000, 0x00000200, 0x00020200, 0x80820000,
+0x00000200, 0x80800200, 0x80820000, 0x00000000,
+0x00000000, 0x80820200, 0x00800200, 0x80020000,
+0x00820200, 0x00020000, 0x80000200, 0x00800200,
+0x80820000, 0x00000200, 0x00020200, 0x80800000,
+0x80020200, 0x80000000, 0x80800000, 0x00820000,
+0x80820200, 0x00020200, 0x00820000, 0x80800200,
+0x00800000, 0x80000200, 0x80020000, 0x00000000,
+0x00020000, 0x00800000, 0x80800200, 0x00820200,
+0x80000000, 0x80820000, 0x00000200, 0x80020200},
+
+/* nibble 1 */
+{0x10042004, 0x00000000, 0x00042000, 0x10040000,
+0x10000004, 0x00002004, 0x10002000, 0x00042000,
+0x00002000, 0x10040004, 0x00000004, 0x10002000,
+0x00040004, 0x10042000, 0x10040000, 0x00000004,
+0x00040000, 0x10002004, 0x10040004, 0x00002000,
+0x00042004, 0x10000000, 0x00000000, 0x00040004,
+0x10002004, 0x00042004, 0x10042000, 0x10000004,
+0x10000000, 0x00040000, 0x00002004, 0x10042004,
+0x00040004, 0x10042000, 0x10002000, 0x00042004,
+0x10042004, 0x00040004, 0x10000004, 0x00000000,
+0x10000000, 0x00002004, 0x00040000, 0x10040004,
+0x00002000, 0x10000000, 0x00042004, 0x10002004,
+0x10042000, 0x00002000, 0x00000000, 0x10000004,
+0x00000004, 0x10042004, 0x00042000, 0x10040000,
+0x10040004, 0x00040000, 0x00002004, 0x10002000,
+0x10002004, 0x00000004, 0x10040000, 0x00042000},
+
+/* nibble 2 */
+{0x41000000, 0x01010040, 0x00000040, 0x41000040,
+0x40010000, 0x01000000, 0x41000040, 0x00010040,
+0x01000040, 0x00010000, 0x01010000, 0x40000000,
+0x41010040, 0x40000040, 0x40000000, 0x41010000,
+0x00000000, 0x40010000, 0x01010040, 0x00000040,
+0x40000040, 0x41010040, 0x00010000, 0x41000000,
+0x41010000, 0x01000040, 0x40010040, 0x01010000,
+0x00010040, 0x00000000, 0x01000000, 0x40010040,
+0x01010040, 0x00000040, 0x40000000, 0x00010000,
+0x40000040, 0x40010000, 0x01010000, 0x41000040,
+0x00000000, 0x01010040, 0x00010040, 0x41010000,
+0x40010000, 0x01000000, 0x41010040, 0x40000000,
+0x40010040, 0x41000000, 0x01000000, 0x41010040,
+0x00010000, 0x01000040, 0x41000040, 0x00010040,
+0x01000040, 0x00000000, 0x41010000, 0x40000040,
+0x41000000, 0x40010040, 0x00000040, 0x01010000},
+
+/* nibble 3 */
+{0x00100402, 0x04000400, 0x00000002, 0x04100402,
+0x00000000, 0x04100000, 0x04000402, 0x00100002,
+0x04100400, 0x04000002, 0x04000000, 0x00000402,
+0x04000002, 0x00100402, 0x00100000, 0x04000000,
+0x04100002, 0x00100400, 0x00000400, 0x00000002,
+0x00100400, 0x04000402, 0x04100000, 0x00000400,
+0x00000402, 0x00000000, 0x00100002, 0x04100400,
+0x04000400, 0x04100002, 0x04100402, 0x00100000,
+0x04100002, 0x00000402, 0x00100000, 0x04000002,
+0x00100400, 0x04000400, 0x00000002, 0x04100000,
+0x04000402, 0x00000000, 0x00000400, 0x00100002,
+0x00000000, 0x04100002, 0x04100400, 0x00000400,
+0x04000000, 0x04100402, 0x00100402, 0x00100000,
+0x04100402, 0x00000002, 0x04000400, 0x00100402,
+0x00100002, 0x00100400, 0x04100000, 0x04000402,
+0x00000402, 0x04000000, 0x04000002, 0x04100400},
+
+/* nibble 4 */
+{0x02000000, 0x00004000, 0x00000100, 0x02004108,
+0x02004008, 0x02000100, 0x00004108, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x00004100,
+0x02000108, 0x02004008, 0x02004100, 0x00000000,
+0x00004100, 0x02000000, 0x00004008, 0x00000108,
+0x02000100, 0x00004108, 0x00000000, 0x02000008,
+0x00000008, 0x02000108, 0x02004108, 0x00004008,
+0x02004000, 0x00000100, 0x00000108, 0x02004100,
+0x02004100, 0x02000108, 0x00004008, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x02000100,
+0x02000000, 0x00004100, 0x02004108, 0x00000000,
+0x00004108, 0x02000000, 0x00000100, 0x00004008,
+0x02000108, 0x00000100, 0x00000000, 0x02004108,
+0x02004008, 0x02004100, 0x00000108, 0x00004000,
+0x00004100, 0x02004008, 0x02000100, 0x00000108,
+0x00000008, 0x00004108, 0x02004000, 0x02000008},
+
+/* nibble 5 */
+{0x20000010, 0x00080010, 0x00000000, 0x20080800,
+0x00080010, 0x00000800, 0x20000810, 0x00080000,
+0x00000810, 0x20080810, 0x00080800, 0x20000000,
+0x20000800, 0x20000010, 0x20080000, 0x00080810,
+0x00080000, 0x20000810, 0x20080010, 0x00000000,
+0x00000800, 0x00000010, 0x20080800, 0x20080010,
+0x20080810, 0x20080000, 0x20000000, 0x00000810,
+0x00000010, 0x00080800, 0x00080810, 0x20000800,
+0x00000810, 0x20000000, 0x20000800, 0x00080810,
+0x20080800, 0x00080010, 0x00000000, 0x20000800,
+0x20000000, 0x00000800, 0x20080010, 0x00080000,
+0x00080010, 0x20080810, 0x00080800, 0x00000010,
+0x20080810, 0x00080800, 0x00080000, 0x20000810,
+0x20000010, 0x20080000, 0x00080810, 0x00000000,
+0x00000800, 0x20000010, 0x20000810, 0x20080800,
+0x20080000, 0x00000810, 0x00000010, 0x20080010},
+
+/* nibble 6 */
+{0x00001000, 0x00000080, 0x00400080, 0x00400001,
+0x00401081, 0x00001001, 0x00001080, 0x00000000,
+0x00400000, 0x00400081, 0x00000081, 0x00401000,
+0x00000001, 0x00401080, 0x00401000, 0x00000081,
+0x00400081, 0x00001000, 0x00001001, 0x00401081,
+0x00000000, 0x00400080, 0x00400001, 0x00001080,
+0x00401001, 0x00001081, 0x00401080, 0x00000001,
+0x00001081, 0x00401001, 0x00000080, 0x00400000,
+0x00001081, 0x00401000, 0x00401001, 0x00000081,
+0x00001000, 0x00000080, 0x00400000, 0x00401001,
+0x00400081, 0x00001081, 0x00001080, 0x00000000,
+0x00000080, 0x00400001, 0x00000001, 0x00400080,
+0x00000000, 0x00400081, 0x00400080, 0x00001080,
+0x00000081, 0x00001000, 0x00401081, 0x00400000,
+0x00401080, 0x00000001, 0x00001001, 0x00401081,
+0x00400001, 0x00401080, 0x00401000, 0x00001001},
+
+/* nibble 7 */
+{0x08200020, 0x08208000, 0x00008020, 0x00000000,
+0x08008000, 0x00200020, 0x08200000, 0x08208020,
+0x00000020, 0x08000000, 0x00208000, 0x00008020,
+0x00208020, 0x08008020, 0x08000020, 0x08200000,
+0x00008000, 0x00208020, 0x00200020, 0x08008000,
+0x08208020, 0x08000020, 0x00000000, 0x00208000,
+0x08000000, 0x00200000, 0x08008020, 0x08200020,
+0x00200000, 0x00008000, 0x08208000, 0x00000020,
+0x00200000, 0x00008000, 0x08000020, 0x08208020,
+0x00008020, 0x08000000, 0x00000000, 0x00208000,
+0x08200020, 0x08008020, 0x08008000, 0x00200020,
+0x08208000, 0x00000020, 0x00200020, 0x08008000,
+0x08208020, 0x00200000, 0x08200000, 0x08000020,
+0x00208000, 0x00008020, 0x08008020, 0x08200000,
+0x00000020, 0x08208000, 0x00208020, 0x00000000,
+0x08000000, 0x08200020, 0x00008000, 0x00208020}};
+
+static unsigned long des_skb[8][64]={
+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{0x00000000,0x00000010,0x20000000,0x20000010,
+0x00010000,0x00010010,0x20010000,0x20010010,
+0x00000800,0x00000810,0x20000800,0x20000810,
+0x00010800,0x00010810,0x20010800,0x20010810,
+0x00000020,0x00000030,0x20000020,0x20000030,
+0x00010020,0x00010030,0x20010020,0x20010030,
+0x00000820,0x00000830,0x20000820,0x20000830,
+0x00010820,0x00010830,0x20010820,0x20010830,
+0x00080000,0x00080010,0x20080000,0x20080010,
+0x00090000,0x00090010,0x20090000,0x20090010,
+0x00080800,0x00080810,0x20080800,0x20080810,
+0x00090800,0x00090810,0x20090800,0x20090810,
+0x00080020,0x00080030,0x20080020,0x20080030,
+0x00090020,0x00090030,0x20090020,0x20090030,
+0x00080820,0x00080830,0x20080820,0x20080830,
+0x00090820,0x00090830,0x20090820,0x20090830},
+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+{0x00000000,0x02000000,0x00002000,0x02002000,
+0x00200000,0x02200000,0x00202000,0x02202000,
+0x00000004,0x02000004,0x00002004,0x02002004,
+0x00200004,0x02200004,0x00202004,0x02202004,
+0x00000400,0x02000400,0x00002400,0x02002400,
+0x00200400,0x02200400,0x00202400,0x02202400,
+0x00000404,0x02000404,0x00002404,0x02002404,
+0x00200404,0x02200404,0x00202404,0x02202404,
+0x10000000,0x12000000,0x10002000,0x12002000,
+0x10200000,0x12200000,0x10202000,0x12202000,
+0x10000004,0x12000004,0x10002004,0x12002004,
+0x10200004,0x12200004,0x10202004,0x12202004,
+0x10000400,0x12000400,0x10002400,0x12002400,
+0x10200400,0x12200400,0x10202400,0x12202400,
+0x10000404,0x12000404,0x10002404,0x12002404,
+0x10200404,0x12200404,0x10202404,0x12202404},
+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+{0x00000000,0x00000001,0x00040000,0x00040001,
+0x01000000,0x01000001,0x01040000,0x01040001,
+0x00000002,0x00000003,0x00040002,0x00040003,
+0x01000002,0x01000003,0x01040002,0x01040003,
+0x00000200,0x00000201,0x00040200,0x00040201,
+0x01000200,0x01000201,0x01040200,0x01040201,
+0x00000202,0x00000203,0x00040202,0x00040203,
+0x01000202,0x01000203,0x01040202,0x01040203,
+0x08000000,0x08000001,0x08040000,0x08040001,
+0x09000000,0x09000001,0x09040000,0x09040001,
+0x08000002,0x08000003,0x08040002,0x08040003,
+0x09000002,0x09000003,0x09040002,0x09040003,
+0x08000200,0x08000201,0x08040200,0x08040201,
+0x09000200,0x09000201,0x09040200,0x09040201,
+0x08000202,0x08000203,0x08040202,0x08040203,
+0x09000202,0x09000203,0x09040202,0x09040203},
+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+{0x00000000,0x00100000,0x00000100,0x00100100,
+0x00000008,0x00100008,0x00000108,0x00100108,
+0x00001000,0x00101000,0x00001100,0x00101100,
+0x00001008,0x00101008,0x00001108,0x00101108,
+0x04000000,0x04100000,0x04000100,0x04100100,
+0x04000008,0x04100008,0x04000108,0x04100108,
+0x04001000,0x04101000,0x04001100,0x04101100,
+0x04001008,0x04101008,0x04001108,0x04101108,
+0x00020000,0x00120000,0x00020100,0x00120100,
+0x00020008,0x00120008,0x00020108,0x00120108,
+0x00021000,0x00121000,0x00021100,0x00121100,
+0x00021008,0x00121008,0x00021108,0x00121108,
+0x04020000,0x04120000,0x04020100,0x04120100,
+0x04020008,0x04120008,0x04020108,0x04120108,
+0x04021000,0x04121000,0x04021100,0x04121100,
+0x04021008,0x04121008,0x04021108,0x04121108},
+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{0x00000000,0x10000000,0x00010000,0x10010000,
+0x00000004,0x10000004,0x00010004,0x10010004,
+0x20000000,0x30000000,0x20010000,0x30010000,
+0x20000004,0x30000004,0x20010004,0x30010004,
+0x00100000,0x10100000,0x00110000,0x10110000,
+0x00100004,0x10100004,0x00110004,0x10110004,
+0x20100000,0x30100000,0x20110000,0x30110000,
+0x20100004,0x30100004,0x20110004,0x30110004,
+0x00001000,0x10001000,0x00011000,0x10011000,
+0x00001004,0x10001004,0x00011004,0x10011004,
+0x20001000,0x30001000,0x20011000,0x30011000,
+0x20001004,0x30001004,0x20011004,0x30011004,
+0x00101000,0x10101000,0x00111000,0x10111000,
+0x00101004,0x10101004,0x00111004,0x10111004,
+0x20101000,0x30101000,0x20111000,0x30111000,
+0x20101004,0x30101004,0x20111004,0x30111004},
+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+{0x00000000,0x08000000,0x00000008,0x08000008,
+0x00000400,0x08000400,0x00000408,0x08000408,
+0x00020000,0x08020000,0x00020008,0x08020008,
+0x00020400,0x08020400,0x00020408,0x08020408,
+0x00000001,0x08000001,0x00000009,0x08000009,
+0x00000401,0x08000401,0x00000409,0x08000409,
+0x00020001,0x08020001,0x00020009,0x08020009,
+0x00020401,0x08020401,0x00020409,0x08020409,
+0x02000000,0x0A000000,0x02000008,0x0A000008,
+0x02000400,0x0A000400,0x02000408,0x0A000408,
+0x02020000,0x0A020000,0x02020008,0x0A020008,
+0x02020400,0x0A020400,0x02020408,0x0A020408,
+0x02000001,0x0A000001,0x02000009,0x0A000009,
+0x02000401,0x0A000401,0x02000409,0x0A000409,
+0x02020001,0x0A020001,0x02020009,0x0A020009,
+0x02020401,0x0A020401,0x02020409,0x0A020409},
+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+{0x00000000,0x00000100,0x00080000,0x00080100,
+0x01000000,0x01000100,0x01080000,0x01080100,
+0x00000010,0x00000110,0x00080010,0x00080110,
+0x01000010,0x01000110,0x01080010,0x01080110,
+0x00200000,0x00200100,0x00280000,0x00280100,
+0x01200000,0x01200100,0x01280000,0x01280100,
+0x00200010,0x00200110,0x00280010,0x00280110,
+0x01200010,0x01200110,0x01280010,0x01280110,
+0x00000200,0x00000300,0x00080200,0x00080300,
+0x01000200,0x01000300,0x01080200,0x01080300,
+0x00000210,0x00000310,0x00080210,0x00080310,
+0x01000210,0x01000310,0x01080210,0x01080310,
+0x00200200,0x00200300,0x00280200,0x00280300,
+0x01200200,0x01200300,0x01280200,0x01280300,
+0x00200210,0x00200310,0x00280210,0x00280310,
+0x01200210,0x01200310,0x01280210,0x01280310},
+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+{0x00000000,0x04000000,0x00040000,0x04040000,
+0x00000002,0x04000002,0x00040002,0x04040002,
+0x00002000,0x04002000,0x00042000,0x04042000,
+0x00002002,0x04002002,0x00042002,0x04042002,
+0x00000020,0x04000020,0x00040020,0x04040020,
+0x00000022,0x04000022,0x00040022,0x04040022,
+0x00002020,0x04002020,0x00042020,0x04042020,
+0x00002022,0x04002022,0x00042022,0x04042022,
+0x00000800,0x04000800,0x00040800,0x04040800,
+0x00000802,0x04000802,0x00040802,0x04040802,
+0x00002800,0x04002800,0x00042800,0x04042800,
+0x00002802,0x04002802,0x00042802,0x04042802,
+0x00000820,0x04000820,0x00040820,0x04040820,
+0x00000822,0x04000822,0x00040822,0x04040822,
+0x00002820,0x04002820,0x00042820,0x04042820,
+0x00002822,0x04002822,0x00042822,0x04042822}
+};
+
+typedef struct des_ks_struct
+ {
+ union {
+ des_cblock _;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ unsigned long pad[2];
+ } ks;
+#define _ ks._
+ } des_key_schedule[16];
+
+typedef struct
+{
+ PCTObject_HEAD
+ des_key_schedule KeySched;
+} DESobject;
+
+static int des_encrypt(input,output,ks,encrypt)
+ unsigned long *input;
+ unsigned long *output;
+ des_key_schedule ks;
+ int encrypt;
+ {
+ register unsigned long l,r,t,u;
+ register int i;
+ register unsigned long *s;
+
+ l=input[0];
+ r=input[1];
+
+ /* do IP */
+ PERM_OP(r,l,t, 4,0x0f0f0f0f);
+ PERM_OP(l,r,t,16,0x0000ffff);
+ PERM_OP(r,l,t, 2,0x33333333);
+ PERM_OP(l,r,t, 8,0x00ff00ff);
+ PERM_OP(r,l,t, 1,0x55555555);
+ /* r and l are reversed - remember that :-) - fix
+ * it in the next step */
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ t=(r<<1)|(r>>31);
+ r=(l<<1)|(l>>31);
+ l=t;
+
+ /* clear the top bits on machines with 8byte longs */
+ l&=0xffffffff;
+ r&=0xffffffff;
+
+ s=(unsigned long *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (encrypt)
+ {
+ for (i=0; i<32; i+=4)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ }
+ }
+ else
+ {
+ for (i=30; i>0; i-=4)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ }
+ }
+ l=(l>>1)|(l<<31);
+ r=(r>>1)|(r<<31);
+ /* clear the top bits on machines with 8byte longs */
+ l&=0xffffffff;
+ r&=0xffffffff;
+
+ /* swap l and r
+ * we will not do the swap so just remember they are
+ * reversed for the rest of the subroutine
+ * luckily FP fixes this problem :-) */
+
+ PERM_OP(r,l,t, 1,0x55555555);
+ PERM_OP(l,r,t, 8,0x00ff00ff);
+ PERM_OP(r,l,t, 2,0x33333333);
+ PERM_OP(l,r,t,16,0x0000ffff);
+ PERM_OP(r,l,t, 4,0x0f0f0f0f);
+
+ output[0]=l;
+ output[1]=r;
+ l=r=t=u=0;
+ return(0);
+ }
+
+static int des_ecb_encrypt(input,output,ks,encrypt)
+ des_cblock *input;
+ des_cblock *output;
+ des_key_schedule ks;
+ int encrypt;
+ {
+ register unsigned long l0,l1;
+ register unsigned char *in,*out;
+ unsigned long ll[2];
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ c2l(in,l0);
+ c2l(in,l1);
+ ll[0]=l0;
+ ll[1]=l1;
+ des_encrypt(ll,ll,ks,encrypt);
+ l0=ll[0];
+ l1=ll[1];
+ l2c(l0,out);
+ l2c(l1,out);
+ l0=l1=ll[0]=ll[1]=0;
+ return(0);
+ }
+
+
+
+static inline void DESdecrypt(self, block)
+ DESobject *self;
+ unsigned char *block;
+{
+ des_cblock output;
+
+ des_ecb_encrypt(block, output, self->KeySched, 0);
+ memcpy(block, output, 8);
+}
+
+static inline void DESencrypt(self, block)
+ DESobject *self;
+ unsigned char *block;
+{
+ des_cblock output;
+
+ des_ecb_encrypt(block, output, self->KeySched, 1);
+ memcpy(block, output, 8);
+}
+
+/* NOW DEFINED IN des_local.h
+ * See ecb_encrypt.c for a pseudo description of these macros.
+ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ * (b)^=(t),\
+ * (a)=((a)^((t)<<(n))))
+ */
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+static char shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+
+/* return 0 if key parity is odd (correct),
+ * return -1 if key parity error,
+ * return -2 if illegal weak key.
+ */
+static int des_set_key(key,schedule)
+des_cblock *key;
+des_key_schedule schedule;
+ {
+ register unsigned long c,d,t,s;
+ register unsigned char *in;
+ register unsigned long *k;
+ register int i;
+
+ k=(unsigned long *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* do PC1 in 60 simple operations */
+/* PERM_OP(d,c,t,4,0x0f0f0f0f);
+ HPERM_OP(c,t,-2, 0xcccc0000);
+ HPERM_OP(c,t,-1, 0xaaaa0000);
+ HPERM_OP(c,t, 8, 0x00ff0000);
+ HPERM_OP(c,t,-1, 0xaaaa0000);
+ HPERM_OP(d,t,-8, 0xff000000);
+ HPERM_OP(d,t, 8, 0x00ff0000);
+ HPERM_OP(d,t, 2, 0x33330000);
+ d=((d&0x00aa00aa)<<7)|((d&0x55005500)>>7)|(d&0xaa55aa55);
+ d=(d>>8)|((c&0xf0000000)>>4);
+ c&=0x0fffffff; */
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0f);
+ HPERM_OP(c,t,-2,0xcccc0000);
+ HPERM_OP(d,t,-2,0xcccc0000);
+ PERM_OP (d,c,t,1,0x55555555);
+ PERM_OP (c,d,t,8,0x00ff00ff);
+ PERM_OP (d,c,t,1,0x55555555);
+ d= (((d&0x000000ff)<<16)| (d&0x0000ff00) |
+ ((d&0x00ff0000)>>16)|((c&0xf0000000)>>4));
+ c&=0x0fffffff;
+
+ for (i=0; i<16; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2)|(c<<26)); d=((d>>2)|(d<<26)); }
+ else
+ { c=((c>>1)|(c<<27)); d=((d>>1)|(d<<27)); }
+ c&=0x0fffffff;
+ d&=0x0fffffff;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= des_skb[0][ (c )&0x3f ]|
+ des_skb[1][((c>> 6)&0x03)|((c>> 7)&0x3c)]|
+ des_skb[2][((c>>13)&0x0f)|((c>>14)&0x30)]|
+ des_skb[3][((c>>20)&0x01)|((c>>21)&0x06) |
+ ((c>>22)&0x38)];
+ t= des_skb[4][ (d )&0x3f ]|
+ des_skb[5][((d>> 7)&0x03)|((d>> 8)&0x3c)]|
+ des_skb[6][ (d>>15)&0x3f ]|
+ des_skb[7][((d>>21)&0x0f)|((d>>22)&0x30)];
+
+ /* table contained 0213 4657 */
+ *(k++)=((t<<16)|(s&0x0000ffff))&0xffffffff;
+ s= ((s>>16)|(t&0xffff0000));
+
+ s=(s<<4)|(s>>28);
+ *(k++)=s&0xffffffff;
+ }
+ return(0);
+ }
+
+static const unsigned char odd_parity[256]={
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
+
+static inline void DESinit(self, key)
+ DESobject *self;
+ unsigned char *key;
+{
+ char oddkey[8];
+ int i;
+
+ for (i=0; i<8; i++)
+ {
+ oddkey[i]=odd_parity[ key[i] ];
+ }
+ des_set_key(oddkey, self->KeySched);
+}
diff --git a/block/DES3.c b/block/DES3.c
new file mode 100644
index 0000000..24c7651
--- /dev/null
+++ b/block/DES3.c
@@ -0,0 +1,690 @@
+
+/*
+ * des.c : Source code for the DES block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+/* des.c */
+/* Copyright (C) 1993 Eric Young */
+/* Integrated into the PCT by A.M. Kuchling, November 1994 */
+/* Fully independent key mode added by Wim Lewis, July 1997 */
+
+typedef unsigned char des_cblock[8];
+
+/* ecb_enc.c */
+/* Copyright (C) 1993 Eric Young - see README for more details */
+
+#define c2l(c,l) (l =((unsigned long)(*((c)++))) , \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<<24)
+
+/* NOTE - c is not incremented as per c2l */
+#define c2ln(c,l1,l2,n) { \
+ c+=n; \
+ l1=l2=0; \
+ switch (n) { \
+ case 8: l2|=((unsigned long)(*(--(c))))<<24; \
+ case 7: l2|=((unsigned long)(*(--(c))))<<16; \
+ case 6: l2|=((unsigned long)(*(--(c))))<< 8; \
+ case 5: l2|=((unsigned long)(*(--(c)))); \
+ case 4: l1|=((unsigned long)(*(--(c))))<<24; \
+ case 3: l1|=((unsigned long)(*(--(c))))<<16; \
+ case 2: l1|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l1|=((unsigned long)(*(--(c)))); \
+ } \
+ }
+
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+/* replacements for htonl and ntohl since I have no idea what to do
+ * when faced with machines with 8 byte longs. */
+#define HDRSIZE 4
+
+#define n2l(c,l) (l =((unsigned long)(*((c)++)))<<24, \
+ l|=((unsigned long)(*((c)++)))<<16, \
+ l|=((unsigned long)(*((c)++)))<< 8, \
+ l|=((unsigned long)(*((c)++))))
+
+#define l2n(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l) )&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+#define D_ENCRYPT(L,R,S) \
+ u=(R^s[S ]); \
+ t=R^s[S+1]; \
+ t=((t>>4)+(t<<28)); \
+ L^= des_SPtrans[1][(t )&0x3f]| \
+ des_SPtrans[3][(t>> 8)&0x3f]| \
+ des_SPtrans[5][(t>>16)&0x3f]| \
+ des_SPtrans[7][(t>>24)&0x3f]| \
+ des_SPtrans[0][(u )&0x3f]| \
+ des_SPtrans[2][(u>> 8)&0x3f]| \
+ des_SPtrans[4][(u>>16)&0x3f]| \
+ des_SPtrans[6][(u>>24)&0x3f];
+
+ /* IP and FP
+ * The problem is more of a geometric problem that random bit fiddling.
+ 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6
+ 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4
+ 16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2
+ 24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0
+
+ 32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7
+ 40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5
+ 48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3
+ 56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1
+
+ The output has been subject to swaps of the form
+ 0 1 -> 3 1 but the odd and even bits have been put into
+ 2 3 2 0
+ different words. The main trick is to remember that
+ t=((l>>size)^r)&(mask);
+ r^=t;
+ l^=(t<<size);
+ can be used to swap and move bits between words.
+
+ So l = 0 1 2 3 r = 16 17 18 19
+ 4 5 6 7 20 21 22 23
+ 8 9 10 11 24 25 26 27
+ 12 13 14 15 28 29 30 31
+ becomes (for size == 2 and mask == 0x3333)
+ t = 2^16 3^17 -- -- l = 0 1 16 17 r = 2 3 18 19
+ 6^20 7^21 -- -- 4 5 20 21 6 7 22 23
+ 10^24 11^25 -- -- 8 9 24 25 10 11 24 25
+ 14^28 15^29 -- -- 12 13 28 29 14 15 28 29
+
+ Thanks for hints from Richard Outerbridge - he told me IP&FP
+ could be done in 15 xor, 10 shifts and 5 ands.
+ When I finally started to think of the problem in 2D
+ I first got ~42 operations without xors. When I remembered
+ how to use xors :-) I got it to its final state.
+ */
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
+
+
+
+/* spr.h */
+/* Copyright (C) 1993 Eric Young - see README for more details */
+static unsigned long des_SPtrans[8][64]={
+/* nibble 0 */
+{0x00820200, 0x00020000, 0x80800000, 0x80820200,
+0x00800000, 0x80020200, 0x80020000, 0x80800000,
+0x80020200, 0x00820200, 0x00820000, 0x80000200,
+0x80800200, 0x00800000, 0x00000000, 0x80020000,
+0x00020000, 0x80000000, 0x00800200, 0x00020200,
+0x80820200, 0x00820000, 0x80000200, 0x00800200,
+0x80000000, 0x00000200, 0x00020200, 0x80820000,
+0x00000200, 0x80800200, 0x80820000, 0x00000000,
+0x00000000, 0x80820200, 0x00800200, 0x80020000,
+0x00820200, 0x00020000, 0x80000200, 0x00800200,
+0x80820000, 0x00000200, 0x00020200, 0x80800000,
+0x80020200, 0x80000000, 0x80800000, 0x00820000,
+0x80820200, 0x00020200, 0x00820000, 0x80800200,
+0x00800000, 0x80000200, 0x80020000, 0x00000000,
+0x00020000, 0x00800000, 0x80800200, 0x00820200,
+0x80000000, 0x80820000, 0x00000200, 0x80020200},
+
+/* nibble 1 */
+{0x10042004, 0x00000000, 0x00042000, 0x10040000,
+0x10000004, 0x00002004, 0x10002000, 0x00042000,
+0x00002000, 0x10040004, 0x00000004, 0x10002000,
+0x00040004, 0x10042000, 0x10040000, 0x00000004,
+0x00040000, 0x10002004, 0x10040004, 0x00002000,
+0x00042004, 0x10000000, 0x00000000, 0x00040004,
+0x10002004, 0x00042004, 0x10042000, 0x10000004,
+0x10000000, 0x00040000, 0x00002004, 0x10042004,
+0x00040004, 0x10042000, 0x10002000, 0x00042004,
+0x10042004, 0x00040004, 0x10000004, 0x00000000,
+0x10000000, 0x00002004, 0x00040000, 0x10040004,
+0x00002000, 0x10000000, 0x00042004, 0x10002004,
+0x10042000, 0x00002000, 0x00000000, 0x10000004,
+0x00000004, 0x10042004, 0x00042000, 0x10040000,
+0x10040004, 0x00040000, 0x00002004, 0x10002000,
+0x10002004, 0x00000004, 0x10040000, 0x00042000},
+
+/* nibble 2 */
+{0x41000000, 0x01010040, 0x00000040, 0x41000040,
+0x40010000, 0x01000000, 0x41000040, 0x00010040,
+0x01000040, 0x00010000, 0x01010000, 0x40000000,
+0x41010040, 0x40000040, 0x40000000, 0x41010000,
+0x00000000, 0x40010000, 0x01010040, 0x00000040,
+0x40000040, 0x41010040, 0x00010000, 0x41000000,
+0x41010000, 0x01000040, 0x40010040, 0x01010000,
+0x00010040, 0x00000000, 0x01000000, 0x40010040,
+0x01010040, 0x00000040, 0x40000000, 0x00010000,
+0x40000040, 0x40010000, 0x01010000, 0x41000040,
+0x00000000, 0x01010040, 0x00010040, 0x41010000,
+0x40010000, 0x01000000, 0x41010040, 0x40000000,
+0x40010040, 0x41000000, 0x01000000, 0x41010040,
+0x00010000, 0x01000040, 0x41000040, 0x00010040,
+0x01000040, 0x00000000, 0x41010000, 0x40000040,
+0x41000000, 0x40010040, 0x00000040, 0x01010000},
+
+/* nibble 3 */
+{0x00100402, 0x04000400, 0x00000002, 0x04100402,
+0x00000000, 0x04100000, 0x04000402, 0x00100002,
+0x04100400, 0x04000002, 0x04000000, 0x00000402,
+0x04000002, 0x00100402, 0x00100000, 0x04000000,
+0x04100002, 0x00100400, 0x00000400, 0x00000002,
+0x00100400, 0x04000402, 0x04100000, 0x00000400,
+0x00000402, 0x00000000, 0x00100002, 0x04100400,
+0x04000400, 0x04100002, 0x04100402, 0x00100000,
+0x04100002, 0x00000402, 0x00100000, 0x04000002,
+0x00100400, 0x04000400, 0x00000002, 0x04100000,
+0x04000402, 0x00000000, 0x00000400, 0x00100002,
+0x00000000, 0x04100002, 0x04100400, 0x00000400,
+0x04000000, 0x04100402, 0x00100402, 0x00100000,
+0x04100402, 0x00000002, 0x04000400, 0x00100402,
+0x00100002, 0x00100400, 0x04100000, 0x04000402,
+0x00000402, 0x04000000, 0x04000002, 0x04100400},
+
+/* nibble 4 */
+{0x02000000, 0x00004000, 0x00000100, 0x02004108,
+0x02004008, 0x02000100, 0x00004108, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x00004100,
+0x02000108, 0x02004008, 0x02004100, 0x00000000,
+0x00004100, 0x02000000, 0x00004008, 0x00000108,
+0x02000100, 0x00004108, 0x00000000, 0x02000008,
+0x00000008, 0x02000108, 0x02004108, 0x00004008,
+0x02004000, 0x00000100, 0x00000108, 0x02004100,
+0x02004100, 0x02000108, 0x00004008, 0x02004000,
+0x00004000, 0x00000008, 0x02000008, 0x02000100,
+0x02000000, 0x00004100, 0x02004108, 0x00000000,
+0x00004108, 0x02000000, 0x00000100, 0x00004008,
+0x02000108, 0x00000100, 0x00000000, 0x02004108,
+0x02004008, 0x02004100, 0x00000108, 0x00004000,
+0x00004100, 0x02004008, 0x02000100, 0x00000108,
+0x00000008, 0x00004108, 0x02004000, 0x02000008},
+
+/* nibble 5 */
+{0x20000010, 0x00080010, 0x00000000, 0x20080800,
+0x00080010, 0x00000800, 0x20000810, 0x00080000,
+0x00000810, 0x20080810, 0x00080800, 0x20000000,
+0x20000800, 0x20000010, 0x20080000, 0x00080810,
+0x00080000, 0x20000810, 0x20080010, 0x00000000,
+0x00000800, 0x00000010, 0x20080800, 0x20080010,
+0x20080810, 0x20080000, 0x20000000, 0x00000810,
+0x00000010, 0x00080800, 0x00080810, 0x20000800,
+0x00000810, 0x20000000, 0x20000800, 0x00080810,
+0x20080800, 0x00080010, 0x00000000, 0x20000800,
+0x20000000, 0x00000800, 0x20080010, 0x00080000,
+0x00080010, 0x20080810, 0x00080800, 0x00000010,
+0x20080810, 0x00080800, 0x00080000, 0x20000810,
+0x20000010, 0x20080000, 0x00080810, 0x00000000,
+0x00000800, 0x20000010, 0x20000810, 0x20080800,
+0x20080000, 0x00000810, 0x00000010, 0x20080010},
+
+/* nibble 6 */
+{0x00001000, 0x00000080, 0x00400080, 0x00400001,
+0x00401081, 0x00001001, 0x00001080, 0x00000000,
+0x00400000, 0x00400081, 0x00000081, 0x00401000,
+0x00000001, 0x00401080, 0x00401000, 0x00000081,
+0x00400081, 0x00001000, 0x00001001, 0x00401081,
+0x00000000, 0x00400080, 0x00400001, 0x00001080,
+0x00401001, 0x00001081, 0x00401080, 0x00000001,
+0x00001081, 0x00401001, 0x00000080, 0x00400000,
+0x00001081, 0x00401000, 0x00401001, 0x00000081,
+0x00001000, 0x00000080, 0x00400000, 0x00401001,
+0x00400081, 0x00001081, 0x00001080, 0x00000000,
+0x00000080, 0x00400001, 0x00000001, 0x00400080,
+0x00000000, 0x00400081, 0x00400080, 0x00001080,
+0x00000081, 0x00001000, 0x00401081, 0x00400000,
+0x00401080, 0x00000001, 0x00001001, 0x00401081,
+0x00400001, 0x00401080, 0x00401000, 0x00001001},
+
+/* nibble 7 */
+{0x08200020, 0x08208000, 0x00008020, 0x00000000,
+0x08008000, 0x00200020, 0x08200000, 0x08208020,
+0x00000020, 0x08000000, 0x00208000, 0x00008020,
+0x00208020, 0x08008020, 0x08000020, 0x08200000,
+0x00008000, 0x00208020, 0x00200020, 0x08008000,
+0x08208020, 0x08000020, 0x00000000, 0x00208000,
+0x08000000, 0x00200000, 0x08008020, 0x08200020,
+0x00200000, 0x00008000, 0x08208000, 0x00000020,
+0x00200000, 0x00008000, 0x08000020, 0x08208020,
+0x00008020, 0x08000000, 0x00000000, 0x00208000,
+0x08200020, 0x08008020, 0x08008000, 0x00200020,
+0x08208000, 0x00000020, 0x00200020, 0x08008000,
+0x08208020, 0x00200000, 0x08200000, 0x08000020,
+0x00208000, 0x00008020, 0x08008020, 0x08200000,
+0x00000020, 0x08208000, 0x00208020, 0x00000000,
+0x08000000, 0x08200020, 0x00008000, 0x00208020}};
+
+static unsigned long des_skb[8][64]={
+/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{0x00000000,0x00000010,0x20000000,0x20000010,
+0x00010000,0x00010010,0x20010000,0x20010010,
+0x00000800,0x00000810,0x20000800,0x20000810,
+0x00010800,0x00010810,0x20010800,0x20010810,
+0x00000020,0x00000030,0x20000020,0x20000030,
+0x00010020,0x00010030,0x20010020,0x20010030,
+0x00000820,0x00000830,0x20000820,0x20000830,
+0x00010820,0x00010830,0x20010820,0x20010830,
+0x00080000,0x00080010,0x20080000,0x20080010,
+0x00090000,0x00090010,0x20090000,0x20090010,
+0x00080800,0x00080810,0x20080800,0x20080810,
+0x00090800,0x00090810,0x20090800,0x20090810,
+0x00080020,0x00080030,0x20080020,0x20080030,
+0x00090020,0x00090030,0x20090020,0x20090030,
+0x00080820,0x00080830,0x20080820,0x20080830,
+0x00090820,0x00090830,0x20090820,0x20090830},
+/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */
+{0x00000000,0x02000000,0x00002000,0x02002000,
+0x00200000,0x02200000,0x00202000,0x02202000,
+0x00000004,0x02000004,0x00002004,0x02002004,
+0x00200004,0x02200004,0x00202004,0x02202004,
+0x00000400,0x02000400,0x00002400,0x02002400,
+0x00200400,0x02200400,0x00202400,0x02202400,
+0x00000404,0x02000404,0x00002404,0x02002404,
+0x00200404,0x02200404,0x00202404,0x02202404,
+0x10000000,0x12000000,0x10002000,0x12002000,
+0x10200000,0x12200000,0x10202000,0x12202000,
+0x10000004,0x12000004,0x10002004,0x12002004,
+0x10200004,0x12200004,0x10202004,0x12202004,
+0x10000400,0x12000400,0x10002400,0x12002400,
+0x10200400,0x12200400,0x10202400,0x12202400,
+0x10000404,0x12000404,0x10002404,0x12002404,
+0x10200404,0x12200404,0x10202404,0x12202404},
+/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */
+{0x00000000,0x00000001,0x00040000,0x00040001,
+0x01000000,0x01000001,0x01040000,0x01040001,
+0x00000002,0x00000003,0x00040002,0x00040003,
+0x01000002,0x01000003,0x01040002,0x01040003,
+0x00000200,0x00000201,0x00040200,0x00040201,
+0x01000200,0x01000201,0x01040200,0x01040201,
+0x00000202,0x00000203,0x00040202,0x00040203,
+0x01000202,0x01000203,0x01040202,0x01040203,
+0x08000000,0x08000001,0x08040000,0x08040001,
+0x09000000,0x09000001,0x09040000,0x09040001,
+0x08000002,0x08000003,0x08040002,0x08040003,
+0x09000002,0x09000003,0x09040002,0x09040003,
+0x08000200,0x08000201,0x08040200,0x08040201,
+0x09000200,0x09000201,0x09040200,0x09040201,
+0x08000202,0x08000203,0x08040202,0x08040203,
+0x09000202,0x09000203,0x09040202,0x09040203},
+/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */
+{0x00000000,0x00100000,0x00000100,0x00100100,
+0x00000008,0x00100008,0x00000108,0x00100108,
+0x00001000,0x00101000,0x00001100,0x00101100,
+0x00001008,0x00101008,0x00001108,0x00101108,
+0x04000000,0x04100000,0x04000100,0x04100100,
+0x04000008,0x04100008,0x04000108,0x04100108,
+0x04001000,0x04101000,0x04001100,0x04101100,
+0x04001008,0x04101008,0x04001108,0x04101108,
+0x00020000,0x00120000,0x00020100,0x00120100,
+0x00020008,0x00120008,0x00020108,0x00120108,
+0x00021000,0x00121000,0x00021100,0x00121100,
+0x00021008,0x00121008,0x00021108,0x00121108,
+0x04020000,0x04120000,0x04020100,0x04120100,
+0x04020008,0x04120008,0x04020108,0x04120108,
+0x04021000,0x04121000,0x04021100,0x04121100,
+0x04021008,0x04121008,0x04021108,0x04121108},
+/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */
+{0x00000000,0x10000000,0x00010000,0x10010000,
+0x00000004,0x10000004,0x00010004,0x10010004,
+0x20000000,0x30000000,0x20010000,0x30010000,
+0x20000004,0x30000004,0x20010004,0x30010004,
+0x00100000,0x10100000,0x00110000,0x10110000,
+0x00100004,0x10100004,0x00110004,0x10110004,
+0x20100000,0x30100000,0x20110000,0x30110000,
+0x20100004,0x30100004,0x20110004,0x30110004,
+0x00001000,0x10001000,0x00011000,0x10011000,
+0x00001004,0x10001004,0x00011004,0x10011004,
+0x20001000,0x30001000,0x20011000,0x30011000,
+0x20001004,0x30001004,0x20011004,0x30011004,
+0x00101000,0x10101000,0x00111000,0x10111000,
+0x00101004,0x10101004,0x00111004,0x10111004,
+0x20101000,0x30101000,0x20111000,0x30111000,
+0x20101004,0x30101004,0x20111004,0x30111004},
+/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */
+{0x00000000,0x08000000,0x00000008,0x08000008,
+0x00000400,0x08000400,0x00000408,0x08000408,
+0x00020000,0x08020000,0x00020008,0x08020008,
+0x00020400,0x08020400,0x00020408,0x08020408,
+0x00000001,0x08000001,0x00000009,0x08000009,
+0x00000401,0x08000401,0x00000409,0x08000409,
+0x00020001,0x08020001,0x00020009,0x08020009,
+0x00020401,0x08020401,0x00020409,0x08020409,
+0x02000000,0x0A000000,0x02000008,0x0A000008,
+0x02000400,0x0A000400,0x02000408,0x0A000408,
+0x02020000,0x0A020000,0x02020008,0x0A020008,
+0x02020400,0x0A020400,0x02020408,0x0A020408,
+0x02000001,0x0A000001,0x02000009,0x0A000009,
+0x02000401,0x0A000401,0x02000409,0x0A000409,
+0x02020001,0x0A020001,0x02020009,0x0A020009,
+0x02020401,0x0A020401,0x02020409,0x0A020409},
+/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */
+{0x00000000,0x00000100,0x00080000,0x00080100,
+0x01000000,0x01000100,0x01080000,0x01080100,
+0x00000010,0x00000110,0x00080010,0x00080110,
+0x01000010,0x01000110,0x01080010,0x01080110,
+0x00200000,0x00200100,0x00280000,0x00280100,
+0x01200000,0x01200100,0x01280000,0x01280100,
+0x00200010,0x00200110,0x00280010,0x00280110,
+0x01200010,0x01200110,0x01280010,0x01280110,
+0x00000200,0x00000300,0x00080200,0x00080300,
+0x01000200,0x01000300,0x01080200,0x01080300,
+0x00000210,0x00000310,0x00080210,0x00080310,
+0x01000210,0x01000310,0x01080210,0x01080310,
+0x00200200,0x00200300,0x00280200,0x00280300,
+0x01200200,0x01200300,0x01280200,0x01280300,
+0x00200210,0x00200310,0x00280210,0x00280310,
+0x01200210,0x01200310,0x01280210,0x01280310},
+/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */
+{0x00000000,0x04000000,0x00040000,0x04040000,
+0x00000002,0x04000002,0x00040002,0x04040002,
+0x00002000,0x04002000,0x00042000,0x04042000,
+0x00002002,0x04002002,0x00042002,0x04042002,
+0x00000020,0x04000020,0x00040020,0x04040020,
+0x00000022,0x04000022,0x00040022,0x04040022,
+0x00002020,0x04002020,0x00042020,0x04042020,
+0x00002022,0x04002022,0x00042022,0x04042022,
+0x00000800,0x04000800,0x00040800,0x04040800,
+0x00000802,0x04000802,0x00040802,0x04040802,
+0x00002800,0x04002800,0x00042800,0x04042800,
+0x00002802,0x04002802,0x00042802,0x04042802,
+0x00000820,0x04000820,0x00040820,0x04040820,
+0x00000822,0x04000822,0x00040822,0x04040822,
+0x00002820,0x04002820,0x00042820,0x04042820,
+0x00002822,0x04002822,0x00042822,0x04042822}
+};
+
+typedef struct des_ks_struct
+ {
+ union {
+ des_cblock _;
+ /* make sure things are correct size on machines with
+ * 8 byte longs */
+ unsigned long pad[2];
+ } ks;
+#define _ ks._
+ } des_key_schedule[16];
+
+typedef struct
+{
+ PCTObject_HEAD
+ des_key_schedule KeySched1, KeySched2, KeySched3;
+} DES3object;
+
+static int des_encrypt(input,output,ks,encrypt)
+ unsigned long *input;
+ unsigned long *output;
+ des_key_schedule ks;
+ int encrypt;
+ {
+ register unsigned long l,r,t,u;
+ register int i;
+ register unsigned long *s;
+
+ l=input[0];
+ r=input[1];
+
+ /* do IP */
+ PERM_OP(r,l,t, 4,0x0f0f0f0f);
+ PERM_OP(l,r,t,16,0x0000ffff);
+ PERM_OP(r,l,t, 2,0x33333333);
+ PERM_OP(l,r,t, 8,0x00ff00ff);
+ PERM_OP(r,l,t, 1,0x55555555);
+ /* r and l are reversed - remember that :-) - fix
+ * it in the next step */
+
+ /* Things have been modified so that the initial rotate is
+ * done outside the loop. This required the
+ * des_SPtrans values in sp.h to be rotated 1 bit to the right.
+ * One perl script later and things have a 5% speed up on a sparc2.
+ * Thanks to Richard Outerbridge <71755.204@CompuServe.COM>
+ * for pointing this out. */
+ t=(r<<1)|(r>>31);
+ r=(l<<1)|(l>>31);
+ l=t;
+
+ /* clear the top bits on machines with 8byte longs */
+ l&=0xffffffff;
+ r&=0xffffffff;
+
+ s=(unsigned long *)ks;
+ /* I don't know if it is worth the effort of loop unrolling the
+ * inner loop */
+ if (encrypt)
+ {
+ for (i=0; i<32; i+=4)
+ {
+ D_ENCRYPT(l,r,i+0); /* 1 */
+ D_ENCRYPT(r,l,i+2); /* 2 */
+ }
+ }
+ else
+ {
+ for (i=30; i>0; i-=4)
+ {
+ D_ENCRYPT(l,r,i-0); /* 16 */
+ D_ENCRYPT(r,l,i-2); /* 15 */
+ }
+ }
+ l=(l>>1)|(l<<31);
+ r=(r>>1)|(r<<31);
+ /* clear the top bits on machines with 8byte longs */
+ l&=0xffffffff;
+ r&=0xffffffff;
+
+ /* swap l and r
+ * we will not do the swap so just remember they are
+ * reversed for the rest of the subroutine
+ * luckily FP fixes this problem :-) */
+
+ PERM_OP(r,l,t, 1,0x55555555);
+ PERM_OP(l,r,t, 8,0x00ff00ff);
+ PERM_OP(r,l,t, 2,0x33333333);
+ PERM_OP(l,r,t,16,0x0000ffff);
+ PERM_OP(r,l,t, 4,0x0f0f0f0f);
+
+ output[0]=l;
+ output[1]=r;
+ l=r=t=u=0;
+ return(0);
+ }
+
+static int des_ecb_encrypt(input,output,ks,encrypt)
+ des_cblock *input;
+ des_cblock *output;
+ des_key_schedule ks;
+ int encrypt;
+ {
+ register unsigned long l0,l1;
+ register unsigned char *in,*out;
+ unsigned long ll[2];
+
+ in=(unsigned char *)input;
+ out=(unsigned char *)output;
+ c2l(in,l0);
+ c2l(in,l1);
+ ll[0]=l0;
+ ll[1]=l1;
+ des_encrypt(ll,ll,ks,encrypt);
+ l0=ll[0];
+ l1=ll[1];
+ l2c(l0,out);
+ l2c(l1,out);
+ l0=l1=ll[0]=ll[1]=0;
+ return(0);
+ }
+
+
+
+static inline void DES3decrypt(self, block)
+ DES3object *self;
+ unsigned char *block;
+{
+ des_cblock output, output2;
+
+ des_ecb_encrypt(block, output, self->KeySched3, 0);
+ des_ecb_encrypt(output, output2, self->KeySched2, 1);
+ des_ecb_encrypt(output2, block, self->KeySched1, 0);
+}
+
+static inline void DES3encrypt(self, block)
+ DES3object *self;
+ unsigned char *block;
+{
+ des_cblock output, output2;
+
+ des_ecb_encrypt(block, output, self->KeySched1, 1);
+ des_ecb_encrypt(output, output2, self->KeySched2, 0);
+ des_ecb_encrypt(output2, block, self->KeySched3, 1);
+}
+
+/* NOW DEFINED IN des_local.h
+ * See ecb_encrypt.c for a pseudo description of these macros.
+ * #define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ * (b)^=(t),\
+ * (a)=((a)^((t)<<(n))))
+ */
+
+#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
+ (a)=(a)^(t)^(t>>(16-(n))))
+
+static char shifts2[16]={0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0};
+
+static int des_set_key(key,schedule)
+des_cblock *key;
+des_key_schedule schedule;
+ {
+ register unsigned long c,d,t,s;
+ register unsigned char *in;
+ register unsigned long *k;
+ register int i;
+
+ k=(unsigned long *)schedule;
+ in=(unsigned char *)key;
+
+ c2l(in,c);
+ c2l(in,d);
+
+ /* do PC1 in 60 simple operations */
+/* PERM_OP(d,c,t,4,0x0f0f0f0f);
+ HPERM_OP(c,t,-2, 0xcccc0000);
+ HPERM_OP(c,t,-1, 0xaaaa0000);
+ HPERM_OP(c,t, 8, 0x00ff0000);
+ HPERM_OP(c,t,-1, 0xaaaa0000);
+ HPERM_OP(d,t,-8, 0xff000000);
+ HPERM_OP(d,t, 8, 0x00ff0000);
+ HPERM_OP(d,t, 2, 0x33330000);
+ d=((d&0x00aa00aa)<<7)|((d&0x55005500)>>7)|(d&0xaa55aa55);
+ d=(d>>8)|((c&0xf0000000)>>4);
+ c&=0x0fffffff; */
+
+ /* I now do it in 47 simple operations :-)
+ * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov)
+ * for the inspiration. :-) */
+ PERM_OP (d,c,t,4,0x0f0f0f0f);
+ HPERM_OP(c,t,-2,0xcccc0000);
+ HPERM_OP(d,t,-2,0xcccc0000);
+ PERM_OP (d,c,t,1,0x55555555);
+ PERM_OP (c,d,t,8,0x00ff00ff);
+ PERM_OP (d,c,t,1,0x55555555);
+ d= (((d&0x000000ff)<<16)| (d&0x0000ff00) |
+ ((d&0x00ff0000)>>16)|((c&0xf0000000)>>4));
+ c&=0x0fffffff;
+
+ for (i=0; i<16; i++)
+ {
+ if (shifts2[i])
+ { c=((c>>2)|(c<<26)); d=((d>>2)|(d<<26)); }
+ else
+ { c=((c>>1)|(c<<27)); d=((d>>1)|(d<<27)); }
+ c&=0x0fffffff;
+ d&=0x0fffffff;
+ /* could be a few less shifts but I am to lazy at this
+ * point in time to investigate */
+ s= des_skb[0][ (c )&0x3f ]|
+ des_skb[1][((c>> 6)&0x03)|((c>> 7)&0x3c)]|
+ des_skb[2][((c>>13)&0x0f)|((c>>14)&0x30)]|
+ des_skb[3][((c>>20)&0x01)|((c>>21)&0x06) |
+ ((c>>22)&0x38)];
+ t= des_skb[4][ (d )&0x3f ]|
+ des_skb[5][((d>> 7)&0x03)|((d>> 8)&0x3c)]|
+ des_skb[6][ (d>>15)&0x3f ]|
+ des_skb[7][((d>>21)&0x0f)|((d>>22)&0x30)];
+
+ /* table contained 0213 4657 */
+ *(k++)=((t<<16)|(s&0x0000ffff))&0xffffffff;
+ s= ((s>>16)|(t&0xffff0000));
+
+ s=(s<<4)|(s>>28);
+ *(k++)=s&0xffffffff;
+ }
+ return(0);
+ }
+
+static const unsigned char odd_parity[256]={
+ 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14,
+ 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31,
+ 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47,
+ 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62,
+ 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79,
+ 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94,
+ 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110,
+112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127,
+128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143,
+145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158,
+161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174,
+176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191,
+193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206,
+208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223,
+224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239,
+241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254};
+
+static inline void DES3init(self, key, keylength)
+ DES3object *self;
+ unsigned char *key;
+ int keylength;
+{
+ char oddkey[16];
+ int i;
+
+ if (keylength != 16 && keylength != 24) {
+ PyErr_SetString(PyExc_ValueError,
+ "DES3 key must be either 16 or 24 bytes long");
+ return;
+ }
+
+ for (i=0; i<16; i++)
+ {
+ oddkey[i]=odd_parity[ key[i] ];
+ }
+ des_set_key(oddkey+0, self->KeySched1);
+ des_set_key(oddkey+8, self->KeySched2);
+ if (keylength == 24) {
+ des_set_key(key+16, self->KeySched3);
+ } else {
+ memcpy(self->KeySched3, self->KeySched1, sizeof(self->KeySched3));
+ }
+}
diff --git a/block/Diamond.c b/block/Diamond.c
new file mode 100644
index 0000000..f199d83
--- /dev/null
+++ b/block/Diamond.c
@@ -0,0 +1,415 @@
+
+/*
+ * diamond.c : Implementation of the Diamond block encryption algorithm
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+
+#define MAX_NUM_ROUNDS 16
+
+typedef struct
+{
+ PCTObject_HEAD
+ unsigned char s[4096*MAX_NUM_ROUNDS], si[4096*MAX_NUM_ROUNDS];
+ int keyindex, rounds;
+ unsigned long accum;
+} Diamondobject;
+
+
+/* Make sure that the following macro is called after BuildCRCTable(). */
+
+#define crc32(crc, c)(((crc>>8)&0x00FFFFFFL)^(Ccitt32Table[(unsigned int)((unsigned int)crc^c)&0xFF]))
+
+/* crc.cpp -- contains table based CCITT 32 bit CRC function.
+ This file is in the Public Domain.
+ */
+
+#define CRC_MASK 0xFFFFFFFFL
+#define CRC32_POLYNOMIAL 0xEDB88320L
+
+static const unsigned int Ccitt32Table[256] =
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+#if 0 /* Not used, since Ccitt32Table is statically initialized */
+/****************************************************************************/
+
+/*
+ * This routine simply builds the coefficient table used to calculate
+ * 32 bit CRC values throughout this program. The 256 long word table
+ * has to be set up once when the program starts. Alternatively, the
+ * values could be hard coded in, which would offer a miniscule improvement
+ * in overall performance of the program.
+ */
+
+int BuildCRCTable()
+{
+ int i;
+ int j;
+ unsigned int value;
+
+ for ( i = 0; i <= 255 ; i++ )
+ {
+ value = i;
+ for ( j = 8 ; j > 0; j-- )
+ {
+ if ( value & 1 )
+ value = ( value >> 1 ) ^ CRC32_POLYNOMIAL;
+ else
+ value >>= 1;
+ }
+ Ccitt32Table[ i ] = value;
+ }
+ return 0;
+}
+#endif
+
+
+/* diamond.c - Encryption designed to exceed DES in security.
+ This file and the Diamond and Diamond Lite Encryption Algorithms
+ described herein are hereby dedicated to the Public Domain by the
+ author and inventor, Michael Paul Johnson. Feel free to use these
+ for any purpose that is legally and morally right. The names
+ "Diamond Encryption Algorithm" and "Diamond Lite Encryption
+ Algorithm" should only be used to describe the algorithms described
+ in this file, to avoid confusion.
+
+ Disclaimers: the following comes with no warranty, expressed or
+ implied. You, the user, must determine the suitability of this
+ information to your own uses. You must also find out what legal
+ requirements exist with respect to this data and programs using
+ it, and comply with whatever valid requirements exist.
+ */
+
+int inline keyrand(self, max_value, key, keysize)
+ Diamondobject *self;
+ int max_value;
+ unsigned char *key;
+ int keysize;
+{ /* value based on key[], sized keysize */
+ int prandvalue, i;
+ unsigned long mask;
+
+ if (!max_value) return 0;
+ mask = 0L; /* Create a mask to get the minimum */
+ for (i=max_value; i > 0; i = i >> 1) /* number of bits to cover the */
+ mask = (mask << 1) | 1L; /* range 0 to max_value. */
+ i=0;
+ do
+ {
+ self->accum = crc32(self->accum, key[self->keyindex++]);
+ if (self->keyindex >= keysize)
+ {
+ self->keyindex = 0; /* Recycle thru the key */
+ self->accum = crc32(self->accum, (keysize & 0xFF));
+ self->accum = crc32(self->accum, ((keysize >> 8) & 0xFF));
+ }
+ prandvalue = (int) (self->accum & mask);
+ if ((++i>97) && (prandvalue > max_value)) /* Don't loop forever. */
+ prandvalue -= max_value; /* Introduce negligible bias. */
+ }
+ while (prandvalue > max_value); /* Discard out of range values. */
+ return prandvalue;
+}
+
+static void inline makeonebox(self, i, j, key, keylen)
+ Diamondobject *self;
+ int i, j;
+ unsigned char *key;
+ int keylen;
+{
+ int n;
+ int pos, m, p;
+ int filled[256];
+
+ for (m = 0; m < 256; m++) /* The filled array is used to make
+ sure that */
+ filled[m] = 0; /* each byte of the array is filled only once. */
+ for (n = 255; n >= 0 ; n--) /* n counts the number of bytes left to fill */
+ {
+ pos = keyrand(self, n, key, keylen); /* pos is the position among the UNFILLED */
+ /* components of the s array that the */
+ /* number n should be placed. */
+ p=0;
+ while (filled[p]) p++;
+ for (m=0; m<pos; m++)
+ {
+ p++;
+ while (filled[p]) p++;
+ }
+ self->s[(4096*i) + (256*j) + p] = n;
+ filled[p] = 1;
+ }
+}
+
+static inline void Diamondinit(self, key, keylen)
+ Diamondobject *self;
+ unsigned char *key;
+ int keylen;
+{
+ int i, j, k;
+#if 0
+ BuildCRCTable();
+#endif
+ self->keyindex = 0;
+ self->accum = 0xFFFFFFFFL;
+
+ if (self->rounds<5 || MAX_NUM_ROUNDS<=self->rounds)
+ {
+ PyErr_SetString(PyExc_ValueError, "Number of rounds for Diamond must be "
+ "between 5 and 15.");
+ return;
+ }
+ for (i = 0; i < self->rounds; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ makeonebox(self, i, j, key, keylen);
+ }
+ }
+ for (i = 0; i < self->rounds; i++)
+ {
+ for (j = 0; j < 16; j++)
+ {
+ for (k = 0; k < 256; k++)
+ {
+ self->si[(4096 * i) + (256 * j) + self->s[(4096 * i) + (256 * j) + k]] = k;
+ }
+ }
+ }
+}
+
+static void permute(self, x, y) /* x and y must be different. */
+ Diamondobject *self;
+ unsigned char *x, *y;
+ {
+ y[0] = (x[0] & 1) | (x[1] & 2) | (x[2] & 4) |
+ (x[3] & 8) | (x[4] & 16) | (x[5] & 32) |
+ (x[6] & 64) | (x[7] & 128);
+ y[1] = (x[1] & 1) | (x[2] & 2) | (x[3] & 4) |
+ (x[4] & 8) | (x[5] & 16) | (x[6] & 32) |
+ (x[7] & 64) | (x[8] & 128);
+ y[2] = (x[2] & 1) | (x[3] & 2) | (x[4] & 4) |
+ (x[5] & 8) | (x[6] & 16) | (x[7] & 32) |
+ (x[8] & 64) | (x[9] & 128);
+ y[3] = (x[3] & 1) | (x[4] & 2) | (x[5] & 4) |
+ (x[6] & 8) | (x[7] & 16) | (x[8] & 32) |
+ (x[9] & 64) | (x[10] & 128);
+ y[4] = (x[4] & 1) | (x[5] & 2) | (x[6] & 4) |
+ (x[7] & 8) | (x[8] & 16) | (x[9] & 32) |
+ (x[10] & 64) | (x[11] & 128);
+ y[5] = (x[5] & 1) | (x[6] & 2) | (x[7] & 4) |
+ (x[8] & 8) | (x[9] & 16) | (x[10] & 32) |
+ (x[11] & 64) | (x[12] & 128);
+ y[6] = (x[6] & 1) | (x[7] & 2) | (x[8] & 4) |
+ (x[9] & 8) | (x[10] & 16) | (x[11] & 32) |
+ (x[12] & 64) | (x[13] & 128);
+ y[7] = (x[7] & 1) | (x[8] & 2) | (x[9] & 4) |
+ (x[10] & 8) | (x[11] & 16) | (x[12] & 32) |
+ (x[13] & 64) | (x[14] & 128);
+ y[8] = (x[8] & 1) | (x[9] & 2) | (x[10] & 4) |
+ (x[11] & 8) | (x[12] & 16) | (x[13] & 32) |
+ (x[14] & 64) | (x[15] & 128);
+ y[9] = (x[9] & 1) | (x[10] & 2) | (x[11] & 4) |
+ (x[12] & 8) | (x[13] & 16) | (x[14] & 32) |
+ (x[15] & 64) | (x[0] & 128);
+ y[10] = (x[10] & 1) | (x[11] & 2) | (x[12] & 4) |
+ (x[13] & 8) | (x[14] & 16) | (x[15] & 32) |
+ (x[0] & 64) | (x[1] & 128);
+ y[11] = (x[11] & 1) | (x[12] & 2) | (x[13] & 4) |
+ (x[14] & 8) | (x[15] & 16) | (x[0] & 32) |
+ (x[1] & 64) | (x[2] & 128);
+ y[12] = (x[12] & 1) | (x[13] & 2) | (x[14] & 4) |
+ (x[15] & 8) | (x[0] & 16) | (x[1] & 32) |
+ (x[2] & 64) | (x[3] & 128);
+ y[13] = (x[13] & 1) | (x[14] & 2) | (x[15] & 4) |
+ (x[0] & 8) | (x[1] & 16) | (x[2] & 32) |
+ (x[3] & 64) | (x[4] & 128);
+ y[14] = (x[14] & 1) | (x[15] & 2) | (x[0] & 4) |
+ (x[1] & 8) | (x[2] & 16) | (x[3] & 32) |
+ (x[4] & 64) | (x[5] & 128);
+ y[15] = (x[15] & 1) | (x[0] & 2) | (x[1] & 4) |
+ (x[2] & 8) | (x[3] & 16) | (x[4] & 32) |
+ (x[5] & 64) | (x[6] & 128);
+ }
+
+static void ipermute(self, x, y) /* x!=y */
+ Diamondobject *self;
+ unsigned char *x, *y;
+ {
+ y[0] = (x[0] & 1) | (x[15] & 2) | (x[14] & 4) |
+ (x[13] & 8) | (x[12] & 16) | (x[11] & 32) |
+ (x[10] & 64) | (x[9] & 128);
+ y[1] = (x[1] & 1) | (x[0] & 2) | (x[15] & 4) |
+ (x[14] & 8) | (x[13] & 16) | (x[12] & 32) |
+ (x[11] & 64) | (x[10] & 128);
+ y[2] = (x[2] & 1) | (x[1] & 2) | (x[0] & 4) |
+ (x[15] & 8) | (x[14] & 16) | (x[13] & 32) |
+ (x[12] & 64) | (x[11] & 128);
+ y[3] = (x[3] & 1) | (x[2] & 2) | (x[1] & 4) |
+ (x[0] & 8) | (x[15] & 16) | (x[14] & 32) |
+ (x[13] & 64) | (x[12] & 128);
+ y[4] = (x[4] & 1) | (x[3] & 2) | (x[2] & 4) |
+ (x[1] & 8) | (x[0] & 16) | (x[15] & 32) |
+ (x[14] & 64) | (x[13] & 128);
+ y[5] = (x[5] & 1) | (x[4] & 2) | (x[3] & 4) |
+ (x[2] & 8) | (x[1] & 16) | (x[0] & 32) |
+ (x[15] & 64) | (x[14] & 128);
+ y[6] = (x[6] & 1) | (x[5] & 2) | (x[4] & 4) |
+ (x[3] & 8) | (x[2] & 16) | (x[1] & 32) |
+ (x[0] & 64) | (x[15] & 128);
+ y[7] = (x[7] & 1) | (x[6] & 2) | (x[5] & 4) |
+ (x[4] & 8) | (x[3] & 16) | (x[2] & 32) |
+ (x[1] & 64) | (x[0] & 128);
+ y[8] = (x[8] & 1) | (x[7] & 2) | (x[6] & 4) |
+ (x[5] & 8) | (x[4] & 16) | (x[3] & 32) |
+ (x[2] & 64) | (x[1] & 128);
+ y[9] = (x[9] & 1) | (x[8] & 2) | (x[7] & 4) |
+ (x[6] & 8) | (x[5] & 16) | (x[4] & 32) |
+ (x[3] & 64) | (x[2] & 128);
+ y[10] = (x[10] & 1) | (x[9] & 2) | (x[8] & 4) |
+ (x[7] & 8) | (x[6] & 16) | (x[5] & 32) |
+ (x[4] & 64) | (x[3] & 128);
+ y[11] = (x[11] & 1) | (x[10] & 2) | (x[9] & 4) |
+ (x[8] & 8) | (x[7] & 16) | (x[6] & 32) |
+ (x[5] & 64) | (x[4] & 128);
+ y[12] = (x[12] & 1) | (x[11] & 2) | (x[10] & 4) |
+ (x[9] & 8) | (x[8] & 16) | (x[7] & 32) |
+ (x[6] & 64) | (x[5] & 128);
+ y[13] = (x[13] & 1) | (x[12] & 2) | (x[11] & 4) |
+ (x[10] & 8) | (x[9] & 16) | (x[8] & 32) |
+ (x[7] & 64) | (x[6] & 128);
+ y[14] = (x[14] & 1) | (x[13] & 2) | (x[12] & 4) |
+ (x[11] & 8) | (x[10] & 16) | (x[9] & 32) |
+ (x[8] & 64) | (x[7] & 128);
+ y[15] = (x[15] & 1) | (x[14] & 2) | (x[13] & 4) |
+ (x[12] & 8) | (x[11] & 16) | (x[10] & 32) |
+ (x[9] & 64) | (x[8] & 128);
+ }
+
+static void inline substitute(self, round, x, y)
+ Diamondobject *self;
+ int round;
+ unsigned char *x, *y;
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ y[i] = self->s[(4096*round) + (256*i) + x[i]];
+}
+
+static void inline isubst(self, round, x, y)
+ Diamondobject *self;
+ int round;
+ unsigned char *x, *y;
+{
+ int i;
+
+ for (i = 0; i < 16; i++)
+ y[i] = self->si[(4096*round) + (256*i) + x[i]];
+}
+
+void Diamondencrypt(self, block)
+ Diamondobject *self;
+ unsigned char *block;
+ {
+ int round;
+ unsigned char y[16], z[16];
+
+ substitute(self, 0, block, y);
+ for (round=1; round < self->rounds; round++)
+ {
+ permute(self, y, z);
+ substitute(self, round, z, y);
+ }
+ for(round=0; round<16; round++) block[round]=y[round];
+ }
+
+ void Diamonddecrypt(self, block)
+ Diamondobject *self;
+ unsigned char *block;
+ {
+ int round;
+ unsigned char y[16], z[16];
+
+ isubst(self, self->rounds-1, block, y);
+ for (round=self->rounds-2; round >= 0; round--)
+ {
+ ipermute(self, y, z);
+ isubst(self, round, z, y);
+ }
+ for(round=0; round<16; round++) block[round]=y[round];
+ }
+
+
+
diff --git a/block/IDEA.c b/block/IDEA.c
new file mode 100644
index 0000000..6db499e
--- /dev/null
+++ b/block/IDEA.c
@@ -0,0 +1,214 @@
+
+/*
+ * idea.c : Source code for the IDEA block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+
+#define low16(x) ((x)/* & 0xFFFF*/)
+typedef unsigned short uint16; /* at LEAST 16 bits, maybe more */
+typedef unsigned short word16;
+typedef unsigned long word32;
+typedef unsigned char byte;
+
+#define MUL(x,y) (x = low16(x-1), t16 = low16((y)-1), \
+ t32 = (word32)x*t16 + x + t16, x = low16(t32), \
+ t16 = t32>>16, x = (x-t16) + (x<t16) + 1)
+
+#ifdef _GNUC_
+/* __const__ simply means there are no side effects for this function,
+ * which is useful info for the gcc optimizer
+ */
+#define CONST __const__
+#else
+#define CONST
+#endif
+
+typedef struct
+{
+ PCTObject_HEAD
+ word16 EK[6*8+4], DK[6*8+4];
+ char Endianness;
+} IDEAobject;
+
+CONST static uint16
+mulInv(x)
+ uint16 x;
+{
+ uint16 t0, t1;
+ uint16 q, y;
+
+ if (x <= 1)
+ return x; /* 0 and 1 are self-inverse */
+ t1 = 0x10001L / x; /* Since x >= 2, this fits into 16 bits */
+ y = 0x10001L % x;
+ if (y == 1)
+ return low16(1 - t1);
+ t0 = 1;
+ do {
+ q = x / y;
+ x = x % y;
+ t0 += q * t1;
+ if (x == 1)
+ return t0;
+ q = y / x;
+ y = y % x;
+ t1 += q * t0;
+ } while (y != 1);
+ return low16(1 - t1);
+} /* mukInv */
+
+static inline void
+IDEAinit(self, key, dummy)
+ IDEAobject *self;
+ unsigned char *key;
+ int dummy;
+{
+ int i, j;
+ uint16 t1, t2, t3;
+ word16 *DK, *EK;
+
+ EK = self->EK;
+ TestEndianness(self->Endianness);
+ for (j = 0; j < 8; j++) {
+ EK[j] = (key[0] << 8) + key[1];
+ key += 2;
+ }
+ for (i = 0; j < 6*8+4; j++) {
+ i++;
+ EK[i + 7] = (EK[i & 7] << 9) | (EK[(i + 1) & 7] >> 7);
+ EK += i & 8;
+ i &= 7;
+ }
+ EK = self->EK;
+ DK = self->DK+6*8+4;
+ t1 = mulInv(*EK++);
+ t2 = -*EK++;
+ t3 = -*EK++;
+ *--DK = mulInv(*EK++);
+ *--DK = t3;
+ *--DK = t2;
+ *--DK = t1;
+
+ for (i = 0; i < 8 - 1; i++) {
+ t1 = *EK++;
+ *--DK = *EK++;
+ *--DK = t1;
+
+ t1 = mulInv(*EK++);
+ t2 = -*EK++;
+ t3 = -*EK++;
+ *--DK = mulInv(*EK++);
+ *--DK = t2;
+ *--DK = t3;
+ *--DK = t1;
+ }
+ t1 = *EK++;
+ *--DK = *EK++;
+ *--DK = t1;
+
+ t1 = mulInv(*EK++);
+ t2 = -*EK++;
+ t3 = -*EK++;
+ *--DK = mulInv(*EK++);
+ *--DK = t3;
+ *--DK = t2;
+ *--DK = t1;
+}
+
+/* IDEA encryption/decryption algorithm */
+/* Note that in and out can be the same buffer */
+static void ideaCipher(self, block, key)
+ IDEAobject *self;
+ byte *block;
+ word16 const *key;
+{
+ register uint16 x1, x2, x3, x4, s2, s3;
+ word16 *in, *out;
+ register uint16 t16; /* Temporaries needed by MUL macro */
+ register word32 t32;
+ int r = 8;
+
+ in = (word16 *) block;
+ x1 = *in++;
+ x2 = *in++;
+ x3 = *in++;
+ x4 = *in;
+ if (self->Endianness==PCT_LITTLE_ENDIAN)
+ {
+ x1 = (x1 >> 8) | (x1 << 8);
+ x2 = (x2 >> 8) | (x2 << 8);
+ x3 = (x3 >> 8) | (x3 << 8);
+ x4 = (x4 >> 8) | (x4 << 8);
+ }
+ do {
+ MUL(x1, *key++);
+ x2 += *key++;
+ x3 += *key++;
+ MUL(x4, *key++);
+
+ s3 = x3;
+ x3 ^= x1;
+ MUL(x3, *key++);
+ s2 = x2;
+ x2 ^= x4;
+ x2 += x3;
+ MUL(x2, *key++);
+ x3 += x2;
+
+ x1 ^= x2;
+ x4 ^= x3;
+
+ x2 ^= s3;
+ x3 ^= s2;
+ } while (--r);
+ MUL(x1, *key++);
+ x3 += *key++;
+ x2 += *key++;
+ MUL(x4, *key);
+
+ out = (word16 *) block;
+
+ if (self->Endianness==PCT_BIG_ENDIAN)
+ {
+ *out++ = x1;
+ *out++ = x3;
+ *out++ = x2;
+ *out = x4;
+ } /* !HIGHFIRST */
+ else
+ {
+ x1 = low16(x1);
+ x2 = low16(x2);
+ x3 = low16(x3);
+ x4 = low16(x4);
+
+ *out++ = (x1 >> 8) | (x1 << 8);
+ *out++ = (x3 >> 8) | (x3 << 8);
+ *out++ = (x2 >> 8) | (x2 << 8);
+ *out = (x4 >> 8) | (x4 << 8);
+ }
+} /* ideaCipher */
+
+
+static inline void IDEAencrypt(self, block)
+ IDEAobject *self;
+ unsigned char *block;
+{
+ ideaCipher(self, block, self->EK);
+}
+
+static inline void IDEAdecrypt(self, block)
+ IDEAobject *self;
+ unsigned char *block;
+{
+ ideaCipher(self, block, self->DK);
+}
+
+
diff --git a/block/RC5.c b/block/RC5.c
new file mode 100644
index 0000000..2a1b983
--- /dev/null
+++ b/block/RC5.c
@@ -0,0 +1,233 @@
+
+/*
+ * RC5.c : Implementation code for the RC5 block cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+#define MAXTABLE 100 /* Maximum size of S-box table; changing this
+ affects the maximum number of rounds
+ possible. */
+typedef unsigned int U32;
+#define LEFT(v,x,y,w,MASK) {U32 t1=(y) % (w), t2,t3=x;\
+ t2=(w)-t1;\
+ v= ( (t3 << t1) & MASK) | \
+ ( (t3 >> t2) & MASK);}
+#define RIGHT(v,x,y,w,MASK) {U32 t1=(y) % (w), t2,t3=x;\
+ t2=(w)-t1;\
+ v= ( (t3 >> t1) & MASK) | \
+ ( (t3 << t2) & MASK);}
+
+
+
+typedef struct
+{
+ PCTObject_HEAD
+ int version; /* Version number of algorithm */
+ int wordsize; /* Word size */
+ int rounds; /* Number of rounds */
+ U32 S[MAXTABLE];
+ U32 mask;
+} RC5object;
+
+static inline void
+RC5init(self, key, keylen)
+ RC5object *self;
+ unsigned char *key;
+ int keylen;
+{
+ unsigned int P = 0, Q = 0;
+ int i;
+
+ if (self->version!=0x10)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "RC5: Bad RC5 algorithm version");
+ return;
+ }
+ if (self->wordsize!=16 && self->wordsize!=32)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "RC5: Unsupported word size");
+ return;
+ }
+ if (self->rounds<0 || 255<self->rounds)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "RC5: rounds must be between 0 and 255");
+ return;
+ }
+ switch(self->wordsize)
+ {
+ case(16):
+ P=0xb7e1; Q=0x9e37; self->mask=0xffff;
+ break;
+ case(32):
+ P=0xb7e15163; Q=0x9e3779b9; self->mask=0xffffffff;
+ break;
+ }
+ for(i=0; i<2*self->rounds+2; i++) self->S[i]=0;
+ {
+ unsigned int *L, A, B;
+ int u=self->wordsize/8, num;
+ int j, t=2*(self->rounds+1), c=(keylen-1)/u;
+ if ((keylen-1) % u) c++;
+ L=malloc(sizeof(unsigned int)*c);
+ if (L==NULL)
+ {
+ PyErr_SetString(PyExc_MemoryError,
+ "RC5: Can't allocate memory");
+ }
+ for(i=0; i<c; i++) L[i]=0;
+ for(i=keylen-1; 0<=i; i--) L[i/u]=(L[i/u]<<8)+key[i];
+ self->S[0]=P;
+ for(i=1; i<t; i++) self->S[i]=(self->S[i-1]+Q) & self->mask;
+ i=j=0;
+ A=B=0;
+ for(num = (t>c) ? 3*t : 3*c; 0<num; num--)
+ {
+ LEFT(A, self->S[i]+A+B, 3, self->wordsize, self->mask);
+ self->S[i]=A;
+ LEFT(B, L[j]+A+B, A+B, self->wordsize, self->mask);
+ L[j]=B;
+ i=(i+1)%t;
+ j=(j+1)%c;
+ }
+ free(L);
+ }
+}
+
+static void RC5Encipher(self, Aptr, Bptr)
+ RC5object *self;
+ U32 *Aptr, *Bptr;
+{
+ int i;
+ register U32 A, B;
+
+ A=(*Aptr+self->S[0]) & self->mask;
+ B=(*Bptr+self->S[1]) & self->mask;
+
+ if (self->rounds)
+ for (i=2; i<=2*self->rounds; i+=2)
+ {
+ LEFT(A,A^B,B,self->wordsize,self->mask);
+ A += self->S[i];
+ LEFT(B,A^B,A,self->wordsize,self->mask);
+ B += self->S[i+1];
+ }
+ *Aptr=A;
+ *Bptr=B;
+}
+
+static void RC5Decipher(self, Aptr, Bptr)
+ RC5object *self;
+ unsigned int *Aptr, *Bptr;
+{
+ int i;
+ U32 A, B;
+
+ A=*Aptr;
+ B=*Bptr;
+
+ if (self->rounds)
+ for (i=2*self->rounds; 2<=i; i-=2)
+ {
+ RIGHT(B,B-self->S[i+1],A,self->wordsize,self->mask);
+ B ^= A;
+ RIGHT(A,A-self->S[i],B,self->wordsize,self->mask);
+ A ^= B;
+ }
+ A = (A-self->S[0]) & self->mask;
+ B = (B-self->S[1]) & self->mask;
+ if (self->wordsize==32)
+ {
+ *Aptr=A;
+ *Bptr=B;
+ }
+ else /* self->wordsize==16 */
+ {
+ *Aptr=A;
+ *Bptr=B;
+ }
+}
+
+static inline void RC5encrypt(self, block)
+ RC5object *self;
+ unsigned char *block;
+{
+ U32 A,B;
+
+ switch(self->wordsize)
+ {
+ case (32):
+ A=block[0] | block[1]<<8 | block[2]<<16 | block[3]<<24;
+ B=block[4] | block[5]<<8 | block[6]<<16 | block[7]<<24;
+ RC5Encipher(self, &A, &B);
+ block[0]=A & 255; A>>=8;
+ block[1]=A & 255; A>>=8;
+ block[2]=A & 255; A>>=8;
+ block[3]=A;
+ block[4]=B & 255; B>>=8;
+ block[5]=B & 255; B>>=8;
+ block[6]=B & 255; B>>=8;
+ block[7]=B;
+ break;
+ case (16):
+ A=block[0] + block[1]*256;
+ B=block[2] + block[3]*256;
+ RC5Encipher(self, &A, &B);
+ block[0] = A & 255; block[1] = A>>8;
+ block[2] = B & 255; block[3] = B>>8;
+
+ A=block[4] + block[5]*256;
+ B=block[6] + block[7]*256;
+ RC5Encipher(self, &A, &B);
+ block[4] = A & 255; block[5] = A>>8;
+ block[6] = B & 255; block[7] = B>>8;
+ break;
+ }
+}
+
+static inline void RC5decrypt(self, block)
+ RC5object *self;
+ unsigned char *block;
+{
+ U32 A,B;
+
+ switch(self->wordsize)
+ {
+ case (32):
+ A=block[0] | block[1]<<8 | block[2]<<16 | block[3]<<24;
+ B=block[4] | block[5]<<8 | block[6]<<16 | block[7]<<24;
+ RC5Decipher(self, &A, &B);
+ block[0]=A & 255; A>>=8;
+ block[1]=A & 255; A>>=8;
+ block[2]=A & 255; A>>=8;
+ block[3]=A;
+ block[4]=B & 255; B>>=8;
+ block[5]=B & 255; B>>=8;
+ block[6]=B & 255; B>>=8;
+ block[7]=B;
+ break;
+ case (16):
+ A=block[0] + block[1]*256;
+ B=block[2] + block[3]*256;
+ RC5Decipher(self, &A, &B);
+ block[0] = A & 255; block[1] = A>>8;
+ block[2] = B & 255; block[3] = B>>8;
+
+ A=block[4] + block[5]*256;
+ B=block[6] + block[7]*256;
+ RC5Decipher(self, &A, &B);
+ block[4] = A & 255; block[5] = A>>8;
+ block[6] = B & 255; block[7] = B>>8;
+ break;
+ }
+}
+
+
diff --git a/block/Skipjack.c b/block/Skipjack.c
new file mode 100644
index 0000000..5f7aad9
--- /dev/null
+++ b/block/Skipjack.c
@@ -0,0 +1,139 @@
+
+/*
+ * Skipjack.c : Implementation code for the Skipjack block cipher
+ * (recently declassified)
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+typedef struct
+{
+ PCTObject_HEAD
+ unsigned char key[12];
+} Skipjackobject;
+
+static unsigned char F[256] =
+{
+ 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9,
+ 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28,
+ 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53,
+ 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2,
+ 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8,
+ 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90,
+ 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76,
+ 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d,
+ 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18,
+ 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4,
+ 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40,
+ 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5,
+ 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2,
+ 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8,
+ 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac,
+ 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46
+};
+
+static inline void
+Skipjackinit(self, key, keylen)
+ Skipjackobject *self;
+ unsigned char *key;
+ int keylen;
+{
+ /* The key is 10 bytes long, but each round uses 4 bytes from it, so
+ the key buffer will be 12 bytes long, with the first two bytes
+ copied into bytes 11 and 12. This lets each round use its key
+ bytes without any modulo operations. */
+ memcpy(self->key, key, 10);
+ memcpy(self->key + 10, key, 2);
+}
+
+static inline void Skipjackencrypt(self, block)
+ Skipjackobject *self;
+ unsigned char *block;
+{
+ int w1, w2, w3, w4;
+ int cv=0, i;
+ unsigned char *key = self->key;
+
+ w1 = (block[0] << 8) + block[1];
+ w2 = (block[2] << 8) + block[3];
+ w3 = (block[4] << 8) + block[5];
+ w4 = (block[6] << 8) + block[7];
+
+#define G(result,w) {int g1 = w>>8, g2= w & 0xFF,g3;\
+ g3 = F[g2 ^ key[cv]] ^ g1; \
+ g1 = F[g3 ^ key[cv+1]] ^ g2; \
+ g2 = F[g1 ^ key[cv+2]] ^ g3; \
+ g3 = F[g2 ^ key[cv+3]] ^ g1; \
+ result = (g2 << 8) + g3; cv = (cv+4) % 10;}
+
+#define ruleA(counter) {int t; G(t,w1); w1 = (counter+1) ^ t ^ w4; \
+ w4 = w3; w3 = w2; w2 = t; \
+ /*printf("%04x %04x %04x %04x\n", w1, w2, w3, w4);*/}
+#define ruleB(counter) {int t; int t2 = w1; G(t,w1); \
+ w1 = w4; w4 = w3; w3 = t2 ^ (counter+1) ^ w2; w2 = t;\
+ /*printf("%04x %04x %04x %04x\n", w1, w2, w3, w4);*/}
+
+
+ /* 8 steps of rule A, 8 of rule B, 8 of A, 8 of B */
+ for(i=0; i<8; i++) {ruleA(i);}
+ for(i=8; i<16; i++) {ruleB(i);}
+ for(i=16; i<24; i++) {ruleA(i);}
+ for(i=24; i<32; i++) {ruleB(i);}
+
+#undef ruleA
+#undef ruleB
+#undef G
+
+ block[0] = w1 >> 8; block[1] = w1 & 255;
+ block[2] = w2 >> 8; block[3] = w2 & 255;
+ block[4] = w3 >> 8; block[5] = w3 & 255;
+ block[6] = w4 >> 8; block[7] = w4 & 255;
+}
+
+static inline void Skipjackdecrypt(self, block)
+ Skipjackobject *self;
+ unsigned char *block;
+{
+ int w1, w2, w3, w4;
+ int cv = 4, i;
+ unsigned char *key = self->key;
+
+ w1 = (block[0] << 8) + block[1];
+ w2 = (block[2] << 8) + block[3];
+ w3 = (block[4] << 8) + block[5];
+ w4 = (block[6] << 8) + block[7];
+
+#define Ginv(result,w) {int g2 = w>>8, g1= w & 0xFF,g3;\
+ g3 = F[g2 ^ key[cv+3]] ^ g1; \
+ g1 = F[g3 ^ key[cv+2]] ^ g2; \
+ g2 = F[g1 ^ key[cv+1]] ^ g3; \
+ g3 = F[g2 ^ key[cv+0]] ^ g1; \
+ result = (g3 << 8) + g2; cv = (cv+10-4) % 10;}
+#define ruleA(counter) {int t; int t2 = w2; Ginv(t,w2); w2 = w3; w3 = w4; \
+ w4 = w1 ^ t2 ^ (counter+1); w1 = t; \
+ /*printf("%04x %04x %04x %04x\n", w1, w2, w3, w4);*/}
+#define ruleB(counter) {int t; Ginv(t, w2); \
+ w2 = t ^ w3 ^ (counter+1); w3 = w4; w4 = w1; w1 = t;\
+ /*printf("%04x %04x %04x %04x\n", w1, w2, w3, w4);*/}
+
+
+ /* 8 steps of rule Binv, 8 of rule Ainv, 8 of Binv, 8 of A */
+ for(i=31; 24<=i; i--) {ruleB(i);}
+ for(i=23; 16<=i; i--) {ruleA(i);}
+ for(i=15; 8<=i; i--) {ruleB(i);}
+ for(i=7; 0<=i; i--) {ruleA(i);}
+
+#undef ruleA
+#undef ruleB
+#undef Ginv
+
+ block[0] = w1 >> 8; block[1] = w1 & 255;
+ block[2] = w2 >> 8; block[3] = w2 & 255;
+ block[4] = w3 >> 8; block[5] = w3 & 255;
+ block[6] = w4 >> 8; block[7] = w4 & 255;
+}
diff --git a/block/cast5.c b/block/cast5.c
new file mode 100644
index 0000000..0843b98
--- /dev/null
+++ b/block/cast5.c
@@ -0,0 +1,437 @@
+/*
+ These are the S-boxes for CAST5 as given in RFC 2144.
+*/
+
+
+static const uint32 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 uint32 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 uint32 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 uint32 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 uint32 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 uint32 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 uint32 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 uint32 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 };
+
diff --git a/buildkit b/buildkit
new file mode 100755
index 0000000..54dc398
--- /dev/null
+++ b/buildkit
@@ -0,0 +1,144 @@
+#!/usr/bin/env python --
+# -*-Python-*-
+# buildkit : Builds the object files
+#
+# Part of the Python Cryptography Toolkit, version 1.1
+#
+
+import sys, re, string
+import os
+
+modules = [
+# Format: "hash" algorithm digestsize
+('hash', 'MD2', 16),
+('hash', 'MD4', 16),
+('hash', 'MD5', 16),
+('hash', 'SHA', 20),
+('hash', 'RIPEMD', 20),
+('hash', 'HAVAL', 32, [('rounds', 5), ('digestsize', 256)] ),
+
+# "block" algorithm blocksize keylength
+('block', 'ARC2', 8, 0),
+('block', 'Blowfish', 8, 0),
+('block', 'CAST', 8, 0),
+('block', 'DES', 8, 8),
+('block', 'DES3', 8, 0),
+('block', 'Diamond', 16, 0, [('rounds', 8)] ),
+('block', 'IDEA', 8, 16),
+('block', 'RC5', 8, 0, [('version', 0x10),
+ ('wordsize', 32),
+ ('rounds', 12)
+ ]),
+('block', 'Skipjack', 8, 10),
+
+# Stream ciphers
+('stream', 'ARC4', 1, 0),
+('stream', 'Sapphire', 1, 0),
+('stream', 'XOR', 1, 0),
+
+# "simple" filenamebase
+#('simple', 'HAVAL')
+]
+
+# This class neatly encapsulates files; comparisions examine the time of
+# creation of the two files.
+
+class File:
+ def __init__(self, filename):
+ self.filename=filename
+ def __cmp__(self, other):
+ try:
+ t1=os.stat(self.filename)[8]
+ except os.error, (error, message):
+ if error==2: return(-1)
+ print error, message
+ raise os.error, (error,message)
+ try:
+ t2=os.stat(other.filename)[8]
+ except os.error, (error, message):
+ if error==2: return(+1)
+ print error, message
+ raise os.error, (error,message)
+ if (t1<t2): return(-1)
+ if (t1>t2): return(+1)
+ return 0
+
+def execute(command):
+ print command
+ status=os.system(command)
+ if (status!=0): raise KeyboardInterrupt
+
+def BuildSourceFile(algorithm, moduletype, substlist):
+ sys.stderr.write(' Building C source code for '+algorithm+'\n')
+ input=open('framewks/'+moduletype+'.in', 'r')
+ output=open('src/'+algorithm+'module.c', 'w')
+ substlist.append( ('@@ALGORITHM@@', algorithm) )
+ substlist.append( ('@@MODNAME@@', algorithm) )
+ output.write('\n\n/* Do not modify this file; '
+ +'it is automatically generated\n')
+ output.write(' from '+moduletype+'.in and '+algorithm+'.c\n */\n\n')
+ while (1):
+ l=input.readline()
+ if (l==''): break
+ for entry in substlist:
+ keyword, value=entry
+ l=re.sub(keyword, str(value), l)
+
+ temp=l
+ l=re.sub('@@IMPLEMENTATION@@', '', l)
+
+ # Check if the @@IMPLEMENTATION@@ keyword has been encountered
+ if (l!=temp):
+ newfile=open(moduletype+'/'+algorithm+'.c', 'r')
+ while (1): # Copy the implementation into the output file
+ l1=newfile.readline()
+ if (l1==''): break
+ output.write(l1)
+ output.write(l)
+ output.close()
+ input.close()
+
+for f in modules:
+ moduletype=f[0]
+ kw1=kw2=kw3=kw4=""
+ if type(f[-1]) == type([]):
+ # Handle any keyword arguments
+ for (kwarg, default) in f[-1]:
+ kw1 = kw1 + '"%s", ' % (kwarg);
+ kw2 = kw2 + 'new->%s = %s; ' % (kwarg, default)
+ kw3 = kw3 + ', &(new->%s)' % (kwarg)
+ kw4 = kw4 + 'i'
+ kw4 = '"' + kw4 + '"'
+ if (moduletype=='block' or moduletype=='stream'):
+ substlist = [('@@BLOCKSIZE@@', f[2]),
+ ('@@KEYSIZE@@', f[3]),
+ ('@@KEYWORDLIST@@', kw1),
+ ('@@KEYWORDDEFAULTS@@', kw2),
+ ('@@KEYWORDPTRS@@', kw3),
+ ('@@KEYWORDFMT@@', kw4)]
+ elif (moduletype=='hash'):
+ substlist=[('@@DIGESTSIZE@@', f[2]),
+ ('@@KEYWORDLIST@@', kw1),
+ ('@@KEYWORDDEFAULTS@@', kw2),
+ ('@@KEYWORDPTRS@@', kw3),
+ ('@@KEYWORDFMT@@', kw4)]
+ elif (moduletype=='simple'):
+ substlist=[]
+ else:
+ sys.stderr.write('Unknown keyword '+moduletype+'\n')
+ algorithm=f[1]
+
+ framework=File('framewks/'+moduletype+'.in')
+ base=File(moduletype+'/'+algorithm+'.c')
+ source=File('src/'+algorithm+'module.c')
+
+ if not os.path.exists(base.filename):
+ print algorithm, 'not present -- skipping'
+ else:
+ try:
+ if (source<base or source<framework):
+ BuildSourceFile(algorithm, moduletype, substlist)
+ except KeyboardInterrupt:
+ print 'Error occurred; deleting', source.filename
+ os.unlink(source.filename)
+ sys.exit(1)
diff --git a/curiosa/README b/curiosa/README
new file mode 100644
index 0000000..3e3747f
--- /dev/null
+++ b/curiosa/README
@@ -0,0 +1,161 @@
+
+ The curiosa/ directory contains various cryptography-related
+hacks that may of interest, but aren't really practical for real use.
+
+ One amusement is to try to write the shortest possible
+encryption program. Recently numerous people have started exporting
+cryptographic systems in their .signatures (and on mailing labels,
+T-shirts, ...). This is aimed at making the North American export
+regulations look silly. The most common one seen in .sig files on
+Usenet is RSA in 3 lines of Perl:
+
+#!/usr/local/bin/perl -s-- -export-a-crypto-system-sig -RSA-in-3-lines-PERL
+($k,$n)=@ARGV;$m=unpack(H.$w,$m."\0"x$w),$_=`echo "16do$w 2+4Oi0$d*-^1[d2%
+Sa2/d0<X+d*La1=z\U$n%0]SX$k"[$m*]\EszlXx++p|dc`,s/^.|\W//g,print pack('H*'
+,$_)while read(STDIN,$m,($w=2*$d-1+length($n||die"$0 [-d] k n\n")&~1)/2)
+
+ Usually we think of Python as a very clearly and spaciously
+formatted language, because the program structure is indicated by
+whitespace. However, it is possible to produce very compact code, as
+the following programs demonstrate:
+
+ * rsa.py (4 lines): Performs RSA public key
+encryption/decryption. It requires two arguments, and can accept a
+single option: '-d' for decryption (the default action is encryption).
+The first argument must be the required exponent, expressed in
+hexadecimal, and the second is the modulus, also in hex. You still
+have to choose the correct exponent, whether the '-d' option is
+present or not; '-d' simply changes the number of bytes read at a
+single time.
+
+ As an example: Let us assume the modulus is 6819722537, the
+encryption exponent is 65537, and the decryption exponent is
+2889233921. Then, after converting the numbers to hex, we can encrypt
+and then decrypt by the following commands:
+
+ echo 'Top secret message.' | rsa.py 10001 1967cb529 >ciphertext
+ cat ciphertext | rsa.py -d ac363601 1967cb529
+
+#!/usr/local/bin/python
+from sys import*;from string import*;a=argv;[s,p,q]=filter(lambda x:x[:1]!=
+'-',a);d='-d'in a;e,n=atol(p,16),atol(q,16);l=(len(q)+1)/2;o,inb=l-d,l-1+d
+while s:s=stdin.read(inb);s and map(stdout.write,map(lambda i,b=pow(reduce(
+lambda x,y:(x<<8L)+y,map(ord,s)),e,n):chr(b>>8*i&255),range(o-1,-1,-1)))
+
+ * arc4.py (5 lines): ARC4 is short for `Alleged RC4'. The
+real RC4 algorithm is proprietary to RSA Data Security Inc. In
+September of 1994, someone posted C code to both the Cypherpunks
+mailing list and to the Usenet newsgroup @code{sci.crypt}, claiming
+that it implemented the RC4 algorithm. This posted code is what I'm
+calling Alleged RC4, or ARC4 for short.
+
+ ARC4 is a private-key cipher; the same key is used to both
+encrypt and decrypt. This is the script most likely to be of
+practical use. It takes one argument, which is the key expressed in
+hex bytes. The key can have any non-zero length.
+
+ An example: To encrypt and then decrypt a message with the key
+'foo', or, in hex, 0x66 0x6f 0x6f:
+
+ cat 'Message.' | arc4.py 666f6f >ciphertext
+ cat ciphertext | arc4.py 666f6f
+
+#!/usr/local/bin/python
+from sys import*;from string import *;t,x,y,j,s,a=range(256),0,0,0,1,argv[1]
+k=(map(lambda b:atoi(a[b:b+2],16), range(0,len(a),2))*256)[:256]
+for i in t[:]:j=(k[i]+t[i]+j)%256;t[i],t[j]=t[j],t[i]
+while(s):s=stdin.read(1);l,x=len(s),(x+1)%256;y,c=(y+t[x])%256,l and ord(s);(
+t[x],t[y])=t[y],t[x];stdout.write(chr(c^t[(t[x]+t[y])%256])[:l])
+
+
+ * otp.py (2 lines): The only truly unbreakable encryption
+method is the one-time pad, or OTP. In the OTP, the plaintext is
+XORed with a stream of random data (the pad) to produce the
+ciphertext. The recipient then XORs the ciphertext and gets the
+plaintext again. This is secure because there is no way for an
+eavesdropper to determine what the intended message is; the only thing
+that can be learned is the length of the message.
+
+ This sounds trivial; just get some random data, XOR it with
+the message, and there you go! But the problem is with that word
+"random"; how do you get truly random data? The rand() function in C
+or your favorite programming language is almost certainly a
+pseudo-random generator; a small amount of state is used to generate a
+sequence of numbers that *looks* random to various statistical tests.
+However, given a few numbers of the sequence, it may be possible to
+derive the rest of the sequence in either the backward or forward
+direction. This is obviously unsafe for a one-time pad; if you could
+get just a few characters of the plaintext, you can compute the value
+of the pad at that point and then derive the rest of the pad.
+
+ Generating truly random numbers is difficult; usually some
+physical phenomenon like keystroke timings, radioactive decay, or the
+noise in a transistor is used. Then there's the problem of key
+distribution; how does your correspondent get the random numbers?
+Governments can afford to send a courier who carries the data in a
+briefcase chained to his/her wrist; can you?
+
+ In any event, let us assume you've magically obtained some
+random numbers and placed them in a file called "pad". otp.py simply
+XORs two files together, so to encrypt a file called "message":
+
+ otp.py pad message >ciphertext
+
+ Decryption is similar:
+ otp.py pad ciphertext >output
+
+#!/usr/local/bin/python
+from sys import*;t=p=1;s=stdout;[i,j]=map(lambda f: open(f, 'r'), argv[1:3])
+while(t and p):t,p=i.read(1),j.read(1);t and p and s.write(chr(ord(t)^ord(p)))
+
+
+ Andrew Kuchling
+ akuchling@acm.org
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2
+
+iQCVAwUBMXIFKQRXhWZuGe+lAQEhlQP+Lz21PC5YjP+RpvFG51THBkDvB+8LVbib
+2erNgCZGyVdIi0SduffwKcEHyhhYnsNxRgqkJslHr5wNkotMgamIWioE1yV2lEGf
+iHktV7RewVWE/GhOZMRqULimuhvFfsyCCgTO1wbW5IKV22904VNli+fkTdgkSRLu
+Kn1cD/HkX6k=
+=hhTw
+-----END PGP SIGNATURE-----
diff --git a/curiosa/arc4.py b/curiosa/arc4.py
new file mode 100644
index 0000000..f854450
--- /dev/null
+++ b/curiosa/arc4.py
@@ -0,0 +1,7 @@
+#!/usr/local/bin/python
+from sys import*;from string import *;t,x,y,j,s,a=range(256),0,0,0,1,argv[1]
+k=(map(lambda b:atoi(a[b:b+2],16), range(0,len(a),2))*256)[:256]
+for i in t[:]:j=(k[i]+t[i]+j)%256;t[i],t[j]=t[j],t[i]
+while(s):s=stdin.read(1);l,x=len(s),(x+1)%256;y,c=(y+t[x])%256,l and ord(s);(
+t[x],t[y])=t[y],t[x];stdout.write(chr(c^t[(t[x]+t[y])%256])[:l])
+
diff --git a/curiosa/gentest.py b/curiosa/gentest.py
new file mode 100644
index 0000000..c20df97
--- /dev/null
+++ b/curiosa/gentest.py
@@ -0,0 +1,8 @@
+import string
+hexstr='0123456789abcdef'
+s=''
+for i in range(0,16,2): s=s+chr(string.atol(hexstr[i:i+2], 16))
+f=open('data', 'w')
+f.write(s)
+f.close()
+
diff --git a/curiosa/otp.py b/curiosa/otp.py
new file mode 100644
index 0000000..e27e017
--- /dev/null
+++ b/curiosa/otp.py
@@ -0,0 +1,3 @@
+#!/usr/local/bin/python
+from sys import*;t=p=1;s=stdout;[i,j]=map(lambda f: open(f, 'r'), argv[1:3])
+while(t and p):t,p=i.read(1),j.read(1);t and p and s.write(chr(ord(t)^ord(p)))
diff --git a/curiosa/rsa.py b/curiosa/rsa.py
new file mode 100644
index 0000000..0506060
--- /dev/null
+++ b/curiosa/rsa.py
@@ -0,0 +1,5 @@
+#!/usr/local/bin/python
+from sys import*;from string import*;a=argv;[s,p,q]=filter(lambda x:x[:1]!=
+'-',a);d='-d'in a;e,n=atol(p,16),atol(q,16);l=(len(q)+1)/2;o,inb=l-d,l-1+d
+while s:s=stdin.read(inb);s and map(stdout.write,map(lambda i,b=pow(reduce(
+lambda x,y:(x<<8L)+y,map(ord,s)),e,n):chr(b>>8*i&255),range(o-1,-1,-1)))
diff --git a/excludefiles b/excludefiles
new file mode 100644
index 0000000..1c89e07
--- /dev/null
+++ b/excludefiles
@@ -0,0 +1,6 @@
+info
+RCS
+*~
+*,v
+excludefiles
+PGP
diff --git a/framewks/block.in b/framewks/block.in
new file mode 100644
index 0000000..19cd5b1
--- /dev/null
+++ b/framewks/block.in
@@ -0,0 +1,561 @@
+/* -*- C -*- */
+/*
+ * block.in : Generic framework for block encryption algorithms
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence. This software is provided "as is" without
+ * warranty of fitness for use or suitability for any purpose, express
+ * or implied. Use at your own risk or not at all.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _HAVE_STDC_HEADERS
+#include <string.h>
+#endif
+
+#include "Python.h"
+#include "modsupport.h"
+
+#ifdef __GNUC__
+#define inline __inline__
+#else
+#define inline
+#endif
+
+
+ /* Cipher operation modes */
+
+#define MODE_ECB 0
+#define MODE_CFB 1
+#define MODE_CBC 2
+#define MODE_OFB 3
+#define MODE_PGP 4
+
+ /* Endianness testing and definitions */
+#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\
+ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;}
+
+#define PCT_LITTLE_ENDIAN 1
+#define PCT_BIG_ENDIAN 0
+
+ /*
+ *
+ * Python interface
+ *
+ */
+
+#define PCTObject_HEAD PyObject_HEAD int cipherMode, count; \
+ unsigned char IV[@@BLOCKSIZE@@], oldCipher[@@BLOCKSIZE@@];
+
+#define PCT_Str(x) #x
+/* GetKeywordArg has been abandoned for PyArg_ParseTupleAndKeywords */
+#define GetKeywordArg(name, default) {\
+ PyObject *arg; \
+ if (kwdict==NULL || \
+ (( arg=PyDict_GetItemString(kwdict, PCT_Str(name)))==NULL )) {new->name = default;} else { \
+ if (!PyInt_Check(arg)) \
+ { \
+ PyErr_SetString(PyExc_TypeError, "Keyword argument must have integer value"); \
+ Py_DECREF(new); \
+ return NULL; \
+ } \
+ new->name = PyInt_AsLong(arg); \
+ } \
+ }
+
+@@IMPLEMENTATION@@
+
+
+staticforward PyTypeObject @@ALGORITHM@@type;
+
+#define is_@@ALGORITHM@@object(v) ((v)->ob_type == &@@ALGORITHM@@type)
+
+static @@ALGORITHM@@object *
+ new@@ALGORITHM@@object()
+{
+ @@ALGORITHM@@object * new;
+ new = PyObject_NEW(@@ALGORITHM@@object, &@@ALGORITHM@@type);
+ new->cipherMode = MODE_ECB;
+ return new;
+}
+
+static void
+@@ALGORITHM@@dealloc(ptr)
+PyObject *ptr;
+{ /* Overwrite the contents of the object, just in case... */
+ int i;
+ @@ALGORITHM@@object *self=(@@ALGORITHM@@object *)ptr;
+
+ for (i = 0; i < sizeof(@@ALGORITHM@@object); i++)
+ *((char *) self + i) = '\0';
+ PyMem_DEL(self);
+}
+
+
+static char @@ALGORITHM@@new__doc__[] =
+"Return a new @@ALGORITHM@@ encryption object.";
+
+static char *kwlist[] = {"key", "mode", "IV", @@KEYWORDLIST@@
+ NULL};
+
+static @@ALGORITHM@@object *
+@@ALGORITHM@@new(self, args, kwdict)
+ PyObject *self; /* Not used */
+ PyObject *args;
+ PyObject *kwdict;
+{
+ unsigned char *key, *IV;
+
+ @@ALGORITHM@@object * new;
+ int i, keylen, IVlen=0, mode=MODE_ECB;
+
+ new = new@@ALGORITHM@@object();
+ /* Set default values */
+ @@KEYWORDDEFAULTS@@
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#|is#" @@KEYWORDFMT@@, kwlist,
+ &key, &keylen, &mode, &IV, &IVlen @@KEYWORDPTRS@@))
+ {
+ Py_XDECREF(new);
+ return NULL;
+ }
+
+ if (@@KEYSIZE@@!=0 && keylen!=@@KEYSIZE@@)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ key must be "
+ "@@KEYSIZE@@ bytes long");
+ return (NULL);
+ }
+ if (@@KEYSIZE@@==0 && keylen==0)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ key cannot be "
+ "the null string (0 bytes long)");
+ return (NULL);
+ }
+ if (IVlen != @@BLOCKSIZE@@ && IVlen != 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ IV must be "
+ "@@BLOCKSIZE@@ bytes long");
+ return (NULL);
+ }
+ if (mode<MODE_ECB || mode>MODE_PGP)
+ {
+ PyErr_SetString(PyExc_ValueError, "Unknown cipher feedback mode");
+ return (NULL);
+ }
+ @@ALGORITHM@@init(new, key, keylen);
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(new);
+ return(NULL);
+ }
+ for (i = 0; i < @@BLOCKSIZE@@; i++)
+ {
+ new->IV[i] = 0;
+ new->oldCipher[i]=0;
+ }
+ for (i = 0; i < IVlen; i++)
+ {
+ new->IV[i] = IV[i];
+ }
+ new->cipherMode = mode;
+ new->count=8;
+ return new;
+}
+
+static char @@ALGORITHM@@_Encrypt__doc__[] =
+"Decrypt the provided string of binary data.";
+
+static PyObject *
+@@ALGORITHM@@_Encrypt(self, args)
+@@ALGORITHM@@object * self;
+ PyObject *args;
+{
+ char *buffer, *str;
+ char temp[@@BLOCKSIZE@@];
+ int i, j, len;
+ PyObject *result;
+
+ if (!PyArg_Parse(args, "s#", &str, &len))
+ return (NULL);
+ if (len==0) /* Handle empty string */
+ {
+ return PyString_FromStringAndSize(NULL, 0);
+ }
+ if ( (len % @@BLOCKSIZE@@) !=0 && self->cipherMode!=MODE_CFB
+ && self->cipherMode!=MODE_PGP)
+ {
+ PyErr_SetString(PyExc_ValueError, "Strings for @@ALGORITHM@@ "
+ "must be a multiple of @@BLOCKSIZE@@ in length");
+ return(NULL);
+ }
+ buffer=malloc(len);
+ if (buffer==NULL)
+ {
+ PyErr_SetString(PyExc_MemoryError, "No memory available in "
+ "@@ALGORITHM@@ encrypt");
+ return(NULL);
+ }
+ switch(self->cipherMode)
+ {
+ case(MODE_ECB):
+ for(i=0; i<len; i+=@@BLOCKSIZE@@)
+ {
+ memcpy(buffer+i, str+i, @@BLOCKSIZE@@);
+ @@ALGORITHM@@encrypt(self, buffer+i);
+ }
+ break;
+ case(MODE_CBC):
+ for(i=0; i<len; i+=@@BLOCKSIZE@@)
+ {
+ for(j=0; j<@@BLOCKSIZE@@; j++)
+ {
+ temp[j]=str[i+j]^self->IV[j];
+ }
+ @@ALGORITHM@@encrypt(self, temp);
+ memcpy(buffer+i, temp, @@BLOCKSIZE@@);
+ memcpy(self->IV, temp, @@BLOCKSIZE@@);
+ }
+ break;
+ case(MODE_CFB):
+ for(i=0; i<len; i++)
+ {
+ @@ALGORITHM@@encrypt(self, self->IV);
+ buffer[i]=str[i]^self->IV[0];
+ memmove(self->IV, self->IV+1, @@BLOCKSIZE@@-1);
+ self->IV[@@BLOCKSIZE@@-1]=buffer[i];
+ }
+ break;
+ case(MODE_PGP):
+ if (len<=@@BLOCKSIZE@@-self->count)
+ { /* If less than one block, XOR it in */
+ for(i=0; i<len; i++)
+ buffer[i] = self->IV[self->count+i] ^= str[i];
+ self->count += len;
+ }
+ else
+ {
+ int j;
+ for(i=0; i<@@BLOCKSIZE@@-self->count; i++)
+ buffer[i] = self->IV[self->count+i] ^= str[i];
+ self->count=0;
+ for(; i<len-@@BLOCKSIZE@@; i+=@@BLOCKSIZE@@)
+ {
+ memcpy(self->oldCipher, self->IV, @@BLOCKSIZE@@);
+ @@ALGORITHM@@encrypt(self, self->IV);
+ for(j=0; j<@@BLOCKSIZE@@; j++)
+ buffer[i+j] = self->IV[j] ^= str[i+j];
+ }
+ /* Do the remaining 1 to BLOCKSIZE bytes */
+ memcpy(self->oldCipher, self->IV, @@BLOCKSIZE@@);
+ @@ALGORITHM@@encrypt(self, self->IV);
+ self->count=len-i;
+ for(j=0; j<len-i; j++)
+ {
+ buffer[i+j] = self->IV[j] ^= str[i+j];
+ }
+ }
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError, "Unknown ciphertext feedback mode; "
+ "this shouldn't happen");
+ return(NULL);
+ }
+ result=PyString_FromStringAndSize(buffer, len);
+ free(buffer);
+ return(result);
+}
+
+static char @@ALGORITHM@@_Decrypt__doc__[] =
+"Decrypt the provided string of binary data.";
+
+
+static PyObject *
+@@ALGORITHM@@_Decrypt(self, args)
+@@ALGORITHM@@object * self;
+ PyObject *args;
+{
+ char *buffer, *str;
+ char temp[@@BLOCKSIZE@@];
+ int i, j, len;
+ PyObject *result;
+
+ if (!PyArg_Parse(args, "s#", &str, &len))
+ return (NULL);
+ if (len==0) /* Handle empty string */
+ {
+ return PyString_FromStringAndSize(NULL, 0);
+ }
+ if ( (len % @@BLOCKSIZE@@) !=0 && self->cipherMode!=MODE_CFB
+ && self->cipherMode!=MODE_PGP)
+ {
+ PyErr_SetString(PyExc_ValueError, "Strings for @@ALGORITHM@@ "
+ "must be a multiple of @@BLOCKSIZE@@ in length");
+ return(NULL);
+ }
+ buffer=malloc(len);
+ if (buffer==NULL)
+ {
+ PyErr_SetString(PyExc_MemoryError, "No memory available in "
+ "@@ALGORITHM@@ decrypt");
+ return(NULL);
+ }
+ switch(self->cipherMode)
+ {
+ case(MODE_ECB):
+ for(i=0; i<len; i+=@@BLOCKSIZE@@)
+ {
+ memcpy(buffer+i, str+i, @@BLOCKSIZE@@);
+ @@ALGORITHM@@decrypt(self, buffer+i);
+ }
+ break;
+ case(MODE_CBC):
+ for(i=0; i<len; i+=@@BLOCKSIZE@@)
+ {
+ memcpy(self->oldCipher, self->IV, @@BLOCKSIZE@@);
+ memcpy(temp, str+i, @@BLOCKSIZE@@);
+ @@ALGORITHM@@decrypt(self, temp);
+ for(j=0; j<@@BLOCKSIZE@@; j++)
+ {
+ buffer[i+j]=temp[j]^self->IV[j];
+ self->IV[j]=str[i+j];
+ }
+ }
+ break;
+ case(MODE_CFB):
+ for(i=0; i<len; i++)
+ {
+ @@ALGORITHM@@encrypt(self, self->IV);
+ buffer[i]=str[i]^self->IV[0];
+ memmove(self->IV, self->IV+1, @@BLOCKSIZE@@-1);
+ self->IV[@@BLOCKSIZE@@-1]=str[i];
+ }
+ break;
+ case(MODE_PGP):
+ if (len<=@@BLOCKSIZE@@-self->count)
+ { /* If less than one block, XOR it in */
+ unsigned char t;
+ for(i=0; i<len; i++)
+ {
+ t=self->IV[self->count+i];
+ buffer[i] = t ^ (self->IV[self->count+i] = str[i]);
+ }
+ self->count += len;
+ }
+ else
+ {
+ int j;
+ unsigned char t;
+ for(i=0; i<@@BLOCKSIZE@@-self->count; i++)
+ {
+ t=self->IV[self->count+i];
+ buffer[i] = t ^ (self->IV[self->count+i] = str[i]);
+ }
+ self->count=0;
+ for(; i<len-@@BLOCKSIZE@@; i+=@@BLOCKSIZE@@)
+ {
+ memcpy(self->oldCipher, self->IV, @@BLOCKSIZE@@);
+ @@ALGORITHM@@encrypt(self, self->IV);
+ for(j=0; j<@@BLOCKSIZE@@; j++)
+ {
+ t=self->IV[j];
+ buffer[i+j] = t ^ (self->IV[j] = str[i+j]);
+ }
+ }
+ /* Do the remaining 1 to BLOCKSIZE bytes */
+ memcpy(self->oldCipher, self->IV, @@BLOCKSIZE@@);
+ @@ALGORITHM@@encrypt(self, self->IV);
+ self->count=len-i;
+ for(j=0; j<len-i; j++)
+ {
+ t=self->IV[j];
+ buffer[i+j] = t ^ (self->IV[j] = str[i+j]);
+ }
+ }
+ break;
+ default:
+ PyErr_SetString(PyExc_SystemError, "Unknown ciphertext feedback mode; "
+ "this shouldn't happen");
+ return(NULL);
+ }
+ result=PyString_FromStringAndSize(buffer, len);
+ free(buffer);
+ return(result);
+}
+
+static char @@ALGORITHM@@_Sync__doc__[] =
+"For objects using the PGP feedback mode, this method modifies the IV, "
+"synchronizing it with the preceding ciphertext.";
+
+static PyObject *
+@@ALGORITHM@@_Sync(self, args)
+@@ALGORITHM@@object * self;
+ PyObject *args;
+{
+ if (self->cipherMode!=MODE_PGP)
+ {
+ PyErr_SetString(PyExc_SystemError, "sync() operation not defined for "
+ "this feedback mode");
+ return(NULL);
+ }
+
+ if (self->count!=8)
+ {
+ memmove(self->IV+@@BLOCKSIZE@@-self->count, self->IV, self->count);
+ memcpy(self->IV, self->oldCipher+self->count, @@BLOCKSIZE@@-self->count);
+ self->count=8;
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#if 0
+void PrintState(self, msg)
+ @@ALGORITHM@@object *self;
+ char * msg;
+{
+ int count;
+
+ printf("%sing: %i IV ", msg, (int)self->count);
+ for(count=0; count<8; count++) printf("%i ", self->IV[count]);
+ printf("\noldCipher:");
+ for(count=0; count<8; count++) printf("%i ", self->oldCipher[count]);
+ printf("\n");
+}
+#endif
+
+
+/* @@ALGORITHM@@ object methods */
+
+static PyMethodDef @@ALGORITHM@@methods[] =
+{
+ {"encrypt", (PyCFunction) @@ALGORITHM@@_Encrypt, 0, @@ALGORITHM@@_Encrypt__doc__},
+ {"decrypt", (PyCFunction) @@ALGORITHM@@_Decrypt, 0, @@ALGORITHM@@_Decrypt__doc__},
+ {"sync", (PyCFunction) @@ALGORITHM@@_Sync, 0, @@ALGORITHM@@_Sync__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+
+static int
+@@ALGORITHM@@setattr(ptr, name, v)
+ PyObject *ptr;
+ char *name;
+ PyObject *v;
+{
+ @@ALGORITHM@@object *self=(@@ALGORITHM@@object *)ptr;
+ if (strcmp(name, "IV") != 0)
+ {
+ PyErr_SetString(PyExc_AttributeError,
+ "non-existent block cipher object attribute");
+ return -1;
+ }
+ if (v==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError,
+ "Can't delete IV attribute of block cipher object");
+ return -1;
+ }
+ if (!PyString_Check(v))
+ {
+ PyErr_SetString(PyExc_TypeError,
+ "IV attribute of block cipher object must be string");
+ return -1;
+ }
+ if (PyString_Size(v)!=@@BLOCKSIZE@@)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ IV must be "
+ "@@BLOCKSIZE@@ bytes long");
+ return -1;
+ }
+ memcpy(self->IV, PyString_AsString(v), @@BLOCKSIZE@@);
+ return (0);
+}
+
+static PyObject *
+@@ALGORITHM@@getattr(s, name)
+ PyObject *s;
+ char *name;
+{
+ @@ALGORITHM@@object *self = (@@ALGORITHM@@object*)s;
+ if (strcmp(name, "IV") == 0)
+ {
+ return(PyString_FromStringAndSize(self->IV, @@BLOCKSIZE@@));
+ }
+ if (strcmp(name, "mode") == 0)
+ {
+ return(PyInt_FromLong((long)(self->cipherMode)));
+ }
+ if (strcmp(name, "blocksize") == 0)
+ {
+ return PyInt_FromLong(@@BLOCKSIZE@@);
+ }
+ if (strcmp(name, "keysize") == 0)
+ {
+ return PyInt_FromLong(@@KEYSIZE@@);
+ }
+ return Py_FindMethod(@@ALGORITHM@@methods, (PyObject *) self, name);
+}
+
+/* List of functions defined in the module */
+
+static struct PyMethodDef modulemethods[] =
+{
+ {"new", (PyCFunction) @@ALGORITHM@@new, METH_VARARGS|METH_KEYWORDS, @@ALGORITHM@@new__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject @@ALGORITHM@@type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "@@ALGORITHM@@", /*tp_name*/
+ sizeof(@@ALGORITHM@@object), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ @@ALGORITHM@@dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ @@ALGORITHM@@getattr, /*tp_getattr*/
+ @@ALGORITHM@@setattr, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc) 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+};
+
+/* Initialization function for the module (*must* be called initxx) */
+
+#define insint(n,v) {PyObject *o=PyInt_FromLong(v); if (o!=NULL) {PyDict_SetItemString(d,n,o); Py_DECREF(o);}}
+
+void
+init@@MODNAME@@()
+{
+ PyObject *m, *d, *x;
+
+ @@ALGORITHM@@type.ob_type = &PyType_Type;
+
+ /* Create the module and add the functions */
+ m = Py_InitModule("@@MODNAME@@", modulemethods);
+
+ /* Add some symbolic constants to the module */
+ d = PyModule_GetDict(m);
+ x = PyString_FromString("@@MODNAME@@.error");
+ PyDict_SetItemString(d, "error", x);
+
+ insint("ECB", MODE_ECB);
+ insint("CFB", MODE_CFB);
+ insint("CBC", MODE_CBC);
+ insint("PGP", MODE_PGP);
+ insint("blocksize", @@BLOCKSIZE@@);
+ insint("keysize", @@KEYSIZE@@);
+
+ /* Check for errors */
+ if (PyErr_Occurred())
+ Py_FatalError("can't initialize module @@MODNAME@@");
+}
+
diff --git a/framewks/hash.in b/framewks/hash.in
new file mode 100644
index 0000000..2a030eb
--- /dev/null
+++ b/framewks/hash.in
@@ -0,0 +1,285 @@
+/*
+ * hash.in : Generic framework for hash function extension modules
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence. This software is provided "as is" without
+ * warranty of fitness for use or suitability for any purpose, express
+ * or implied. Use at your own risk or not at all.
+ *
+ */
+
+/* Basic object type */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef _HAVE_STDC_HEADERS
+#include <string.h>
+#endif
+
+#define Py_USE_NEW_NAMES
+#include "Python.h"
+#include "modsupport.h"
+
+/* Endianness testing and definitions */
+#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\
+ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;}
+
+#define PCT_LITTLE_ENDIAN 1
+#define PCT_BIG_ENDIAN 0
+
+/* This is where the actual code for the hash function will go */
+
+#define PCTObject_HEAD PyObject_HEAD
+#define PCT_Str(x) #x
+/* GetKeywordArg has been abandoned for PyArg_ParseTupleAndKeywords */
+#define GetKeywordArg(name, default) {\
+ PyObject *arg; \
+ if (kwdict==NULL || \
+ (( arg=PyDict_GetItemString(kwdict, PCT_Str(name)))==NULL )) {new->name = default;} else { \
+ if (!PyInt_Check(arg)) \
+ { \
+ PyErr_SetString(PyExc_TypeError, "Keyword argument must have integer value"); \
+ Py_DECREF(new); \
+ return NULL; \
+ } \
+ new->name = PyInt_AsLong(arg); \
+ } \
+ }
+
+@@IMPLEMENTATION@@
+
+staticforward PyTypeObject @@ALGORITHM@@type;
+
+#define is_@@ALGORITHM@@object(v) ((v)->ob_type == &@@ALGORITHM@@type)
+
+static @@ALGORITHM@@object *
+new@@ALGORITHM@@object()
+{
+ @@ALGORITHM@@object *new;
+
+ new = PyObject_NEW(@@ALGORITHM@@object, &@@ALGORITHM@@type);
+ return new;
+}
+
+/* Internal methods for a hashing object */
+
+static void
+@@ALGORITHM@@_dealloc(ptr)
+ PyObject *ptr;
+{
+ @@ALGORITHM@@object *@@ALGORITHM@@ptr=(@@ALGORITHM@@object *)ptr;
+ PyMem_DEL(@@ALGORITHM@@ptr);
+}
+
+
+/* External methods for a hashing object */
+
+static char @@ALGORITHM@@_copy__doc__[] =
+"Return a copy of the hashing object.";
+
+static PyObject *
+@@ALGORITHM@@_copy(self, args)
+ @@ALGORITHM@@object *self;
+ PyObject *args;
+{
+ @@ALGORITHM@@object *newobj;
+
+ if ( (newobj = new@@ALGORITHM@@object())==NULL)
+ return(NULL);
+
+ if (!PyArg_NoArgs(args))
+ {Py_DECREF(newobj); return(NULL);}
+
+ @@ALGORITHM@@copy(self, newobj);
+ return((PyObject *)newobj);
+}
+
+static char @@ALGORITHM@@_digest__doc__[] =
+"Return the digest value as a string of binary data.";
+
+static PyObject *
+@@ALGORITHM@@_digest(self, args)
+ @@ALGORITHM@@object *self;
+ PyObject *args;
+{
+
+ if (!PyArg_NoArgs(args))
+ return NULL;
+
+ return (PyObject *)@@ALGORITHM@@digest(self);
+}
+
+static char @@ALGORITHM@@_hexdigest__doc__[] =
+"Return the digest value as a string of hexadecimal digits.";
+
+static PyObject *
+@@ALGORITHM@@_hexdigest(self, args)
+ @@ALGORITHM@@object *self;
+ PyObject *args;
+{
+ PyObject *value, *retval;
+ unsigned char *raw_digest, *hex_digest;
+ int i, j, size;
+
+ if (!PyArg_NoArgs(args))
+ return NULL;
+
+ /* Get the raw (binary) digest value */
+ value = (PyObject *)@@ALGORITHM@@digest(self);
+ size = PyString_Size(value);
+ raw_digest = PyString_AsString(value);
+
+ /* Create a new string */
+ retval = PyString_FromStringAndSize(NULL, size * 2 );
+ hex_digest = PyString_AsString(retval);
+
+ /* Make hex version of the digest */
+ for(i=j=0; i<size; i++)
+ {
+ char c;
+ c = raw_digest[i] / 16; c = (c>9) ? c+'a'-10 : c + '0';
+ hex_digest[j++] = c;
+ c = raw_digest[i] % 16; c = (c>9) ? c+'a'-10 : c + '0';
+ hex_digest[j++] = c;
+ }
+ Py_DECREF(value);
+ return retval;
+}
+
+static char @@ALGORITHM@@_update__doc__[] =
+"Update this hashing object's state with the provided string.";
+
+static PyObject *
+@@ALGORITHM@@_update(self, args)
+ @@ALGORITHM@@object *self;
+ PyObject *args;
+{
+ unsigned char *cp;
+ int len;
+
+ if (!PyArg_Parse(args, "s#", &cp, &len))
+ return NULL;
+
+ @@ALGORITHM@@update(self, cp, len);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef @@ALGORITHM@@_methods[] = {
+ {"copy", (PyCFunction)@@ALGORITHM@@_copy, 0, @@ALGORITHM@@_copy__doc__},
+ {"digest", (PyCFunction)@@ALGORITHM@@_digest, 0, @@ALGORITHM@@_digest__doc__},
+ {"hexdigest", (PyCFunction)@@ALGORITHM@@_hexdigest, 0, @@ALGORITHM@@_hexdigest__doc__},
+ {"update", (PyCFunction)@@ALGORITHM@@_update, 0, @@ALGORITHM@@_update__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+@@ALGORITHM@@_getattr(self, name)
+ @@ALGORITHM@@object *self;
+ char *name;
+{
+ if (strcmp(name, "blocksize")==0)
+ return PyInt_FromLong(1);
+ if (strcmp(name, "digestsize")==0)
+ return PyInt_FromLong(@@DIGESTSIZE@@);
+
+ return Py_FindMethod(@@ALGORITHM@@_methods, (PyObject *)self, name);
+}
+
+static PyTypeObject @@ALGORITHM@@type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "@@ALGORITHM@@", /*tp_name*/
+ sizeof(@@ALGORITHM@@object), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ @@ALGORITHM@@_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ @@ALGORITHM@@_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+};
+
+
+/* The single module-level function: new() */
+
+static char @@ALGORITHM@@_new__doc__[] =
+ "Return a new @@ALGORITHM@@ hashing object. An optional string "
+ "argument may be provided; if present, this string will be "
+ " automatically hashed.";
+
+static char *kwlist[] = {"string", @@KEYWORDLIST@@
+ NULL};
+
+static PyObject *
+@@ALGORITHM@@_new(self, args, kwdict)
+ PyObject *self;
+ PyObject *args;
+ PyObject *kwdict;
+{
+ @@ALGORITHM@@object *new;
+ unsigned char *cp = NULL;
+ int len;
+
+ if ((new = new@@ALGORITHM@@object()) == NULL)
+ return NULL;
+
+ @@KEYWORDDEFAULTS@@
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#" @@KEYWORDFMT@@, kwlist,
+ &cp, &len @@KEYWORDPTRS@@)) {
+ Py_DECREF(new);
+ return NULL;
+ }
+
+ @@ALGORITHM@@init(new);
+
+ if (PyErr_Occurred()) {Py_DECREF(new); return NULL;}
+ if (cp)
+ @@ALGORITHM@@update(new, cp, len);
+
+ return (PyObject *)new;
+}
+
+
+/* List of functions exported by this module */
+
+static struct PyMethodDef @@ALGORITHM@@_functions[] = {
+ {"new", (PyCFunction)@@ALGORITHM@@_new, METH_VARARGS|METH_KEYWORDS, @@ALGORITHM@@_new__doc__},
+ {"@@MODNAME@@", (PyCFunction)@@ALGORITHM@@_new, METH_VARARGS|METH_KEYWORDS, @@ALGORITHM@@_new__doc__},
+ {NULL, NULL} /* Sentinel */
+};
+
+
+/* Initialize this module. */
+
+#define insint(n,v) {PyObject *o=PyInt_FromLong(v); if (o!=NULL) {PyDict_SetItemString(d,n,o); Py_DECREF(o);}}
+
+void
+init@@MODNAME@@()
+{
+ PyObject *d, *m;
+
+ @@ALGORITHM@@type.ob_type = &PyType_Type;
+ m = Py_InitModule("@@MODNAME@@", @@ALGORITHM@@_functions);
+
+ /* Add some symbolic constants to the module */
+ d = PyModule_GetDict(m);
+ insint("blocksize", 1); /* For future use, in case some hash
+ functions require an integral number of
+ blocks */
+ insint("digestsize", @@DIGESTSIZE@@);
+
+ /* Check for errors */
+ if (PyErr_Occurred())
+ Py_FatalError("can't initialize module @@MODNAME@@");
+}
+
+
diff --git a/framewks/simple.in b/framewks/simple.in
new file mode 100644
index 0000000..6e9a9fd
--- /dev/null
+++ b/framewks/simple.in
@@ -0,0 +1,3 @@
+
+
+@@IMPLEMENTATION@@
diff --git a/framewks/stream.in b/framewks/stream.in
new file mode 100644
index 0000000..f196c10
--- /dev/null
+++ b/framewks/stream.in
@@ -0,0 +1,279 @@
+/* -*- C -*- */
+
+/*
+ * stream.in : Generic framework for stream ciphers
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence. This software is provided "as is" without
+ * warranty of fitness for use or suitability for any purpose, express
+ * or implied. Use at your own risk or not at all.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _HAVE_STDC_HEADERS
+#include <string.h>
+#endif
+
+#include "Python.h"
+#include "modsupport.h"
+
+#ifdef __GNUC__
+#define inline __inline__
+#else
+#define inline
+#endif
+
+
+ /* Endianness testing and definitions */
+#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\
+ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;}
+
+#define PCT_LITTLE_ENDIAN 1
+#define PCT_BIG_ENDIAN 0
+
+
+ /*
+ *
+ * Python interface
+ *
+ */
+
+#define PCTObject_HEAD PyObject_HEAD int dummy /* dummy is never used */
+#define PCT_Str(x) #x
+/* GetKeywordArg has been abandoned for PyArg_ParseTupleAndKeywords */
+#define GetKeywordArg(name, default) {\
+ PyObject *arg; \
+ if (kwdict==NULL || \
+ (( arg=PyDict_GetItemString(kwdict, PCT_Str(name)))==NULL )) {new->name = default;} else { \
+ if (!PyInt_Check(arg)) \
+ { \
+ PyErr_SetString(PyExc_TypeError, "Keyword argument must have integer value"); \
+ Py_DECREF(new); \
+ return NULL; \
+ } \
+ new->name = PyInt_AsLong(arg); \
+ } \
+ }
+
+@@IMPLEMENTATION@@
+
+
+staticforward PyTypeObject @@ALGORITHM@@type;
+
+#define is_@@ALGORITHM@@object(v) ((v)->ob_type == &@@ALGORITHM@@type)
+
+static @@ALGORITHM@@object *
+ new@@ALGORITHM@@object()
+{
+ @@ALGORITHM@@object * new;
+ new = PyObject_NEW(@@ALGORITHM@@object, &@@ALGORITHM@@type);
+ return new;
+}
+
+static void
+@@ALGORITHM@@dealloc(self)
+@@ALGORITHM@@object * self;
+{ /* Overwrite the contents of the object, just in case... */
+ int i;
+
+ for (i = 0; i < sizeof(@@ALGORITHM@@object); i++)
+ *((char *) self + i) = '\0';
+ PyMem_DEL(self);
+}
+
+static char @@ALGORITHM@@new__doc__[] =
+"Return a new @@ALGORITHM@@ encryption object.";
+
+static char *kwlist[] = {"key", @@KEYWORDLIST@@
+ NULL};
+
+static @@ALGORITHM@@object *
+@@ALGORITHM@@new(self, args, kwdict)
+ PyObject *self; /* Not used */
+ PyObject *args;
+ PyObject *kwdict;
+{
+ unsigned char *key;
+ @@ALGORITHM@@object * new;
+ int keylen;
+
+ new = new@@ALGORITHM@@object();
+ @@KEYWORDDEFAULTS@@
+ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s#" @@KEYWORDFMT@@, kwlist,
+ &key, &keylen @@KEYWORDPTRS@@))
+ {
+ Py_DECREF(new);
+ return (NULL);
+ }
+
+ if (@@KEYSIZE@@!=0 && keylen != @@KEYSIZE@@)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ key must be "
+ "@@KEYSIZE@@ bytes long");
+ return (NULL);
+ }
+ if (@@KEYSIZE@@== 0 && keylen == 0)
+ {
+ PyErr_SetString(PyExc_ValueError, "@@ALGORITHM@@ key cannot be "
+ "the null string (0 bytes long)");
+ return (NULL);
+ }
+ @@ALGORITHM@@init(new, key, keylen);
+ if (PyErr_Occurred())
+ {
+ Py_DECREF(new);
+ return (NULL);
+ }
+ return new;
+}
+
+static char @@ALGORITHM@@_Encrypt__doc__[] =
+"Decrypt the provided string of binary data.";
+
+static PyObject *
+@@ALGORITHM@@_Encrypt(self, args)
+@@ALGORITHM@@object * self;
+ PyObject *args;
+{
+ unsigned char *buffer, *str;
+ int len;
+ PyObject *result;
+
+ if (!PyArg_Parse(args, "s#", &str, &len))
+ return (NULL);
+ if (len == 0) /* Handle empty string */
+ {
+ return PyString_FromStringAndSize(NULL, 0);
+ }
+ buffer = malloc(len);
+ if (buffer == NULL)
+ {
+ PyErr_SetString(PyExc_MemoryError, "No memory available in "
+ "@@ALGORITHM@@ encrypt");
+ return (NULL);
+ }
+ memcpy(buffer, str, len);
+ @@ALGORITHM@@encrypt(self, buffer, len);
+ result = PyString_FromStringAndSize(buffer, len);
+ free(buffer);
+ return (result);
+}
+
+static char @@ALGORITHM@@_Decrypt__doc__[] =
+"Decrypt the provided string of binary data.";
+
+static PyObject *
+@@ALGORITHM@@_Decrypt(self, args)
+@@ALGORITHM@@object * self;
+ PyObject *args;
+{
+ char *buffer, *str;
+ int len;
+ PyObject *result;
+
+ if (!PyArg_Parse(args, "s#", &str, &len))
+ return (NULL);
+ if (len == 0) /* Handle empty string */
+ {
+ return PyString_FromStringAndSize(NULL, 0);
+ }
+ buffer = malloc(len);
+ if (buffer == NULL)
+ {
+ PyErr_SetString(PyExc_MemoryError, "No memory available in "
+ "@@ALGORITHM@@ decrypt");
+ return (NULL);
+ }
+ memcpy(buffer, str, len);
+ @@ALGORITHM@@decrypt(self, buffer, len);
+ result = PyString_FromStringAndSize(buffer, len);
+ free(buffer);
+ return (result);
+}
+
+/* @@ALGORITHM@@object methods */
+
+static PyMethodDef @@ALGORITHM@@methods[] =
+{
+ {"encrypt", (PyCFunction) @@ALGORITHM@@_Encrypt, 0, @@ALGORITHM@@_Encrypt__doc__},
+ {"decrypt", (PyCFunction) @@ALGORITHM@@_Decrypt, 0, @@ALGORITHM@@_Decrypt__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+@@ALGORITHM@@getattr(self, name)
+@@ALGORITHM@@object * self;
+ char *name;
+{
+ if (strcmp(name, "blocksize") == 0)
+ {
+ return PyInt_FromLong(@@BLOCKSIZE@@);
+ }
+ if (strcmp(name, "keysize") == 0)
+ {
+ return PyInt_FromLong(@@KEYSIZE@@);
+ }
+ return Py_FindMethod(@@ALGORITHM@@methods, (PyObject *) self, name);
+}
+
+
+/* List of functions defined in the module */
+
+static struct PyMethodDef modulemethods[] =
+{
+ {"new", (PyCFunction) @@ALGORITHM@@new, METH_VARARGS|METH_KEYWORDS, @@ALGORITHM@@new__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyTypeObject @@ALGORITHM@@type =
+{
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size*/
+ "@@ALGORITHM@@", /*tp_name*/
+ sizeof(@@ALGORITHM@@object), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ @@ALGORITHM@@dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ @@ALGORITHM@@getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+ 0, /*tp_as_number*/
+};
+
+/* Initialization function for the module (*must* be called initxx) */
+
+#define insint(n,v) {PyObject *o=PyInt_FromLong(v); if (o!=NULL) {PyDict_SetItemString(d,n,o); Py_DECREF(o);}}
+
+void
+ init@@MODNAME@@()
+{
+ PyObject *m, *d, *x;
+
+ @@ALGORITHM@@type.ob_type = &PyType_Type;
+ /* Create the module and add the functions */
+ m = Py_InitModule("@@MODNAME@@", modulemethods);
+
+ /* Add some symbolic constants to the module */
+ d = PyModule_GetDict(m);
+ x = PyString_FromString("@@MODNAME@@.error");
+ PyDict_SetItemString(d, "error", x);
+
+ insint("blocksize", @@BLOCKSIZE@@);
+ insint("keysize", @@KEYSIZE@@);
+
+ /* Check for errors */
+ if (PyErr_Occurred())
+ Py_FatalError("can't initialize module @@MODNAME@@");
+}
+
+
diff --git a/info/architecture.txt b/info/architecture.txt
new file mode 100644
index 0000000..d36b3ac
--- /dev/null
+++ b/info/architecture.txt
@@ -0,0 +1,647 @@
+Network Working Group T. Ylonen
+INTERNET-DRAFT T. Kivinen
+draft-ietf-secsh-architecture-01.txt M. Saarinen
+Expires in six months SSH
+ 7 November 1997
+
+ SSH Protocol Architecture
+
+Status of This memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other documents
+at any time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as ``work in progress.''
+
+To learn the current status of any Internet-Draft, please check
+the ``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast),
+or ftp.isi.edu (US West Coast).
+
+Abstract
+
+SSH is a protocol for secure remote login and other secure network
+services over an insecure network.
+
+This document describes the architecture of the SSH protocol, and the
+notation and terminology used in SSH protocol documents. It also discusses
+the SSH algorithm naming system that allows local extensions.
+
+The SSH protocol consists of three major components: Transport layer
+protocol provides server authentication, confidentiality, and integrity
+with perfect forward secrecy. User authentication protocol authenticates
+the client to the server. Connection protocol multiplexes the encrypted
+tunnel into several logical channels. Details of these protocols are
+described in separate documents.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 1]
+
+INTERNET-DRAFT 7 November 1997
+
+Table of Contents
+
+1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+2. Specification of Requirements . . . . . . . . . . . . . . . . . 2
+3. Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 3.1. Host Keys . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 3.2. Extensibility . . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.3. Policy Issues . . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.4. Security Properties . . . . . . . . . . . . . . . . . . . . 5
+ 3.5. Packet Size and Overhead . . . . . . . . . . . . . . . . . . 5
+ 3.6. Localization and Character Set Support . . . . . . . . . . . 6
+4. Data Type Representations Used in the SSH Protocols . . . . . . 7
+ 4.1. Encoding of Network Addresses . . . . . . . . . . . . . . . 8
+5. Algorithm Naming . . . . . . . . . . . . . . . . . . . . . . . . 8
+6. Message Numbers . . . . . . . . . . . . . . . . . . . . . . . . 9
+7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 9
+8. Security Considerations . . . . . . . . . . . . . . . . . . . . 10
+9. References . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
+10. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 11
+
+
+
+1. Introduction
+
+SSH is a protocol for secure remote login and other secure network
+services over an insecure network. It consists of three major
+components:
+
+o Transport layer protocol [SSH-TRANS] provides server authentication,
+ confidentiality, and integrity. It may optionally also provide
+ compression. The transport layer will typically be run over a TCP/IP
+ connection, but might also be used on top of any other reliable data
+ stream.
+
+o User authentication protocol [SSH-USERAUTH] authenticates the client-
+ side user to the server. It runs over the transport layer protocol.
+
+o Connection protocol [SSH-CONN] multiplexes the encrypted tunnel into
+ several logical channels. It runs over the user authentication
+ protocol.
+
+The client sends a service request once a secure transport layer
+connection has been established. A second service request is sent after
+user authentication is complete. This allows new protocols to be defined
+and coexist with the protocols listed above.
+
+The connection protocol provides channels that can be used for a wide
+range of purposes. Standard methods are provided for setting up secure
+interactive shell sessions and for forwarding ("tunneling") arbitrary
+TCP/IP ports and X11 connections.
+
+2. Specification of Requirements
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 2]
+
+INTERNET-DRAFT 7 November 1997
+
+All of the documents related to the SSH protocols shall use the keywords
+"MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD
+NOT", "RECOMMENDED, "MAY", and "OPTIONAL" to describe requirements.
+They are to be interpreted as described in [RFC-2119].
+
+3. Architecture
+
+3.1. Host Keys
+
+Each server host MUST have a host key. Hosts MAY have multiple host
+keys using multiple different algorithms. Multiple hosts MAY share the
+same host key. Every host MUST have at least one key using each REQUIRED
+public key algorithm (currently DSS [FIPS-186]).
+
+The server host key is used during key exchange to verify that the
+client is really talking to the correct server. For this to be possible,
+the client must have a priori knowledge of the server's public host key.
+
+Two different trust models can be used:
+
+o The client has a local database that associates each host name (as
+ typed by the user) with the corresponding public host key. This
+ method requires no centrally administered infrastructure, and no
+ third-party coordination. The downside is that the database of name-
+ key associations may become burdensome to maintain.
+
+o The host name - key association is certified by some trusted
+ certification authority. The client only knows the CA root key, and
+ can verify the validity of all host keys certified by accepted CAs.
+
+ The second alternative eases the maintenance problem, since ideally
+ only a single CA key needs to be securely stored on the client. On
+ the other hand, each host key must be appropriately certified by a
+ central authority before authorization is possible. Also, a lot of
+ trust is placed on the central infrastructure.
+
+The protocol provides the option that the server name - host key
+association is not checked when connecting the host for the first time.
+This allows communication without prior communication of host keys or
+certification. The connection still provides protection against passive
+listening; however, it becomes vulnerable to active man-in-the-middle
+attacks. Implementations SHOULD NOT normally allow such connections by
+default, as they pose a potential security problem. However, as there
+is no widely deployed key infrastructure available on the Internet yet,
+this option makes the protocol much more usable during the transition
+time until such an infrastructure emerges, while still providing a much
+higher level of security than that offered by older solutions (e.g.
+telnet [RFC-854] and rlogin [RFC-1282]).
+Implementations SHOULD try to make best effort to check host keys. An
+example of a possible strategy is to only accept a host key without
+checking the first time a host is connected, save the key in a local
+database, and compare against that key on all future connections to that
+host.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 3]
+
+INTERNET-DRAFT 7 November 1997
+
+Implementations MAY provide additional methods for verifying the
+correctness of host keys, e.g. a hexadecimal fingerprint derived from
+the SHA-1 hash of the public key. Such fingerprints can easily be
+verified by using telephone or other external communication channels.
+
+All implementations SHOULD provide an option to not accept host keys
+that cannot be verified.
+
+We believe that ease of use is critical to end-user acceptance of
+security solutions, and no improvement in security is gained if the new
+solutions are not used. Thus, providing the option not to check the
+the server host key is believed to improve overall security of the
+Internet, even though it reduces the security of the protocol in
+configurations where it is allowed.
+
+3.2. Extensibility
+
+We believe that the protocol will evolve over time, and some
+organizations will want to use their own encryption, authentication
+and/or key exchange methods. Central registration of all extensions is
+cumbersome, especially for experimental or classified features. On the
+other hand, having no central registration leads to conflicts in method
+identifiers, making interoperability difficult.
+
+We have chosen to identify algorithms, methods, formats, and extension
+protocols with textual names that are of a specific format. DNS names
+are used to create local namespaces where experimental or classified
+extensions can be defined without fear of conflicts with other
+implementations.
+
+One design goal has been to keep the base protocol as simple as
+possible, and to require as few algorithms as possible. However, all
+implementations MUST support a minimal set of algorithms to ensure
+interoperability (this does not imply that the local policy on all hosts
+would necessary allow these algorithms). The mandatory algorithms are
+specified in the relevant protocol documents.
+
+Additional algorithms, methods, formats, and extension protocols can be
+defined in separate drafts. See Section ``Algorithm Naming'' for more
+information.
+
+3.3. Policy Issues
+
+The protocol allows full negotiation of encryption, integrity, key
+exchange, compression, and public key algorithms and formats.
+Encryption, integrity, public key, and compression algorithms can be
+different for each direction.
+
+The following policy issues SHOULD be addressed in the configuration
+mechanisms of each implementation:
+
+o Encryption, integrity, and compression algorithms, separately for
+ each direction. The policy MUST specify which is the preferred
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 4]
+
+INTERNET-DRAFT 7 November 1997
+
+ algorithm (e.g. the first algorithm listed in each category).
+
+o Public key algorithms and key exchange method to be used for host
+ authentication. The existence of trusted host keys for different
+ public key algorithms also affects this choice.
+
+o The authentication methods that are to be required by the server for
+ each user. The server's policy MAY require multiple authentication
+ for some or all users. The required algorithms MAY depend on the
+ location from where the user is trying to log in from.
+
+o The operations that the user is allowed to perform using the
+ connection protocol. Some issues are related to security; for
+ example, the policy SHOULD NOT allow the server to start sessions or
+ run commands on the client machine, and MUST NOT allow connections to
+ the authentication agent unless forwarding it has been requested.
+ Other issues, such as which TCP/IP ports can be forwarded and by
+ whom, are clear local policy issues. Many of these issues may
+ involve traversing or bypassing firewalls, and are interrelated with
+ the local security policy.
+
+3.4. Security Properties
+
+The primary goal of the SSH protocols is improved security on the
+Internet. It attempts to do this in a way that is easy to deploy, even
+at the cost of absolute security.
+
+o All encryption, integrity, and public key algorithms used are well-
+ known, well-established algorithms.
+
+o All algorithms are used with cryptographically sound key sizes that
+ are believed to provide protection against even the strongest
+ cryptanalytic attacks for decades.
+
+o All algorithms are negotiated, and in case some algorithm is broken,
+ it is easy to switch to some other algorithm without modifying the
+ base protocol.
+
+Specific concessions were made to make wide-spread fast deployment
+easier. The particular case where this comes up is verifying that the
+server host key really belongs to the desired host; the protocol allows
+the verification to be left out (but this is NOT RECOMMENDED). This is
+believed to significantly improve usability in the short term, until
+widespread Internet public key infrastructures emerge.
+
+3.5. Packet Size and Overhead
+
+Some readers will worry about the increase in packet size due to new
+headers, padding, and MAC. The minimum packet size in the order of 28
+bytes (depending on negotiated algorithms). The increase is negligible
+for large packets, but very significant for one-byte packets (telnet-
+type sessions). There are, however, several factors that make this a
+non-issue in almost all cases:
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 5]
+
+INTERNET-DRAFT 7 November 1997
+
+o The minimum size of a TCP/IP header is 32 bytes. Thus, the increase
+ is actually from 33 to 51 bytes (roughly).
+
+o The minimum size of the data field of an ethernet packet is 46 bytes
+ [RFC-894]. Thus, the increase is by no more than 5 bytes. When
+ ethernet headers are considered, the increase is by less than 10
+ percent.
+
+o The total fraction of telnet-type data in the Internet is negligible,
+ even with increased packet sizes.
+
+The only environment where the packet size increase is likely to have
+significant effect is PPP [RFC-1134] over slow modem lines (PPP
+compresses the TCP/IP headers, emphasizing the increase in packet size).
+However, with modern modems, the time needed to transfer is on the order
+of 2ms, which is a lot faster than people can type.
+
+There are also issues related to the maximum packet size. To minimize
+delays in screen updates, one does not want excessively large packets
+for interactive sessions. The maximum packet size is negotiated
+separately for each channel.
+
+3.6. Localization and Character Set Support
+
+For the most part, the SSH protocols do not directly pass text that
+would be displayed to the user. However, there are some places where
+such data might be passed. When applicable, the character set for the
+data MUST be explicitly specified. In most places, ISO 10646 with UTF-8
+encoding is used [RFC-2044]. When applicable, a field is also be
+provided for a language tag [RFC-1766].
+
+One big issue is the character set of the interactive session. There is
+no clear solution, as different applications may display data in
+different formats. Different types of terminal emulation may also be
+employed in the client, and the character set to be used is effectively
+determined by the terminal emulation. Thus, no place is provided for
+specifying the character set or encoding for terminal session data
+directly. However, the terminal emulation type (e.g. "vt100") is
+transmitted to the remote site, and it implicitly specifies the
+character set and encoding. Applications typically use the terminal
+type to determine what character set they use, or the character set is
+determined using some external means. The terminal emulation may also
+allow configuring the default character set. In any case, character set
+for the terminal session is considered primarily a client local issue.
+
+Internal names used to identify algorithms or protocols are normally
+never displayed to users, and must be in US-ASCII.
+
+The client and server user names are inherently constrained by what the
+server is prepared to accept. They might, however, occasionally be
+displayed in logs, reports, etc. They MUST be encoded using ISO 10646
+UTF-8, but other encodings may be required in some cases. It is up to
+the server to decide how to map user names to accepted user names.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 6]
+
+INTERNET-DRAFT 7 November 1997
+
+Straight bit-wise binary comparison is RECOMMENDED.
+
+For localization purposes, the protocol attempts to minimize the number
+of textual messages transmitted. When present, such messages typically
+relate to errors, debugging information, or some externally configured
+data. For data that is normally displayed, it SHOULD be possible to
+fetch a localized message instead of the transmitted by using a numeric
+code. The remaining messages SHOULD be configurable.
+
+4. Data Type Representations Used in the SSH Protocols
+
+ byte
+ A byte represents an arbitrary 8-bit value (octet) [RFC1700].
+ Fixed length data is sometimes represented as an array of bytes,
+ written byte[n], where n is the number of bytes in the array.
+
+ boolean
+ A boolean value is stored as a single byte. The value 0
+ represents false, and the value 1 represents true. All non-zero
+ values MUST be interpreted as true; however, applications MUST not
+ store values other than 0 and 1.
+
+ uint32
+ Represents a 32-bit unsigned integer. Stored as four bytes in the
+ order of decreasing significance (network byte order).
+
+ For example, the value 699921578 (0x29b7f4aa) is stored as 29 b7
+ f4 aa.
+
+ string
+ Arbitrary length binary string. Strings are allowed to contain
+ arbitrary binary data, including null characters and 8-bit
+ characters. They are stored as a uint32 containing its length
+ (number of bytes that follow) and zero (= empty string) or more
+ bytes that are the value of the string. Terminating null
+ characters are not used.
+
+ Strings are also used to store text. In that case, US-ASCII is
+ used for internal names, and ISO-10646 UTF-8 for text that might
+ be displayed to the user. Terminating null character SHOULD
+ normally not be stored in the string.
+
+ For example, the US-ASCII string "testing" is represented as 00 00
+ 00 07 t e s t i n g. The UTF8 mapping does not alter the encoding
+ of US-ASCII characters.
+
+ mpint
+ Represents multiple precision integers in two's complement format,
+ stored as a string, 8 bits per byte, MSB first. Negative numbers
+ have one in the most significant bit of the first byte of the data
+ partition of. If the most significant bit would be set for a
+ positive number, the number MUST be preceded by a zero byte.
+ Unnecessary leading zero or 255 bytes MUST NOT be included. The
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 7]
+
+INTERNET-DRAFT 7 November 1997
+
+ value zero MUST be stored as a string with zero bytes of data.
+
+ By convention, a number that is used in modular computations in
+ Z_n SHOULD be represented in the range 0 <= x < n.
+
+ Examples:
+
+ value (hex) representation (hex)
+ ---------------------------------------------------------------
+ 0 00 00 00 00
+ 9a378f9b2e332a7 00 00 00 08 09 a3 78 f9 b2 e3 32 a7
+ 80 00 00 00 02 00 80
+ -1234 00 00 00 02 ed cc
+ -deadbeef 00 00 00 05 ff 21 52 41 11
+
+4.1. Encoding of Network Addresses
+
+Network addresses are encoded as strings. DNS names MUST NOT be used, as
+DNS is an insecure protocol.
+
+If an address contains a colon (':', ascii 58), it is interpreted as an
+IPv6 address. The encoding of IPv6 addresses is described in RFC-1884.
+IPv4 addresses are expressed in the standard dot-separated decimal
+format (e.g. 127.0.0.1).
+
+5. Algorithm Naming
+
+The SSH protocols refer to particular hash, encryption, integrity,
+compression, and key exchange algorithms or protocols by names. There
+are some standard algorithms that all implementations MUST support.
+There are also algorithms that are defined in the protocol specification
+but are OPTIONAL. Furthermore, it is expected that some organizations
+will want to use their own algorithms.
+
+In this protocol, all algorithm identifiers MUST be printable US-ASCII
+strings no longer than 64 characters. Names MUST be case-sensitive.
+
+There are two formats for algorithm names:
+
+o Names that do not contain an at-sign (@) are reserved to be assigned
+ by IANA (Internet Assigned Numbers Authority). Examples include
+ `3des-cbc', `sha-1', `hmac-sha1', and `zlib' (the quotes are not part
+ of the name). Additional names of this format may be registered with
+ IANA; see Section ``IANA Considerations''. Names of this format MUST
+ NOT be used without first registering with IANA. Registered names
+ MUST NOT contain an at-sign (@) or a comma (,).
+
+o Anyone can define additional algorithms by using names in the format
+ name@domainname, e.g. "ourcipher-cbc@ssh.fi". The format of the part
+ preceding the at sign is not specified; it MUST consist of US-ASCII
+ characters except at-sign and comma. The part following the at-sign
+ MUST be a valid fully qualified internet domain name [RFC-1034]
+ controlled by the person or organization defining the name. It is up
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 8]
+
+INTERNET-DRAFT 7 November 1997
+
+ to each domain how it manages its local namespace.
+
+6. Message Numbers
+
+SSH packets have message numbers in the range 1-255. These numbers have
+been allocated as follows:
+
+ Transport layer protocol:
+
+ 1-19 Transport layer generic (e.g. disconnect, ignore, debug,
+ etc)
+ 20-29 Algorithm negotiation
+ 30-49 Key exchange method specific (numbers can be reused for
+ different authentication methods)
+
+ User authentication protocol:
+
+ 50-59 User authentication generic
+ 60-79 User authentication method specific (numbers can be reused
+ for different authentication methods)
+
+ Connection protocol:
+
+ 80-89 Connection protocol generic
+ 90-127 Channel related messages
+
+ Reserved for client protocols:
+
+ 128-191 Reserved
+
+ Local extensions:
+
+ 192-255 Local extensions
+
+7. IANA Considerations
+
+Allocation of the following types of names in the SSH protocols is
+assigned to IANA:
+
+o encryption algorithm names,
+
+o MAC algorithm names,
+
+o public key algorithm names (public key algorithm also implies
+ encoding and signature/encryption capability),
+
+o key exchange method names, and
+
+o protocol (service) names.
+
+The IANA-allocated names MUST be printable US-ASCII strings, and MUST
+NOT contain the characters at-sign ('@'), comma (','), or whitespace or
+control characters (ascii codes 32 or less). Names are case-sensitive,
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 9]
+
+INTERNET-DRAFT 7 November 1997
+
+and MUST not be longer than 64 characters.
+
+Each category of names listed above has a separate namespace. However,
+using the same name in multiple categories SHOULD be avoided to minimize
+confusion.
+8. Security Considerations
+
+Special care should be taken to ensure that all of the random numbers
+are of good quality. The random numbers SHOULD be produced with safe
+mechanisms discussed in [RFC1750].
+
+When displaying text, such as error or debug messages to the user, the
+client software SHOULD replace any control characters (except tab,
+carriage return and newline) with safe sequences to avoid attacks by
+sending terminal control characters.
+
+Not using MAC or encryption SHOULD be avoided. The user authentication
+protocol is subject to man-in-the-middle attacks if the encryption is
+disabled. The SSH protocol does not protect against message alteration
+if no MAC is used.
+
+9. References
+
+[FIPS-186] Federal Information Processing Standards Publication (FIPS
+PUB) 186, Digital Signature Standard, 18 May 1994.
+
+[RFC-854] Postel, J. and Reynolds, J., "Telnet Protocol Specification",
+May 1983.
+
+[RFC-894] Hornig, C., "A Standard for the Transmission of IP Datagrams
+over Ethernet Networks", April 1984.
+
+[RFC-1034] Mockapetris, P., "Domain Names - Concepts and Facilities",
+November 1987.
+
+[RFC-1134] Perkins, D., "The Point-to-Point Protocol: A Proposal for
+Multi-Protocol Transmission o Datagrams Over Point-to-Point Links",
+November 1989.
+
+[RFC-1282] Kantor, B., "BSD Rlogin", December 1991.
+
+[RFC-1700] Reynolds, J. and Postel, J., "Assigned Numbers", October 1994
+(also STD 2).
+
+[RFC-1750] Eastlake, D., Crocker, S., and Schiller, J., "Randomness
+Recommendations for Security", December 1994.
+
+[RFC-1766] Alvestrand, H., "Tags for the Identification of Languages",
+March 1995.
+
+[RFC-2044] Yergeau, F., "UTF-8, a Transformation Format of Unicode and
+ISO 10646", October 1996.
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 10]
+
+INTERNET-DRAFT 7 November 1997
+
+[RFC-2119] Bradner, S., "Key words for use in RFCs to indicate
+Requirement Levels", March 1997
+
+[Schneier] Schneier, B., "Applied Cryptography Second Edition", John
+Wiley & Sons, New York, NY, 1995.
+
+[SSH-TRANS] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Transport
+Layer Protocol", Internet Draft, draft-ietf-secsh-transport-02.txt
+
+[SSH-USERAUTH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH
+Authentication Protocol", Internet Draft, draft-ietf-secsh-
+userauth-02.txt
+
+[SSH-CONNECT] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Connection
+Protocol", Internet Draft, draft-ietf-secsh-connect-02.txt
+
+10. Authors' Addresses
+
+ Tatu Ylonen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: ylo@ssh.fi
+
+ Tero Kivinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: kivinen@ssh.fi
+
+ Markku-Juhani O. Saarinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: mjos@ssh.fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 11]
diff --git a/info/connect.txt b/info/connect.txt
new file mode 100644
index 0000000..2cf1aea
--- /dev/null
+++ b/info/connect.txt
@@ -0,0 +1,1001 @@
+Network Working Group T. Ylonen
+INTERNET-DRAFT T. Kivinen
+draft-ietf-secsh-connect-03.txt M. Saarinen
+Expires in six months SSH
+ 7 November 1997
+
+ SSH Connection Protocol
+
+Status of This memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other documents
+at any time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as ``work in progress.''
+
+To learn the current status of any Internet-Draft, please check
+the ``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast),
+or ftp.isi.edu (US West Coast).
+
+Abstract
+
+SSH is a protocol for secure remote login and other secure network
+services over an insecure network.
+
+This document describes the SSH connection protocol. It provides
+interactive login sessions, remote execution of commands, forwarded
+TCP/IP connections, and forwarded X11 connections. All of these
+channels are multiplexed into a single encrypted tunnel.
+
+The SSH Connection Protocol has been designed to run on top of
+the SSH transport layer and user authentication protocols.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 1]
+
+INTERNET-DRAFT 7 November 1997
+
+Table of Contents
+
+1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+2. Global Requests . . . . . . . . . . . . . . . . . . . . . . . . 2
+3. Channel Mechanism . . . . . . . . . . . . . . . . . . . . . . . 3
+ 3.1. Opening a Channel . . . . . . . . . . . . . . . . . . . . . 3
+ 3.2. Data Transfer . . . . . . . . . . . . . . . . . . . . . . . 4
+ 3.3. Closing a Channel . . . . . . . . . . . . . . . . . . . . . 5
+ 3.4. Channel-Specific Requests . . . . . . . . . . . . . . . . . 6
+4. Interactive Sessions . . . . . . . . . . . . . . . . . . . . . . 6
+ 4.1. Opening a Session . . . . . . . . . . . . . . . . . . . . . 6
+ 4.2. Requesting a Pseudo-Terminal . . . . . . . . . . . . . . . . 7
+ 4.3. X11 Forwarding . . . . . . . . . . . . . . . . . . . . . . . 7
+ 4.3.1. Requesting X11 Forwarding . . . . . . . . . . . . . . . 7
+ 4.3.2. X11 Channels . . . . . . . . . . . . . . . . . . . . . . 8
+ 4.4. Authentication Agent Forwarding . . . . . . . . . . . . . . 8
+ 4.4.1. Requesting Authentication Agent Forwarding . . . . . . . 8
+ 4.4.2. Authentication Agent Channels . . . . . . . . . . . . . 8
+ 4.5. Environment Variable Passing . . . . . . . . . . . . . . . . 9
+ 4.6. Starting a Shell or a Command . . . . . . . . . . . . . . . 9
+ 4.7. Session Data Transfer . . . . . . . . . . . . . . . . . . . 10
+ 4.8. Window Dimension Change Message . . . . . . . . . . . . . . 10
+ 4.9. Local Flow Control . . . . . . . . . . . . . . . . . . . . . 10
+ 4.10. Signals . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 4.11. Returning Exit Status . . . . . . . . . . . . . . . . . . . 11
+5. TCP/IP Port Forwarding . . . . . . . . . . . . . . . . . . . . . 11
+ 5.1. Requesting Port Forwarding . . . . . . . . . . . . . . . . . 12
+ 5.2. TCP/IP Forwarding Channels . . . . . . . . . . . . . . . . . 12
+6. Encoding of Terminal Modes . . . . . . . . . . . . . . . . . . . 13
+7. Summary of Message Numbers . . . . . . . . . . . . . . . . . . . 15
+8. Security Considerations . . . . . . . . . . . . . . . . . . . . 15
+9. References . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
+10. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 16
+
+
+
+1. Introduction
+
+The SSH Connection Protocol has been designed to run on top of the SSH
+transport layer and user authentication protocols. It provides
+interactive login sessions, remote execution of commands, forwarded
+TCP/IP connections, and forwarded X11 connections. The service name for
+this protocol (after user authentication) is "ssh-connection".
+
+This document should be read only after reading the SSH architecture
+document [SSH-ARCH]. This document freely uses terminology and notation
+from the architecture document without reference or further explanation.
+
+2. Global Requests
+
+There are several kinds of requests that affect the state of the remote
+end "globally", independent of any channels. An example is a request to
+start TCP/IP forwarding for a specific port. All such requests use the
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 2]
+
+INTERNET-DRAFT 7 November 1997
+
+following format.
+
+ byte SSH_MSG_GLOBAL_REQUEST
+ string request name (restricted to US-ASCII)
+ boolean want reply
+ ... request-specific data follows
+
+The recipient will respond to this message with SSH_MSG_REQUEST_SUCCESS,
+SSH_MSG_REQUEST_FAILURE, or some request-specific continuation messages
+if `want reply' is TRUE.
+
+ byte SSH_MSG_REQUEST_SUCCESS
+
+If the recipient does not recognize or support the request, it simply
+responds with SSH_MSG_REQUEST_FAILURE.
+
+ byte SSH_MSG_REQUEST_FAILURE
+
+3. Channel Mechanism
+
+All terminal sessions, forwarded connections, etc. are channels. Either
+side may open a channel. Multiple channels are multiplexed into a
+single connection.
+
+Channels are identified by numbers at each end. The number referring to
+a channel may be different on each side. Requests to open a channel
+contain the sender's channel number. Any other channel-related messages
+contain the recipient's channel number for the channel.
+
+Channels are flow-controlled. No data may be sent to a channel until a
+message is received to indicate that window space is available.
+
+3.1. Opening a Channel
+
+When either side wishes to open a new channel, it allocates a local
+number for the channel. It then sends the following message to the
+other side, and includes the local channel number and initial window
+size in the message.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string channel type (restricted to US-ASCII)
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ ... channel type specific data follows
+
+The channel type is a name as described in the SSH architecture
+document, with similar extension mechanisms. `sender channel' is a local
+identifier for the channel used by the sender of this message. `initial
+window size' specifies how many bytes of channel data can be sent to the
+sender of this message without adjusting the window. `Maximum packet
+size' specifies the maximum size of an individual data packet that can
+be sent to the sender (for example, one might want to use smaller
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 3]
+
+INTERNET-DRAFT 7 November 1997
+
+packets for interactive connections to get better interactive response
+on slow links).
+
+The remote side then decides whether it can open the channel, and
+responds with either
+ byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
+ uint32 recipient channel
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ ... channel type specific data follows
+
+where `recipient channel' is the channel number given in the original
+open request, and `sender channel' is the channel number allocated by
+the other side, or
+
+ byte SSH_MSG_CHANNEL_OPEN_FAILURE
+ uint32 recipient channel
+ uint32 reason code
+ string additional textual information (ISO-10646 UTF-8
+ [[RFC-2044]])
+ string language tag (as defined in [[RFC-1766]])
+
+If the recipient of the SSH_MSG_CHANNEL_OPEN message does not support
+the specified channel type, it simply responds with
+SSH_MSG_CHANNEL_OPEN_FAILURE. The client MAY show the additional
+information to the user. If this is done, the client software should
+take the precautions discussed in [SSH-ARCH].
+
+The following reason codes are defined:
+
+#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
+#define SSH_OPEN_CONNECT_FAILED 2
+#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
+#define SSH_OPEN_RESOURCE_SHORTAGE 4
+
+3.2. Data Transfer
+
+The window size specifies how many bytes the other party can send before
+it must wait for the window to be adjusted. Both parties use the
+following message to adjust the window.
+
+ byte SSH_MSG_CHANNEL_WINDOW_ADJUST
+ uint32 recipient channel
+ uint32 bytes to add
+
+After receiving this message, the recipient MAY send the given number of
+bytes more that it was previously allowed to send; the window size is
+incremented.
+
+Data transfer is done with messages of the following type.
+
+ byte SSH_MSG_CHANNEL_DATA
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 4]
+
+INTERNET-DRAFT 7 November 1997
+
+ uint32 recipient channel
+ string data
+
+The maximum amount of data allowed is the current window size. The
+window size is decremented by the amount of data sent. Both parties MAY
+ignore all extra data sent after the allowed window is empty.
+
+Additionally, some channels can transfer several types of data. An
+example of this is stderr data from interactive sessions. Such data can
+be passed with SSH_MSG_CHANNEL_EXTENDED_DATA messages, where a separate
+integer specifies the type of the data. The available types and their
+interpretation depend on the type of the channel.
+
+ byte SSH_MSG_CHANNEL_EXTENDED_DATA
+ uint32 recipient_channel
+ uint32 data_type_code
+ string data
+
+Data sent with these messages consumes the same window as ordinary data.
+
+Currently, only the following type is defined.
+
+#define SSH_EXTENDED_DATA_STDERR 1
+
+3.3. Closing a Channel
+
+When a party will no longer send more data to a channel, it SHOULD send
+SSH_MSG_CHANNEL_EOF.
+
+ byte SSH_MSG_CHANNEL_EOF
+ uint32 recipient_channel
+
+No explicit response is sent to this message; however, the application
+may send EOF to whatever is at the other end of the channel. Note that
+the channel remains open after this message, and more data may still be
+sent in the other direction. This message does not consume window space
+and can be sent even if no window space is available.
+
+When either party wishes to terminate the channel, it sends
+SSH_MSG_CHANNEL_CLOSE. Upon receiving this message, a party MUST send
+back a SSH_MSG_CHANNEL_CLOSE unless it has already sent this message for
+the channel. The channel is considered closed for a party when it has
+both sent and received SSH_MSG_CHANNEL_CLOSE, and the party may then
+reuse the channel number. A party MAY send SSH_MSG_CHANNEL_CLOSE
+without having sent or received SSH_MSG_CHANNEL_EOF.
+ byte SSH_MSG_CHANNEL_CLOSE
+ uint32 recipient_channel
+
+This message does not consume window space and can be sent even if no
+window space is available.
+
+It is recommended that any data sent before this message is delivered to
+the actual destination, if possible.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 5]
+
+INTERNET-DRAFT 7 November 1997
+
+3.4. Channel-Specific Requests
+
+Many channel types have extensions that are specific to that particular
+channel type. An example is requesting a pty (pseudo terminal) for an
+interactive session.
+
+All channel-specific requests use the following format.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string request type (restricted to US-ASCII)
+ boolean want reply
+ ... type-specific data
+
+If want reply is FALSE, no response will be sent to the request.
+Otherwise, the recipient responds with either SSH_MSG_CHANNEL_SUCCESS or
+SSH_MSG_CHANNEL_FAILURE, or request-specific continuation messages. If
+the request is not recognized or is not supported for the channel,
+SSH_MSG_CHANNEL_FAILURE is returned.
+
+This message does not consume window space and can be sent even if no
+window space is available. Request types are local to each channel type.
+
+The client is allowed to send further messages without waiting for the
+response to the request.
+
+ byte SSH_MSG_CHANNEL_SUCCESS
+ uint32 recipient_channel
+
+ byte SSH_MSG_CHANNEL_FAILURE
+ uint32 recipient_channel
+
+These messages do not consume window space and can be sent even if no
+window space is available.
+4. Interactive Sessions
+
+A session is a remote execution of a program. The program may be a
+shell, an application, a system command, or some built-in subsystem. It
+may or may not have a tty, and may or may not involve X11 forwarding.
+Multiple sessions can be active simultaneously.
+
+4.1. Opening a Session
+
+A session is started by sending the following message.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "session"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+
+Client implementations SHOULD reject any session channel open requests
+to make it more difficult for a corrupt server to attack the client.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 6]
+
+INTERNET-DRAFT 7 November 1997
+
+4.2. Requesting a Pseudo-Terminal
+
+A pseudo-terminal can be allocated for the session by sending the
+following message.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient_channel
+ string "pty-req"
+ boolean want_reply
+ string TERM environment variable value (e.g., vt100)
+ uint32 terminal width, characters (e.g., 80)
+ uint32 terminal height, rows (e.g., 24)
+ uint32 terminal width, pixels (e.g., 480)
+ uint32 terminal height, pixels (e.g., 640)
+ string encoded terminal modes
+
+The encoding of terminal modes is described in Section ``Encoding of
+Terminal Modes''. Zero dimension parameters MUST be ignored. The
+character/row dimensions override the pixel dimensions (when nonzero).
+Pixel dimensions refer to the drawable area of the window.
+
+The dimension parameters are only informational.
+
+The client SHOULD ignore pty requests.
+
+4.3. X11 Forwarding
+
+4.3.1. Requesting X11 Forwarding
+
+X11 forwarding may be requested for a session by sending
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "x11-req"
+ boolean want reply
+ boolean single connection
+ string x11 authentication protocol
+ string x11 authentication cookie
+ uint32 x11 screen number
+
+It is recommended that the authentication cookie that is sent be a fake,
+random cookie, and that the cookie is checked and replaced by the real
+cookie when a connection request is received.
+
+X11 connection forwarding should stop when the session channel is
+closed; however, already opened forwardings should not be automatically
+closed when the session channel is closed.
+
+If `single connection' is TRUE, only a single connection should be
+forwarded. No more connections will be forwarded after the first, or
+after the session channel has been closed.
+
+`X11 authentication protocol is the name of the X11 authentication
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 7]
+
+INTERNET-DRAFT 7 November 1997
+
+method used, i.e. "MIT-MAGIC-COOKIE-1".
+
+4.3.2. X11 Channels
+
+X11 channels are opened with a channel open request. The resulting
+channels are independent of the session, and closing the session channel
+does not close the forwarded X11 channels.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "x11"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ string originator address (e.g. "192.168.7.38")
+ uint32 originator port
+
+The recipient should respond with SSH_MSG_CHANNEL_OPEN_CONFIRMATION or
+SSH_MSG_CHANNEL_OPEN_FAILURE.
+
+Implementations MUST reject any X11 channel open requests if they have
+not requested X11 forwarding.
+
+4.4. Authentication Agent Forwarding
+
+It is RECOMMENDED that authentication agent forwarding is allowed even
+when either or both parties do not support the SSH authentication agent
+protocol [SSH-AGENT].
+
+4.4.1. Requesting Authentication Agent Forwarding
+
+Authentication agent forwarding may be requested for a session by
+sending
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "auth-agent-req"
+ boolean want reply
+
+The server responds with either SSH_MSG_CHANNEL_SUCCESS or
+SSH_MSG_CHANNEL_FAILURE (if `want reply' is TRUE). The client MAY send
+further messages without waiting for the response to this message.
+
+4.4.2. Authentication Agent Channels
+
+When an application requests a connection to the authentication agent,
+the following message is sent to the originator of the session.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "auth-agent"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 8]
+
+INTERNET-DRAFT 7 November 1997
+
+The recipient should respond with open confirmation or open failure.
+
+Implementations MUST reject any agent channel open requests if they have
+not requested agent forwarding.
+
+4.5. Environment Variable Passing
+
+Environment variables may be passed to the shell/command to be started
+later. Typically, each machine will have a preconfigured set of
+variables that it will allow. Since uncontrolled setting of environment
+variables can be very dangerous, it is recommended that implementations
+allow setting only variables whose names have been explicitly configured
+to be allowed.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "env"
+ boolean want reply
+ string variable name
+ string variable value
+
+4.6. Starting a Shell or a Command
+
+Once the session has been set up, a program is started at the remote
+end. Program can be a shell, an application program or a subsystem with
+a host-independent name. Only one of these requests can succeed per
+channel.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "shell"
+ boolean want reply
+
+This message will request the user's default shell (typically defined in
+/etc/passwd in UNIX systems) to be started at the other end.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "exec"
+ boolean want reply
+ string command
+
+This message will request the server to start the execution of the given
+command. The command string may contain a path. Normal precautions MUST
+be taken to prevent the execution of unauthorized commands.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "subsystem"
+ boolean want reply
+ string subsystem name
+
+This last form executes a predefined subsystem. It expected that these
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 9]
+
+INTERNET-DRAFT 7 November 1997
+
+will include a general file transfer mechanism, and possibly other
+features. Implementations may also allow configuring more such
+mechanisms.
+
+The server SHOULD not halt the execution of the protocol stack when
+starting a shell or a program. All input and output from these SHOULD be
+redirected the the channel or to the encrypted tunnel.
+
+It is RECOMMENDED to request and check the reply for these messages. The
+client SHOULD ignore these messages.
+
+4.7. Session Data Transfer
+
+Data transfer for a session is done using SSH_MSG_CHANNEL_DATA and
+SSH_MSG_CHANNEL_EXTENDED_DATA packets and the window mechanism. The
+extended data type SSH_EXTENDED_DATA_STDERR has been defined for stderr
+data.
+
+4.8. Window Dimension Change Message
+
+When the window (terminal) size changes on the client side, it MAY send
+a message to the other side to inform it of the new dimensions.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient_channel
+ string "window-change"
+ boolean FALSE
+ uint32 terminal width, columns
+ uint32 terminal height, rows
+ uint32 terminal width, pixels
+ uint32 terminal height, pixels
+
+No response SHOULD be sent to this message.
+
+4.9. Local Flow Control
+
+On many systems it is possible to determine if a pseudo-terminal is
+using control-S control-Q flow control. When flow control is allowed,
+it is often desirable to do the flow control at the client end to speed
+up responses to user requests. This is facilitated by the following
+notification. Initially, the server is responsible for flow control.
+(Here, again, client means the side originating the session, and server
+the other side.)
+
+The message below is used by the server to inform the client when it can
+or cannot perform flow control (control-S/control-Q processing). If
+`client can do' is TRUE, the client is allowed to do flow control using
+control-S and control-Q. The client MAY ignore this message.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "xon-xoff"
+ boolean FALSE
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 10]
+
+INTERNET-DRAFT 7 November 1997
+
+ boolean client can do
+
+No response is sent to this message.
+
+4.10. Signals
+
+A signal can be delivered to the remote process/service using the
+following message. Some systems may not implement signals, in which
+case they SHOULD ignore this message.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "signal"
+ boolean FALSE
+ uint32 signal number
+
+4.11. Returning Exit Status
+
+When the command running at the other end terminates, The following
+message can be sent to return the exit status of the command. Returning
+the status is RECOMMENDED. No acknowledgment is sent for this message.
+The channel needs to be closed with SSH_MSG_CHANNEL_CLOSE after this
+message.
+
+The client SHOULD ignore these messages.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient_channel
+ string "exit-status"
+ boolean FALSE
+ uint32 exit_status
+
+The remote command may also terminate violently due to a signal. Such a
+condition can be indicated by the following message. A zero exit_status
+usually means that the command terminated successfully.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "exit-signal"
+ boolean FALSE
+ uint32 signal number
+ boolean core dumped
+ string error message (ISO-10646 UTF-8 [[RFC-2044]])
+ string language tag (as defined in [[RFC-1766]])
+
+The `error message' contains an additional explanation of the error
+message. The message may consist of multiple lines. The client software
+MAY display this message to the user.
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 11]
+
+INTERNET-DRAFT 7 November 1997
+
+5. TCP/IP Port Forwarding
+
+5.1. Requesting Port Forwarding
+
+A party need not explicitly request forwardings from its own end to the
+other direction. However, it if wishes to have connections to a port on
+the other side be forwarded to the local side, it must explicitly
+request this.
+
+ byte SSH_MSG_GLOBAL_REQUEST
+ string "tcpip-forward"
+ boolean want reply
+ string address to bind (e.g. "0.0.0.0")
+ uint32 port number to bind
+
+`Address to bind' and `port number to bind' specify the IP address and
+port to which the socket to be listened is bound. The address should be
+"0.0.0.0" if connections are allowed from anywhere. (Note that the
+client can still filter connections based on information passed in the
+open request.)
+
+Implementations should only allow forwarding privileged ports if the
+user has been authenticated as a privileged user.
+
+Client implementations SHOULD reject these messages; they are normally
+only sent by the client.
+
+A port forwarding can be cancelled with the following message. Note
+that channel open requests may be received until a reply to this message
+is received.
+
+ byte SSH_MSG_GLOBAL_REQUEST
+ string "cancel-tcpip-forward"
+ boolean want reply
+ string address_to_bind (e.g. "127.0.0.1")
+ uint32 port number to bind
+
+Client implementations SHOULD reject these messages; they are normally
+only sent by the client.
+
+5.2. TCP/IP Forwarding Channels
+
+When a connection comes to a port for which remote forwarding has been
+requested, a channel is opened to forward the port to the other side.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "forwarded-tcpip"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ string address that was connected
+ uint32 port that was connected
+ string originator IP address
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 12]
+
+INTERNET-DRAFT 7 November 1997
+
+ uint32 originator port
+
+Implementations MUST reject these messages unless they have previously
+requested a remote TCP/IP port forwarding with the given port number.
+
+When a connection comes to a locally forwarded TCP/IP port, the
+following packet is sent to the other side. Note that these messages
+MAY be sent also for ports for which no forwarding has been explicitly
+requested. The receiving side must decide whether to allow the
+forwarding.
+
+ byte SSH_MSG_CHANNEL_OPEN
+ string "direct-tcpip"
+ uint32 sender channel
+ uint32 initial window size
+ uint32 maximum packet size
+ string host to connect
+ uint32 port to connect
+ string originator IP address
+ uint32 originator port
+
+`Host to connect' and `port to connect' specify the TCP/IP host and port
+where the recipient should connect the channel. `Host to connect' may
+be either a domain name or a numeric IP address.
+
+`Originator IP address' is the numeric IP address of the machine where
+the connection request comes from, and `originator port' is the port on
+the originator host from where the connection came from.
+
+Forwarded TCP/IP channels are independent of any sessions, and closing a
+session channel does not in any way imply that forwarded connections
+should be closed.
+
+Client implementations SHOULD reject direct TCP/IP open requests for
+security reasons.
+
+6. Encoding of Terminal Modes
+
+Terminal modes (as passed in a pty request) are encoded into a byte
+stream. It is intended that the coding be portable across different
+environments.
+
+The tty mode description is a stream of bytes. The stream consists of
+opcode-argument pairs. It is terminated by opcode TTY_OP_END (0).
+Opcodes 1-159 have a single uint32 argument. Opcodes 160-255 are not yet
+defined, and cause parsing to stop (they should only be used after any
+other data).
+
+The client SHOULD put in the stream any modes it knows about, and the
+server MAY ignore any modes it does not know about. This allows some
+degree of machine-independence, at least between systems that use a
+POSIX-like tty interface. The protocol can support other systems as
+well, but the client may need to fill reasonable values for a number of
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 13]
+
+INTERNET-DRAFT 7 November 1997
+
+parameters so the server pty gets set to a reasonable mode (the server
+leaves all unspecified mode bits in their default values, and only some
+combinations make sense).
+
+The following opcodes have been defined. The naming of opcodes mostly
+follows the POSIX terminal mode flags.
+
+0 TTY_OP_END Indicates end of options.
+1 VINTR Interrupt character; 255 if none. Similarly for the
+ other characters. Not all of these characters are
+ supported on all systems.
+2 VQUIT The quit character (sends SIGQUIT signal on POSIX
+ systems).
+3 VERASE Erase the character to left of the cursor.
+4 VKILL Kill the current input line.
+5 VEOF End-of-file character (sends EOF from the terminal).
+6 VEOL End-of-line character in addition to carriage return
+ and/or linefeed.
+7 VEOL2 Additional end-of-line character.
+8 VSTART Continues paused output (normally control-Q).
+9 VSTOP Pauses output (normally control-S).
+10 VSUSP Suspends the current program.
+11 VDSUSP Another suspend character.
+12 VREPRINT Reprints the current input line.
+13 VWERASE Erases a word left of cursor.
+14 VLNEXT Enter the next character typed literally, even if it
+ is a special character
+15 VFLUSH Character to flush output.
+16 VSWTCH Switch to a different shell layer.
+17 VSTATUS Prints system status line (load, command, pid etc).
+18 VDISCARD Toggles the flushing of terminal output.
+30 IGNPAR The ignore parity flag. The parameter SHOULD be 0 if
+ this flag is FALSE set, and 1 if it is TRUE.
+31 PARMRK Mark parity and framing errors.
+32 INPCK Enable checking of parity errors.
+33 ISTRIP Strip 8th bit off characters.
+34 INLCR Map NL into CR on input.
+35 IGNCR Ignore CR on input.
+36 ICRNL Map CR to NL on input.
+37 IUCLC Translate uppercase characters to lowercase.
+38 IXON Enable output flow control.
+39 IXANY Any char will restart after stop.
+40 IXOFF Enable input flow control.
+41 IMAXBEL Ring bell on input queue full.
+50 ISIG Enable signals INTR, QUIT, [[D]]SUSP.
+51 ICANON Canonicalize input lines.
+52 XCASE Enable input and output of uppercase characters by
+ preceding their lowercase equivalents with `\'.
+53 ECHO Enable echoing.
+54 ECHOE Visually erase chars.
+55 ECHOK Kill character discards current line.
+56 ECHONL Echo NL even if ECHO is off.
+57 NOFLSH Don't flush after interrupt.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 14]
+
+INTERNET-DRAFT 7 November 1997
+
+58 TOSTOP Stop background jobs from output.
+59 IEXTEN Enable extensions.
+60 ECHOCTL Echo control characters as ^(Char).
+61 ECHOKE Visual erase for line kill.
+62 PENDIN Retype pending input.
+70 OPOST Enable output processing.
+71 OLCUC Convert lowercase to uppercase.
+72 ONLCR Map NL to CR-NL.
+73 OCRNL Translate carriage return to newline (output).
+74 ONOCR Translate newline to carriage return-newline
+ (output).
+75 ONLRET Newline performs a carriage return (output).
+90 CS7 7 bit mode.
+91 CS8 8 bit mode.
+92 PARENB Parity enable.
+93 PARODD Odd parity, else even.
+
+128 TTY_OP_ISPEED Specifies the input baud rate in bits per second.
+129 TTY_OP_OSPEED Specifies the output baud rate in bits per second.
+
+7. Summary of Message Numbers
+
+ #define SSH_MSG_GLOBAL_REQUEST 80
+ #define SSH_MSG_REQUEST_SUCCESS 81
+ #define SSH_MSG_REQUEST_FAILURE 82
+ #define SSH_MSG_CHANNEL_OPEN 90
+ #define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91
+ #define SSH_MSG_CHANNEL_OPEN_FAILURE 92
+ #define SSH_MSG_CHANNEL_WINDOW_ADJUST 93
+ #define SSH_MSG_CHANNEL_DATA 94
+ #define SSH_MSG_CHANNEL_EXTENDED_DATA 95
+ #define SSH_MSG_CHANNEL_EOF 96
+ #define SSH_MSG_CHANNEL_CLOSE 97
+ #define SSH_MSG_CHANNEL_REQUEST 98
+ #define SSH_MSG_CHANNEL_SUCCESS 99
+ #define SSH_MSG_CHANNEL_FAILURE 100
+
+8. Security Considerations
+
+This protocol is assumed to run on top of a secure, authenticated
+transport. User authentication and protection against network-level
+attacks are assumed to be provided by the underlying protocols.
+
+This protocol can, however, be used to execute commands on remote
+machines. The protocol also permits the server to run commands on the
+client. Implementations may wish to disallow this to prevent an
+attacker from coming from the server machine to the client machine.
+
+X11 forwarding provides major security improvements over normal cookie-
+based X11 forwarding. The cookie never needs to be transmitted in the
+clear, and traffic is encrypted and integrity-protected. No useful
+authentication data will remain on the server machine after the
+connection has been closed. On the other hand, in some situations a
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 15]
+
+INTERNET-DRAFT 7 November 1997
+
+forwarded X11 connection might be used to get access to the local X
+server across security perimeters.
+
+Port forwardings can potentially allow an intruder to cross security
+perimeters such as firewalls. They do not offer anything fundamentally
+new that a user couldn't do otherwise; however, they make opening
+tunnels very easy. Implementations should allow policy control over
+what can be forwarded. Administrators should be able to deny
+forwardings where appropriate.
+
+Since this protocol normally runs inside an encrypted tunnel, firewalls
+will not be able to examine the traffic.
+
+It is RECOMMENDED that implementations disable all of the potentially
+dangerous features (e.g. agent forwarding, X11 forwarding, and TCP/IP
+forwarding) if the host key has changed.
+
+9. References
+
+[RFC-1766] Alvestrand, H., "Tags for the Identification of Languages",
+March 1995.
+
+[RFC-1884] Hinden, R., and Deering, S., "IP Version 6 Addressing
+Architecture", December 1995
+
+[RFC-2044] Yergeau, F., "UTF-8, a Transformation Format of Unicode and
+ISO 10646", October 1996.
+
+[SSH-ARCH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Protocol
+Architecture", Internet Draft, draft-ietf-secsh-architecture-00.txt
+
+[SSH-TRANS] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Transport
+Layer Protocol", Internet Draft, draft-ietf-secsh-transport-02.txt
+
+[SSH-USERAUTH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH
+Authentication Protocol", Internet Draft, draft-ietf-secsh-
+userauth-02.txt
+
+10. Authors' Addresses
+
+ Tatu Ylonen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: ylo@ssh.fi
+
+ Tero Kivinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: kivinen@ssh.fi
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 16]
+
+INTERNET-DRAFT 7 November 1997
+
+ Markku-Juhani O. Saarinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: mjos@ssh.fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 17]
diff --git a/info/digisign.py b/info/digisign.py
new file mode 100644
index 0000000..8c7c363
--- /dev/null
+++ b/info/digisign.py
@@ -0,0 +1,340 @@
+#
+# digisign.py : Digital signature (using the q-NEW algorithm)
+#
+# Maintained by A.M. Kuchling (amk@magnet.com)
+# Date: 1997/09/05
+#
+# Distribute and use freely; there are no restrictions on further
+# dissemination and usage except those imposed by the laws of your
+# country of residence.
+#
+
+# TODO :
+# Add more comments and docstrings
+# Write documentation
+# Use mpz or gmp if available
+# Add assertions (later)
+
+import types, string, marshal
+
+# The code will try to use the SHA module, if present; otherwise
+# the MD5 module will be used. HASHBITS is the number of bits
+# in the hashing algorithm.
+
+try:
+ import sha ; hash = sha ; HASHBITS=160
+except ImportError:
+ import md5 ; hash = md5 ; HASHBITS=128
+
+class RandomPool:
+ """Cryptographically strong generation of random strings"""
+ def __init__(self, seed=None):
+ """Initialize the generator, using a provided string as the seed.
+ If the string is omitted, the class will try to do its best to get
+ some random data, and print a warning."""
+ if seed==None: seed=self.getseed()
+ S=range(256)
+ seed=map(ord, seed)
+ x = y = 0 ; i1 = i2 = 0
+ for i in range(256):
+ i2 = (seed[i1] + S[i] + i2) % 256
+ S[i], S[i2] = S[i2], S[i]
+ i1 = (i1 + 1) % len(seed)
+ self.S, self.x, self.y = S,x,y
+
+ def random(self, N):
+ "Return an N-byte string containing random bytes"
+ x,y, S = self.x, self.y, self.S
+ output=[None]*N
+ for i in range(N):
+ x = (x + 1) % 256
+ y = (y + S[x]) % 256
+ S[x], S[y] = S[y], S[x]
+ xorIndex = (S[x] + S[y]) % 256
+ output[i] = chr( S[xorIndex] )
+ self.x, self.y = x,y
+ return string.join(output, '')
+ def getseed(self):
+ """If no seed was provided by the user (bad user!), try to generate
+ a useful seed. This may print a warning."""
+ try:
+ # If possible, use /dev/urandom. On FreeBSD 2.1.5 or later,
+ # and Linux 1.3.X or later, /dev/urandom is maintained by the
+ # OS, and uses random things like disk interrupt timings and
+ # keyboard noise. It must be opened in unbuffered mode
+ # for some reason.
+ f=open('/dev/urandom', 'r', 0)
+ seed=f.read(256)
+ f.close()
+ return seed
+ except IOError:
+ # Presumably /dev/urandom isn't there... Use a lame
+ # time-based scheme that isn't very good, and print a warning
+ # to encourage the programmer to improve things.
+ import time, os, sys
+ print " (Using poor time-based scheme to initialize random-number generator)"
+ seed=str( 'dummy data' )
+ for i in range(0, 16):
+ rand='%s%s%s' % (time.time(), os.getpid(), sys.getrefcount(i) )
+ rand=hash.new( rand ).digest()
+ seed=seed+rand
+ return seed
+
+_randpool=None
+
+def RandomNumber(N, randfunc):
+ "Return an N-bit random number. N must be a multiple of 8."
+ if N % 8 != 0:
+ raise ValueError, "N must be a multiple of 8"
+ str=randfunc(N/8)
+ char=ord(str[0])|128
+ return Str2Int(chr(char)+str[1:])
+
+def Int2Str(n):
+ "Convert a long integer to a string form"
+ s=''
+ while n>0:
+ s=chr(n & 255)+s
+ n=n>>8
+ return s
+
+def Str2Int(s):
+ "Convert a string to a long integer"
+ if type(s)!=types.StringType: return s # Integers will be left alone
+ return reduce(lambda x,y : x*256+ord(y), s, 0L)
+
+sieve=[2,3,5,7,11,13,17,19,23,29,31,37,41]
+def isPrime(N):
+ """Test if a number N is prime, using a simple sieve check,
+ followed by a more elaborate XXX test."""
+ for i in sieve:
+ if (N % i)==0: return 0
+ N1=N - 1L ; n=1L
+ while (n<N): n=n<<1L # Compute number of bits in N
+ for j in sieve:
+ a=long(j) ; d=1L ; t=n
+ while (t): # Iterate over the bits in N1
+ x=(d*d) % N
+ if x==1L and d!=1L and d!=N1: return 0 # Square root of 1 found
+ if N1 & t: d=(x*a) % N
+ else: d=x
+ t=t>>1L
+ if d!=1L: return 0
+ return 1
+
+def getPrime(N, randfunc):
+ "Find a prime number measuring N bits"
+ number=RandomNumber(N, randfunc) | 1 # Ensure the number is odd
+ while (not isPrime(number)):
+ number=number+2
+ return number
+
+
+
+class Key:
+ """Key object (both public and private)
+
+ Methods
+ generate -- Generate a fresh public/private key pair
+ sign -- Sign a message, returning the signature
+ verify -- Verify a signature for the message
+ cansign -- Return TRUE if the key can sign messages
+ publickey -- Return a new key containing only the public data
+
+ Attributes:
+ size -- Size (in bits) of messages that can be processed.
+ """
+ def generate(self, bits=1024, randfunc=None, progress_func=None):
+ """Generate a private key with a modulus of the given size
+ bits -- modulus size of the generated key; the bigger it is,
+ the more secure the key (and the slower key generation
+ and signing is). For security, use a bit size of 768
+ or 1024; 512 or 384 is too small for comfort (though you may
+ use it in testing).
+ randfunc -- A function that generates random data.
+ (Optional, but recommended)
+ progress_func -- (Optional) As a key is generated, this function
+ will be used to output progress messages.
+ """
+ global _randpool
+ if randfunc==None:
+ _randpool=RandomPool()
+ randfunc=_randpool.random
+
+ if bits<384: raise ValueError, 'Key length <384 bits'
+
+ # Generate prime numbers p and q. q is a 160-bit prime
+ # number. p is another prime number (the modulus) whose bit
+ # size is chosen by the caller, and is generated so that p-1
+ # is a multiple of q.
+ #
+ # Note that only a single seed is used to
+ # generate p and q; if someone generates a key for you, you can
+ # use the seed to duplicate the key generation. This can
+ # protect you from someone generating values of p,q that have
+ # some special form that's easy to break.
+ if progress_func: progress_func('p,q\n')
+ while (1):
+ self.q = getPrime(160, randfunc)
+# assert pow(2, 159L)<self.q<pow(2, 160L)
+ self.seed = S = Int2Str(self.q)
+ C, N, V = 0, 2, {}
+ # Compute b and n such that bits-1 = b + n*HASHBITS
+ n= (bits-1) / HASHBITS
+ b= (bits-1) % HASHBITS ; powb=pow(long(2), b)
+ powL1=pow(long(2), bits-1)
+ while C<4096:
+ # The V array will contain (bits-1) bits of random
+ # data, that are assembled to produce a candidate
+ # value for p.
+ for k in range(0, n+1):
+ V[k]=Str2Int(hash.new(S+str(N)+str(k)).digest())
+ p = V[n] % powb
+ for k in range(n-1, -1, -1):
+ p= (p << long(HASHBITS) )+V[k]
+ p = p+powL1 # Ensure the high bit is set
+
+ # Ensure that p-1 is a multiple of q
+ p = p - (p % (2*self.q)-1)
+
+ # If p is still the right size, and it's prime, we're done!
+ if powL1<=p and isPrime(p): break
+
+ # Otherwise, increment the counter and try again
+ C, N = C+1, N+n+1
+ if C<4096: break # Ended early, so exit the while loop
+ if progress_func: progress_func('4096 values of p tried\n')
+
+ self.p = p
+ power=(p-1)/self.q
+
+ # Next parameter: g = h**((p-1)/q) mod p, such that h is any
+ # number <p-1, and g>1. g is kept; h can be discarded.
+ if progress_func: progress_func('h,g\n')
+ while (1):
+ h=Str2Int(randfunc(bits)) % (p-1)
+ g=pow(h, power, p)
+ if 1<h<p-1 and g>1: break
+ self.g=g
+
+ # x is the private key information, and is
+ # just a random number between 0 and q.
+ # y=g**x mod p, and is part of the public information.
+ if progress_func: progress_func('x,y\n')
+ while (1):
+ x=Str2Int(randfunc(20))
+ if 0<x<self.q: break
+ self.x, self.y=x, pow(g, x, p)
+
+ self.size = 160
+
+ def cansign(self):
+ """Return a Boolean denoting whether the object contains
+ private components, and hence can sign messages."""
+ if hasattr(self, 'x'): return 1
+ else: return 0
+ def canencrypt(self):
+ return 0
+
+ def publickey(self):
+ new=Key()
+ new.p = self.p
+ new.q = self.q
+ new.g = self.g
+ new.y = self.y
+ # x isn't copied, of course, since it's the private key.
+# assert not (hasattr(new, 'x') or hasattr(new, 'seed') )
+ return new
+
+ def _sign(self, M, K):
+ if (self.q<=K):
+ raise ValueError, 'K is greater than q'
+ if M<0:
+ raise ValueError, 'Illegal value of M (<0)'
+ if M>=pow(2,161L):
+ raise ValueError, 'Illegal value of M (too large)'
+ r=pow(self.g, K, self.p) % self.q
+ s=(K- (r*M*self.x % self.q)) % self.q
+ return marshal.dumps( (r,s) )
+ def _verify(self, M, sig):
+ r, s = marshal.loads(sig)
+ if r<=0 or r>=self.q or s<=0 or s>=self.q: return 0
+ if M<0:
+ raise ValueError, 'Illegal value of M (<0)'
+ if M>=pow(2,161L):
+ raise ValueError, 'Illegal value of M (too large)'
+ if M<=0 or M>=pow(2,161L): return 0
+ v1=pow(self.g, s, self.p)
+ v2=pow(self.y, M*r, self.p)
+ v=((v1*v2) % self.p)
+ v=v % self.q
+ if v==r: return 1
+ return 0
+
+ def sign(self, M, randfunc=None, K=None):
+ if (not self.cansign()):
+ raise TypeError, 'Not a private key object'
+ if type(M)==types.StringType: M=Str2Int(M)
+
+ if K==None:
+ # Generate a random value of K, that must be <q
+ global _randpool
+ if randfunc==None:
+ if _randpool==None:
+ _randpool=RandomPool()
+ randfunc=_randpool.random
+ K=RandomNumber(160, randfunc) >> 1
+# assert K<self.q
+ else:
+ if type(K)==types.StringType: K=Str2Int(K)
+ return self._sign(M, K)
+ def verify(self, M, signature):
+ if type(M)==types.StringType: M=Str2Int(M)
+ return self._verify(M, signature)
+ validate=verify
+
+new=Key
+
+if __name__=='__main__':
+ import sys, string
+ BITS=512
+ if len(sys.argv)>1:
+ BITS=string.atoi(sys.argv[1])
+ print ' Generating', BITS, 'bit key'
+ key=new()
+ key.generate(BITS, progress_func=sys.stdout.write)
+ print ' Key data: (the private key is x)'
+ for i in 'xygqp': print '\t', i, ':', hex(getattr(key, i))
+ message="This is a contract."
+
+ if key.cansign():
+ print ' Signature test'
+ print "Message:", message
+ signature=key.sign(message)
+ print "Signature:", repr(signature)
+ result=key.verify(message, signature)
+ if not result:
+ print " Sig. verification failed when it should have succeeded"
+ else: print 'Signature verified'
+
+ # Test on a mangled message
+ result=key.verify(message[:-1], signature)
+ if result:
+ print " Sig. verification succeeded when it should have failed"
+
+ # Change a single bit in the message
+ badtext=message[:-3]+chr( 1 ^ ord(message[-3]) )+message[-3:]
+ result=key.verify(badtext, signature)
+ if result:
+ print " Sig. verification succeeded when it should have failed"
+
+ import pickle
+ print 'Removing private key data'
+ pubonly=key.publickey()
+ pickledata=pickle.dumps(pubonly)
+ pubonly=pickle.loads(pickledata)
+ result=pubonly.verify(message, signature)
+ if not result:
+ print " Sig. verification failed when it should have succeeded"
+ else:
+ print 'Signature verified'
diff --git a/info/libdsign.tex b/info/libdsign.tex
new file mode 100644
index 0000000..8a31698
--- /dev/null
+++ b/info/libdsign.tex
@@ -0,0 +1,146 @@
+\section{Standard Module \sectcode{digisign}}
+\label{module-digisign}
+
+This module provides a simple class to create keys for generating and
+verifying \dfn{digital signatures}. These digital signatures act like
+handwritten signatures in the real world; only one key can sign a
+message, but anyone can use the key to verify that the signature
+corresponds to the message. If even a single bit of the message is
+changed, verifying the signature will fail.
+
+The algorithm used is Nyberg and Ruppel's q-NEW. The \code{Key} class
+contains a single q-NEW key. A newly generated key is a \dfn{private
+key}. It includes private information, and can both sign messages, or
+verify a previously generated signature for a given message. It's
+possible to create a copy of the key without the private information,
+using the \code{publickey} method; this public key can only verify
+signatures produced with the private key, and thus doesn't have to be
+kept secret.
+
+For example, you could generate a private key, create the matching
+public key, and send the public key to all your correspondents. Then,
+when you wish to send a message, you can sign it using the private
+key, and send the signature along with the message; your
+correspondents can then verify the signature using the public key,
+assuring them that the message wasn't changed while being transmitted.
+
+
+\stmodindex{digisign}
+\renewcommand{\indexsubitem}{(in module digisign)}
+
+\subsection{The {\tt Key} class}
+
+The \code{Key} class encapsulates a single key. To create a new key
+object, call either \code{digisign.new()} or \code{digisign.Key()},
+which will return an empty \code{Key} instance, and then call the
+\code{generate()} method of the empty instance to create a random
+private key. To obtain a \code{Key} instance containing only the
+public key, call the \code{publickey} method. Both private and public
+\code{Key} instances can be pickled.
+
+The \code{generate} and \code{sign} methods require random data. Both
+those functions have a keyword parameter named \code{randfunc}; this
+parameter must be a function (or a bound method) which will take a
+single integer parameter N and return N bytes of random data.
+
+It is critical that the random number generator be
+\dfn{cryptographically strong}; consult Schneier's book for the
+details. You may wish to use the \code{RandomPool} class described
+below, which is such a generator. Be sure you know what you're doing
+before writing your own generator, since keys produced with a poor
+generator will offer little or no security. Simple linear generators,
+like the one in the
+\code{whrandom} module, are not strong, and should never be used with
+this module.
+
+\begin{funcdesc}{cansign}{}
+Return true if this key contains the private information required to
+generate new signatures. Return false if the key can only be used to
+verify signatures.
+\end{funcdesc}
+
+\begin{funcdesc}{publickey}{}
+Return a new \code{Key} instance containing only the public key
+information. This new instance cannot generate signatures, though it
+can verify them.
+\end{funcdesc}
+
+\begin{funcdesc}{generate}{bits\, randfunc\, progress_func}
+Generate a new private key that can sign messages and verify its own
+signatures. \var{bits} is the size of the key in bits, and has a
+minimum value of 384; as this value increases, the key becomes harder
+to break, and signing and verifying gets slower. A value of 768 or
+1024 is recommended for security; key sizes of 384 or 512 bits may be
+used in testing for the sake of speed, but they're easily breakable in
+1996.
+
+\var{randfunc} is a function that generates random strings, as described above.
+The function \var{progress_func} will be called at various points
+during key generation, and passed a string explaining the algorithm's
+progress. Key generation is a lengthy process, so this can be used
+to keep the user informed while it's going on.
+\end{funcdesc}
+
+\begin{funcdesc}{sign}{M \optional{\, randfunc\, K} }
+Generate and return a string containing a signature for the short
+message string \var{M}. \var{M} is limited in size to 20 bytes or
+less. If you wish to sign a larger piece of data, like a 1K email
+message, the usual procedure is to take the hash of the message and
+use that as \var{M}. This can be done using the \code{md5} module.
+
+The optional parameter \var{K} is a random
+value required to produce a signature; it can be a string of no more
+than 20 bytes in length. Alternatively (and more easily), the
+\var{randfunc} parameter can be provided, and a value of \var{K} will
+be automatically generated.
+
+{\bf Important:} The same value of \var{K} must \emph{never} be used
+twice, because that would allow a third party to determine the private
+key data. An attacker can save every message and signature produced
+by a key, and try all possible pairings in case a value of \var{K} was
+reused. Once an attacker has the private key data, they can sign
+messages as they like. (If automatically generated, \var{K} is a
+159-bit number, so the odds of the same number being used twice are
+infinitesimal as long as a good random number generator is used.)
+\end{funcdesc}
+
+\begin{funcdesc}{verify}{M\, signature}
+Return true if \var{signature} matches the message \var{M}. If they
+don't match, return false; this may happen because \var{M} or
+\var{signature} was modified, or because the signature was generated
+with a different key.
+\end{funcdesc}
+
+\subsection{The {\tt RandomPool} class}
+
+The \code{RandomPool} class provides cryptographically strong
+generation of random data.
+
+\begin{funcdesc}{RandomPool}{\optional{seed}}
+Return a \code{RandomPool} instance, initialized using the string
+\var{seed}. The instance can then be used to get random data.
+The more randomness that can be in the \var{seed} string, the more
+secure the resulting random data will be.
+
+If \var{seed} is omitted, the class will try to get random data on its
+own, reading from \file{/dev/urandom} on those systems that support
+it, and otherwise using the current system time. The system time
+isn't a very good source of randomness, so a warning will be printed
+to \code{sys.stdout}.
+\end{funcdesc}
+
+\begin{funcdesc}{random}{N}
+Return an \var{N}-byte string containing random data.
+
+When bound to an instance, this method can be passed as the
+\var{randfunc} parameters to \code{Key}'s \code{generate} and
+\code{sign} methods. Simply create a \code{RandomPool} object
+\var{R}, and pass \code{\var{R}.random} as the parameter.
+\end{funcdesc}
+
+
+\begin{seealso}
+\seetext{XXX Nyberg and Ruppel's paper},
+\seetext{Schneier's book}
+\end{seealso}
+
diff --git a/info/mail b/info/mail
new file mode 100644
index 0000000..a62055a
--- /dev/null
+++ b/info/mail
@@ -0,0 +1,1867 @@
+BABYL OPTIONS: -*- rmail -*-
+Version: 5
+Labels:
+Note: This is the header of an rmail file.
+Note: If you are seeing it in rmail,
+Note: it means the file has no messages in it.
+
+1, answered,,
+Summary-line: 18-Sep pobox@tiac.net [87] #Re: Digital signature module
+Mail-from: From python-list-request@cwi.nl Wed Sep 17 23:01:39 1997
+Return-Path: python-list-request@cwi.nl
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id XAA17092; Wed, 17 Sep 1997 23:01:38 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ id XAA09314; Wed, 17 Sep 1997 23:01:37 -0400
+Received: from hera.cwi.nl(192.16.191.1) by grommit.magnet.com via smap (3.1)
+ id xma009311; Wed, 17 Sep 97 23:01:27 -0400
+Received: by hera.cwi.nl
+ id EAA17446; Thu, 18 Sep 1997 04:50:03 +0200 (MET DST)
+To: python-list@cwi.nl
+Sender: python-list-request@cwi.nl
+Errors-To: python-list-request@cwi.nl
+From: pobox@tiac.net (Jeff Macdonald)
+Newsgroups: comp.lang.python
+Subject: Re: Digital signature module
+Date: Thu, 18 Sep 1997 02:31:28 GMT
+X-Organization: slightly
+Message-ID: <34208e46.8913966@news.tiac.net>
+References: <199709171152.HAA27968@dolphin.automatrix.com>
+ <199709171526.LAA20637@lemur.magnet.com>
+Reply-To: pobox@tiac.net
+X-Newsreader: Forte Free Agent 1.11/32.235
+
+*** EOOH ***
+Return-Path: python-list-request@cwi.nl
+To: python-list@cwi.nl
+Sender: python-list-request@cwi.nl
+Errors-To: python-list-request@cwi.nl
+From: pobox@tiac.net (Jeff Macdonald)
+Newsgroups: comp.lang.python
+Subject: Re: Digital signature module
+Date: Thu, 18 Sep 1997 02:31:28 GMT
+X-Organization: slightly
+References: <199709171152.HAA27968@dolphin.automatrix.com>
+ <199709171526.LAA20637@lemur.magnet.com>
+Reply-To: pobox@tiac.net
+X-Newsreader: Forte Free Agent 1.11/32.235
+
+Andrew Kuchling <amk@magnet.com> wrote:
+
+.. stuff deleted
+
+> What exactly are you thinking of doing with Diffie-Hellman,
+>though? It only lets two sides agree on some shared secret data,
+>which is only really useful with some additional encryption algorithm.
+
+or with a secure hash, to do some MAC (?) type authorization.
+Basically, once both sides have the shared secret, they hash that with
+some plain text data (and probably time stamp stuff too).
+
+>It's not hard to implement D-H with the things already in the digisign
+>module:
+
+I'll pull that over...
+
+>
+> 1) Generate a large prime p with the PrimeNumber function, and
+>a primitive root a (2 will do).
+
+Do you have any pointers to the generation of the primitive number?
+I've seen posts that say 2 is good, but I would like to know why.
+
+... rest of Diffie-Hellman removed
+
+>Skip Montanaro <skip@calendar.com> wrote:
+>>Python already supports arbitrarily long integers. Is that not enough?
+>
+> Depends on the application; the implementation of Python's
+>long integers is in pure C, and the algorithms used are all fairly
+>straightforward. By way of contrast, in GMP 2.0.2 the algorithms are
+>more elaborate, different ones are used for operands of different
+>sizes, and there's optimized inline assembly code for x86, AXP,
+>PowerPC, and a dozen other processors.
+>
+> The most recent version of gmp module can be used as a module,
+>or it can be dropped on top of Objects/longobject.c, making Python use
+>GMP long integers by default. Unfortunately that also alters the
+>format in which long integers are marshalled, which means marshal
+>isn't compatible with everyone else when long integers are in use, and
+>you have to regenerate all your *.pyc files.
+>
+>
+> Andrew Kuchling
+> amk@magnet.com
+> http://starship.skyport.net/crew/amk/
+
+I missed that line about the arbitrarly long ints, and just looked it
+up in Mark Lutz's book.
+
+And on a completely different subject, I got Tom Christiansen's
+<tchrist@jhereg.perl.com> 'Uneeded mime' message to my non-mime post,
+to which I replied :
+Tom,
+me thinks your perl script has gone amuck... perhaps you should be
+using python... :)
+
+and his reply was:
+
+yup, you're right.
+
+Which hopefully means that he's working on a Python book..... :)
+
+
+1, answered,,
+Summary-line: 19-Sep Jeff_Macdonald@VirtualBui [116] #Re: Digital signature module
+Mail-from: From Jeff_Macdonald@VirtualBuilder.com Fri Sep 19 19:57:15 1997
+Return-Path: Jeff_Macdonald@VirtualBuilder.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id TAA14038 for <amk@magnet.com>; Fri, 19 Sep 1997 19:57:14 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id TAA03445; Fri, 19 Sep 1997 19:57:08 -0400
+Received: from maildeliver0.tiac.net(199.0.65.19) by grommit.magnet.com via smap (3.1)
+ id xma003443; Fri, 19 Sep 97 19:56:57 -0400
+Received: from mailrelay.tiac.net (mailrelay.tiac.net [199.0.65.237]) by maildeliver0.tiac.net (8.8.0/8.8) with ESMTP id TAA30586 for <amk@magnet.com>; Fri, 19 Sep 1997 19:56:28 -0400 (EDT)
+Received: from jeffmacd (pobox.tiac.net [199.3.136.237])
+ by mailrelay.tiac.net (8.8.7/8.8.7) with SMTP id TAA04019
+ for <amk@magnet.com>; Fri, 19 Sep 1997 19:57:47 -0400 (EDT)
+Message-Id: <3.0.3.32.19970919195427.007d6870@pop.tiac.net>
+X-Sender: pobox@pop.tiac.net
+X-Mailer: QUALCOMM Windows Eudora Pro Version 3.0.3 (32)
+Date: Fri, 19 Sep 1997 19:54:27 -0400
+To: Andrew Kuchling <amk@magnet.com>
+From: Jeff Macdonald <Jeff_Macdonald@VirtualBuilder.com>
+Subject: Re: Digital signature module
+In-Reply-To: <199709191907.PAA05854@lemur.magnet.com>
+References: <34208e46.8913966@news.tiac.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+
+*** EOOH ***
+Return-Path: Jeff_Macdonald@VirtualBuilder.com
+X-Sender: pobox@pop.tiac.net
+X-Mailer: QUALCOMM Windows Eudora Pro Version 3.0.3 (32)
+Date: Fri, 19 Sep 1997 19:54:27 -0400
+To: Andrew Kuchling <amk@magnet.com>
+From: Jeff Macdonald <Jeff_Macdonald@VirtualBuilder.com>
+Subject: Re: Digital signature module
+In-Reply-To: <199709191907.PAA05854@lemur.magnet.com>
+References: <34208e46.8913966@news.tiac.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+At 03:07 PM 9/19/97 -0400, you wrote:
+>
+> BTW, according to Schneier's _Applied Cryptography_, 2nd ed.,
+>(p-1)/2 should also be prime for security. So p should be generated
+>like this:
+>
+>while (1):
+> p2=digisign.PrimeNumber(< desired bit size - 1 >)
+> p=p2*2+1
+> if digisign.isPrime(p): break
+>
+>Also according to Schneier, you can check if a number g is a
+>generator, by taking the prime factors of p-1; if pow(g, (p-1)/factor,
+>p)!=1 for all the factors, it's a generator. Following on the above
+>example, there are only two factors, 2 and p2:
+>
+>while (1):
+> g=<some random number>
+> if not (pow(g, 2, p)==1 or
+> pow(g, p2, p)==1):
+> break
+>
+
+Your talent for transforming algorithms to code is very impressive. It's hard
+to believe I was a math major. :) I've been trying to code this for weeks.
+
+>Hmm... it doesn't look too difficult to produce a Diffie-Hellman class
+>after all, though I can't imagine what its interface should look like.
+>Do you have any ideas about that?
+>
+
+I've looked into several crypto libs, and the interface that I think would
+make
+most sense is to follow Bruce's book. Here's from Alice's point of view.
+
+(n,g)=dh.generatePrimes(bitsizeOfN) # set dh.n
+# send bob n,g
+X=dh.generateX(RandomFunction) # set dh.x
+# send bob X
+# get Bob's Y
+k=dh.generate(Y)
+
+Bob would need to use n and g, so we also need a
+
+dh.setPrimes(n,g)
+
+to be able to generate a Y. So from Bob's view:
+
+# get n and g
+dh.setPrimes(n,g)
+# generate Y
+Y=dh.generateX(RandomFunction)
+# send Alice Y
+# get Alice X
+k=dh.generate(X)
+
+A more general interface may look like this:
+
+dh.setPrimes(n,g)
+dh.generatePrimes(bitSize)
+dh.generatePublic(RandomFuction)
+dh.generatePrivate(publicKey)
+
+In either Peter G. or Eric Y.'s lib, there are values of n and g that where
+pre-computed for 512, 768, 1024, 2048 and 4096 bits. I believe these values
+were suggest by NIST. This should speed things up, the only change to the
+interface would be:
+
+dh.setPrimes(bitSize) # sh.setPrimes(n,g) should still exist
+
+That would use the pre-computed values of n and g. Both parties would
+have to agree on the bit size.
+
+This looks very clean to me, what do you think?
+
+I do have Bruce's book, and will be picking up 'Handbook of Applied
+Crytpography'
+this weekend. This book supposedly goes into more detail with the algorithms.
+
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: PGP for Personal Privacy 5.0
+Charset: noconv
+
+iQCVAwUBNCMQsRxijdIqz8FNAQHqJwP/fF5vHyPlrzdihlj3BmnToFvrtz8W8l0p
+7ZCcNCHIMwXC1a0Oi4TOi/Rx1banAs8C1bu/x42dwZbkBuMO4gYuh8pnImxLrYp6
+BIUV13usq3eciAkq7Jvl/0h3K8ns6MVWiUjw+RAukb+yqRO3hObxonoTR5PTZum0
+MaPYKsjtFMc=
+=vQPL
+-----END PGP SIGNATURE-----
+
+----------------------------------------------
+| Internet solutions for small companies |
+| |
+| email: Jeff_Macdonald@VirtualBuilder.com |
+| Web: www.VirtualBuilder.com |
+| PGP: www.VirtualBuilder.com/pgpkey.html |
+----------------------------------------------
+
+
+
+1, answered,,
+Summary-line: 20-Sep Jeff_Macdonald@VirtualBui [161] #Diffie-Hellman
+Mail-from: From Jeff_Macdonald@VirtualBuilder.com Sat Sep 20 01:22:02 1997
+Return-Path: Jeff_Macdonald@VirtualBuilder.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id BAA17238 for <amk@magnet.com>; Sat, 20 Sep 1997 01:22:02 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id BAA05386; Sat, 20 Sep 1997 01:22:02 -0400
+Received: from maildeliver0.tiac.net(199.0.65.19) by grommit.magnet.com via smap (3.1)
+ id xma005384; Sat, 20 Sep 97 01:21:55 -0400
+Received: from mailrelay.tiac.net (mailrelay.tiac.net [199.0.65.237]) by maildeliver0.tiac.net (8.8.0/8.8) with ESMTP id BAA28643 for <amk@magnet.com>; Sat, 20 Sep 1997 01:21:54 -0400 (EDT)
+Received: from jeffmacd (pobox.tiac.net [199.3.136.237])
+ by mailrelay.tiac.net (8.8.7/8.8.7) with SMTP id BAA20887
+ for <amk@magnet.com>; Sat, 20 Sep 1997 01:23:17 -0400 (EDT)
+Message-Id: <3.0.3.32.19970920011955.007da980@pop.tiac.net>
+X-Sender: pobox@pop.tiac.net
+X-Mailer: QUALCOMM Windows Eudora Pro Version 3.0.3 (32)
+Date: Sat, 20 Sep 1997 01:19:55 -0400
+To: Andrew Kuchling <amk@magnet.com>
+From: Jeff Macdonald <Jeff_Macdonald@VirtualBuilder.com>
+Subject: Diffie-Hellman
+In-Reply-To: <199709191907.PAA05854@lemur.magnet.com>
+References: <34208e46.8913966@news.tiac.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+
+*** EOOH ***
+Return-Path: Jeff_Macdonald@VirtualBuilder.com
+X-Sender: pobox@pop.tiac.net
+X-Mailer: QUALCOMM Windows Eudora Pro Version 3.0.3 (32)
+Date: Sat, 20 Sep 1997 01:19:55 -0400
+To: Andrew Kuchling <amk@magnet.com>
+From: Jeff Macdonald <Jeff_Macdonald@VirtualBuilder.com>
+Subject: Diffie-Hellman
+In-Reply-To: <199709191907.PAA05854@lemur.magnet.com>
+References: <34208e46.8913966@news.tiac.net>
+Mime-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+>
+> BTW, according to Schneier's _Applied Cryptography_, 2nd ed.,
+>(p-1)/2 should also be prime for security. So p should be generated
+>like this:
+>
+>while (1):
+> p2=digisign.PrimeNumber(< desired bit size - 1 >)
+> p=p2*2+1
+> if digisign.isPrime(p): break
+>
+
+Andrew, I tried the above algo, but your getPrime only take bits that are a
+multiple
+of 8 (besides, digisign doesn't have PrimeNumber!).
+
+>Also according to Schneier, you can check if a number g is a
+>generator, by taking the prime factors of p-1; if pow(g, (p-1)/factor,
+>p)!=1 for all the factors, it's a generator. Following on the above
+>example, there are only two factors, 2 and p2:
+>
+
+not comment below...
+
+>while (1):
+> g=<some random number>
+> if not (pow(g, 2, p)==1 or <<--- this should be _and_, no?
+> pow(g, p2, p)==1):
+> break
+>
+
+also, my books don't show a pow(a,b,c) but a pow(a,b). Shouldn't this be
+modpow(a,b,c)?
+I also can't find a modpow(a,b,c) either. Wait, is that part of mpz?
+
+I really think a BigInteger class would help alot. Look at java's
+BigIntger. You can
+generate primes, and do all that fancy math stuff with it.
+
+Below I've implemented the primes n and g in java. Am I interpeting your
+code the
+right way? I'm using Java-Linux JDK 1.1.3..
+
+import java.math.BigInteger;
+import java.util.Random;
+import java.lang.Integer;
+
+public class dh
+{
+
+ public BigInteger n;
+ public BigInteger g;
+
+ public dh(int bits)
+ {
+ BigInteger one=new BigInteger("1");
+ BigInteger two=new BigInteger("2");
+ BigInteger prime;
+ BigInteger sub_prime;
+ BigInteger generator;
+
+ while(true) {
+ sub_prime=new BigInteger(bits-1,1,new Random()); // this generates a prime
+ prime=sub_prime.multiply(two);
+ prime=prime.add(one);
+
+ if(prime.isProbablePrime(1)) {
+ break;
+ }
+ }
+
+ n=prime;
+
+ while (true) {
+ generator=new BigInteger(8,1,new Random()); // this generates a
+prime with 8 bits
+
+ if(!(generator.modPow(two,prime).equals(one)) &&
+ !(generator.modPow(sub_prime,prime).equals(one))) {
+ break;
+ }
+ }
+
+
+ g=generator;
+
+ }
+
+
+ static public void main(String[] args) {
+
+ Integer bits=new Integer(args[0]);
+
+ dh myDH=new dh(bits.intValue());
+
+ System.out.print("n is: ");
+ System.out.println(myDH.n);
+ System.out.println("n has " + myDH.n.bitLength() + " bits.");
+ System.out.print("g is: ");
+ System.out.println(myDH.g);
+ System.out.println("g has " + myDH.g.bitLength() + " bits.");
+
+ System.exit(0);
+ }
+}
+
+
+>Hmm... it doesn't look too difficult to produce a Diffie-Hellman class
+>after all, though I can't imagine what its interface should look like.
+>Do you have any ideas about that?
+>
+>
+> Andrew Kuchling
+> amk@magnet.com
+> http://starship.skyport.net/crew/amk/
+>
+>
+-----BEGIN PGP SIGNATURE-----
+Version: PGP for Personal Privacy 5.0
+Charset: noconv
+
+iQCVAwUBNCNc+RxijdIqz8FNAQEUmQP+JAKEGpjo8n+wjiAlFY7ohopAbGetubz1
+6QJyft9w4dZYbYAGV66bjIrrZu8oIVAwvCbKlCmThW14u90iMIndaMlJH29SPZ9m
+mUyUJYRal8NH3QWBtpv6n7619r88ImnU1NxaSA2EQ1F6ZZwfIIb6YQsxFeR2w1id
+3T+8Q0sWRn0=
+=f6RN
+-----END PGP SIGNATURE-----
+
+----------------------------------------------
+| Internet solutions for small companies |
+| |
+| email: Jeff_Macdonald@VirtualBuilder.com |
+| Web: www.VirtualBuilder.com |
+| PGP: www.VirtualBuilder.com/pgpkey.html |
+----------------------------------------------
+
+
+
+1,,
+Summary-line: 18-Aug wiml@omnigroup.com [229] #PCT patches
+Mail-from: From wiml@omnigroup.com Mon Aug 18 19:15:33 1997
+Return-Path: wiml@omnigroup.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id TAA01155 for <amk@magnet.com>; Mon, 18 Aug 1997 19:15:32 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id TAA00517; Mon, 18 Aug 1997 19:00:44 -0400
+Received: from ignem.omnigroup.com(198.151.161.40) by grommit.magnet.com via smap (3.1)
+ id xma000511; Mon, 18 Aug 97 19:00:41 -0400
+Received: from reason.omnigroup.com (reason [198.151.161.25])
+ by ignem.omnigroup.com (8.8.5/8.8.5) with SMTP id QAA02952;
+ Mon, 18 Aug 1997 16:00:39 -0700 (GMT-0700)
+From: William Lewis <wiml@omnigroup.com>
+Message-Id: <199708182300.QAA02952@ignem.omnigroup.com>
+Received: by reason.omnigroup.com (NX5.67g/NX3.0X)
+ id AA25820; Mon, 18 Aug 97 16:00:46 -0700
+Date: Mon, 18 Aug 97 16:00:46 -0700
+To: amk@magnet.com
+Cc: wiml@hhhh.org
+Subject: PCT patches
+
+*** EOOH ***
+Return-Path: wiml@omnigroup.com
+From: William Lewis <wiml@omnigroup.com>
+Date: Mon, 18 Aug 97 16:00:46 -0700
+To: amk@magnet.com
+Cc: wiml@hhhh.org
+Subject: PCT patches
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+Here's a patch against PCT version 1.0.1. It allows DES3 to use
+independent keys, fixes some bugs in the RSA module and the block
+cipher framework, and adds a "mode" attribute to block cipher objects.
+
+diff -rc pycrypt101.orig/Extensions/Crypto/Lib/RSA.py pycrypt101/Extensions/Crypto/Lib/RSA.py
+*** pycrypt101.orig/Extensions/Crypto/Lib/RSA.py Sun Apr 14 19:14:27 1996
+- --- pycrypt101/Extensions/Crypto/Lib/RSA.py Fri Aug 1 12:43:41 1997
+***************
+*** 12,18 ****
+ import pubkey
+
+ error = 'RSA module'
+! keydata=['d', 'e', 'n']
+
+ # Generate an RSA key with N bits
+ def generate(N, randfunc, verbose=None):
+- --- 12,18 ----
+ import pubkey
+
+ error = 'RSA module'
+! keydata=['d', 'e', 'n', 'p', 'q']
+
+ # Generate an RSA key with N bits
+ def generate(N, randfunc, verbose=None):
+***************
+*** 42,48 ****
+ if len(tuple) in [3,5] :
+ obj.d=tuple[2]
+ if len(tuple)==5:
+! obj.p=tuple[4] ; obj.q=tuple[5]
+ return obj
+
+ class RSAobj(pubkey.pubkey):
+- --- 42,48 ----
+ if len(tuple) in [3,5] :
+ obj.d=tuple[2]
+ if len(tuple)==5:
+! obj.p=tuple[3] ; obj.q=tuple[4]
+ return obj
+
+ class RSAobj(pubkey.pubkey):
+Only in pycrypt101/Extensions/Crypto/Lib: RSA.py~
+Only in pycrypt101/Extensions/Crypto/block: cast.c
+Only in pycrypt101/Extensions/Crypto/block: cast5.c
+Only in pycrypt101/Extensions/Crypto/block: casttest.py
+diff -rc pycrypt101.orig/Extensions/Crypto/block/des3.c pycrypt101/Extensions/Crypto/block/des3.c
+*** pycrypt101.orig/Extensions/Crypto/block/des3.c Thu Dec 21 16:29:35 1995
+- --- pycrypt101/Extensions/Crypto/block/des3.c Mon Aug 18 15:56:37 1997
+***************
+*** 13,18 ****
+- --- 13,19 ----
+ /* des.c */
+ /* Copyright (C) 1993 Eric Young */
+ /* Integrated into the PCT by A.M. Kuchling, November 1994 */
++ /* Fully independet key mode added by Wim Lewis, July 1997 */
+
+ typedef unsigned char des_cblock[8];
+
+***************
+*** 430,436 ****
+ typedef struct
+ {
+ PCTObject_HEAD
+! des_key_schedule KeySched1, KeySched2;
+ } DES3object;
+
+ static int des_encrypt(input,output,ks,encrypt)
+- --- 431,437 ----
+ typedef struct
+ {
+ PCTObject_HEAD
+! des_key_schedule KeySched1, KeySched2, KeySched3;
+ } DES3object;
+
+ static int des_encrypt(input,output,ks,encrypt)
+***************
+*** 544,550 ****
+ {
+ des_cblock output, output2;
+
+! des_ecb_encrypt(block, output, self->KeySched1, 0);
+ des_ecb_encrypt(output, output2, self->KeySched2, 1);
+ des_ecb_encrypt(output2, block, self->KeySched1, 0);
+ }
+- --- 545,551 ----
+ {
+ des_cblock output, output2;
+
+! des_ecb_encrypt(block, output, self->KeySched3, 0);
+ des_ecb_encrypt(output, output2, self->KeySched2, 1);
+ des_ecb_encrypt(output2, block, self->KeySched1, 0);
+ }
+***************
+*** 557,563 ****
+
+ des_ecb_encrypt(block, output, self->KeySched1, 1);
+ des_ecb_encrypt(output, output2, self->KeySched2, 0);
+! des_ecb_encrypt(output2, block, self->KeySched1, 1);
+ }
+
+ /* NOW DEFINED IN des_local.h
+- --- 558,564 ----
+
+ des_ecb_encrypt(block, output, self->KeySched1, 1);
+ des_ecb_encrypt(output, output2, self->KeySched2, 0);
+! des_ecb_encrypt(output2, block, self->KeySched3, 1);
+ }
+
+ /* NOW DEFINED IN des_local.h
+***************
+*** 643,652 ****
+ return(0);
+ }
+
+! static inline void DES3init(self, key)
+ DES3object *self;
+ unsigned char *key;
+ {
+ des_set_key(key+0, self->KeySched1);
+ des_set_key(key+8, self->KeySched2);
+ }
+- --- 644,665 ----
+ return(0);
+ }
+
+! static inline void DES3init(self, key, keylength)
+ DES3object *self;
+ unsigned char *key;
++ int keylength;
+ {
++ if (keylength != 16 && keylength != 24) {
++ PyErr_SetString(PyExc_ValueError,
++ "DES3 key must be either 16 or 24 bytes long");
++ return;
++ }
++
+ des_set_key(key+0, self->KeySched1);
+ des_set_key(key+8, self->KeySched2);
++ if (keylength == 24) {
++ des_set_key(key+16, self->KeySched3);
++ } else {
++ memcpy(self->KeySched3, self->KeySched1, sizeof(self->KeySched3));
++ }
+ }
+Only in pycrypt101/Extensions/Crypto/block: des3.c~
+diff -rc pycrypt101.orig/Extensions/Crypto/config.pct pycrypt101/Extensions/Crypto/config.pct
+*** pycrypt101.orig/Extensions/Crypto/config.pct Tue Jan 30 17:24:24 1996
+- --- pycrypt101/Extensions/Crypto/config.pct Fri Aug 1 13:45:52 1997
+***************
+*** 15,24 ****
+ block ARC2 8 0
+ block Blowfish 8 0
+ block DES 8 8
+! block DES3 8 16
+ block IDEA 8 16
+ block RC5 8 0
+ block Diamond 16 0
+
+ # Stream ciphers
+ stream ARC4 1 0
+- --- 15,25 ----
+ block ARC2 8 0
+ block Blowfish 8 0
+ block DES 8 8
+! block DES3 8 0
+ block IDEA 8 16
+ block RC5 8 0
+ block Diamond 16 0
+
+ # Stream ciphers
+ stream ARC4 1 0
+Only in pycrypt101/Extensions/Crypto: config.pct~
+diff -rc pycrypt101.orig/Extensions/Crypto/framewks/block.in pycrypt101/Extensions/Crypto/framewks/block.in
+*** pycrypt101.orig/Extensions/Crypto/framewks/block.in Thu Dec 21 16:28:55 1995
+- --- pycrypt101/Extensions/Crypto/framewks/block.in Mon Aug 18 15:45:59 1997
+***************
+*** 441,447 ****
+ "@@BLOCKSIZE@@ bytes long");
+ return -1;
+ }
+! memcpy(self->IV, PyString_AsString, @@BLOCKSIZE@@);
+ return (0);
+ }
+
+- --- 441,447 ----
+ "@@BLOCKSIZE@@ bytes long");
+ return -1;
+ }
+! memcpy(self->IV, PyString_AsString(v), @@BLOCKSIZE@@);
+ return (0);
+ }
+
+***************
+*** 454,459 ****
+- --- 454,463 ----
+ if (strcmp(name, "IV") == 0)
+ {
+ return(PyString_FromStringAndSize(self->IV, @@BLOCKSIZE@@));
++ }
++ if (strcmp(name, "mode") == 0)
++ {
++ return(PyInt_FromLong((long)(self->cipherMode)));
+ }
+ return Py_FindMethod(@@ALGORITHM@@methods, (PyObject *) self, name);
+ }
+Only in pycrypt101/Extensions/Crypto/framewks: block.in~
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2
+Comment: Processed by Mailcrypt 3.4, an Emacs/PGP interface
+
+iQCVAwUBM/jT1F8UnN8n93LBAQGm1wP/Zqo3wKLiN1wa7eIUXSspn27UKM83dt1S
+oJzl3HeHR+JNkOLTUdz37rkX4NbHVhr3wyuE/Hhi7C0LVG/kDfV3cpw2VYCyQgVK
+b91ILoS5C8AgGwUm+mXKtEd73wt7hdOZTDsx0uboNb9c0PqEIzOB5SroNIEl9GLk
+7D+C7KyyuYM=
+=VPS6
+-----END PGP SIGNATURE-----
+
+
+1, answered,,
+Summary-line: 15-Sep JeffBauer@Bigfoot.com [57] #pycrypt101 Makefile.pre.in diffs
+Mail-from: From JeffBauer@Bigfoot.com Mon Sep 15 17:07:06 1997
+Return-Path: JeffBauer@Bigfoot.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id RAA01368 for <amk@magnet.com>; Mon, 15 Sep 1997 17:07:05 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id RAA07289; Mon, 15 Sep 1997 17:07:04 -0400
+Received: from sasha.pov.net(207.152.31.2) by grommit.magnet.com via smap (3.1)
+ id xma007284; Mon, 15 Sep 97 17:06:41 -0400
+Received: from jbauer.remote.pov.net (jbauer.remote.pov.net [207.152.31.187]) by sasha.pov.net (8.6.12/8.6.12) with SMTP id QAA08178 for <amk@magnet.com>; Mon, 15 Sep 1997 16:11:23 -0500
+Received: by jbauer.remote.pov.net with Microsoft Mail
+ id <01BCC1F1.8909C810@jbauer.remote.pov.net>; Mon, 15 Sep 1997 16:07:58 -0500
+Message-ID: <01BCC1F1.8909C810@jbauer.remote.pov.net>
+From: Jeff Bauer <JeffBauer@Bigfoot.com>
+To: "'amk@magnet.com'" <amk@magnet.com>
+Subject: pycrypt101 Makefile.pre.in diffs
+Date: Mon, 15 Sep 1997 16:07:21 -0500
+MIME-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+
+*** EOOH ***
+Return-Path: JeffBauer@Bigfoot.com
+From: Jeff Bauer <JeffBauer@Bigfoot.com>
+To: "'amk@magnet.com'" <amk@magnet.com>
+Subject: pycrypt101 Makefile.pre.in diffs
+Date: Mon, 15 Sep 1997 16:07:21 -0500
+MIME-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+
+Hi Andrew.
+
+I finally got around to getting pycrypt101 to compile on my
+Solaris 2.5.1 machine for Python 1.4. FWIW, I've included
+my Makefile.pre.in diffs. Is there a precompiled version of
+pycrypt/python available for NT? I could look into doing the
+project myself, but U.S. export policies would make it an
+pointless exercise in wish fulfillment :( <<-- meaning that I
+couldn't share my efforts with anyone. Maybe I should
+plan a vacation to Australia and take my laptop along ...
+
+Are you going to the 6th Python Workshop?
+
+Best regards,
+
+Jeff Bauer
+
+_______________________________________________
+
+diff Makefile.pre.in.origin Makefile.pre.in.sunos5
+43a44,45
+> VERSION= 1.4
+>
+96,97c98,99
+< CC= @CC@ -I/usr/local/include
+< SYSLIBS= -L/usr/local/lib $(LIBM) $(LIBC)
+---
+> CC= @CC@
+> SYSLIBS= $(LIBM) $(LIBC)
+113,115c115,117
+< INCLUDEPY= $(installdir)/include/Py
+< LIBP= $(exec_installdir)/lib/python
+< LIBPL= $(LIBP)/lib
+---
+> INCLUDEPY= $(prefix)/include/python$(VERSION)
+> LIBP= $(exec_prefix)/lib/python$(VERSION)
+> LIBPL= $(LIBP)/config
+
+
+1,,
+Summary-line: 15-Sep JeffBauer@Bigfoot.com [44] #RE: pycrypt101 Makefile.pre.in diffs
+Mail-from: From JeffBauer@Bigfoot.com Mon Sep 15 20:44:15 1997
+Return-Path: JeffBauer@Bigfoot.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id UAA05975 for <amk@magnet.com>; Mon, 15 Sep 1997 20:44:14 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id UAA09777; Mon, 15 Sep 1997 20:44:13 -0400
+Received: from sasha.pov.net(207.152.31.2) by grommit.magnet.com via smap (3.1)
+ id xma009773; Mon, 15 Sep 97 20:44:06 -0400
+Received: from jbauer.remote.pov.net (jbauer.remote.pov.net [207.152.31.187]) by sasha.pov.net (8.6.12/8.6.12) with SMTP id TAA17127 for <amk@magnet.com>; Mon, 15 Sep 1997 19:49:01 -0500
+Received: by jbauer.remote.pov.net with Microsoft Mail
+ id <01BCC20F.D99CA130@jbauer.remote.pov.net>; Mon, 15 Sep 1997 19:44:59 -0500
+Message-ID: <01BCC20F.D99CA130@jbauer.remote.pov.net>
+From: Jeff Bauer <JeffBauer@Bigfoot.com>
+To: "'Andrew Kuchling'" <amk@magnet.com>
+Subject: RE: pycrypt101 Makefile.pre.in diffs
+Date: Mon, 15 Sep 1997 19:42:16 -0500
+MIME-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+
+*** EOOH ***
+Return-Path: JeffBauer@Bigfoot.com
+From: Jeff Bauer <JeffBauer@Bigfoot.com>
+To: "'Andrew Kuchling'" <amk@magnet.com>
+Subject: RE: pycrypt101 Makefile.pre.in diffs
+Date: Mon, 15 Sep 1997 19:42:16 -0500
+MIME-Version: 1.0
+Content-Type: text/plain; charset="us-ascii"
+Content-Transfer-Encoding: 7bit
+
+
+>>my Makefile.pre.in diffs. Is there a precompiled version of
+>>pycrypt/python available for NT? I could look into doing the
+>>project myself, but U.S. export policies would make it an
+
+ >Not as far as I know.
+
+>>Are you going to the 6th Python Workshop?
+
+ >Yes; you too?
+
+Yep.
+
+> Thanks for the patches; I'll look at them later. Actually, I
+>think it's about time I returned to working on pycrypt, and would like
+>to hear suggestions for new features. Various people have sent me
+>bugfixes which I haven't gotten around to examining yet, and someone
+>submitted a CAST128 implementation (a block cipher algorithm,
+>specified in an informational RFC somewhere). Do you have any
+>suggestions for new features?
+
+Not really, except for NT support. I know Mark Hammond is too busy
+to consider it, but his locale would be ideal from a distribution angle.
+I have a Newton clinical application that will encrypt the data with IDEA
+and ship it to my Sun box via an internal modem connected to any ISP.
+I presently have the C code working for IDEA, but it would be nice to
+have everything work natively in Python. Interoperability with NT
+would widen the circle of available systems, which is not so important
+for this project, as it is for me to commit to this kind of security
+framework.
+
+Best regards,
+
+Jeff Bauer
+
+
+1,,
+Summary-line: 28-Jul wiml@hhhh.org[1035] #Re: Python Cryptography Toolkit
+Mail-from: From wiml@omnigroup.com Mon Jul 28 18:55:29 1997
+Return-Path: wiml@omnigroup.com
+Received: from grommit.magnet.com (grommit-int.magnet.com [208.192.176.4]) by lemur.magnet.com with SMTP id SAA02128 for <amk@magnet.com>; Mon, 28 Jul 1997 18:55:29 -0400 (EDT)
+Received: by grommit.magnet.com (951211.SGI.8.6.12.PATCH1042/Magnet)
+ for <amk@magnet.com> id SAA23549; Mon, 28 Jul 1997 18:55:28 -0400
+Received: from ignem.omnigroup.com(198.151.161.40) by grommit.magnet.com via smap (3.1)
+ id xma023544; Mon, 28 Jul 97 18:55:05 -0400
+Received: from reason.omnigroup.com (reason [198.151.161.25])
+ by ignem.omnigroup.com (8.8.5/8.8.5) with SMTP id PAA19358
+ for <amk@magnet.com>; Mon, 28 Jul 1997 15:55:08 -0700 (GMT-0700)
+Message-Id: <199707282255.PAA19358@ignem.omnigroup.com>
+Received: by reason.omnigroup.com (NX5.67g/NX3.0X)
+ id AA08245; Mon, 28 Jul 97 15:55:16 -0700
+Date: Mon, 28 Jul 97 15:55:16 -0700
+To: amk@magnet.com
+Subject: Re: Python Cryptography Toolkit
+From: wiml@hhhh.org
+Reply-To: wiml@hhhh.org
+
+*** EOOH ***
+Return-Path: wiml@omnigroup.com
+Date: Mon, 28 Jul 97 15:55:16 -0700
+To: amk@magnet.com
+Subject: Re: Python Cryptography Toolkit
+From: wiml@hhhh.org
+Reply-To: wiml@hhhh.org
+
+-----BEGIN PGP SIGNED MESSAGE-----
+
+You write:
+> Unfortunately, I couldn't read your e-mail, since I retired that PGP
+> key long ago; sorry!
+
+It did look a little old :-) Mostly I just wanted to protect the code
+from any evil whitespace-gobbling mailers it might encounter.
+
+What follows is an implementation of CAST (CAST-128, CAST5) as described
+in rfc2144. It's not the fastest code ever written but it works.
+There are some test vectors in casttest.py; if compiled with
+- -DTEST the C code will perform the much more elaborate "Full Maintenance
+Test". It should be reasonably portable.
+
+I also wanted to say thanks for the PCT; it's a nicely designed and
+useful adjunct to one of my favorite programming languages.
+
+#! /bin/sh
+# This is a shell archive, meaning:
+# 1. Remove everything above the #! /bin/sh line.
+# 2. Save the resulting text in a file.
+# 3. Execute the file with /bin/sh (not csh) to create the files:
+# cast.c
+# cast5.c
+# casttest.py
+# This archive created: Tue Jul 22 22:15:02 1997
+export PATH; PATH=/bin:$PATH
+echo shar: extracting "'cast.c'" '(11926 characters)'
+if test -f 'cast.c'
+then
+ echo shar: will not over-write existing file "'cast.c'"
+else
+sed 's/^X//' << \SHAR_EOF > 'cast.c'
+X/*
+X cast.c -- implementation of CAST-128 (aka CAST5) as described in RFC2144
+X
+X compile -DPCT for use in the Python Cryptography Toolkit
+X (this should work automatically)
+X compile -DTEST to include main() which performs the tests
+X specified in RFC2144
+X
+X Written by Wim Lewis <wiml@hhhh.org> based entirely on RFC2144. This code
+X is in the public domain. Consult your local laws for possible restrictions
+X on use, distribution, and import/export. RFC2144 states that this
+X algorithm "is available worldwide on a royalty-free basis for commercial
+X and non-commercial uses".
+X
+X This code is a pretty straightforward transliteration of the RFC into C.
+X It has not been optimized much at all: byte-order-independent arithmetic
+X operations are used where order-dependent pointer ops or unions might be
+X faster; the code could be rearranged to give the optimizer a better
+X chance to speed things up; etc.
+X
+X This code requires a vaguely ANSI-ish compiler.
+X
+X Tested with gcc 2.5.8 on i486, i586, i686, hp pa-risc, mc68040, sparc;
+X also with gcc 2.7.2 and (with minor changes) native Sun compiler on sparc
+X
+X History:
+X 21 Jul 1997: wiml : first working version & Python module
+X*/
+X
+X
+X/* adjust these according to your compiler/platform. On some machines
+X uint32 will have to be a long. It's OK if uint32 is more than 32 bits. */
+Xtypedef unsigned int uint32;
+Xtypedef unsigned char uint8;
+X
+X#ifdef PCTObject_HEAD
+X#define PCT
+X#endif
+X
+X#ifdef PCT
+X#define PCTstatic static
+X#else
+X#define PCTstatic
+X#endif
+X
+X/* this struct probably belongs in cast.h */
+Xtypedef struct {
+X /* masking and rotate keys */
+X uint32 Km[16];
+X uint8 Kr[16];
+X /* number of rounds (depends on original unpadded keylength) */
+X int rounds;
+X} cast_keyschedule;
+X
+X/* these are the eight 32*256 S-boxes */
+X#include "../block/cast5.c"
+X
+X/* fetch a uint32 from an array of uint8s (with a given offset) */
+X#define fetch(ptr, base) (((((( ptr[base]<< 8 ) | ptr[base+1] )<< 8 ) | ptr[base+2] )<< 8 ) | ptr[base+3])
+X
+X/* this is the round function f(D, Km, Kr) */
+Xstatic inline uint32 castfunc(D, Kmi, Kri, type)
+X uint32 D, Kmi;
+X uint8 Kri;
+X int type;
+X{
+X uint32 I, f;
+X short Ia, Ib, Ic, Id;
+X
+X switch(type) {
+X case 0:
+X I = (Kmi + D) ;
+X break;
+X case 1:
+X I = (Kmi ^ D) ;
+X break;
+X default:
+X case 2:
+X I = (Kmi - D) ;
+X break;
+X }
+X
+X I &= 0xFFFFFFFF;
+X I = ( I << Kri ) | ( I >> ( 32-Kri ) );
+X Ia = ( I >> 24 ) & 0xFF;
+X Ib = ( I >> 16 ) & 0xFF;
+X Ic = ( I >> 8 ) & 0xFF;
+X Id = ( I ) & 0xFF;
+X
+X switch(type) {
+X case 0:
+X f = ((S1[Ia] ^ S2[Ib]) - S3[Ic]) + S4[Id];
+X break;
+X case 1:
+X f = ((S1[Ia] - S2[Ib]) + S3[Ic]) ^ S4[Id];
+X break;
+X default:
+X case 2:
+X f = ((S1[Ia] + S2[Ib]) ^ S3[Ic]) - S4[Id];
+X break;
+X }
+X
+X return f;
+X}
+X
+X/* encrypts/decrypts one block of data according to the key schedule
+X pointed to by `key'. Encrypts if decrypt=0, otherwise decrypts. */
+XPCTstatic void castcrypt(key, block, decrypt)
+X cast_keyschedule *key;
+X uint8 *block;
+X int decrypt;
+X{
+X uint32 L, R, tmp, f;
+X uint32 Kmi;
+X uint8 Kri;
+X short functype, round;
+X
+X L = fetch(block, 0);
+X R = fetch(block, 4);
+X
+X/* printf("L0 = %08x R0 = %08x\n", L, R); */
+X
+X for(round = 0; round < key->rounds; round ++) {
+X
+X if (!decrypt) {
+X Kmi = key->Km[round];
+X Kri = key->Kr[round];
+X functype = round % 3;
+X } else {
+X Kmi = key->Km[(key->rounds) - round - 1];
+X Kri = key->Kr[(key->rounds) - round - 1];
+X functype = (((key->rounds) - round - 1) % 3);
+X }
+X
+X f = castfunc(R, Kmi, Kri, functype);
+X
+X tmp = L;
+X L = R;
+X R = tmp ^ f;
+X
+X/* printf("L%d = %08x R%d = %08x\n", round+1, L, round+1, R); */
+X }
+X
+X block[0] = ( R & 0xFF000000 ) >> 24;
+X block[1] = ( R & 0x00FF0000 ) >> 16;
+X block[2] = ( R & 0x0000FF00 ) >> 8;
+X block[3] = ( R & 0x000000FF );
+X block[4] = ( L & 0xFF000000 ) >> 24;
+X block[5] = ( L & 0x00FF0000 ) >> 16;
+X block[6] = ( L & 0x0000FF00 ) >> 8;
+X block[7] = ( L & 0x000000FF );
+X}
+X
+X/* fetch a uint8 from an array of uint32s */
+X#define b(a,n) (((a)[n/4] >> (24-((n&3)*8))) & 0xFF)
+X
+X/* key schedule round functions */
+X
+X#define XZRound(T, F, ki1, ki2, ki3, ki4, \
+X si11, si12, si13, si14, si15,\
+X si25,\
+X si35,\
+X si45 ) \
+X T[0] = F[ki1] ^ S5[si11 ] ^ S6[si12 ] ^ S7[si13 ] ^ S8[si14 ] ^ S7[si15];\
+X T[1] = F[ki2] ^ S5[b(T, 0)] ^ S6[b(T,2)] ^ S7[b(T, 1)] ^ S8[b(T,3)] ^ S8[si25];\
+X T[2] = F[ki3] ^ S5[b(T, 7)] ^ S6[b(T,6)] ^ S7[b(T, 5)] ^ S8[b(T,4)] ^ S5[si35];\
+X T[3] = F[ki4] ^ S5[b(T,10)] ^ S6[b(T,9)] ^ S7[b(T,11)] ^ S8[b(T,8)] ^ S6[si45];
+X
+X#define zxround() XZRound(z, x, 0, 2, 3, 1, \
+X b(x,13), b(x,15), b(x,12), b(x,14),\
+X b(x, 8), b(x,10), b(x, 9), b(x,11))
+X
+X#define xzround() XZRound(x, z, 2, 0, 1, 3, \
+X b(z,5), b(z,7), b(z,4), b(z,6), \
+X b(z,0), b(z,2), b(z,1), b(z,3))
+X
+X#define Kround(T, base, F,\
+X i11, i12, i13, i14, i15,\
+X i21, i22, i23, i24, i25,\
+X i31, i32, i33, i34, i35,\
+X i41, i42, i43, i44, i45)\
+X T[base+0] = S5[b(F,i11)] ^ S6[b(F,i12)] ^ S7[b(F,i13)] ^ S8[b(F,i14)] ^ S5[b(F,i15)];\
+X T[base+1] = S5[b(F,i21)] ^ S6[b(F,i22)] ^ S7[b(F,i23)] ^ S8[b(F,i24)] ^ S6[b(F,i25)];\
+X T[base+2] = S5[b(F,i31)] ^ S6[b(F,i32)] ^ S7[b(F,i33)] ^ S8[b(F,i34)] ^ S7[b(F,i35)];\
+X T[base+3] = S5[b(F,i41)] ^ S6[b(F,i42)] ^ S7[b(F,i43)] ^ S8[b(F,i44)] ^ S8[b(F,i45)];
+X
+X/* generates sixteen 32-bit subkeys based on a 4x32-bit input key;
+X modifies the input key *in as well. */
+Xstatic void schedulekeys_half(in, keys)
+X uint32 *in;
+X uint32 *keys;
+X{
+X uint32 x[4], z[4];
+X
+X x[0] = in[0];
+X x[1] = in[1];
+X x[2] = in[2];
+X x[3] = in[3];
+X
+X zxround();
+X Kround(keys, 0, z,
+X 8, 9, 7, 6, 2,
+X 10, 11, 5, 4, 6,
+X 12, 13, 3, 2, 9,
+X 14, 15, 1, 0, 12);
+X xzround();
+X Kround(keys, 4, x,
+X 3, 2, 12, 13, 8,
+X 1, 0, 14, 15, 13,
+X 7, 6, 8, 9, 3,
+X 5, 4, 10, 11, 7);
+X zxround();
+X Kround(keys, 8, z,
+X 3, 2, 12, 13, 9,
+X 1, 0, 14, 15, 12,
+X 7, 6, 8, 9, 2,
+X 5, 4, 10, 11, 6);
+X xzround();
+X Kround(keys, 12, x,
+X 8, 9, 7, 6, 3,
+X 10, 11, 5, 4, 7,
+X 12, 13, 3, 2, 8,
+X 14, 15, 1, 0, 13);
+X
+X in[0] = x[0];
+X in[1] = x[1];
+X in[2] = x[2];
+X in[3] = x[3];
+X}
+X
+X/* generates a key schedule from an input key */
+XPCTstatic void castschedulekeys(schedule, key, keybytes)
+X cast_keyschedule *schedule;
+X uint8 *key;
+X int keybytes;
+X{
+X uint32 x[4];
+X uint8 paddedkey[16];
+X uint32 Kr_wide[16];
+X int i;
+X
+X for(i = 0; i < keybytes; i++)
+X paddedkey[i] = key[i];
+X for( ; i < 16 ; i++)
+X paddedkey[i] = 0;
+X
+X if (keybytes <= 10)
+X schedule->rounds = 12;
+X else
+X schedule->rounds = 16;
+X
+X x[0] = fetch(paddedkey, 0);
+X x[1] = fetch(paddedkey, 4);
+X x[2] = fetch(paddedkey, 8);
+X x[3] = fetch(paddedkey, 12);
+X
+X schedulekeys_half(x, schedule->Km);
+X schedulekeys_half(x, Kr_wide);
+X
+X for(i = 0; i < 16; i ++) {
+X /* The Kr[] subkeys are used for 32-bit circular shifts,
+X so we only need to keep them modulo 32 */
+X schedule->Kr[i] = (uint8)(Kr_wide[i] & 0x1F);
+X }
+X}
+X
+X#ifdef TEST
+X
+X/* This performs a variety of encryptions and verifies that the results
+X match those specified in RFC2144 appendix B. Also verifies that
+X decryption restores the original data. */
+X
+X#include <stdio.h>
+X
+Xstatic cast_keyschedule sched;
+X
+Xvoid encrypt(key, keylen, in, out)
+X uint8 *key;
+X int keylen;
+X uint8 *in, *out;
+X{
+X int i;
+X uint8 k[16];
+X
+X castschedulekeys(&sched, key, keylen);
+X
+X for(i = 0; i < 8; i++)
+X out[i] = in[i];
+X castcrypt(&sched, out, 0);
+X}
+X
+Xvoid tst(key, keylen, data, result)
+X uint8 *key;
+X int keylen;
+X uint8 *data, *result;
+X{
+X uint8 d[8];
+X int i;
+X
+X encrypt(key, keylen, data, d);
+X
+X for(i = 0; i < 8; i++)
+X if (d[i] != result[i])
+X break;
+X
+X if (i == 8) {
+X printf("-- test ok (encrypt)\n");
+X } else {
+X for(i = 0; i < 8; i++)
+X printf(" %02x", d[i]);
+X printf(" (computed)\n");
+X for(i = 0; i < 8; i++)
+X printf(" %02x", result[i]);
+X printf(" (expected)\n");
+X }
+X
+X /* uses key schedule already set up */
+X castcrypt(&sched, d, 1);
+X if (bcmp(d, data, 8))
+X printf(" test FAILED (decrypt)\n");
+X else
+X printf(" test ok (decrypt)\n");
+X
+X}
+X
+Xuint8 key[16] = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+X 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A };
+Xuint8 data[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
+X
+X/* expected results of encrypting the above with 128, 80, and 40
+X bits of key length */
+Xuint8 out1[8] = { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
+Xuint8 out2[8] = { 0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B };
+Xuint8 out3[8] = { 0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E };
+X
+X/* expected results of the "full maintenance test" */
+Xuint8 afinal[16] = { 0xEE, 0xA9, 0xD0, 0xA2, 0x49, 0xFD, 0x3B, 0xA6,
+X 0xB3, 0x43, 0x6F, 0xB8, 0x9D, 0x6D, 0xCA, 0x92 };
+Xuint8 bfinal[16] = { 0xB2, 0xC9, 0x5E, 0xB0, 0x0C, 0x31, 0xAD, 0x71,
+X 0x80, 0xAC, 0x05, 0xB8, 0xE8, 0x3D, 0x69, 0x6E };
+X
+Xmain()
+X{
+X /* Appendix B.1 : Single Plaintext-Key-Ciphertext Sets */
+X tst(key, 16, data, out1);
+X tst(key, 10, data, out2);
+X tst(key, 5, data, out3);
+X
+X /* Appendix B.2 : Full Maintenance Test */
+X {
+X uint8 abuf[16];
+X uint8 bbuf[16];
+X int i;
+X
+X bcopy(key, abuf, 16);
+X bcopy(key, bbuf, 16);
+X
+X printf("\nrunning full maintenance test...\n");
+X
+X for(i = 0; i < 1000000; i++) {
+X castschedulekeys(&sched, bbuf, 16);
+X castcrypt(&sched, abuf, 0);
+X castcrypt(&sched, abuf+8, 0);
+X
+X castschedulekeys(&sched, abuf, 16);
+X castcrypt(&sched, bbuf, 0);
+X castcrypt(&sched, bbuf+8, 0);
+X
+X if (!(i % 10000)) {
+X fprintf(stdout, "\r%d%% ", i / 10000);
+X fflush(stdout);
+X }
+X }
+X
+X printf("\r \r");
+X
+X for(i = 0; i < 16; i ++)
+X if (abuf[i] != afinal[i] || bbuf[i] != bfinal[i])
+X break;
+X
+X if(i == 16) {
+X printf("-- full maintenance test ok\n");
+X } else {
+X for(i = 0; i < 16; i++)
+X printf(" %02x", abuf[i]);
+X printf("\n");
+X for(i = 0; i < 16; i++)
+X printf(" %02x", bbuf[i]);
+X printf("\n");
+X }
+X
+X printf("running maintenance test in reverse...\n");
+X for(i = 0; i < 1000000; i++) {
+X castschedulekeys(&sched, abuf, 16);
+X castcrypt(&sched, bbuf+8, 1);
+X castcrypt(&sched, bbuf, 1);
+X
+X castschedulekeys(&sched, bbuf, 16);
+X castcrypt(&sched, abuf+8, 1);
+X castcrypt(&sched, abuf, 1);
+X
+X if (!(i % 10000)) {
+X fprintf(stdout, "\r%d%% ", i / 10000);
+X fflush(stdout);
+X }
+X }
+X
+X printf("\r \r");
+X if (bcmp(abuf, key, 16) || bcmp(bbuf, key, 16))
+X printf("-- reverse maintenance test FAILED\n");
+X else
+X printf("-- reverse maintenance test ok\n");
+X }
+X}
+X
+X#endif
+X
+X#ifdef PCT
+X
+X/* code to interface with the Python Cryptography Toolkit */
+X
+Xtypedef struct
+X{
+X PCTObject_HEAD
+X cast_keyschedule schedule;
+X} CASTobject;
+X
+Xstatic void
+XCASTinit(self, key, keylength)
+X CASTobject *self;
+X unsigned char *key;
+X int keylength;
+X{
+X /* presumably this will optimize out */
+X if (sizeof(uint32) < 4 || sizeof(uint8) != 1) {
+X PyErr_SetString(PyExc_SystemError,
+X "CAST module compiled with bad typedefs!");
+X }
+X
+X /* make sure the key length is within bounds */
+X if (keylength < 5 || keylength > 16) {
+X PyErr_SetString(PyExc_ValueError, "CAST key must be "
+X "at least 5 bytes and no more than 16 bytes long");
+X return;
+X }
+X
+X /* do the actual key schedule setup */
+X castschedulekeys(&(self->schedule), key, keylength);
+X}
+X
+Xstatic void
+XCASTencrypt(self, block)
+X CASTobject *self;
+X unsigned char *block;
+X{
+X castcrypt(&(self->schedule), block, 0);
+X}
+X
+Xstatic void CASTdecrypt(self, block)
+X CASTobject *self;
+X unsigned char *block;
+X{
+X castcrypt(&(self->schedule), block, 1);
+X}
+X
+X#endif
+SHAR_EOF
+if test 11926 -ne "`wc -c < 'cast.c'`"
+then
+ echo shar: error transmitting "'cast.c'" '(should have been 11926 characters)'
+fi
+fi # end of overwriting check
+echo shar: extracting "'cast5.c'" '(24921 characters)'
+if test -f 'cast5.c'
+then
+ echo shar: will not over-write existing file "'cast5.c'"
+else
+sed 's/^X//' << \SHAR_EOF > 'cast5.c'
+X/*
+X These are the S-boxes for CAST5 as given in RFC 2144.
+X*/
+X
+X
+Xstatic const uint32 S1[256] = {
+X0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
+X0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5,
+X0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d,
+X0x22d4ff8e, 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2,
+X0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d, 0xa1c9e0d6,
+X0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b,
+X0x22568e3a, 0xa2d341d0, 0x66db40c8, 0xa784392f, 0x004dff2f,
+X0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+X0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0,
+X0x90ecf52e, 0x22b0c054, 0xbc8e5935, 0x4b6d2f7f, 0x50bb64a2,
+X0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411,
+X0x4bff345d, 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165,
+X0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50, 0x882240f2,
+X0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319,
+X0xb949e354, 0xb04669fe, 0xb1b6ab8a, 0xc71358dd, 0x6385c545,
+X0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+X0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5,
+X0xf61b1891, 0xbb72275e, 0xaa508167, 0x38901091, 0xc6b505eb,
+X0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af,
+X0xaa56d291, 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9,
+X0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779, 0x64459eab,
+X0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6,
+X0x3fab0950, 0x325ff6c2, 0x81383f05, 0x6963c5c8, 0x76cb5ad6,
+X0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+X0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241,
+X0x051ef495, 0xaa573b04, 0x4a805d8d, 0x548300d0, 0x00322a3c,
+X0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275,
+X0x915a0bf5, 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82,
+X0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324, 0xcfa4bd3f,
+X0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98,
+X0xe31231b2, 0x2ad5ad6c, 0x954329de, 0xadbe4528, 0xd8710f69,
+X0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+X0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6,
+X0x032268d4, 0xc9600acc, 0xce387e6d, 0xbf6bb16c, 0x6a70fb78,
+X0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8,
+X0xb347cc96, 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a,
+X0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a, 0x3f04442f,
+X0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d,
+X0x2ad37c96, 0x0175cb9d, 0xc69dff09, 0xc75b65f0, 0xd9db40d8,
+X0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+X0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af,
+X0x51c85f4d, 0x56907596, 0xa5bb15e6, 0x580304f0, 0xca042cf1,
+X0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09,
+X0xbc306ed9, 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0,
+X0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872, 0xaf1fbda7,
+X0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7,
+X0x26470db8, 0xf881814c, 0x474d6ad7, 0x7c0c5e5c, 0xd1231959,
+X0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+X0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c,
+X0xe1e696ff, 0xb141ab08, 0x7cca89b9, 0x1a69e783, 0x02cc4843,
+X0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00,
+X0x5c8165bf };
+X
+Xstatic const uint32 S2[256] = {
+X0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
+X0xeec5207a, 0x55889c94, 0x72fc0651, 0xada7ef79, 0x4e1d7235,
+X0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d,
+X0xa1d6eff3, 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909,
+X0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb, 0xd1da4181,
+X0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b,
+X0x25a1ff41, 0xe180f806, 0x1fc41080, 0x179bee7a, 0xd37ac6a9,
+X0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+X0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154,
+X0x0d554b63, 0x5d681121, 0xc866c359, 0x3d63cf73, 0xcee234c0,
+X0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084,
+X0xe4eb573b, 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d,
+X0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c, 0x10843094,
+X0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74,
+X0xd9e0a227, 0x4ec73a34, 0xfc884f69, 0x3e4de8df, 0xef0e0088,
+X0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+X0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1,
+X0x27e19ba5, 0xd5a6c252, 0xe49754bd, 0xc5d655dd, 0xeb667064,
+X0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7,
+X0xe5d05860, 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755,
+X0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b, 0xeccf01db,
+X0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6,
+X0x5ee22b95, 0x5f0e5304, 0x81ed6f61, 0x20e74364, 0xb45e1378,
+X0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+X0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402,
+X0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf, 0xa20c3005, 0x8871df63,
+X0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835,
+X0x9f63293c, 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3,
+X0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13, 0x73f98417,
+X0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741,
+X0x7cbad9a2, 0x2180036f, 0x50d99c08, 0xcb3f4861, 0xc26bd765,
+X0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+X0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb,
+X0x846a3bae, 0x8ff77888, 0xee5d60f6, 0x7af75673, 0x2fdd5cdb,
+X0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc,
+X0xd152de58, 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8,
+X0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906, 0xb8da230c,
+X0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560,
+X0x61a3c9e8, 0xbca8f54d, 0xc72feffa, 0x22822e99, 0x82c570b4,
+X0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+X0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a,
+X0xf7e19798, 0x7619b72f, 0x8f1c9ba4, 0xdc8637a0, 0x16a7d3b1,
+X0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc,
+X0x520365d6, 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e,
+X0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f, 0x5483697b,
+X0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9,
+X0x6c387e8a, 0x0ae6d249, 0xb284600c, 0xd835731d, 0xdcb1c647,
+X0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+X0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589,
+X0xa345415e, 0x5c038323, 0x3e5d3bb9, 0x43d79572, 0x7e6dd07c,
+X0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605,
+X0x4523ecf1 };
+X
+Xstatic const uint32 S3[256] = {
+X0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
+X0x369fe44b, 0x8c1fc644, 0xaececa90, 0xbeb1f9bf, 0xeefbcaea,
+X0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83,
+X0x927010d5, 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e,
+X0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e, 0x553fb2c0,
+X0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd,
+X0x9255c5ed, 0x1257a240, 0x4e1a8302, 0xbae07fff, 0x528246e7,
+X0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+X0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1,
+X0x1fb78dfc, 0x8e6bd2c1, 0x437be59b, 0x99b03dbf, 0xb5dbc64b,
+X0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28,
+X0xccc36f71, 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f,
+X0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04, 0xa747d2d0,
+X0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4,
+X0x0a0fb402, 0x0f7fef82, 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49,
+X0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+X0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403,
+X0xe83ec305, 0x4f91751a, 0x925669c2, 0x23efe941, 0xa903f12e,
+X0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb,
+X0x02778176, 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e,
+X0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148, 0xef303cab,
+X0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88,
+X0x7d29dc96, 0x2756d3dc, 0x8b907cee, 0xb51fd240, 0xe7c07ce3,
+X0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+X0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9,
+X0xbda8229c, 0x127dadaa, 0x438a074e, 0x1f97c090, 0x081bdb8a,
+X0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec,
+X0x64380e51, 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4,
+X0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f, 0x4b39fffa,
+X0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa,
+X0x27627545, 0x825cf47a, 0x61bd8ba0, 0xd11e42d1, 0xcead04f4,
+X0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+X0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb,
+X0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b, 0x1f081fab, 0x108618ae,
+X0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d,
+X0x2c3f8cc5, 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67,
+X0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45, 0x3a609437,
+X0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c,
+X0x02717ef6, 0x4feb5536, 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0,
+X0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+X0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33,
+X0xabcc4f33, 0x7688c55d, 0x7b00a6b0, 0x947b0001, 0x570075d2,
+X0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b,
+X0xee971b69, 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767,
+X0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2, 0x67214cb8,
+X0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d,
+X0x606e6dc6, 0x60543a49, 0x5727c148, 0x2be98a1d, 0x8ab41738,
+X0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+X0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31,
+X0x9c305a00, 0x52bce688, 0x1b03588a, 0xf7baefd5, 0x4142ed9c,
+X0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c,
+X0xee353783 };
+X
+Xstatic const uint32 S4[256] = {
+X0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
+X0x64ad8c57, 0x85510443, 0xfa020ed1, 0x7e287aff, 0xe60fb663,
+X0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63,
+X0x241e4adf, 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220,
+X0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15, 0xee4d111a,
+X0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe,
+X0x081b08ca, 0x05170121, 0x80530100, 0xe83e5efe, 0xac9af4f8,
+X0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+X0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400,
+X0x547eebe6, 0x446d4ca0, 0x6cf3d6f5, 0x2649abdf, 0xaea0c7f5,
+X0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03,
+X0xf80eb2bb, 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746,
+X0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5, 0x4d351805,
+X0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91,
+X0x9f46222f, 0x3991467d, 0xa5bf6d8e, 0x1143c44f, 0x43958302,
+X0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+X0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25,
+X0x79098b02, 0xe4eabb81, 0x28123b23, 0x69dead38, 0x1574ca16,
+X0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8,
+X0x09114003, 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340,
+X0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6, 0xe756bdff,
+X0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391,
+X0x6b65811c, 0x5e146119, 0x6e85cb75, 0xbe07c002, 0xc2325577,
+X0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+X0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a,
+X0xeca1d7c7, 0x041afa32, 0x1d16625a, 0x6701902c, 0x9b757a54,
+X0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48,
+X0x56e55a79, 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5,
+X0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df, 0xb7747f9d,
+X0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035,
+X0x213d42f6, 0x2c1c7c26, 0x61c2f50f, 0x6552daf9, 0xd2c231f8,
+X0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+X0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86,
+X0x311170a7, 0x3e9b640c, 0xcc3e10d7, 0xd5cad3b6, 0x0caec388,
+X0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f,
+X0xc1de8417, 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3,
+X0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2, 0x6f7de532,
+X0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5,
+X0x001d7b95, 0x82e5e7d2, 0x109873f6, 0x00613096, 0xc32d9521,
+X0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+X0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7,
+X0x0ce454a9, 0xd60acd86, 0x015f1919, 0x77079103, 0xdea03af6,
+X0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651,
+X0xb8a5c3ef, 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf,
+X0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876, 0x39e4460c,
+X0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e,
+X0x492fc295, 0x9266beab, 0xb5676e69, 0x9bd3ddda, 0xdf7e052f,
+X0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+X0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979,
+X0x932bcdf6, 0xb657c34d, 0x4edfd282, 0x7ae5290c, 0x3cb9536b,
+X0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1,
+X0x0aef7ed2 };
+X
+Xstatic const uint32 S5[256] = {
+X0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff,
+X0x1dd358f5, 0x44dd9d44, 0x1731167f, 0x08fbf1fa, 0xe7f511cc,
+X0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a,
+X0x69befd7a, 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180,
+X0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff, 0x5f480a01,
+X0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb,
+X0x8dba1cfe, 0x41a99b02, 0x1a550a04, 0xba8f65cb, 0x7251f4e7,
+X0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+X0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88,
+X0x8709e6b0, 0xd7e07156, 0x4e29fea7, 0x6366e52d, 0x02d1c000,
+X0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02,
+X0xd642a0c9, 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec,
+X0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981, 0x5c1ff900,
+X0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976,
+X0x90c79505, 0xb0a8a774, 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27,
+X0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+X0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980,
+X0x524755f4, 0x03b63cc9, 0x0cc844b2, 0xbcf3f0aa, 0x87ac36e9,
+X0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da,
+X0x01c94910, 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284,
+X0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1, 0x136e05db,
+X0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf,
+X0xb6f589de, 0xec2941da, 0x26e46695, 0xb7566419, 0xf654efc5,
+X0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+X0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd,
+X0x9e0885f9, 0x68cb3e47, 0x086c010f, 0xa21de820, 0xd18b69de,
+X0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d,
+X0xb0d70eba, 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4,
+X0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be, 0x580a249f,
+X0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715,
+X0x646c6bd7, 0x44904db3, 0x66b4f0a3, 0xc0f1648a, 0x697ed5af,
+X0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+X0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8,
+X0xc1092910, 0x8bc95fc6, 0x7d869cf4, 0x134f616f, 0x2e77118d,
+X0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010,
+X0xaf462ba2, 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487,
+X0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7, 0x445f7382,
+X0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3,
+X0x20936079, 0x459b80a5, 0xbe60e2db, 0xa9c23101, 0xeba5315c,
+X0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+X0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e,
+X0x75922283, 0x784d6b17, 0x58ebb16e, 0x44094f85, 0x3f481d87,
+X0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a,
+X0x2b092801, 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0,
+X0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad, 0x6cf6e479,
+X0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3,
+X0xa09c7f70, 0x5346aba0, 0x5ce96c28, 0xe176eda3, 0x6bac307f,
+X0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+X0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a,
+X0xeeb9491d, 0x34010718, 0xbb30cab8, 0xe822fe15, 0x88570983,
+X0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08,
+X0xefe9e7d4 };
+X
+Xstatic const uint32 S6[256] = {
+X0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7,
+X0x016843b4, 0xeced5cbc, 0x325553ac, 0xbf9f0960, 0xdfa1e2ed,
+X0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732,
+X0x8989b138, 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e,
+X0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367, 0xa3149619,
+X0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f,
+X0xa888614a, 0x2900af98, 0x01665991, 0xe1992863, 0xc8f30c60,
+X0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+X0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c,
+X0x4c7f4448, 0xdab5d440, 0x6dba0ec3, 0x083919a7, 0x9fbaeed9,
+X0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a,
+X0xba7dd9cd, 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d,
+X0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8, 0x284caf89,
+X0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906,
+X0xefe8c36e, 0xf890cdd9, 0x80226dae, 0xc340a4a3, 0xdf7e9c09,
+X0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+X0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc,
+X0xcf222ebf, 0x25ac6f48, 0xa9a99387, 0x53bddb65, 0xe76ffbe7,
+X0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d,
+X0xc8087dfc, 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0,
+X0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf, 0x5f04456d,
+X0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5,
+X0xe2220abe, 0xd2916ebf, 0x4ec75b95, 0x24f2c3c0, 0x42d15d99,
+X0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+X0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af,
+X0x692573e4, 0xe9a9d848, 0xf3160289, 0x3a62ef1d, 0xa787e238,
+X0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407,
+X0x592af950, 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa,
+X0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f, 0x89dff0bb,
+X0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585,
+X0xdc049441, 0xc8098f9b, 0x7dede786, 0xc39a3373, 0x42410005,
+X0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+X0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a,
+X0x1f8fb214, 0xd372cf08, 0xcc3c4a13, 0x8cf63166, 0x061c87be,
+X0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb,
+X0x3fc06976, 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459,
+X0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0, 0x3007cd3e,
+X0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241,
+X0x8809286c, 0xf592d891, 0x08a930f6, 0x957ef305, 0xb7fbffbd,
+X0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+X0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123,
+X0x257f0c3d, 0x9348af49, 0x361400bc, 0xe8816f4a, 0x3814f200,
+X0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a,
+X0x54f4a084, 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab,
+X0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25, 0x653d7e6a,
+X0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76,
+X0x0404a8c8, 0xb8e5a121, 0xb81a928a, 0x60ed5869, 0x97c55b96,
+X0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+X0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1,
+X0xf544edeb, 0xb0e93524, 0xbebb8fbd, 0xa2d762cf, 0x49c92f54,
+X0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd,
+X0xd675cf2f };
+X
+Xstatic const uint32 S7[256] = {
+X0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f,
+X0xab9bc912, 0xde6008a1, 0x2028da1f, 0x0227bce7, 0x4d642916,
+X0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2,
+X0xb28707de, 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd,
+X0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43, 0x4d495001,
+X0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4,
+X0x1286becf, 0xb6eacb19, 0x2660c200, 0x7565bde4, 0x64241f7a,
+X0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+X0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a,
+X0xeb12ff82, 0xe3486911, 0xd34d7516, 0x4e7b3aff, 0x5f43671b,
+X0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0,
+X0xcb3a6c88, 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e,
+X0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816, 0x0a961288,
+X0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745,
+X0xcf19df58, 0xbec3f756, 0xc06eba30, 0x07211b24, 0x45c28829,
+X0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+X0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f,
+X0xaff60ff4, 0xea2c4e6d, 0x16e39264, 0x92544a8b, 0x009b4fc3,
+X0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9,
+X0xbe838688, 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d,
+X0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28, 0xda6d0c74,
+X0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f,
+X0xeed82b29, 0x1d382fe3, 0x0c4fb99a, 0xbb325778, 0x3ec6d97b,
+X0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+X0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32,
+X0xebd4e7be, 0xbe8b9d2d, 0x7979fb06, 0xe7225308, 0x8b75cf77,
+X0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0,
+X0x5dda0033, 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a,
+X0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a, 0x2711fd60,
+X0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476,
+X0x488dcf25, 0x36c9d566, 0x28e74e41, 0xc2610aca, 0x3d49a9cf,
+X0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+X0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887,
+X0x2b9f4fd5, 0x625aba82, 0x6a017962, 0x2ec01b9c, 0x15488aa9,
+X0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9,
+X0x3453dc1e, 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07,
+X0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c, 0x66626c1c,
+X0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae,
+X0x9ea294fb, 0x52cf564c, 0x9883fe66, 0x2ec40581, 0x763953c3,
+X0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+X0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f,
+X0x3d321c5d, 0xc3f5e194, 0x4b269301, 0xc79f022f, 0x3c997e7e,
+X0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f,
+X0xc61e45be, 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567,
+X0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767, 0x1814386b,
+X0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390,
+X0x5479f8e6, 0x1cb8d647, 0x97fd61a9, 0xea7759f4, 0x2d57539d,
+X0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+X0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc,
+X0x3d40f021, 0xc3c0bdae, 0x4958c24c, 0x518f36b2, 0x84b1d370,
+X0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b,
+X0x954b8aa3 };
+X
+Xstatic const uint32 S8[256] = {
+X0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7,
+X0xe6c1121b, 0x0e241600, 0x052ce8b5, 0x11a9cfb0, 0xe5952f11,
+X0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a,
+X0x37ddddfc, 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940,
+X0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd, 0x0b15a15d,
+X0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7,
+X0x72df191b, 0x7580330d, 0x94074251, 0x5c7dcdfa, 0xabbe6d63,
+X0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+X0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022,
+X0xce949ad4, 0xb84769ad, 0x965bd862, 0x82f3d055, 0x66fb9767,
+X0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e,
+X0x647a78fc, 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6,
+X0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c, 0xbbd35049,
+X0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548,
+X0x58cb7e07, 0x3b74ef2e, 0x522fffb1, 0xd24708cc, 0x1c7e27cd,
+X0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+X0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd,
+X0xc18910b1, 0xe11dbf7b, 0x06cd1af8, 0x7170c608, 0x2d5e3354,
+X0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34,
+X0x77d51b42, 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564,
+X0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5, 0xe6459788,
+X0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b,
+X0x24259fd7, 0xf8bef472, 0x835ffcb8, 0x6df4c1f2, 0x96f5b195,
+X0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+X0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187,
+X0xea7a6e98, 0x7cd16efc, 0x1436876c, 0xf1544107, 0xbedeee14,
+X0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d,
+X0x151682eb, 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f,
+X0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054, 0xb6f2cf3b,
+X0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5,
+X0xbae7dfdc, 0x42cbda70, 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6,
+X0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+X0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4,
+X0xc5c8b37e, 0x0d809ea2, 0x398feb7c, 0x132a4f94, 0x43b7950e,
+X0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289,
+X0xacf3ebc3, 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4,
+X0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4, 0xe87b40e4,
+X0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694,
+X0x38d7e5b2, 0x57720101, 0x730edebc, 0x5b643113, 0x94917e4f,
+X0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+X0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f,
+X0xad1163ed, 0xea7b5965, 0x1a00726e, 0x11403092, 0x00da6d77,
+X0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8,
+X0xcee7d28a, 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37,
+X0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c, 0xaa12e4f2,
+X0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b,
+X0x67cdb156, 0x350d8384, 0x5938fa0f, 0x42399ef3, 0x36997b07,
+X0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+X0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82,
+X0x0d2059d1, 0xa466bb1e, 0xf8da0a82, 0x04f19130, 0xba6e4ec0,
+X0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283,
+X0xea8bf59e };
+X
+SHAR_EOF
+if test 24921 -ne "`wc -c < 'cast5.c'`"
+then
+ echo shar: error transmitting "'cast5.c'" '(should have been 24921 characters)'
+fi
+fi # end of overwriting check
+echo shar: extracting "'casttest.py'" '(675 characters)'
+if test -f 'casttest.py'
+then
+ echo shar: will not over-write existing file "'casttest.py'"
+else
+sed 's/^X//' << \SHAR_EOF > 'casttest.py'
+X
+Ximport cast
+X
+Xtestkey = '\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45\x67\x89\x34\x56\x78\x9A'
+Xtestdata = '\x01\x23\x45\x67\x89\xAB\xCD\xEF'
+X
+Xcipher128 = '\x23\x8B\x4F\xE5\x84\x7E\x44\xB2'
+Xcipher80 = '\xEB\x6A\x71\x1A\x2C\x02\x27\x1B'
+Xcipher40 = '\x7A\xC8\x16\xD1\x6E\x9B\x30\x2E'
+X
+Xprint 'cast-128:',
+Xk = cast.new(testkey, cast.ECB)
+Xif k.encrypt(testdata) == cipher128:
+X print 'ok'
+Xelse:
+X print 'not ok'
+X
+Xprint 'cast5-80:',
+Xk = cast.new(testkey[:10], cast.ECB)
+Xif k.encrypt(testdata) == cipher80:
+X print 'ok'
+Xelse:
+X print 'not ok'
+X
+Xprint 'cast5-40:',
+Xk = cast.new(testkey[:5], cast.ECB)
+Xif k.encrypt(testdata) == cipher40:
+X print 'ok'
+Xelse:
+X print 'not ok'
+X
+X
+SHAR_EOF
+if test 675 -ne "`wc -c < 'casttest.py'`"
+then
+ echo shar: error transmitting "'casttest.py'" '(should have been 675 characters)'
+fi
+fi # end of overwriting check
+# End of shell archive
+exit 0
+
+
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2
+Comment: Processed by Mailcrypt 3.4, an Emacs/PGP interface
+
+iQCVAwUBM90jSV8UnN8n93LBAQFiFgQAqoqtg7jvvYdJpfsVu3Qg5FbbBI9EH1An
+NtRKtUTU44v/cF1Bs/J7WBXtWrEC7nqb4LApFSL8RcKrWDZRcjFhb4nHyFkJpAg8
+hSHXi3LTZLMh1D/o0cm5YA/BCp1RnAQCPpnSJvfPc/H6m2KpjmdeZcp1dYBF77EH
+vpa7UKaJuDg=
+=i+5W
+-----END PGP SIGNATURE-----
+
+ \ No newline at end of file
diff --git a/info/rfc2104.html b/info/rfc2104.html
new file mode 100644
index 0000000..6eab319
--- /dev/null
+++ b/info/rfc2104.html
@@ -0,0 +1,625 @@
+<!-- X-URL: http://www.pmg.lcs.mit.edu/cgi-bin/rfc/view-plain?number=2104 -->
+<BASE HREF="http://www.pmg.lcs.mit.edu/cgi-bin/rfc/view-plain?number=2104">
+
+<title>RFC 2104</title>
+<pre width=80>
+
+
+
+
+
+
+Network Working Group H. Krawczyk
+Request for Comments: <a href="/cgi-bin/rfc/view?2104">2104</a> IBM
+Category: Informational M. Bellare
+ UCSD
+ R. Canetti
+ IBM
+ February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ HMAC: Keyed-Hashing for Message Authentication
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+Abstract
+
+ This document describes HMAC, a mechanism for message authentication
+ using cryptographic hash functions. HMAC can be used with any
+ iterative cryptographic hash function, e.g., MD5, SHA-1, in
+ combination with a secret shared key. The cryptographic strength of
+ HMAC depends on the properties of the underlying hash function.
+
+1. Introduction
+
+ Providing a way to check the integrity of information transmitted
+ over or stored in an unreliable medium is a prime necessity in the
+ world of open computing and communications. Mechanisms that provide
+ such integrity check based on a secret key are usually called
+ "message authentication codes" (MAC). Typically, message
+ authentication codes are used between two parties that share a secret
+ key in order to validate information transmitted between these
+ parties. In this document we present such a MAC mechanism based on
+ cryptographic hash functions. This mechanism, called HMAC, is based
+ on work by the authors [BCK1] where the construction is presented and
+ cryptographically analyzed. We refer to that work for the details on
+ the rationale and security analysis of HMAC, and its comparison to
+ other keyed-hash methods.
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 1]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ HMAC can be used in combination with any iterated cryptographic hash
+ function. MD5 and SHA-1 are examples of such hash functions. HMAC
+ also uses a secret key for calculation and verification of the
+ message authentication values. The main goals behind this
+ construction are
+
+ * To use, without modifications, available hash functions.
+ In particular, hash functions that perform well in software,
+ and for which code is freely and widely available.
+
+ * To preserve the original performance of the hash function without
+ incurring a significant degradation.
+
+ * To use and handle keys in a simple way.
+
+ * To have a well understood cryptographic analysis of the strength of
+ the authentication mechanism based on reasonable assumptions on the
+ underlying hash function.
+
+ * To allow for easy replaceability of the underlying hash function in
+ case that faster or more secure hash functions are found or
+ required.
+
+ This document specifies HMAC using a generic cryptographic hash
+ function (denoted by H). Specific instantiations of HMAC need to
+ define a particular hash function. Current candidates for such hash
+ functions include SHA-1 [SHA], MD5 [MD5], RIPEMD-<a href="/cgi-bin/rfc/view?128">128</a>/<a href="/cgi-bin/rfc/view?160">160</a> [RIPEMD].
+ These different realizations of HMAC will be denoted by HMAC-SHA1,
+ HMAC-MD5, HMAC-RIPEMD, etc.
+
+ Note: To the date of writing of this document MD5 and SHA-1 are the
+ most widely used cryptographic hash functions. MD5 has been recently
+ shown to be vulnerable to collision search attacks [Dobb]. This
+ attack and other currently known weaknesses of MD5 do not compromise
+ the use of MD5 within HMAC as specified in this document (see
+ [Dobb]); however, SHA-1 appears to be a cryptographically stronger
+ function. To this date, MD5 can be considered for use in HMAC for
+ applications where the superior performance of MD5 is critical. In
+ any case, implementers and users need to be aware of possible
+ cryptanalytic developments regarding any of these cryptographic hash
+ functions, and the eventual need to replace the underlying hash
+ function. (See section 6 for more information on the security of
+ HMAC.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 2]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+2. Definition of HMAC
+
+ The definition of HMAC requires a cryptographic hash function, which
+ we denote by H, and a secret key K. We assume H to be a cryptographic
+ hash function where data is hashed by iterating a basic compression
+ function on blocks of data. We denote by B the byte-length of such
+ blocks (B=64 for all the above mentioned examples of hash functions),
+ and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
+ SHA-1). The authentication key K can be of any length up to B, the
+ block length of the hash function. Applications that use keys longer
+ than B bytes will first hash the key using H and then use the
+ resultant L byte string as the actual key to HMAC. In any case the
+ minimal recommended length for K is L bytes (as the hash output
+ length). See section 3 for more information on keys.
+
+ We define two fixed and different strings ipad and opad as follows
+ (the 'i' and 'o' are mnemonics for inner and outer):
+
+ ipad = the byte 0x36 repeated B times
+ opad = the byte 0x5C repeated B times.
+
+ To compute HMAC over the data `text' we perform
+
+ H(K XOR opad, H(K XOR ipad, text))
+
+ Namely,
+
+ (1) append zeros to the end of K to create a B byte string
+ (e.g., if K is of length 20 bytes and B=64, then K will be
+ appended with 44 zero bytes 0x00)
+ (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+ (1) with ipad
+ (3) append the stream of data 'text' to the B byte string resulting
+ from step (2)
+ (4) apply H to the stream generated in step (3)
+ (5) XOR (bitwise exclusive-OR) the B byte string computed in
+ step (1) with opad
+ (6) append the H result from step (4) to the B byte string
+ resulting from step (5)
+ (7) apply H to the stream generated in step (6) and output
+ the result
+
+ For illustration purposes, sample code based on MD5 is provided as an
+ appendix.
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 3]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+3. Keys
+
+ The key for HMAC can be of any length (keys longer than B bytes are
+ first hashed using H). However, less than L bytes is strongly
+ discouraged as it would decrease the security strength of the
+ function. Keys longer than L bytes are acceptable but the extra
+ length would not significantly increase the function strength. (A
+ longer key may be advisable if the randomness of the key is
+ considered weak.)
+
+ Keys need to be chosen at random (or using a cryptographically strong
+ pseudo-random generator seeded with a random seed), and periodically
+ refreshed. (Current attacks do not indicate a specific recommended
+ frequency for key changes as these attacks are practically
+ infeasible. However, periodic key refreshment is a fundamental
+ security practice that helps against potential weaknesses of the
+ function and keys, and limits the damage of an exposed key.)
+
+4. Implementation Note
+
+ HMAC is defined in such a way that the underlying hash function H can
+ be used with no modification to its code. In particular, it uses the
+ function H with the pre-defined initial value IV (a fixed value
+ specified by each iterative hash function to initialize its
+ compression function). However, if desired, a performance
+ improvement can be achieved at the cost of (possibly) modifying the
+ code of H to support variable IVs.
+
+ The idea is that the intermediate results of the compression function
+ on the B-byte blocks (K XOR ipad) and (K XOR opad) can be precomputed
+ only once at the time of generation of the key K, or before its first
+ use. These intermediate results are stored and then used to
+ initialize the IV of H each time that a message needs to be
+ authenticated. This method saves, for each authenticated message,
+ the application of the compression function of H on two B-byte blocks
+ (i.e., on (K XOR ipad) and (K XOR opad)). Such a savings may be
+ significant when authenticating short streams of data. We stress
+ that the stored intermediate values need to be treated and protected
+ the same as secret keys.
+
+ Choosing to implement HMAC in the above way is a decision of the
+ local implementation and has no effect on inter-operability.
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 4]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+5. Truncated output
+
+ A well-known practice with message authentication codes is to
+ truncate the output of the MAC and output only part of the bits
+ (e.g., [MM, ANSI]). Preneel and van Oorschot [PV] show some
+ analytical advantages of truncating the output of hash-based MAC
+ functions. The results in this area are not absolute as for the
+ overall security advantages of truncation. It has advantages (less
+ information on the hash result available to an attacker) and
+ disadvantages (less bits to predict for the attacker). Applications
+ of HMAC can choose to truncate the output of HMAC by outputting the t
+ leftmost bits of the HMAC computation for some parameter t (namely,
+ the computation is carried in the normal way as defined in section 2
+ above but the end result is truncated to t bits). We recommend that
+ the output length t be not less than half the length of the hash
+ output (to match the birthday attack bound) and not less than 80 bits
+ (a suitable lower bound on the number of bits that need to be
+ predicted by an attacker). We propose denoting a realization of HMAC
+ that uses a hash function H with t bits of output as HMAC-H-t. For
+ example, HMAC-SHA1-80 denotes HMAC computed using the SHA-1 function
+ and with the output truncated to 80 bits. (If the parameter t is not
+ specified, e.g. HMAC-MD5, then it is assumed that all the bits of the
+ hash are output.)
+
+6. Security
+
+ The security of the message authentication mechanism presented here
+ depends on cryptographic properties of the hash function H: the
+ resistance to collision finding (limited to the case where the
+ initial value is secret and random, and where the output of the
+ function is not explicitly available to the attacker), and the
+ message authentication property of the compression function of H when
+ applied to single blocks (in HMAC these blocks are partially unknown
+ to an attacker as they contain the result of the inner H computation
+ and, in particular, cannot be fully chosen by the attacker).
+
+ These properties, and actually stronger ones, are commonly assumed
+ for hash functions of the kind used with HMAC. In particular, a hash
+ function for which the above properties do not hold would become
+ unsuitable for most (probably, all) cryptographic applications,
+ including alternative message authentication schemes based on such
+ functions. (For a complete analysis and rationale of the HMAC
+ function the reader is referred to [BCK1].)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 5]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ Given the limited confidence gained so far as for the cryptographic
+ strength of candidate hash functions, it is important to observe the
+ following two properties of the HMAC construction and its secure use
+ for message authentication:
+
+ 1. The construction is independent of the details of the particular
+ hash function H in use and then the latter can be replaced by any
+ other secure (iterative) cryptographic hash function.
+
+ 2. Message authentication, as opposed to encryption, has a
+ "transient" effect. A published breaking of a message authentication
+ scheme would lead to the replacement of that scheme, but would have
+ no adversarial effect on information authenticated in the past. This
+ is in sharp contrast with encryption, where information encrypted
+ today may suffer from exposure in the future if, and when, the
+ encryption algorithm is broken.
+
+ The strongest attack known against HMAC is based on the frequency of
+ collisions for the hash function H ("birthday attack") [PV,BCK2], and
+ is totally impractical for minimally reasonable hash functions.
+
+ As an example, if we consider a hash function like MD5 where the
+ output length equals L=16 bytes (<a href="/cgi-bin/rfc/view?128">128</a> bits) the attacker needs to
+ acquire the correct message authentication tags computed (with the
+ _same_ secret key K!) on about 2**64 known plaintexts. This would
+ require the processing of at least 2**64 blocks under H, an
+ impossible task in any realistic scenario (for a block length of 64
+ bytes this would take <a href="/cgi-bin/rfc/view?250">250</a>,000 years in a continuous 1Gbps link, and
+ without changing the secret key K during all this time). This attack
+ could become realistic only if serious flaws in the collision
+ behavior of the function H are discovered (e.g. collisions found
+ after 2**30 messages). Such a discovery would determine the immediate
+ replacement of the function H (the effects of such failure would be
+ far more severe for the traditional uses of H in the context of
+ digital signatures, public key certificates, etc.).
+
+ Note: this attack needs to be strongly contrasted with regular
+ collision attacks on cryptographic hash functions where no secret key
+ is involved and where 2**64 off-line parallelizable (!) operations
+ suffice to find collisions. The latter attack is approaching
+ feasibility [VW] while the birthday attack on HMAC is totally
+ impractical. (In the above examples, if one uses a hash function
+ with, say, <a href="/cgi-bin/rfc/view?160">160</a> bit of output then 2**64 should be replaced by 2**80.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 6]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ A correct implementation of the above construction, the choice of
+ random (or cryptographically pseudorandom) keys, a secure key
+ exchange mechanism, frequent key refreshments, and good secrecy
+ protection of keys are all essential ingredients for the security of
+ the integrity verification mechanism provided by HMAC.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 7]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+Appendix -- Sample Code
+
+ For the sake of illustration we provide the following sample code for
+ the implementation of HMAC-MD5 as well as some corresponding test
+ vectors (the code is based on MD5 code as described in [MD5]).
+
+/*
+** Function: hmac_md5
+*/
+
+void
+hmac_md5(text, text_len, key, key_len, digest)
+unsigned char* text; /* pointer to data stream */
+int text_len; /* length of data stream */
+unsigned char* key; /* pointer to authentication key */
+int key_len; /* length of authentication key */
+caddr_t digest; /* caller digest to be filled in */
+
+{
+ MD5_CTX context;
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len &gt; 64) {
+
+ MD5_CTX tctx;
+
+ MD5Init(&amp;tctx);
+ MD5Update(&amp;tctx, key, key_len);
+ MD5Final(tk, &amp;tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+
+
+
+Krawczyk, et. al. Informational [Page 8]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ bzero( k_ipad, sizeof k_ipad);
+ bzero( k_opad, sizeof k_opad);
+ bcopy( key, k_ipad, key_len);
+ bcopy( key, k_opad, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i&lt;64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+ MD5Init(&amp;context); /* init context for 1st
+ * pass */
+ MD5Update(&amp;context, k_ipad, 64) /* start with inner pad */
+ MD5Update(&amp;context, text, text_len); /* then text of datagram */
+ MD5Final(digest, &amp;context); /* finish up 1st pass */
+ /*
+ * perform outer MD5
+ */
+ MD5Init(&amp;context); /* init context for 2nd
+ * pass */
+ MD5Update(&amp;context, k_opad, 64); /* start with outer pad */
+ MD5Update(&amp;context, digest, 16); /* then results of 1st
+ * hash */
+ MD5Final(digest, &amp;context); /* finish up 2nd pass */
+}
+
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ key_len = 16 bytes
+ data = "Hi There"
+ data_len = 8 bytes
+ digest = 0x<a href="/cgi-bin/rfc/view?9294727">9294727</a>a<a href="/cgi-bin/rfc/view?3638">3638</a>bb1c13f48ef<a href="/cgi-bin/rfc/view?8158">8158</a>bfc9d
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0x<a href="/cgi-bin/rfc/view?750">750</a>c<a href="/cgi-bin/rfc/view?783">783</a>e6ab0b<a href="/cgi-bin/rfc/view?503">503</a>eaa86e<a href="/cgi-bin/rfc/view?310">310</a>a5db<a href="/cgi-bin/rfc/view?738">738</a>
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+
+
+Krawczyk, et. al. Informational [Page 9]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be<a href="/cgi-bin/rfc/view?34521">34521</a>d<a href="/cgi-bin/rfc/view?144">144</a>c88dbb8c<a href="/cgi-bin/rfc/view?733">733</a>f0e8b3f6
+
+Acknowledgments
+
+ Pau-Chen Cheng, Jeff Kraemer, and Michael Oehler, have provided
+ useful comments on early drafts, and ran the first interoperability
+ tests of this specification. Jeff and Pau-Chen kindly provided the
+ sample code and test vectors that appear in the appendix. Burt
+ Kaliski, Bart Preneel, Matt Robshaw, Adi Shamir, and Paul van
+ Oorschot have provided useful comments and suggestions during the
+ investigation of the HMAC construction.
+
+References
+
+ [ANSI] ANSI X9.9, "American National Standard for Financial
+ Institution Message Authentication (Wholesale)," American
+ Bankers Association, <a href="/cgi-bin/rfc/view?1981">1981</a>. Revised <a href="/cgi-bin/rfc/view?1986">1986</a>.
+
+ [Atk] Atkinson, R., "IP Authentication Header", RFC <a href="/cgi-bin/rfc/view?1826">1826</a>, August
+ <a href="/cgi-bin/rfc/view?1995">1995</a>.
+
+ [BCK1] M. Bellare, R. Canetti, and H. Krawczyk,
+ "Keyed Hash Functions and Message Authentication",
+ Proceedings of Crypto'96, LNCS <a href="/cgi-bin/rfc/view?1109">1109</a>, pp. 1-15.
+ (http://www.research.ibm.com/security/keyed-md5.html)
+
+ [BCK2] M. Bellare, R. Canetti, and H. Krawczyk,
+ "Pseudorandom Functions Revisited: The Cascade Construction",
+ Proceedings of FOCS'96.
+
+ [Dobb] H. Dobbertin, "The Status of MD5 After a Recent Attack",
+ RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer <a href="/cgi-bin/rfc/view?1996">1996</a>.
+ http://www.rsa.com/rsalabs/pubs/cryptobytes.html
+
+ [PV] B. Preneel and P. van Oorschot, "Building fast MACs from hash
+ functions", Advances in Cryptology -- CRYPTO'95 Proceedings,
+ Lecture Notes in Computer Science, Springer-Verlag Vol.<a href="/cgi-bin/rfc/view?963">963</a>,
+ <a href="/cgi-bin/rfc/view?1995">1995</a>, pp. 1-14.
+
+ [MD5] Rivest, R., "The MD5 Message-Digest Algorithm",
+ RFC <a href="/cgi-bin/rfc/view?1321">1321</a>, April <a href="/cgi-bin/rfc/view?1992">1992</a>.
+
+
+
+Krawczyk, et. al. Informational [Page 10]
+
+RFC <a href="/cgi-bin/rfc/view?2104">2104</a> HMAC February <a href="/cgi-bin/rfc/view?1997">1997</a>
+
+
+ [MM] Meyer, S. and Matyas, S.M., Cryptography, New York Wiley,
+ <a href="/cgi-bin/rfc/view?1982">1982</a>.
+
+ [RIPEMD] H. Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-<a href="/cgi-bin/rfc/view?160">160</a>: A
+ strengthened version of RIPEMD", Fast Software Encryption,
+ LNCS Vol <a href="/cgi-bin/rfc/view?1039">1039</a>, pp. 71-82.
+ ftp://ftp.esat.kuleuven.ac.be/pub/COSIC/bosselae/ripemd/.
+
+ [SHA] NIST, FIPS PUB <a href="/cgi-bin/rfc/view?180">180</a>-1: Secure Hash Standard, April <a href="/cgi-bin/rfc/view?1995">1995</a>.
+
+ [Tsu] G. Tsudik, "Message authentication with one-way hash
+ functions", In Proceedings of Infocom'92, May <a href="/cgi-bin/rfc/view?1992">1992</a>.
+ (Also in "Access Control and Policy Enforcement in
+ Internetworks", Ph.D. Dissertation, Computer Science
+ Department, University of Southern California, April <a href="/cgi-bin/rfc/view?1991">1991</a>.)
+
+ [VW] P. van Oorschot and M. Wiener, "Parallel Collision
+ Search with Applications to Hash Functions and Discrete
+ Logarithms", Proceedings of the 2nd ACM Conf. Computer and
+ Communications Security, Fairfax, VA, November <a href="/cgi-bin/rfc/view?1994">1994</a>.
+
+Authors' Addresses
+
+ Hugo Krawczyk
+ IBM T.J. Watson Research Center
+ P.O.Box <a href="/cgi-bin/rfc/view?704">704</a>
+ Yorktown Heights, NY <a href="/cgi-bin/rfc/view?10598">10598</a>
+
+ EMail: hugo@watson.ibm.com
+
+ Mihir Bellare
+ Dept of Computer Science and Engineering
+ Mail Code 0<a href="/cgi-bin/rfc/view?114">114</a>
+ University of California at San Diego
+ <a href="/cgi-bin/rfc/view?9500">9500</a> Gilman Drive
+ La Jolla, CA <a href="/cgi-bin/rfc/view?92093">92093</a>
+
+ EMail: mihir@cs.ucsd.edu
+
+ Ran Canetti
+ IBM T.J. Watson Research Center
+ P.O.Box <a href="/cgi-bin/rfc/view?704">704</a>
+ Yorktown Heights, NY <a href="/cgi-bin/rfc/view?10598">10598</a>
+
+ EMail: canetti@watson.ibm.com
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 11]
+
+</pre>
diff --git a/info/rfc2104.txt b/info/rfc2104.txt
new file mode 100644
index 0000000..0291fe4
--- /dev/null
+++ b/info/rfc2104.txt
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+
+Network Working Group H. Krawczyk
+Request for Comments: 2104 IBM
+Category: Informational M. Bellare
+ UCSD
+ R. Canetti
+ IBM
+ February 1997
+
+
+ HMAC: Keyed-Hashing for Message Authentication
+
+Status of This Memo
+
+ This memo provides information for the Internet community. This memo
+ does not specify an Internet standard of any kind. Distribution of
+ this memo is unlimited.
+
+Abstract
+
+ This document describes HMAC, a mechanism for message authentication
+ using cryptographic hash functions. HMAC can be used with any
+ iterative cryptographic hash function, e.g., MD5, SHA-1, in
+ combination with a secret shared key. The cryptographic strength of
+ HMAC depends on the properties of the underlying hash function.
+
+1. Introduction
+
+ Providing a way to check the integrity of information transmitted
+ over or stored in an unreliable medium is a prime necessity in the
+ world of open computing and communications. Mechanisms that provide
+ such integrity check based on a secret key are usually called
+ "message authentication codes" (MAC). Typically, message
+ authentication codes are used between two parties that share a secret
+ key in order to validate information transmitted between these
+ parties. In this document we present such a MAC mechanism based on
+ cryptographic hash functions. This mechanism, called HMAC, is based
+ on work by the authors [BCK1] where the construction is presented and
+ cryptographically analyzed. We refer to that work for the details on
+ the rationale and security analysis of HMAC, and its comparison to
+ other keyed-hash methods.
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 1]
+
+RFC 2104 HMAC February 1997
+
+
+ HMAC can be used in combination with any iterated cryptographic hash
+ function. MD5 and SHA-1 are examples of such hash functions. HMAC
+ also uses a secret key for calculation and verification of the
+ message authentication values. The main goals behind this
+ construction are
+
+ * To use, without modifications, available hash functions.
+ In particular, hash functions that perform well in software,
+ and for which code is freely and widely available.
+
+ * To preserve the original performance of the hash function without
+ incurring a significant degradation.
+
+ * To use and handle keys in a simple way.
+
+ * To have a well understood cryptographic analysis of the strength of
+ the authentication mechanism based on reasonable assumptions on the
+ underlying hash function.
+
+ * To allow for easy replaceability of the underlying hash function in
+ case that faster or more secure hash functions are found or
+ required.
+
+ This document specifies HMAC using a generic cryptographic hash
+ function (denoted by H). Specific instantiations of HMAC need to
+ define a particular hash function. Current candidates for such hash
+ functions include SHA-1 [SHA], MD5 [MD5], RIPEMD-128/160 [RIPEMD].
+ These different realizations of HMAC will be denoted by HMAC-SHA1,
+ HMAC-MD5, HMAC-RIPEMD, etc.
+
+ Note: To the date of writing of this document MD5 and SHA-1 are the
+ most widely used cryptographic hash functions. MD5 has been recently
+ shown to be vulnerable to collision search attacks [Dobb]. This
+ attack and other currently known weaknesses of MD5 do not compromise
+ the use of MD5 within HMAC as specified in this document (see
+ [Dobb]); however, SHA-1 appears to be a cryptographically stronger
+ function. To this date, MD5 can be considered for use in HMAC for
+ applications where the superior performance of MD5 is critical. In
+ any case, implementers and users need to be aware of possible
+ cryptanalytic developments regarding any of these cryptographic hash
+ functions, and the eventual need to replace the underlying hash
+ function. (See section 6 for more information on the security of
+ HMAC.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 2]
+
+RFC 2104 HMAC February 1997
+
+
+2. Definition of HMAC
+
+ The definition of HMAC requires a cryptographic hash function, which
+ we denote by H, and a secret key K. We assume H to be a cryptographic
+ hash function where data is hashed by iterating a basic compression
+ function on blocks of data. We denote by B the byte-length of such
+ blocks (B=64 for all the above mentioned examples of hash functions),
+ and by L the byte-length of hash outputs (L=16 for MD5, L=20 for
+ SHA-1). The authentication key K can be of any length up to B, the
+ block length of the hash function. Applications that use keys longer
+ than B bytes will first hash the key using H and then use the
+ resultant L byte string as the actual key to HMAC. In any case the
+ minimal recommended length for K is L bytes (as the hash output
+ length). See section 3 for more information on keys.
+
+ We define two fixed and different strings ipad and opad as follows
+ (the 'i' and 'o' are mnemonics for inner and outer):
+
+ ipad = the byte 0x36 repeated B times
+ opad = the byte 0x5C repeated B times.
+
+ To compute HMAC over the data `text' we perform
+
+ H(K XOR opad, H(K XOR ipad, text))
+
+ Namely,
+
+ (1) append zeros to the end of K to create a B byte string
+ (e.g., if K is of length 20 bytes and B=64, then K will be
+ appended with 44 zero bytes 0x00)
+ (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+ (1) with ipad
+ (3) append the stream of data 'text' to the B byte string resulting
+ from step (2)
+ (4) apply H to the stream generated in step (3)
+ (5) XOR (bitwise exclusive-OR) the B byte string computed in
+ step (1) with opad
+ (6) append the H result from step (4) to the B byte string
+ resulting from step (5)
+ (7) apply H to the stream generated in step (6) and output
+ the result
+
+ For illustration purposes, sample code based on MD5 is provided as an
+ appendix.
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 3]
+
+RFC 2104 HMAC February 1997
+
+
+3. Keys
+
+ The key for HMAC can be of any length (keys longer than B bytes are
+ first hashed using H). However, less than L bytes is strongly
+ discouraged as it would decrease the security strength of the
+ function. Keys longer than L bytes are acceptable but the extra
+ length would not significantly increase the function strength. (A
+ longer key may be advisable if the randomness of the key is
+ considered weak.)
+
+ Keys need to be chosen at random (or using a cryptographically strong
+ pseudo-random generator seeded with a random seed), and periodically
+ refreshed. (Current attacks do not indicate a specific recommended
+ frequency for key changes as these attacks are practically
+ infeasible. However, periodic key refreshment is a fundamental
+ security practice that helps against potential weaknesses of the
+ function and keys, and limits the damage of an exposed key.)
+
+4. Implementation Note
+
+ HMAC is defined in such a way that the underlying hash function H can
+ be used with no modification to its code. In particular, it uses the
+ function H with the pre-defined initial value IV (a fixed value
+ specified by each iterative hash function to initialize its
+ compression function). However, if desired, a performance
+ improvement can be achieved at the cost of (possibly) modifying the
+ code of H to support variable IVs.
+
+ The idea is that the intermediate results of the compression function
+ on the B-byte blocks (K XOR ipad) and (K XOR opad) can be precomputed
+ only once at the time of generation of the key K, or before its first
+ use. These intermediate results are stored and then used to
+ initialize the IV of H each time that a message needs to be
+ authenticated. This method saves, for each authenticated message,
+ the application of the compression function of H on two B-byte blocks
+ (i.e., on (K XOR ipad) and (K XOR opad)). Such a savings may be
+ significant when authenticating short streams of data. We stress
+ that the stored intermediate values need to be treated and protected
+ the same as secret keys.
+
+ Choosing to implement HMAC in the above way is a decision of the
+ local implementation and has no effect on inter-operability.
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 4]
+
+RFC 2104 HMAC February 1997
+
+
+5. Truncated output
+
+ A well-known practice with message authentication codes is to
+ truncate the output of the MAC and output only part of the bits
+ (e.g., [MM, ANSI]). Preneel and van Oorschot [PV] show some
+ analytical advantages of truncating the output of hash-based MAC
+ functions. The results in this area are not absolute as for the
+ overall security advantages of truncation. It has advantages (less
+ information on the hash result available to an attacker) and
+ disadvantages (less bits to predict for the attacker). Applications
+ of HMAC can choose to truncate the output of HMAC by outputting the t
+ leftmost bits of the HMAC computation for some parameter t (namely,
+ the computation is carried in the normal way as defined in section 2
+ above but the end result is truncated to t bits). We recommend that
+ the output length t be not less than half the length of the hash
+ output (to match the birthday attack bound) and not less than 80 bits
+ (a suitable lower bound on the number of bits that need to be
+ predicted by an attacker). We propose denoting a realization of HMAC
+ that uses a hash function H with t bits of output as HMAC-H-t. For
+ example, HMAC-SHA1-80 denotes HMAC computed using the SHA-1 function
+ and with the output truncated to 80 bits. (If the parameter t is not
+ specified, e.g. HMAC-MD5, then it is assumed that all the bits of the
+ hash are output.)
+
+6. Security
+
+ The security of the message authentication mechanism presented here
+ depends on cryptographic properties of the hash function H: the
+ resistance to collision finding (limited to the case where the
+ initial value is secret and random, and where the output of the
+ function is not explicitly available to the attacker), and the
+ message authentication property of the compression function of H when
+ applied to single blocks (in HMAC these blocks are partially unknown
+ to an attacker as they contain the result of the inner H computation
+ and, in particular, cannot be fully chosen by the attacker).
+
+ These properties, and actually stronger ones, are commonly assumed
+ for hash functions of the kind used with HMAC. In particular, a hash
+ function for which the above properties do not hold would become
+ unsuitable for most (probably, all) cryptographic applications,
+ including alternative message authentication schemes based on such
+ functions. (For a complete analysis and rationale of the HMAC
+ function the reader is referred to [BCK1].)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 5]
+
+RFC 2104 HMAC February 1997
+
+
+ Given the limited confidence gained so far as for the cryptographic
+ strength of candidate hash functions, it is important to observe the
+ following two properties of the HMAC construction and its secure use
+ for message authentication:
+
+ 1. The construction is independent of the details of the particular
+ hash function H in use and then the latter can be replaced by any
+ other secure (iterative) cryptographic hash function.
+
+ 2. Message authentication, as opposed to encryption, has a
+ "transient" effect. A published breaking of a message authentication
+ scheme would lead to the replacement of that scheme, but would have
+ no adversarial effect on information authenticated in the past. This
+ is in sharp contrast with encryption, where information encrypted
+ today may suffer from exposure in the future if, and when, the
+ encryption algorithm is broken.
+
+ The strongest attack known against HMAC is based on the frequency of
+ collisions for the hash function H ("birthday attack") [PV,BCK2], and
+ is totally impractical for minimally reasonable hash functions.
+
+ As an example, if we consider a hash function like MD5 where the
+ output length equals L=16 bytes (128 bits) the attacker needs to
+ acquire the correct message authentication tags computed (with the
+ _same_ secret key K!) on about 2**64 known plaintexts. This would
+ require the processing of at least 2**64 blocks under H, an
+ impossible task in any realistic scenario (for a block length of 64
+ bytes this would take 250,000 years in a continuous 1Gbps link, and
+ without changing the secret key K during all this time). This attack
+ could become realistic only if serious flaws in the collision
+ behavior of the function H are discovered (e.g. collisions found
+ after 2**30 messages). Such a discovery would determine the immediate
+ replacement of the function H (the effects of such failure would be
+ far more severe for the traditional uses of H in the context of
+ digital signatures, public key certificates, etc.).
+
+ Note: this attack needs to be strongly contrasted with regular
+ collision attacks on cryptographic hash functions where no secret key
+ is involved and where 2**64 off-line parallelizable (!) operations
+ suffice to find collisions. The latter attack is approaching
+ feasibility [VW] while the birthday attack on HMAC is totally
+ impractical. (In the above examples, if one uses a hash function
+ with, say, 160 bit of output then 2**64 should be replaced by 2**80.)
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 6]
+
+RFC 2104 HMAC February 1997
+
+
+ A correct implementation of the above construction, the choice of
+ random (or cryptographically pseudorandom) keys, a secure key
+ exchange mechanism, frequent key refreshments, and good secrecy
+ protection of keys are all essential ingredients for the security of
+ the integrity verification mechanism provided by HMAC.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 7]
+
+RFC 2104 HMAC February 1997
+
+
+Appendix -- Sample Code
+
+ For the sake of illustration we provide the following sample code for
+ the implementation of HMAC-MD5 as well as some corresponding test
+ vectors (the code is based on MD5 code as described in [MD5]).
+
+/*
+** Function: hmac_md5
+*/
+
+void
+hmac_md5(text, text_len, key, key_len, digest)
+unsigned char* text; /* pointer to data stream */
+int text_len; /* length of data stream */
+unsigned char* key; /* pointer to authentication key */
+int key_len; /* length of authentication key */
+caddr_t digest; /* caller digest to be filled in */
+
+{
+ MD5_CTX context;
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, key, key_len);
+ MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+
+
+
+Krawczyk, et. al. Informational [Page 8]
+
+RFC 2104 HMAC February 1997
+
+
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ bzero( k_ipad, sizeof k_ipad);
+ bzero( k_opad, sizeof k_opad);
+ bcopy( key, k_ipad, key_len);
+ bcopy( key, k_opad, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+ MD5Init(&context); /* init context for 1st
+ * pass */
+ MD5Update(&context, k_ipad, 64) /* start with inner pad */
+ MD5Update(&context, text, text_len); /* then text of datagram */
+ MD5Final(digest, &context); /* finish up 1st pass */
+ /*
+ * perform outer MD5
+ */
+ MD5Init(&context); /* init context for 2nd
+ * pass */
+ MD5Update(&context, k_opad, 64); /* start with outer pad */
+ MD5Update(&context, digest, 16); /* then results of 1st
+ * hash */
+ MD5Final(digest, &context); /* finish up 2nd pass */
+}
+
+Test Vectors (Trailing '\0' of a character string not included in test):
+
+ key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ key_len = 16 bytes
+ data = "Hi There"
+ data_len = 8 bytes
+ digest = 0x9294727a3638bb1c13f48ef8158bfc9d
+
+ key = "Jefe"
+ data = "what do ya want for nothing?"
+ data_len = 28 bytes
+ digest = 0x750c783e6ab0b503eaa86e310a5db738
+
+ key = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+
+
+Krawczyk, et. al. Informational [Page 9]
+
+RFC 2104 HMAC February 1997
+
+
+ key_len 16 bytes
+ data = 0xDDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD...
+ ..DDDDDDDDDDDDDDDDDDDD
+ data_len = 50 bytes
+ digest = 0x56be34521d144c88dbb8c733f0e8b3f6
+
+Acknowledgments
+
+ Pau-Chen Cheng, Jeff Kraemer, and Michael Oehler, have provided
+ useful comments on early drafts, and ran the first interoperability
+ tests of this specification. Jeff and Pau-Chen kindly provided the
+ sample code and test vectors that appear in the appendix. Burt
+ Kaliski, Bart Preneel, Matt Robshaw, Adi Shamir, and Paul van
+ Oorschot have provided useful comments and suggestions during the
+ investigation of the HMAC construction.
+
+References
+
+ [ANSI] ANSI X9.9, "American National Standard for Financial
+ Institution Message Authentication (Wholesale)," American
+ Bankers Association, 1981. Revised 1986.
+
+ [Atk] Atkinson, R., "IP Authentication Header", RFC 1826, August
+ 1995.
+
+ [BCK1] M. Bellare, R. Canetti, and H. Krawczyk,
+ "Keyed Hash Functions and Message Authentication",
+ Proceedings of Crypto'96, LNCS 1109, pp. 1-15.
+ (http://www.research.ibm.com/security/keyed-md5.html)
+
+ [BCK2] M. Bellare, R. Canetti, and H. Krawczyk,
+ "Pseudorandom Functions Revisited: The Cascade Construction",
+ Proceedings of FOCS'96.
+
+ [Dobb] H. Dobbertin, "The Status of MD5 After a Recent Attack",
+ RSA Labs' CryptoBytes, Vol. 2 No. 2, Summer 1996.
+ http://www.rsa.com/rsalabs/pubs/cryptobytes.html
+
+ [PV] B. Preneel and P. van Oorschot, "Building fast MACs from hash
+ functions", Advances in Cryptology -- CRYPTO'95 Proceedings,
+ Lecture Notes in Computer Science, Springer-Verlag Vol.963,
+ 1995, pp. 1-14.
+
+ [MD5] Rivest, R., "The MD5 Message-Digest Algorithm",
+ RFC 1321, April 1992.
+
+
+
+Krawczyk, et. al. Informational [Page 10]
+
+RFC 2104 HMAC February 1997
+
+
+ [MM] Meyer, S. and Matyas, S.M., Cryptography, New York Wiley,
+ 1982.
+
+ [RIPEMD] H. Dobbertin, A. Bosselaers, and B. Preneel, "RIPEMD-160: A
+ strengthened version of RIPEMD", Fast Software Encryption,
+ LNCS Vol 1039, pp. 71-82.
+ ftp://ftp.esat.kuleuven.ac.be/pub/COSIC/bosselae/ripemd/.
+
+ [SHA] NIST, FIPS PUB 180-1: Secure Hash Standard, April 1995.
+
+ [Tsu] G. Tsudik, "Message authentication with one-way hash
+ functions", In Proceedings of Infocom'92, May 1992.
+ (Also in "Access Control and Policy Enforcement in
+ Internetworks", Ph.D. Dissertation, Computer Science
+ Department, University of Southern California, April 1991.)
+
+ [VW] P. van Oorschot and M. Wiener, "Parallel Collision
+ Search with Applications to Hash Functions and Discrete
+ Logarithms", Proceedings of the 2nd ACM Conf. Computer and
+ Communications Security, Fairfax, VA, November 1994.
+
+Authors' Addresses
+
+ Hugo Krawczyk
+ IBM T.J. Watson Research Center
+ P.O.Box 704
+ Yorktown Heights, NY 10598
+
+ EMail: hugo@watson.ibm.com
+
+ Mihir Bellare
+ Dept of Computer Science and Engineering
+ Mail Code 0114
+ University of California at San Diego
+ 9500 Gilman Drive
+ La Jolla, CA 92093
+
+ EMail: mihir@cs.ucsd.edu
+
+ Ran Canetti
+ IBM T.J. Watson Research Center
+ P.O.Box 704
+ Yorktown Heights, NY 10598
+
+ EMail: canetti@watson.ibm.com
+
+
+
+
+
+
+Krawczyk, et. al. Informational [Page 11]
diff --git a/info/transport.txt b/info/transport.txt
new file mode 100644
index 0000000..ad10cf9
--- /dev/null
+++ b/info/transport.txt
@@ -0,0 +1,1178 @@
+Network Working Group T. Ylonen
+INTERNET-DRAFT T. Kivinen
+draft-ietf-secsh-transport-03.txt M. Saarinen
+Expires in six months SSH
+ 7 November 1997
+
+
+ SSH Transport Layer Protocol
+
+Status of This memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other documents
+at any time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as ``work in progress.''
+
+To learn the current status of any Internet-Draft, please check
+the ``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast),
+or ftp.isi.edu (US West Coast).
+
+Abstract
+
+SSH is a protocol for secure remote login and other secure network
+services over an insecure network.
+
+This document describes the SSH transport layer protocol which
+typically runs on top of TCP/IP. The protocol can be used as a basis
+for a number of secure network services. It provides strong
+encryption, server authentication, and integrity protection. It may
+also provide compression.
+
+Key exchange method, public key algorithm, symmetric encryption
+algorithm, message authentication algorithm, and hash algorithm are
+all negotiated.
+
+This document also describes the Diffie-Hellman key exchange method
+and the minimal set of algorithms that are needed to implement the
+SSH transport layer protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 1]
+
+INTERNET-DRAFT 7 November 1997
+
+Table of Contents
+
+1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+2. Conventions Used in This Document . . . . . . . . . . . . . . . 3
+3. Connection Setup . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 3.1. Use over TCP/IP . . . . . . . . . . . . . . . . . . . . . . 3
+ 3.2. Protocol Version Exchange . . . . . . . . . . . . . . . . . 3
+ 3.3. Compatibility with Old SSH Versions . . . . . . . . . . . . 4
+ 3.3.1. Old Client, New Server . . . . . . . . . . . . . . . . . 4
+ 3.3.2. New Client, Old Server . . . . . . . . . . . . . . . . . 4
+4. Binary Packet Protocol . . . . . . . . . . . . . . . . . . . . . 4
+ 4.1. Maximum Packet Length . . . . . . . . . . . . . . . . . . . 5
+ 4.2. Compression . . . . . . . . . . . . . . . . . . . . . . . . 5
+ 4.3. Encryption . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 4.4. Data Integrity . . . . . . . . . . . . . . . . . . . . . . . 7
+ 4.5. Key Exchange Methods . . . . . . . . . . . . . . . . . . . . 8
+ 4.6. Public Key Algorithms . . . . . . . . . . . . . . . . . . . 8
+5. Key Exchange . . . . . . . . . . . . . . . . . . . . . . . . . . 9
+ 5.1. Algorithm Negotiation . . . . . . . . . . . . . . . . . . . 10
+ 5.2. Output from Key Exchange . . . . . . . . . . . . . . . . . . 12
+ 5.3. Taking Keys into Use . . . . . . . . . . . . . . . . . . . . 13
+6. Diffie-Hellman Key Exchange . . . . . . . . . . . . . . . . . . 13
+ 6.1. diffie-hellman-group1-sha1 . . . . . . . . . . . . . . . . . 15
+7. Key Re-Exchange . . . . . . . . . . . . . . . . . . . . . . . . 15
+8. Service Request . . . . . . . . . . . . . . . . . . . . . . . . 16
+9. Additional Messages . . . . . . . . . . . . . . . . . . . . . . 16
+ 9.1. Disconnection Message . . . . . . . . . . . . . . . . . . . 17
+ 9.2. Ignored Data Message . . . . . . . . . . . . . . . . . . . . 17
+ 9.3. Debug Message . . . . . . . . . . . . . . . . . . . . . . . 17
+ 9.4. Reserved Messages . . . . . . . . . . . . . . . . . . . . . 18
+10. Summary of Message Numbers . . . . . . . . . . . . . . . . . . 18
+11. Security Considerations . . . . . . . . . . . . . . . . . . . . 18
+12. References . . . . . . . . . . . . . . . . . . . . . . . . . . 19
+13. Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . 20
+
+
+
+1. Introduction
+
+The SSH transport layer is a secure low level transport protocol. It
+provides strong encryption, cryptographic host authentication, and
+integrity protection.
+
+Authentication in this protocol level is host-based; this protocol does
+not perform user authentication. A higher level protocol for user
+authentication can be designed on top of this protocol.
+
+The protocol has been designed to be simple, flexible, to allow
+parameter negotiation, and to minimize the number of round-trips. Key
+exchange method, public key algorithm, symmetric encryption algorithm,
+message authentication algorithm, and hash algorithm are all negotiated.
+It is expected that in most environments, only 2 round-trips will be
+needed for full key exchange, server authentication, service request,
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 2]
+
+INTERNET-DRAFT 7 November 1997
+
+and acceptance notification of service request. The worst case is 3
+round-trips.
+
+2. Conventions Used in This Document
+
+The keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and
+"MAY" that appear in this document are to be interpreted as described in
+[RFC-2119].
+
+The used data types and terminology are specified in the architecture
+document [SSH-ARCH].
+
+The architecture document also discusses the algorithm naming
+conventions that MUST be used with the SSH protocols.
+3. Connection Setup
+
+SSH works over any 8-bit clean, binary-transparent transport. The
+underlying transport SHOULD protect against transmission errors as such
+errors cause the SSH connection to terminate.
+
+The client initiates the connection.
+
+3.1. Use over TCP/IP
+
+When used over TCP/IP, the server normally listens for connections on
+port 22. This port number has been registered with the IANA, and has
+been officially assigned for SSH.
+
+3.2. Protocol Version Exchange
+
+When the connection has been established, both sides MUST send an
+identification string of the form "SSH-protoversion-softwareversion
+comments", followed by carriage return and newline characters (ascii 13
+and 10, respectively). No null character is sent. The maximum length
+of the string is 255 characters, including the carriage return and
+newline.
+
+The part of the identification string preceding carriage return and
+newline is used in the Diffie-Hellman key exchange (Section ``Diffie-
+Hellman Key Exchange'').
+
+The server MAY send other lines of data before sending the version
+string. Each line SHOULD be terminated by a carriage return and
+newline. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
+in ISO-10646 UTF-8 [RFC-2044] (language is not specified). Clients MUST
+be able to process such lines; they MAY be silently ignored, or MAY be
+displayed to the client user; if they are displayed, control character
+filtering discussed in [SSH-ARCH] SHOULD be used. The primary use of
+this feature is to allow TCP-wrappers to display an error message before
+disconnecting.
+
+Version strings MUST consist of printable US-ASCII characters, not
+including whitespaces or a minus sign (-). The version string is
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 3]
+
+INTERNET-DRAFT 7 November 1997
+
+primarily used to trigger compatible extensions and to indicate the
+capabilities of an implementation. The comment string should contain
+additional information that might be useful in solving user problems.
+
+The protocol version described in this document is 2.0.
+
+Key exchange will begin immediately after sending this identifier. All
+packets following the identification string SHALL use the binary packet
+protocol, to be described below.
+
+3.3. Compatibility with Old SSH Versions
+
+During a transition period, it is important to be able to work
+compatibly with installed SSH clients and servers using an older version
+of the protocol. Information in this section is only relevant for
+implementations supporting compatibility with SSH versions 1.x.
+
+3.3.1. Old Client, New Server
+
+Server implementations MAY support a configurable "compatibility" flag
+that enables compatibility with old versions. When this flag is on, the
+server SHOULD not send any further data after its initialization string
+until it has received an identification string from the client. The
+server can then determine whether the client is using an old protocol,
+and can revert to the old protocol if desired.
+
+When compatibility with old clients is not needed, the server MAY send
+its initial key exchange data immediately after the identification
+string.
+
+3.3.2. New Client, Old Server
+
+Since the new client MAY immediately send additional data after its
+identification string (before receiving server's identification), the
+old protocol may already have been corrupted when the client learns that
+the server is old. When this happens, the client SHOULD close the
+connection to the server, and reconnect using the old protocol.
+
+4. Binary Packet Protocol
+
+Each packet is of the following format.
+
+ uint32 packet_length
+ byte padding_length
+ byte[n1] payload; n1 = packet_length - padding_length - 1
+ byte[n2] random padding; n2 = padding_length
+ byte[m] mac (message authentication code); m = mac_length
+
+ packet_length
+ The length of the packet (bytes), not including MAC or the
+ packet_length field itself.
+
+ padding_length
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 4]
+
+INTERNET-DRAFT 7 November 1997
+
+ Length of padding (bytes).
+
+ payload
+ The useful contents of the packet. If compression has been
+ negotiated, this field is compressed. Initially, compression MUST
+ be "none".
+
+ Padding
+ Arbitrary-length padding, such that the total length of
+ (packet_length || padding_length || payload || padding) is a
+ multiple of the cipher block size or 8, whichever is larger.
+ There MUST be at least four bytes of padding. The padding SHOULD
+ consist of random bytes. The maximum amount of padding is 255
+ bytes.
+
+ MAC
+ Message authentication code. If message authentication has been
+ negotiated, this field contains the MAC bytes. Initially, the MAC
+ algorithm MUST be "none".
+
+Note that length of the concatenation of packet length, padding length,
+payload, and padding MUST be a multiple of the cipher block size or 8,
+whichever is larger. This constraint MUST be enforced even when using
+stream ciphers. Note that the packet length field is also encrypted,
+and processing it requires special care when sending or receiving
+packets.
+
+The minimum size of a packet is 16 (or the cipher block size, whichever
+is larger) bytes (plus MAC); implementations SHOULD decrypt the length
+after receiving the first 8 (or cipher block size, whichever is larger)
+bytes of a packet.
+
+4.1. Maximum Packet Length
+
+All implementations MUST be able to process packets with uncompressed
+payload length of 32768 bytes or less and total packet size of 35000
+bytes or less (including length, padding length, payload, padding, and
+MAC). Implementations SHOULD support longer packets, where they might
+be needed e.g. if an implementation wants to send a very large number of
+certificates. Such packets MAY be sent if the version string indicates
+that the other party is able to process them. However, implementations
+SHOULD check that the packet length is reasonable for the implementation
+to avoid denial-of-service and/or buffer overflow attacks.
+
+4.2. Compression
+
+If compression has been negotiated, the payload field (and only it) will
+be compressed using the negotiated algorithm. The length field and MAC
+will be computed from the compressed payload.
+
+Compression MAY be stateful, depending on the method. Compression MUST
+be independent for each direction, and implementations MUST allow
+independently choosing the algorithm for each direction.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 5]
+
+INTERNET-DRAFT 7 November 1997
+
+The following compression methods are currently defined:
+
+ none REQUIRED no compression
+ zlib OPTIONAL GNU ZLIB (LZ77) compression
+
+The "zlib" compression is described in [RFC-1950] and in [RFC-1951].
+The compression context is initialized after each key exchange, and is
+passed from one packet to the next with only a partial flush being
+performed at the end of each packet. A partial flush means that all
+data will be output, but the next packet will continue using compression
+tables from the end of the previous packet.
+
+Additional methods may be defined as specified in [SSH-ARCH].
+
+4.3. Encryption
+
+An encryption algorithm and a key will be negotiated during the key
+exchange. When encryption is in effect, the packet length, padding
+length, payload and padding fields of each packet MUST be encrypted with
+the given algorithm.
+
+The encrypted data in all packets sent in one direction SHOULD be
+considered a single data stream. For example, initialization vectors
+SHOULD be passed from the end of one packet to the beginning of the next
+packet. All ciphers SHOULD use keys with an effective key length of 128
+bits or more.
+
+The ciphers in each direction MUST run independently of each other, and
+implementations MUST allow independently choosing the algorithm for each
+direction (if multiple algorithms are allowed by local policy).
+
+The following ciphers are currently defined:
+
+ 3des-cbc REQUIRED three-key 3DES in CBC mode
+ blowfish-cbc RECOMMENDED Blowfish in CBC mode
+ arcfour OPTIONAL the ARCFOUR stream cipher
+ idea-cbc OPTIONAL IDEA in CBC mode
+ cast128-cbc OPTIONAL CAST-128 in CBC mode
+ none OPTIONAL no encryption; NOT RECOMMENDED
+
+The "3des-cbc" cipher is three-key triple-DES (encrypt-decrypt-encrypt),
+where the first 8 bytes of the key are used for the first encryption,
+the next 8 bytes for the decryption, and the following 8 bytes for the
+final encryption. This requires 24 bytes of key data (of which 168 bits
+are actually used). To implement CBC mode, outer chaining MUST be used
+(i.e., there is only one initialization vector). This is a block cipher
+with 8 byte blocks. This algorithm is defined in [Schneier].
+
+The "blowfish-cbc" cipher is Blowfish in CBC mode, with 128 bit keys
+[Schneier]. This is a block cipher with 8 byte blocks.
+
+The "arcfour" is the Arcfour stream cipher with 128 bit keys. The
+Arcfour cipher is believed to be compatible with the RC4 cipher
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 6]
+
+INTERNET-DRAFT 7 November 1997
+
+[Schneier]. RC4 is a registered trademark of RSA Data Security Inc.
+
+The "idea-cbc" cipher is the IDEA cipher in CBC mode [Schneier]. IDEA
+is patented by Ascom AG.
+
+The "cast128-cbc" cipher is the CAST-128 cipher in CBC mode [RFC-2144].
+
+The "none" algorithm specifies that no encryption is to be done. Note
+that this method provides no confidentiality protection, and it is not
+recommended. Some functionality (e.g. password authentication) may be
+disabled for security reasons if this cipher is chosen.
+
+Additional methods may be defined as specified in [SSH-ARCH].
+
+4.4. Data Integrity
+
+Data integrity is protected by including with each packet a message
+authentication code (MAC) that is computed from a shared secret, packet
+sequence number, and the contents of the packet.
+
+The message authentication algorithm and key are negotiated during key
+exchange. Initially, no MAC will be in effect, and its length MUST be
+zero. After key exchange, the selected MAC will be computed before
+encryption from the concatenation of packet data:
+
+ mac = MAC(key, sequence_number || unencrypted_packet)
+
+where unencrypted_packet is the entire packet without MAC (the length
+fields, payload and padding), and sequence_number is an implicit packet
+sequence number represented as uint32. The sequence number is initial-
+ized to zero for the first packet, and is incremented after every packet
+(regardless of whether encryption or MAC is in use). It is never reset,
+even if keys/algorithms are renegotiated later. It wraps around to zero
+after every 2^32 packets. The packet sequence number itself is not
+included in the packet sent over the wire.
+
+The MAC algorithms for each direction MUST run independently, and
+implementations MUST allow choosing the algorithm independently for both
+directions.
+
+The MAC bytes resulting from the MAC algorithm MUST be transmitted
+without encryption as the last part of the packet. The number of MAC
+bytes depends on the algorithm chosen.
+
+The following MAC algorithms are currently defined:
+
+ hmac-sha1 REQUIRED HMAC-SHA1 (length = 20)
+ hmac-sha-96 RECOMMENDED first 96 bits of HMAC-SHA1 (length = 12)
+ hmac-md5 OPTIONAL HMAC-MD5 (length = 16)
+ hmac-md5-96 OPTIONAL first 96 bits of HMAC-MD5 (length = 12)
+ none OPTIONAL no MAC; NOT RECOMMENDED
+
+The "hmac-*" algorithms are described in [RFC-2104]. The "*-n" MACs use
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 7]
+
+INTERNET-DRAFT 7 November 1997
+
+only the first n bits of the resulting value.
+
+The hash algorithms are described in [Schneier].
+
+The "none" method is NOT RECOMMENDED. An active attacker may be able to
+modify transmitted data if this is used.
+
+Additional methods may be defined as specified in [SSH-ARCH].
+
+4.5. Key Exchange Methods
+
+The key exchange method specifies how one-time session keys are
+generated for encryption and for authentication, and how the server
+authentication is done.
+
+Only one REQUIRED key exchange method has been defined:
+
+ diffie-hellman-group1-sha1 REQUIRED
+
+This method is described later in this document.
+
+Additional methods may be defined as specified in [SSH-ARCH].
+
+4.6. Public Key Algorithms
+
+This protocol has been designed to be able to operate with almost any
+public key format, encoding, and algorithm (signature and/or
+encryption).
+
+There are several aspects that define a public key type:
+
+o Key format: how is the key encoded and how are certificates
+ represented. The key blobs in this protocol MAY contain certificates
+ in addition to keys.
+
+o Signature and/or encryption algorithms. Some key types may not
+ support both signing and encryption. Key usage may also be
+ restricted by policy statements in e.g. certificates. In this case,
+ different key types SHOULD be defined for the different policy
+ alternatives.
+
+o Encoding of signatures and/or encrypted data. This includes but is
+ not limited to padding, byte order, and data formats.
+
+The following public key and/or certificate formats are currently
+defined:
+
+ssh-dss REQUIRED sign Simple DSS
+x509v3 RECOMMENDED sign X.509 certificates
+spki OPTIONAL sign SPKI certificates
+pgp OPTIONAL sign OpenPGP certificates
+
+Additional key types may be defined as specified in [SSH-ARCH].
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 8]
+
+INTERNET-DRAFT 7 November 1997
+
+The key type MUST always be explicitly known (from algorithm negotiation
+or some other source). It is not normally included in the key blob.
+
+Certificates and public keys are encoded as:
+
+ uint32 the combined length of the format identifier and associated data
+ string certificate or public key format identifier
+ byte[n] key/certificate data
+
+The certificate part may have be a zero length string, but a public key
+is required. This is the public key that will be used for
+authentication; the certificate sequence contained in the certificate
+blob can be used to provide authorization.
+
+The "ssh-dss" key format has the following specific encoding:
+
+ uint32 length
+ string "ssh-dss"
+ mpint p
+ mpint q
+ mpint g
+ mpint y
+
+Here the "p", "q", "g", and "y" parameters form the signature key blob.
+
+Signing and verifying using this key format are done according to the
+Digital Signature Standard [FIPS-186] using the SHA-1 hash. A
+description can also be found in [Schneier].
+
+The resulting signature is encoded as:
+
+ uint32 length
+ string "ssh-dss"
+ mpint r
+ mpint s
+
+The "x509v3" method indicates that the certificates, the public key, and
+the resulting signature are in X.509v3 compatible DER-encoded format.
+The formats used in X.509v3 is described in [PKIX-Part1].
+
+The "spki" method indicates that the certificate blob contains a
+sequence of SPKI certificates. The format of SPKI certificates is
+described in [SPKI].
+
+The "pgp" method indicates the the certificates, the public key, and the
+signature are in OpenPGP compatible binary format. [PGP]
+
+5. Key Exchange
+
+Key exchange begins by each side sending lists of supported algorithms.
+Each side has a preferred algorithm in each category, and it is assumed
+that most implementations at any given time will use the same preferred
+algorithm. Each side MAY guess which algorithm the other side is using,
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 9]
+
+INTERNET-DRAFT 7 November 1997
+
+and MAY send an initial key exchange packet according to the algorithm
+if appropriate for the preferred method. If all algorithms were guessed
+right, the optimistically sent packet MUST be handled as the first key
+exchange packet. However, if the guess was wrong, and a packet was
+optimistically sent by one or both parties, such packets MUST be ignored
+(even if the error in the guess would not affect the contents of the
+initial packet(s)), and the appropriate side MUST send the correct
+initial packet.
+
+Server authentication in the key exchange MAY be implicit. After a key
+exchange with implicit server authentication, the client MUST wait for
+response to its service request message before sending any further data.
+
+5.1. Algorithm Negotiation
+
+Key exchange begins by each side sending the following packet:
+
+ byte SSH_MSG_KEXINIT
+ byte[16] cookie (random bytes)
+ string kex_algorithms
+ string server_host_key_algorithms
+ string encryption_algorithms_client_to_server
+ string encryption_algorithms_server_to_client
+ string mac_algorithms_client_to_server
+ string mac_algorithms_server_to_client
+ string compression_algorithms_client_to_server
+ string compression_algorithms_server_to_client
+ string languages_client_to_server
+ string languages_server_to_client
+ boolean first_kex_packet_follows
+ uint32 0 (reserved for future extension)
+
+Each of the algorithm strings MUST be a comma-separated list of
+algorithm names (see ``Algorithm Naming'' in [SSH-ARCH]). Each
+supported (allowed) algorithm MUST be listed, in order of preference.
+
+The first algorithm in each list MUST be the preferred (guessed)
+algorithm. Each string MUST contain at least one algorithm name.
+
+ cookie
+ The cookie MUST be a random value generated by the sender. Its
+ purpose is to make it impossible for either side to fully
+ determine the keys and the session identifier.
+
+ kex_algorithms
+ Key exchange algorithms were defined above. The first algorithm
+ MUST be the preferred (and guessed) algorithm. If both sides make
+ the same guess, that algorithm MUST used. Otherwise, the
+ following algorithm MUST be used to choose a key exchange method:
+ iterate over client's kex algorithms, one at a time. Choose the
+ first algorithm that satisfies the following conditions:
+
+ o the server also supports the algorithm,
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 10]
+
+INTERNET-DRAFT 7 November 1997
+
+ o if the algorithm requires an encryption-capable host key, there is
+ an encryption-capable algorithm on the server's
+ server_host_key_algorithms that is also supported by the client,
+ and
+
+ o if the algorithm requires a signature-capable host key, there is a
+ signature-capable algorithm on the server's
+ server_host_key_algorithms that is also supported by the client.
+
+ If no algorithm satisfying all these conditions can be found, the
+ connection fails, and both sides MUST disconnect.
+
+ server_host_key_algorithms
+ List of the algorithms supported for the server host key. The
+ server lists the algorithms for which it has host keys; the client
+ lists the algorithms that it is willing to accept. (There MAY be
+ multiple host keys for a host, possibly with different
+ algorithms.)
+
+ Some host keys may not support both signatures and encryption
+ (this can be determined from the algorithm), and thus not all host
+ keys are valid for all key exchange methods.
+
+ Algorithm selection depends on whether the chosen key exchange
+ algorithm requires a signature- or encryption capable host key.
+ It MUST be possible to determine this from the public key
+ algorithm name. The first algorithm on the client's list that
+ satisfies the requirements and is also supported by the server
+ MUST be chosen. If there is no such algorithm, both sides MUST
+ disconnect.
+
+ encryption_algorithms
+ Lists the acceptable symmetric encryption algorithms in order of
+ preference. The chosen encryption algorithm to each direction
+ MUST be the first algorithm on the client's list that is also on
+ the server's list. If there is no such algorithm, both sides MUST
+ disconnect.
+
+ Note that "none" must be explicitly listed if it is to be
+ acceptable. The defined algorithm names are listed in Section
+ ``Encryption''.
+
+ mac_algorithms
+ Lists the acceptable MAC algorithms in order of preference. The
+ chosen MAC algorithm MUST be the first algorithm on the client's
+ list that is also on the server's list. If there is no such
+ algorithm, both sides MUST disconnect.
+
+ Note that "none" must be explicitly listed if it is to be
+ acceptable. The MAC algorithm names are listed in Section ``Data
+ Integrity''.
+
+ compression_algorithms
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 11]
+
+INTERNET-DRAFT 7 November 1997
+
+ Lists the acceptable compression algorithms in order of
+ preference. The chosen compression algorithm MUST be the first
+ algorithm on the client's list that is also on the server's list.
+ If there is no such algorithm, both sides MUST disconnect.
+
+ Note that "none" must be explicitly listed if it is to be
+ acceptable. The compression algorithm names are listed in Section
+ ``Compression''.
+
+ languages
+ This is a comma-separated list of language tags in order of
+ preference [RFC-1766]. Both parties MAY ignore this list. If
+ there are no language preferences, this list SHOULD be empty.
+
+ first_kex_packet_follows
+ Indicates whether a guessed key exchange packet follows. If a
+ guessed packet will be sent, this MUST be true. If no guessed
+ packet will be sent, this MUST be false.
+
+ After receiving the SSH_MSG_KEXINIT packet from the other side,
+ each party will know whether their guess was right. If the other
+ party's guess was wrong, and this field was true, the next packet
+ MUST be silently ignored, and both sides MUST then act as
+ determined by the negotiated key exchange method. If the guess
+ was right, key exchange MUST continue using the guessed packet.
+
+After the KEXINIT packet exchange, the key exchange algorithm is run.
+It may involve several packet exchanges, as specified by the key
+exchange method.
+
+5.2. Output from Key Exchange
+
+The key exchange produces two values: a shared secret K, and an exchange
+hash H. Encryption and authentication keys are derived from these. The
+exchange hash H from the first key exchange is additionally used as the
+session identifier, which is a unique identifier for this connection.
+It is used by authentication methods as a part of the data that is
+signed as a proof of possession of a private key. Once computed, the
+session identifier is not changed, even if keys are later re-exchanged.
+
+Each key exchange method specifies a hash function that is used in the
+key exchange. The same hash algorithm MUST be used in key derivation.
+Here, we'll call it HASH.
+
+Encryption keys MUST be computed as HASH of a known value and K as
+follows:
+
+o Initial IV client to server: HASH(K || "A" || session_id) ("A" means
+ the single character A, ascii 65).
+
+o Initial IV server to client: HASH(K || "B" || session_id)
+
+o Encryption key client to server: HASH(K || "C" || session_id)
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 12]
+
+INTERNET-DRAFT 7 November 1997
+
+o Encryption key server to client: HASH(K || "D" || session_id)
+
+o Integrity key client to server: HASH(K || "E" || session_id)
+
+o Integrity key server to client: HASH(K || "F" || session_id)
+
+Key data MUST be taken from the beginning of the hash output. 128 bits
+(16 bytes) SHOULD be used for algorithms with variable-length keys. For
+other algorithms, as many bytes as are needed are taken from the
+beginning of the hash value. If the key length in longer than the output
+of the HASH, the key is extended by computing HASH of the concatenation
+of K and the entire key so far, and appending the resulting bytes (as
+many as HASH generates) to the key. This process is repeated until
+enough key material is available; the key is taken from the beginning of
+this value. In other words,
+
+ K1 = HASH(K || X || session_id) (X is e.g. "A")
+ K2 = HASH(K || K1)
+ K3 = HASH(K || K1 || K2)
+ ...
+ key = K1 || K2 || K3 || ...
+
+5.3. Taking Keys into Use
+
+Key exchange ends by each side sending an SSH_MSG_NEWKEYS message. This
+message is sent with the old keys and algorithms. All messages sent
+after this message MUST use the new keys and algorithms.
+
+When this message is received, the new keys and algorithms MUST be taken
+into use for receiving.
+
+This message is the only valid message after key exchange, in addition
+to SSH_MSG_DEBUG, SSH_MSG_DISCONNECT and SSH_MSG_IGNORE messages. The
+purpose of this message is to ensure that a party is able to respond
+with a disconnect message that the other party can understand if
+something goes wrong with the key exchange. Implementations MUST NOT
+accept any other messages after key exchange before receiving
+SSH_MSG_NEWKEYS.
+
+ byte SSH_MSG_NEWKEYS
+
+6. Diffie-Hellman Key Exchange
+
+The Diffie-Hellman key exchange provides a shared secret that can not be
+determined by either party alone. The key exchange is combined with a
+signature with the host key to provide host authentication.
+
+In the following description (C is the client, S is the server; p is a
+large safe prime, g is a generator for a subgroup of GF(p), and q is the
+order of the subgroup; V_S is S's version string; V_C is C's version
+string; K_S is S's public host key; I_C is C's KEXINIT message and I_S
+S's KEXINIT message which have been exchanged before this part begins):
+1. C generates a random number x (1 < x < q) and computes e = g^x mod p.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 13]
+
+INTERNET-DRAFT 7 November 1997
+
+ C sends "e" to S.
+
+2. S generates a random number y (0 < y < q) and computes f = g^y mod p.
+ S receives "e". It computes K = e^y mod p, H = hash(V_C || V_S ||
+ I_C || I_S || K_S || e || f || K), and signature s on H with its
+ private host key. S sends "K_S || f || s" to C. The signing
+ operation may involve a second hashing operation.
+
+3. C verifies that K_S really is the host key for S (e.g. using
+ certificates or a local database). C is also allowed to accept the
+ key without verification; however, doing so will render the protocol
+ insecure against active attacks (but may be desirable for practical
+ reasons in the short term in many environments). C then computes K =
+ f^x mod p, H = hash(V_C || V_S || I_C || I_S || K_S || e || f || K),
+ and verifies the signature s on H.
+
+ Either side MUST NOT send or accept e or f values that are not in the
+ range [1, p-1]. If this condition is violated, the key exchange
+ fails.
+
+This is implemented with the following messages. The hash algorithm for
+computing the exchange hash is defined by the method name, and is called
+HASH. The public key algorithm for signing is negotiated with the
+KEXINIT messages.
+
+First, the client sends:
+
+ byte SSH_MSG_KEXDH_INIT
+ mpint e
+
+The server responds with:
+
+ byte SSH_MSG_KEXDH_REPLY
+ string server public host key and certificates (K_S)
+ mpint f
+ string signature of H
+
+The hash H is computed as the HASH hash of the concatenation of the
+following:
+
+ string V_C, the client's version string (CR and NL excluded)
+ string V_S, the server's version string (CR and NL excluded)
+ string I_C, the payload of the client's SSH_MSG_KEXINIT
+ string I_S, the payload of the server's SSH_MSG_KEXINIT
+ string K_S, the host key
+ mpint e, exchange value sent by the client
+ mpint f, exchange value sent by the server
+ mpint K, the shared secret
+
+This value is called the exchange hash, and it is used to authenticate
+the key exchange.
+
+The signature algorithm MUST be applied over H, not the original data.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 14]
+
+INTERNET-DRAFT 7 November 1997
+
+Most signature algorithms include hashing and additional padding. For
+example, a "ssh-dss" specifies SHA-1 hashing; in that case, the data is
+first hashed with HASH to compute H, and H is then hashed with SHA-1 as
+part of the signing operation.
+
+6.1. diffie-hellman-group1-sha1
+
+The "diffie-hellman-group1-sha1" method specifies Diffie-Hellman key
+exchange with SHA-1 as HASH, and the following group:
+
+The prime p is equal to 2^1024 - 2^960 - 1 + 2^64 * floor( 2^894 Pi +
+129093 ). Its hexadecimal value is
+
+ FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
+ 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
+ EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
+ E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
+ EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381
+ FFFFFFFF FFFFFFFF.
+
+In decimal, this value is
+
+ 179769313486231590770839156793787453197860296048756011706444
+ 423684197180216158519368947833795864925541502180565485980503
+ 646440548199239100050792877003355816639229553136239076508735
+ 759914822574862575007425302077447712589550957937778424442426
+ 617334727629299387668709205606050270810842907692932019128194
+ 467627007.
+
+The generator used with this prime is g = 2. The group order q is (p -
+1) / 2.
+
+This group was taken from the ISAKMP/Oakley specification, and was
+originally generated by Richard Schroeppel at the University of Arizona.
+Properties of this prime are described in [Orm96].
+
+7. Key Re-Exchange
+
+Key re-exchange is started by sending a SSH_MSG_KEXINIT packet when not
+already doing a key exchange (as described in Section ``Algorithm
+Negotiation''). When this message is received, a party MUST respond
+with its own SSH_MSG_KEXINIT message except when the received
+SSH_MSG_KEXINIT already was a reply. Either party MAY initiate the re-
+exchange, but roles MUST NOT be changed (i.e., the server remains the
+server, and the client remains the client).
+
+Key re-exchange is performed using whatever encryption was in effect
+when the exchange was started. Encryption, compression, and MAC methods
+are not changed before a new SSH_MSG_NEWKEYS is sent after the key
+exchange (as in the initial key exchange). Re-exchange is processed
+identically to the initial key exchange, except for the session
+identifier that will remain unchanged. It is permissible to change some
+or all of the algorithms during the re-exchange. Host keys can also
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 15]
+
+INTERNET-DRAFT 7 November 1997
+
+change. All keys and initialization vectors are recomputed after the
+exchange. Compression and encryption contexts are reset.
+
+It is recommended that the keys are changed after each gigabyte of
+transmitted data or after each hour of connection time, whichever comes
+sooner. However, since the re-exchange is a public key operation, it
+requires a fair amount of processing power and should not be performed
+too often.
+
+More application data may be sent after the SSH_MSG_NEWKEYS packet has
+been sent; key exchange does not affect the protocols that lie above the
+SSH transport layer.
+
+8. Service Request
+
+After the key exchange, the client requests a service. The service is
+identified by a name. The format of names and procedures for defining
+new names are defined in [SSH-ARCH].
+
+Currently, the following names have been reserved:
+
+ ssh-userauth
+ ssh-connection
+
+Similar local naming policy is applied to the service names that is
+applied to the algorithm names; a local service should use the
+servicename@domain syntax.
+
+ byte SSH_MSG_SERVICE_REQUEST
+ string service name
+
+If the server rejects the service request, it SHOULD send an appropriate
+SSH_MSG_DISCONNECT message and MUST disconnect.
+
+When the service starts, it may have access to the session identifier
+generated during the key exchange.
+
+If the server supports the service (and permits the client to use it),
+it MUST respond with
+ byte SSH_MSG_SERVICE_ACCEPT
+ string service name
+
+Message numbers used by services should be in the area reserved for them
+(see Section ``Summary of Message Numbers''). The transport level will
+continue to process its own messages.
+
+Note that after a key exchange with implicit server authentication, the
+client MUST wait for response to its service request message before
+sending any further data.
+
+9. Additional Messages
+
+Either party may send any of the following messages at any time.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 16]
+
+INTERNET-DRAFT 7 November 1997
+
+9.1. Disconnection Message
+
+ byte SSH_MSG_DISCONNECT
+ uint32 reason code
+ string description [[RFC-2044]]
+ string language tag [[RFC-1766]]
+
+This message causes immediate termination of the connection. All
+implementations MUST be able to process this message; they SHOULD be
+able to send this message.
+
+The sender MUST NOT send or receive any data after this message, and the
+recipient MUST NOT accept any data after receiving this message. The
+description field gives a more specific explanation in a human-readable
+form. The error code gives the reason in a more machine-readable format
+(suitable for localization), and can have the following values:
+
+ #define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1
+ #define SSH_DISCONNECT_PROTOCOL_ERROR 2
+ #define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3
+ #define SSH_DISCONNECT_HOST_AUTHENTICATION_FAILED 4
+ #define SSH_DISCONNECT_MAC_ERROR 5
+ #define SSH_DISCONNECT_COMPRESSION_ERROR 6
+ #define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7
+ #define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8
+ #define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9
+ #define SSH_DISCONNECT_CONNECTION_LOST 10
+ #define SSH_DISCONNECT_BY_APPLICATION 11
+
+If the description string is displayed, control character filtering
+discussed in [SSH-ARCH] should be used to avoid attacks by sending
+terminal control characters.
+
+9.2. Ignored Data Message
+
+ byte SSH_MSG_IGNORE
+ string data
+
+All implementations MUST understand (and ignore) this message at any
+time (after receiving the protocol version). No implementation is
+required to send them. This message can be used as an additional
+protection measure against advanced traffic analysis techniques.
+
+9.3. Debug Message
+
+ byte SSH_MSG_DEBUG
+ boolean always_display
+ string message [[RFC-2044]]
+ string language tag [[RFC-1766]]
+
+All implementations MUST understand this message, but they are allowed
+to ignore it. This message is used to pass information to the other
+side that may help debugging. If always_display is true, the message
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 17]
+
+INTERNET-DRAFT 7 November 1997
+
+SHOULD be displayed. Otherwise, it SHOULD NOT be displayed unless
+debugging information has been explicitly requested by the user.
+
+The message doesn't need to contain a newline. It is, however, allowed
+to consist of multiple lines separated by CRLF (carriage return - line
+feed) pairs.
+
+If the message string is displayed, terminal control character filtering
+discussed in [SSH-ARCH] should be used to avoid attacks by sending
+terminal control characters.
+
+9.4. Reserved Messages
+
+An implementation MUST respond to all unrecognized messages with an
+SSH_MSG_UNIMPLEMENTED message in the order in which they were received.
+Such messages MUST be otherwise ignored. Later protocol versions may
+define other meanings for these message types.
+
+ byte SSH_MSG_UNIMPLEMENTED
+ uint32 packet sequence number of rejected message
+
+10. Summary of Message Numbers
+
+The following message numbers have been defined in this protocol.
+
+ #define SSH_MSG_DISCONNECT 1
+ #define SSH_MSG_IGNORE 2
+ #define SSH_MSG_UNIMPLEMENTED 3
+ #define SSH_MSG_DEBUG 4
+ #define SSH_MSG_SERVICE_REQUEST 5
+ #define SSH_MSG_SERVICE_ACCEPT 6
+
+ #define SSH_MSG_KEXINIT 20
+ #define SSH_MSG_NEWKEYS 21
+
+ /* Numbers 30-49 used for kex packets.
+ Different kex methods may reuse message numbers in
+ this range. */
+ #define SSH_MSG_KEXDH_INIT 30
+ #define SSH_MSG_KEXDH_REPLY 31
+
+11. Security Considerations
+
+This protocol provides a secure encrypted channel over an unsecure
+network. It performs server host authentication, key exchange,
+encryption, and integrity protection. It also derives a unique session
+id that may be used by higher-level protocols.
+
+It is expected that this protocol will sometimes be used without
+insisting on reliable association between the server host key and the
+server host name. Such use is inherently insecure, but may be necessary
+in non-security critical environments, and still provides protection
+against passive attacks. However, implementors of protocols running on
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 18]
+
+INTERNET-DRAFT 7 November 1997
+
+top of this protocol should keep this possibility in mind.
+
+This protocol is designed to be used over a reliable transport. If
+transmission errors or message manipulation occur, the connection is
+closed. The connection SHOULD be re-established if this occurs. Denial
+of service attacks of this type ("wire cutter") are almost impossible to
+avoid.
+
+12. References
+
+[FIPS-186] Federal Information Processing Standards Publication (FIPS
+PUB) 186, Digital Signature Standard, 18 May 1994.
+
+[Orm96] Orman, H., "The Oakley Key Determination Protocol", version 1,
+TR97-92, Department of Computer Science Technical Report, University of
+Arizona.
+
+[RFC-1034] Mockapetris, P., "Domain Names - Concepts and Facilities",
+November 1987.
+
+[RFC-1766] Alvestrand, H., "Tags for the Identification of Languages",
+March 1995.
+
+[RFC-1950] Deutch, P. and Gailly, J-L., "ZLIB Compressed Data Format
+Specification version 3.3", May 1996.
+
+[RFC-1951] Deutch, P., "DEFLATE Compressed Data Format Specification
+version 1.3", May 1996.
+
+[RFC-2044] Yergeau, F., "UTF-8, a Transformation Format of Unicode and
+ISO 10646", October 1996.
+
+[RFC-2104] Krawczyk, H., Bellare, M., and Canetti, R., "HMAC: Keyed-
+Hashing for Message Authentication", February 1997
+
+[RFC-2119] Bradner, S., "Key words for use in RFCs to indicate
+Requirement Levels", March 1997.
+
+[RFC-2144] Adams, C., "The CAST-128 Encryption Algorithm", May 1997.
+
+[Schneier] Schneier, B., "Applied Cryptography Second Edition:
+protocols, algorithms, and source code in C", 2nd edition, John Wiley &
+Sons, New York, NY, 1996.
+
+[SSH-ARCH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Protocol
+Architecture", Internet Draft, draft-ietf-secsh-architecture-00.txt
+
+#91;SSH-USERAUTH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH
+Authentication Protocol", Internet Draft, draft-ietf-secsh-
+userauth-02.txt
+
+[SSH-CONNECT] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Connection
+Protocol", Internet Draft, draft-ietf-secsh-connect-02.txt
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 19]
+
+INTERNET-DRAFT 7 November 1997
+
+[PGP] (XXX n.a.)
+
+[PKIX-Part1] (XXX n.a.)
+
+13. Authors' Addresses
+
+ Tatu Ylonen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: ylo@ssh.fi
+
+ Tero Kivinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: kivinen@ssh.fi
+
+ Markku-Juhani O. Saarinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: mjos@ssh.fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 20]
diff --git a/info/userauth.txt b/info/userauth.txt
new file mode 100644
index 0000000..bb2d72c
--- /dev/null
+++ b/info/userauth.txt
@@ -0,0 +1,647 @@
+Network Working Group T. Ylonen
+INTERNET-DRAFT T. Kivinen
+draft-ietf-secsh-userauth-03.txt M. Saarinen
+Expires in six months SSH
+ 7 November 1997
+
+ SSH Authentication Protocol
+
+Status of This memo
+
+This document is an Internet-Draft. Internet-Drafts are working
+documents of the Internet Engineering Task Force (IETF), its areas,
+and its working groups. Note that other groups may also distribute
+working documents as Internet-Drafts.
+
+Internet-Drafts are draft documents valid for a maximum of six
+months and may be updated, replaced, or obsoleted by other documents
+at any time. It is inappropriate to use Internet-Drafts as reference
+material or to cite them other than as ``work in progress.''
+
+To learn the current status of any Internet-Draft, please check
+the ``1id-abstracts.txt'' listing contained in the Internet-Drafts
+Shadow Directories on ftp.is.co.za (Africa), nic.nordu.net (Europe),
+munnari.oz.au (Pacific Rim), ds.internic.net (US East Coast),
+or ftp.isi.edu (US West Coast).
+
+Abstract
+
+SSH is a protocol for secure remote login and other secure network
+services over an insecure network.
+
+This document describes the SSH authentication protocol framework and
+public key, password, and host-based client authentication methods.
+Additional authentication methods are deferred to separate documents.
+
+The SSH authentication protocol runs on top the SSH transport layer
+protocol and provides a single authenticated tunnel for the SSH
+connection protocol.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 1]
+
+INTERNET-DRAFT 7 November 1997
+
+Table of Contents
+
+1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . 2
+2. The Authentication Protocol Framework . . . . . . . . . . . . . 2
+ 2.1. Authentication Requests . . . . . . . . . . . . . . . . . . 3
+ 2.2. Responses to Authentication Requests . . . . . . . . . . . . 3
+ 2.3. The none Authentication Request . . . . . . . . . . . . . . 4
+ 2.4. Completion of User Authentication . . . . . . . . . . . . . 5
+ 2.5. Banner Message . . . . . . . . . . . . . . . . . . . . . . . 5
+3. Authentication Protocol Message Numbers . . . . . . . . . . . . 5
+4. Public Key Authentication Method: publickey . . . . . . . . . . 6
+5. Password Authentication Method: password . . . . . . . . . . . . 7
+6. Host-Based Authentication: hostbased . . . . . . . . . . . . . . 9
+7. Security Considerations . . . . . . . . . . . . . . . . . . . . 10
+8. References . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
+9. Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 11
+
+
+
+1. Introduction
+
+The SSH authentication protocol is a general-purpose user authentication
+protocol. It is intended to be run over the SSH transport layer
+protocol [SSH-TRANS]. This protocol assumes that the underlying
+protocols provide integrity and confidentiality protection.
+
+This document should be read only after reading the SSH architecture
+document [SSH-ARCH]. This document freely uses terminology and notation
+from the architecture document without reference or further explanation.
+
+The service name for this protocol is "ssh-userauth".
+
+When this protocol starts, it receives the session identifier from the
+lower-level protocol. The session identifier uniquely identifies this
+session and is suitable for signing to prove ownership of a private key.
+This protocol also needs to know whether the lower-level protocol
+provides confidentiality protection.
+
+2. The Authentication Protocol Framework
+
+The server drives the authentication by telling the client which
+authentications can usefully continue the dialog at any given time. The
+client has the freedom to try the methods listed by the server in any
+order. This gives the server complete control over the authentication
+process if it so desired, but also gives enough flexibility for the
+client to use the methods it supports or that are most convenient for
+the user when multiple methods are offered by the server.
+
+Authentication methods are identified by names, as defined in [SSH-
+ARCH]. The "none" method is reserved, and MUST NOT be listed as
+supported. However, it MAY be sent by the client. The server MUST
+always reject this request, unless the client is to be allowed in
+without any authentication, in which case the server MUST accept this
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 2]
+
+INTERNET-DRAFT 7 November 1997
+
+request. The main purpose of sending this request is to get the list of
+supported methods from the server.
+
+The server SHOULD have a timeout for authentication, and disconnect if
+the authentication has not been accepted within the timeout period. The
+RECOMMENDED timeout period is 10 minutes. Additionally, the
+implementation SHOULD limit the number of failed authentication attempts
+a client may perform in a single session (the RECOMMENDED limit is 20
+attempts). If the threshold is exceeded, the server SHOULD disconnect.
+
+2.1. Authentication Requests
+
+All authentication requests MUST use the following message format. Only
+the first few fields are defined; the remaining fields depend on the
+authentication method.
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name (in ISO-10646 UTF-8 encoding)
+ string service name (in US-ASCII)
+ string method name (US-ASCII)
+ rest of the packet is method-specific
+
+The user name and service are repeated in every new authentication
+attempt, and MAY change. The server implementation MUST carefully check
+them in every message, and MUST flush any accumulated authentication
+state if they change. If it is unable to flush some authentication
+state, it MUST disconnect if the user or service name changes.
+
+The service name specifies the service to start after authentication.
+There may be several different authenticated services provided. If the
+requested service is not available, the server MAY disconnect
+immediately or any time later. Sending a proper disconnect message is
+RECOMMENDED. In any case, if the service does not exist, authentication
+MUST NOT be accepted.
+
+If the requested user does not exist, the server MAY disconnect, or MAY
+send a bogus list of acceptable authentications but never accept any.
+This makes it possible for the server to avoid disclosing information
+about which accounts exist. In any case, if the user does not exist,
+the authentication request MUST NOT be accepted.
+
+While there is usually little point for clients to send requests that
+the server does not list as acceptable, sending such requests is not an
+error, and the server SHOULD simply reject requests that it does not
+recognize.
+
+An authentication request MAY result in a further exchange of messages.
+All such messages depend on the authentication method used, and the
+client MAY at any time continue with a new SSH_MSG_USERAUTH_REQUEST
+message, in which case the server MUST abandon the previous
+authentication attempt and continue with the new one.
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 3]
+
+INTERNET-DRAFT 7 November 1997
+
+2.2. Responses to Authentication Requests
+
+If the server rejects the authentication request, it MUST respond with
+
+ byte SSH_MSG_USERAUTH_FAILURE
+ string authentications that can continue
+ boolean partial success
+
+"Authentications that can continue" is a comma-separated list of
+authentication method names that may productively continue the
+authentication dialog.
+
+It is RECOMMENDED that servers only include those methods in the list
+that are actually useful. However, it is not illegal to include methods
+that cannot be used to authenticate the user.
+
+Already successfully completed authentications SHOULD NOT be included in
+the list, unless they really should be performed again for some reason.
+
+"Partial success" MUST be true if the authentication request to which
+this is a response was successful. It MUST be false if the request was
+not successfully processed.
+
+When the server accepts authentication, it MUST respond with
+
+ byte SSH_MSG_USERAUTH_SUCCESS
+
+Note that this is not sent after each step in a multi-method authentica-
+tion sequence, but only when authentication is complete.
+
+The client MAY send several authentication requests without waiting for
+responses from previous requests. The server MUST acknowledge any
+failed requests with a SSH_MSG_USERAUTH_FAILURE message. However,
+SSH_MSG_USERAUTH_SUCCESS MUST sent only once, and once
+SSH_MSG_USERAUTH_SUCCESS has been sent, any further authentication
+requests received after that SHOULD be silently ignored.
+
+Any non-authentication messages sent by the client after the request
+that resulted in SSH_MSG_USERAUTH_SUCCESS being sent MUST be passed to
+the service being run on top of this protocol. Such messages can be
+identified by their message numbers (see Section ``Message Numbers'').
+
+2.3. The none Authentication Request
+
+A client may request a list of authentication methods that may continue
+by using the "none" authentication method.
+
+If no authentication at all is needed for the user, the server MUST
+return SSH_MSG_USERAUTH_SUCCESS. Otherwise, the server MUST return
+SSH_MSG_USERAUTH_FAILURE and MAY return with it a list of authentication
+methods that can continue.
+
+This method MUST NOT be listed as supported by the server.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 4]
+
+INTERNET-DRAFT 7 November 1997
+
+2.4. Completion of User Authentication
+
+Authentication is complete when the server has responded with
+SSH_MSG_USERAUTH_SUCCESS; all authentication related messages received
+after sending this message SHOULD be silently ignored.
+
+After sending SSH_MSG_USERAUTH_SUCCESS, the server starts the requested
+service.
+
+2.5. Banner Message
+
+In some jurisdictions, sending a warning message before authentication
+may be relevant to getting legal protection. Many UNIX machines, for
+example, normally display text from /etc/issue, or use "tcp wrappers" or
+similar software to display a banner before issuing a login prompt.
+
+The SSH server may send a SSH_MSG_USERAUTH_BANNER message at any time
+before authentication is successful. This message contains text to be
+displayed to the client user before authentication is attempted. The
+format is as follows.
+
+ byte SSH_MSG_USERAUTH_BANNER
+ string message (ISO-10646 UTF-8)
+ string language tag (as defined in RFC 1766)
+
+The client SHOULD by default display the message on the screen.
+However, since the message is likely to be sent for every login attempt,
+and since some client software will need to open a separate window for
+this warning, the client software may allow the user to explicitly
+disable the display of banners from the server. The message may consist
+of multiple lines.
+
+If the message string is displayed, control character filtering
+discussed in [SSH-ARCH] SHOULD be used to avoid attacks by sending
+terminal control characters.
+
+3. Authentication Protocol Message Numbers
+
+All message numbers used by this authentication protocol are in the
+range 50..79, which is part of the range reserved for protocols running
+on top of the SSH transport layer protocol.
+
+Message numbers 80 and higher are reserved for protocols running after
+this authentication protocol, so receiving one of them before
+authentication is complete is an error, to which the server MUST respond
+by disconnecting (preferably with a proper disconnect message sent first
+to ease troubleshooting).
+
+After successful authentication, such messages are passed to the higher-
+level service.
+
+These are the general authentication message codes:
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 5]
+
+INTERNET-DRAFT 7 November 1997
+
+ #define SSH_MSG_USERAUTH_REQUEST 50
+ #define SSH_MSG_USERAUTH_FAILURE 51
+ #define SSH_MSG_USERAUTH_SUCCESS 52
+ #define SSH_MSG_USERAUTH_BANNER 53
+
+In addition to the above, there is a range of message numbers (25..29)
+reserved for method-specific messages. These messages are only sent by
+the server (client only sends SSH_MSG_USERAUTH_REQUEST messages).
+Different authentication methods reuse the same message numbers.
+
+4. Public Key Authentication Method: publickey
+
+The only REQUIRED authentication method is public key authentication.
+All implementations MUST support this method; however, not all users
+need to have public keys, and most local policies are not likely to
+require public key authentication for all users in near future.
+
+With this method, the possession of a private key serves as
+authentication. This method works by sending a signature created with a
+private key of the user. The server MUST check that the key is a valid
+authenticator for the user, and MUST check that the signature is valid.
+If both hold, the authentication request MUST be accepted; otherwise it
+MUST be rejected. (Note that the server MAY require additional
+authentications after successful authentication.)
+
+Private keys are often stored encrypted at the client host, and the user
+must supply a passphrase before the signature can be generated. Even if
+they are not, the signing operation involves some expensive computation.
+To avoid unnecessary processing and user interaction, the following
+message is provided for querying whether authentication using the key
+would be acceptable.
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name
+ string service
+ string "publickey"
+ boolean FALSE
+ string public key algorithm name
+ string public key blob
+
+Public key algorithms are defined in the transport layer specification
+[SSH-TRANS]. The public key blob may contain certificates.
+
+Any public key algorithm may be offered for use in authentication. In
+particular, the list is not constrained by what was negotiated during
+key exchange (as that was affected by which algorithms the server had a
+host key). If the server does not support some algorithm, it MUST
+simply reject the request.
+
+The server MUST respond to this message with either
+SSH_MSG_USERAUTH_FAILURE or with
+
+ byte SSH_MSG_USERAUTH_PK_OK
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 6]
+
+INTERNET-DRAFT 7 November 1997
+
+ string public key algorithm name from the request
+ string public key blob from the request
+
+To do actual authentication, the client MAY then send a signature
+generated using the private key. Client MAY send the signature directly
+without first verifying whether the key is acceptable. The signature is
+sent using the following packet
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name
+ string service
+ string "publickey"
+ boolean TRUE
+ string public key algorithm name
+ string public key to be used for authentication
+ string signature
+
+Signature is a signature by the corresponding private key over the
+following data, in this order:
+
+o session identifier, and
+
+o packet payload without the signature.
+
+When the server receives this message, it MUST check whether the
+supplied key is acceptable for authentication, and if so, it MUST check
+whether the signature is correct.
+
+If both checks succeed, this method is successful. Note that the server
+may require additional authentications. The server MUST respond with
+SSH_MSG_USERAUTH_SUCCESS (if no more authentications are needed), or
+SSH_MSG_USERAUTH_FAILURE (if the request failed, or more authentications
+are needed).
+
+The following method-specific message numbers are used by the publickey
+authentication method.
+
+ /* Key-based */
+ #define SSH_MSG_USERAUTH_PK_OK 60
+
+5. Password Authentication Method: password
+
+Password authentication uses the following packets. Note that a server
+MAY request the user to change password. All implementations SHOULD
+support password authentication.
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name
+ string service
+ string "password"
+ boolean FALSE
+ string plaintext password (ISO-10646 UTF-8)
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 7]
+
+INTERNET-DRAFT 7 November 1997
+
+Note that the password is encoded in ISO-10646 UTF-8. It is up to the
+server how it interprets the password and validates it against the
+password database. However, if the client reads the password in some
+other encoding (e.g., ISO 8859-1 (ISO Latin1)), it MUST convert the
+password to ISO-10646 UTF-8 before transmitting, and the server MUST
+convert the password to the encoding used on that system for passwords.
+
+Note that even though the cleartext password is transmitted in the
+packet, the entire packet is encrypted by the transport layer. Both the
+server and the client should check whether the underlying transport
+layer provides confidentiality (i.e., encryption is being used). If no
+confidentiality is provided ("none" cipher), password authentication
+SHOULD be disabled. If there is no confidentiality or no MAC, password
+change SHOULD be disabled.
+
+Normally, the server responds to this message with success or failure.
+However, the server MAY also respond with
+SSH_MSG_USERAUTH_PASSWD_CHANGEREQ.
+
+ byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
+ string prompt (ISO-10646 UTF-8)
+ string language tag (as defined in RFC 1766)
+
+In this case, the software client SHOULD request a new password from the
+user, and send a new request using the following message. The client
+may also send this message instead of the normal password authentication
+request without the server asking for it.
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name
+ string service
+ string "password"
+ boolean TRUE
+ string plaintext old password (ISO-10646 UTF-8)
+ string plaintext new password (ISO-10646 UTF-8)
+
+The server must reply to request message with SSH_MSG_USERAUTH_SUCCESS,
+SSH_MSG_USERAUTH_FAILURE, or another SSH_MSG_USERAUTH_PASSWD_CHANGEREQ.
+The meaning of these is as follows:
+
+ SSH_MSG_USERAUTH_SUCCESS
+ Password has been changed, and authentication has been
+ successfully completed.
+
+ SSH_MSG_USERAUTH_FAILURE with partial success
+ The password has been changed, but more authentications are
+ needed.
+
+ SSH_MSG_USERAUTH_FAILURE without partial success
+ The password has not been changed. Either password changing was
+ not supported, or the old password was bad. Note that if the
+ server has already sent SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, we know
+ that it supports changing the password.
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 8]
+
+INTERNET-DRAFT 7 November 1997
+
+ SSH_MSG_USERAUTH_CHANGEREQ
+ The password was not changed because the new password was not
+ acceptable (e.g. too easy to guess).
+
+The following method-specific message numbers are used by the password
+authentication method.
+
+ #define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60
+
+6. Host-Based Authentication: hostbased
+
+Some sites wish to allow authentication based on the host where the user
+is coming from and the user name on the remote host. While this form of
+authentication is not suitable for high-security sites, it can be very
+convenient in many environments. This form of authentication is
+OPTIONAL. When used, special care SHOULD be taken to prevent a regular
+user from obtaining the private host key.
+The client requests this form of authentication by sending the following
+message. It is similar to the UNIX "rhosts" and "hosts.equiv" styles of
+authentication, except that the identity of the client host is checked
+more rigorously.
+
+This method works by having the client send a signature created with the
+private key of the client host, which the server checks with that host's
+public key. Once the client host's identity is established,
+authorization, but no further authentication, is performed based on the
+user names on the server and client, and the client host name.
+
+ byte SSH_MSG_USERAUTH_REQUEST
+ string user name
+ string service
+ string "hostbased"
+ string public key algorithm for host key
+ string public host key and certificates for client host
+ string client host name (FQDN; US-ASCII)
+ string client user name on the remote host (ISO-10646 UTF-8)
+ string signature
+
+Public key algorithm names for use in "public key algorithm for host
+key" are defined in the transport layer specification. The "public host
+key for client host" may include certificates.
+
+Signature is a signature with the private host key of the following
+data, in this order:
+
+o session identifier, and
+
+o packet payload without the signature.
+
+The server MUST verify that the host key actually belongs to the client
+host named in the message, that the given user on that host is allowed
+to log in, and that the signature is a valid signature on the
+appropriate value by the given host key. The server MAY ignore the
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 9]
+
+INTERNET-DRAFT 7 November 1997
+
+client user name, if it wants to authenticate only the client host.
+
+It is RECOMMENDED that whenever possible, the server perform additional
+checks to verify that the network address obtained from the (untrusted)
+network matches the given client host name. This makes exploiting
+compromised host keys more difficult. Note that this may require
+special handling for connections coming through a firewall.
+
+7. Security Considerations
+
+The purpose of this protocol is to perform client user authentication.
+It assumed that this runs over a secure transport layer protocol, which
+has already authenticated the server machine, established an encrypted
+communications channel, and computed a unique session identifier for
+this session. The transport layer provides forward secrecy for password
+authentication and other methods that rely on secret data.
+
+The server may go into a "sleep" period after repeated unsuccesful
+authentications to make key search harder.
+
+If the transport layer does not provide encryption, authentication
+methods that rely on secret data SHOULD be disabled. If it does not
+provide MAC protection, requests to change authentication data (e.g.
+password change) SHOULD be disabled to avoid an attacker from modifying
+the ciphertext without being noticed, rendering the new authentication
+data unusable (denial of service).
+
+Several authentication methods with different security characteristics
+are allowed. It is up to the server's local policy to decide which
+methods (or combinations of methods) it is willing to accept for each
+user. Authentication is no stronger than the weakest combination
+allowed.
+
+Special care should be taken when designing debug messages. These
+messages may reveal surprising amounts of information about the host if
+not properly designed. Debug messages can be disabled (during user
+authentication phase) if high security is sought after.
+
+8. References
+
+[RFC-1766] Alvestrand, H., "Tags for the Identification of Languages",
+March 1995.
+
+[RFC-2044] Yergeau, F., "UTF-8, a Transformation Format of Unicode and
+ISO 10646", October 1996.
+
+[SSH-ARCH] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Protocol
+Architecture", Internet Draft, draft-secsh-architecture-00.txt
+
+[SSH-TRANS] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Transport
+Layer Protocol", Internet Draft, draft-secsh-transport-02.txt
+
+[SSH-CONNECT] Ylonen, T., Kivinen, T, and Saarinen, M., "SSH Connection
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 10]
+
+INTERNET-DRAFT 7 November 1997
+
+Protocol", Internet Draft, draft-secsh-connect-02.txt
+
+9. Author's Address
+
+ Tatu Ylonen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: ylo@ssh.fi
+
+ Tero Kivinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: kivinen@ssh.fi
+
+ Markku-Juhani O. Saarinen
+ SSH Communications Security Ltd.
+ Tekniikantie 12
+ FIN-02150 ESPOO
+ Finland
+ E-mail: mjos@ssh.fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+T. Ylonen, T. Kivinen, and M. Saarinen [page 11]
diff --git a/not-for-export b/not-for-export
new file mode 100644
index 0000000..bae482a
--- /dev/null
+++ b/not-for-export
@@ -0,0 +1,10 @@
+Crypto-1.1a2/Demo/cipher
+Crypto-1.1a2/stream
+Crypto-1.1a2/block
+Crypto-1.1a2/framewks/block.in
+Crypto-1.1a2/framewks/stream.in
+Crypto-1.1a2/curiosa
+Crypto-1.1a2/Protocol/PGP
+Crypto-1.1a2/Protocol/AllOrNothing.py
+Crypto-1.1a2/PublicKey/RSA.py
+Crypto-1.1a2/PublicKey/ElGamal.py
diff --git a/stream/ARC4.c b/stream/ARC4.c
new file mode 100644
index 0000000..590fabb
--- /dev/null
+++ b/stream/ARC4.c
@@ -0,0 +1,72 @@
+
+/*
+ * arc4.c : Implementation for the Alleged-RC4 stream cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+typedef struct
+{
+ PCTObject_HEAD;
+ unsigned char state[256];
+ unsigned char x,y;
+} ARC4object;
+
+#define ARC4decrypt ARC4encrypt /* Encryption and decryption are symmetric */
+
+static inline void ARC4encrypt(self, block, len)
+ ARC4object *self;
+ unsigned char *block;
+ int len;
+{
+ register int i, x=self->x, y=self->y;
+
+ for (i=0; i<len; i++)
+ {
+ x = (x + 1) % 256;
+ y = (y + self->state[x]) % 256;
+ {
+ register int t; /* Exchange state[x] and state[y] */
+ t = self->state[x];
+ self->state[x] = self->state[y];
+ self->state[y] = t;
+ }
+ {
+ register int xorIndex; /* XOR the data with the stream data */
+ xorIndex=(self->state[x]+self->state[y]) % 256;
+ block[i] ^= self->state[xorIndex];
+ }
+ }
+ self->x=x;
+ self->y=y;
+}
+
+
+static void ARC4init(self, key, keylen)
+ ARC4object *self;
+ unsigned char *key;
+ int keylen;
+{
+ register int i, index1, index2;
+
+ for(i=0; i<256; i++) self->state[i]=i;
+ self->x=0; self->y=0;
+ index1=0; index2=0;
+ for(i=0; i<256; i++)
+ {
+ register int t;
+ index2 = ( key[index1] + self->state[i] + index2) % 256;
+ t = self->state[i];
+ self->state[i] = self->state[index2];
+ self->state[index2] = t;
+ index1 = (index1 + 1) % keylen;
+ }
+}
+
+
+
diff --git a/stream/Sapphire.c b/stream/Sapphire.c
new file mode 100644
index 0000000..00a9978
--- /dev/null
+++ b/stream/Sapphire.c
@@ -0,0 +1,125 @@
+
+/*
+ * sapphire.c : Implementation for the Sapphire stream cipher
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+typedef struct
+{
+ PCTObject_HEAD;
+ unsigned char state[256];
+ unsigned char index[5];/* Rotor, ratchet, avalanche, last_plain, last_cipher */
+} Sapphireobject;
+
+#define rotor self->index[0]
+#define ratchet self->index[1]
+#define avalanche self->index[2]
+#define last_plain self->index[3]
+#define last_cipher self->index[4]
+
+static inline void Sapphireencrypt(self, block, len)
+ Sapphireobject *self;
+ unsigned char *block;
+ unsigned int len;
+{
+ unsigned char temp;
+ unsigned int i;
+
+ for(i=0; i<len; i++)
+ {
+ ratchet += self->state[rotor++];
+ temp = self->state[last_cipher];
+ self->state[last_cipher] = self->state[ratchet];
+ self->state[ratchet] = self->state[last_plain];
+ self->state[last_plain] = self->state[rotor];
+ self->state[rotor] = temp;
+ avalanche += self->state[temp];
+
+ temp = block[i];
+ block[i] ^= self->state[ 0xFF & (self->state[rotor] + self->state[ratchet]) ]
+ ^ self->state[self->state[(self->state[avalanche] +
+ self->state[last_plain] +
+ self->state[last_cipher]
+ ) & 0xFF
+ ]
+ ];
+ last_plain = temp;
+ last_cipher = block[i];
+ }
+}
+
+static inline void Sapphiredecrypt(self, block, len)
+ Sapphireobject *self;
+ unsigned char *block;
+ unsigned int len;
+{
+ unsigned char temp;
+ unsigned int i;
+
+ for(i=0; i<len; i++)
+ {
+ ratchet += self->state[rotor++];
+ temp = self->state[last_cipher];
+ self->state[last_cipher] = self->state[ratchet];
+ self->state[ratchet] = self->state[last_plain];
+ self->state[last_plain] = self->state[rotor];
+ self->state[rotor] = temp;
+ avalanche += self->state[temp];
+ temp = block[i];
+ block[i] ^= self->state[ 0xFF & (self->state[rotor] +self->state[ratchet]) ]
+ ^ self->state[self->state[(self->state[avalanche] +
+ self->state[last_plain] +
+ self->state[last_cipher]
+ ) & 0xFF
+ ]
+ ];
+ last_cipher = temp;
+ last_plain = block[i];
+ }
+}
+
+static void Sapphireinit(self, key, keylen)
+ Sapphireobject *self;
+ unsigned char *key;
+ int keylen;
+{
+ int i;
+ unsigned char toswap, keypos, rsum, swaptemp;
+
+ for (i = 0; i < 256; i++)
+ self->state[i] = i;
+
+ keypos = 0;
+ rsum = 0;
+ for (i = 255; i >= 0; i--)
+ { unsigned int retry_limiter=0, mask=1;
+ while (mask < i)
+ mask = (mask << 1) + 1;
+ do
+ {
+ rsum = self->state[rsum] + key[keypos++];
+ if (keypos >= keylen)
+ {
+ keypos = 0;
+ rsum += keylen;
+ }
+ toswap = mask & rsum;
+ if (++retry_limiter > 11)
+ toswap %= i;
+ } while (toswap > i);
+ swaptemp = self->state[i];
+ self->state[i] = self->state[toswap];
+ self->state[toswap] = swaptemp;
+ }
+ rotor=self->state[1];
+ ratchet=self->state[3];
+ avalanche=self->state[5];
+ last_plain=self->state[7];
+ last_cipher=self->state[rsum];
+}
diff --git a/stream/XOR.c b/stream/XOR.c
new file mode 100644
index 0000000..5244d63
--- /dev/null
+++ b/stream/XOR.c
@@ -0,0 +1,51 @@
+/*
+ * xor.c : Source for the trivial cipher which XORs the message with the key.
+ * The key can be up to 32 bytes long.
+ *
+ * Part of the Python Cryptography Toolkit, version 1.1
+ *
+ * Distribute and use freely; there are no restrictions on further
+ * dissemination and usage except those imposed by the laws of your
+ * country of residence.
+ *
+ */
+
+typedef struct
+{
+ PCTObject_HEAD;
+ unsigned char key[32];
+ int keylen, last_pos;
+} XORobject;
+
+static inline void
+XORinit(self, key, len)
+ XORobject *self;
+ unsigned char *key;
+ int len;
+{
+ int i;
+
+ if (32 <= len) len=32;
+ self->keylen = len;
+ self->last_pos = 0;
+
+ for(i=0; i<len; i++)
+ {
+ self->key[i] = key[i];
+ }
+}
+
+static inline void XORencrypt(self, block, len)
+ XORobject *self;
+ unsigned char *block;
+ int len;
+{
+ int i, j = self->last_pos;
+ for(i=0; i<len; i++, j=(j+1) % self->keylen)
+ {
+ block[i] ^= self->key[j];
+ }
+ self->last_pos = j;
+}
+
+#define XORdecrypt XORencrypt
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..fbd481e
--- /dev/null
+++ b/test.py
@@ -0,0 +1,41 @@
+#
+# Test script for the Python Cryptography package.
+#
+
+import sys
+args = sys.argv[1:]
+quiet = "--quiet" in args
+if quiet: args.remove('--quiet')
+
+from Crypto.Util import test
+
+if not quiet:
+ print 'Public-key Functions:'
+ print '====================='
+
+if args: test.TestPKModules(args, verbose= not quiet)
+else: test.TestPKModules(verbose= not quiet)
+
+
+if not quiet:
+ print '\nHash Functions:'
+ print '==============='
+
+if args: test.TestHashModules(args, verbose= not quiet)
+else: test.TestHashModules(verbose= not quiet)
+
+if not quiet:
+ print '\nStream Ciphers:'
+ print '==============='
+
+if args: test.TestStreamModules(args, verbose= not quiet)
+else: test.TestStreamModules(verbose= not quiet)
+
+if not quiet:
+ print '\nBlock Ciphers:'
+ print '=============='
+
+if args: test.TestBlockModules(args, verbose= not quiet)
+else: test.TestBlockModules(verbose= not quiet)
+
+