Anonymous avatar Anonymous committed 9429449

New package: Ecrypto.

Comments (0)

Files changed (16)

+2002-06-13  Simon Josefsson  <jas@extundo.com>
+
+	* ecrypto: New package, from Ecrypto2.0.tgz (29436 bytes, MD5
+	01e74632426b429b9468158ad52ef973) from
+	http://web.mit.edu/thouis/www/ecrypto.html written by Ray Jones
+	<rjones at pobox.com>.
+# Makefile for Crypto lisp code
+
+# This file is part of XEmacs.
+
+# XEmacs is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2, or (at your option) any
+# later version.
+
+# XEmacs is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with XEmacs; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# This XEmacs package contains single file (mostly) independent lisp packages
+
+VERSION = 0.1
+AUTHOR_VERSION = 2.0
+MAINTAINER = Simon Josefsson <simon@josefsson.org>
+PACKAGE = crypto
+PKG_TYPE = regular
+REQUIRES = 
+CATEGORY = standard
+
+ELCS = ascii-armor.elc blowfish.elc des.elc idea.elc paranoid.elc rander.elc \
+	rc16.elc sha1.elc
+
+include ../../../XEmacs.rules
+
+all:: $(ELCS) auto-autoloads.elc
+
+srckit: srckit-std
+
+binkit: binkit-common
+this is the Ecrypto library, a group of files implementing strong
+crypto in elisp.  it is made up of the following:
+
+idea.el
+  this file contains the code for the IDEA cipher.  it is reasonably
+  secure, in terms of cleaning up intermediate computations.  the
+  functions in it operate on 16-bit vectors.  CBC and a CBC-based
+  package transform are provided.
+
+md5.el, md5-old.el, sha1.el, sha1-old.el
+  code for the MD5 and SHA-1 hash algorithms.  md5.el and sha1.el are
+  the actual implementations, geared towards speed and data security
+  (ie, wiping possibly sensitive data).  both files have to be
+  compiled before being loaded.  md5-old.el and sha1-old.el are
+  the original implementations, much more readable, less optimized,
+  but slower and likely to leave secure data around for the GC to
+  clean up.
+
+ascii-armor.el
+  provides routines for converting a vector of 16-bit numbers into its
+  equivalent ascii-armor, and vice versa.  it could be easily extended
+  to work for octet-streams, but hasn't, yet.
+
+rc16.el
+  code for Julian Assange's extension of RC4 to 16 bits.
+
+rander.el
+  this code attempts to provide cryptographically secure random
+  numbers, but probably fails.  it draws together various sources of
+  randomness from within emacs, including the microsecond timings of
+  keypresses, though your emacs may not provide such timings.  this
+  code should be considered somewhat untrustworthy.  it uses rc16.el
+  for its core.
+
+paranoid.el
+  a slight modification to comint-read-noecho.  it leaves even less
+  possibly sensitive data lying around for the GC to clean up. 
+
+NOTES
+----------------------------------------
+IDEA is patented, but i believe that this software, which is GPL'd,
+doesn't require any license fee or registration.  Diffie-Hellman was
+patented, but that expired in 1997.  RC4 was a trade secret, it is no
+longer, and so RC16 (which is based on RC4) is safe to use (with
+credit to Julian Assange).
+
+until this code has been extensively tested and examined by multiple
+parties, i wouldn't trust it any more than a Cracker-Jack Secret
+Decoder Ring.
+
+enjoy.
+
+ray jones
+rjones@pobox.com
+* ascii-armor for strings
+* md5/sha1 for 16-bit vecs
+* evaluation of rander.  is rc16 a good RNG as used?
+;;;  ascii-armor.el -- translate data into and from ascii-armor 
+;;;                    (radix64)
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: base64, ascii-armor, radix64, oink
+;; Created: 1998-04-14
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl)
+
+(defun ascii-armor-char (val)
+  (cond ((< val 26) (+ val ?A))
+	((< val 52) (+ (- val 26) ?a))
+	((< val 62) (+ (- val 52) ?0))
+	((= val 62) ?+)
+	((= val 63) ?/)
+	(t (error "no ascii-armor character for %d!" val))))
+
+(defun ascii-armor-val (char)
+  (cond ((and (<= ?A char) (<= char ?Z)) (- char ?A))
+	((and (<= ?a char) (<= char ?z)) (+ (- char ?a) 26))
+	((and (<= ?0 char) (<= char ?9)) (+ (- char ?0) 52))
+	((= char ?+) 62)
+	((= char ?/) 63)
+	(t nil)))
+
+(defun ascii-armor-length (n)
+  "calculate the number of characters needed to encode N octets."
+
+  (let* (
+	 ;; number of bits
+	 (n1 (* n 8))
+	 ;; ascii armor is 6 bits per symbol...
+	 (n2 (car (ceiling* n1 6)))
+	 ;; but always a multiple of 4 symbols
+	 (n3 (* 4 (car (ceiling* n2 4)))))
+    n3))
+
+(defun ascii-armor-data-length (str)
+  "calculate the number of octets stored in an ascii-armor string"
+
+  (let ((len (length str)))
+    (while (and (> len 0) 
+                (eq ?= (aref str (1- len))))
+      (decf len))
+    (/ (* len 6) 8)))
+
+;; translate a vector of 16-bit values into an ascii-armor string
+(defun vec16-to-ascii-armor (vec)
+  (let* ((in-len (length vec))
+	 (out-len (ascii-armor-length (* 2 in-len)))
+	 (out-str (make-string out-len ?=))
+	 (out-idx 0)
+	 (bits-start 0))
+    ;; helper function
+    (flet ((next-out (val)
+	     (aset out-str out-idx
+		   (ascii-armor-char
+		    (logand ?\x3f val)))
+	     (incf out-idx)))
+
+      (dotimes (in-idx in-len)
+	(incf bits-start 16)
+	;; read out as many bits from the current index as possible
+	(while (> bits-start 0)
+	  ;; do the next 6 bits straddle a boundary in vec?
+	  
+	  (if (< bits-start 6)
+	      ;; straddle
+	      (let ((hi-val (aref vec in-idx))
+		    ;; pad with 0s
+		    (lo-val (if (< in-idx (1- in-len))
+				(aref vec (1+ in-idx))
+			      0)))
+		(next-out (logior
+			   (ash hi-val (- 6 bits-start))
+			   (ash lo-val (- 6 bits-start 16)))))
+	    
+	    ;; 6 bits all from the current entry in vec
+	    (next-out (ash (aref vec in-idx) (- 6 bits-start))))
+
+	  (decf bits-start 6))))
+
+    ;; pad with ?=, if out-str isn't full
+    (while (< out-idx out-len)
+      (aset out-str out-idx ?=)
+      (incf out-idx))
+  
+    out-str))
+
+;; translate an ascii-armor string to a 16-bit vector
+(defun ascii-armor-to-vec16 (string)
+  ;; ascii armor is padded, so this doesn't have to be rounded, just
+  ;; truncated.
+  (let* ((out-len (/ (ascii-armor-data-length string) 2))
+	 (out-vec (make-vector out-len 0))
+	 (buf 0)
+	 (bits-in-buf 0)
+	 (in-idx 0))
+    (dotimes (out-idx out-len)
+      ;; shift bits from the string until there are enough to stick
+      ;; into the output vector
+      (while (< bits-in-buf 16)
+	(let ((val (ascii-armor-val (aref string in-idx))))
+	  (when val
+	    (setq buf (logior (ash buf 6)
+			      val))
+	    (incf bits-in-buf 6))
+	  (incf in-idx)))
+
+      (aset out-vec out-idx (ash buf (- 16 bits-in-buf)))
+      (decf bits-in-buf 16)
+      ;; turn off the used bits
+      (setq buf (logand buf (lognot (ash ?\xffff bits-in-buf)))))
+
+    out-vec))
+
+(provide 'ascii-armor)
+;;;  blowfish.el -- block cipher
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: Blowfish, Schneier, oink, cipher, cypher, cryptography
+;; Created: 1998-04-01
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; this code is Bruce Schneier's Blowfish encryption algorithm.  it is
+;; fast, license-free, unpatented, and beleived secure.  it takes a
+;; key of length 32-448 bits.  it works on 64-bit blocks.  further
+;; information is available in Applied Cryptography by Schneier or at
+;; http://www.counterpane.com/blowfish.html
+
+;; to use, given a key:
+;;
+;; (let ((subkeys (blowfish-generate-keys key)) ;; returns a pair, the
+;;                                              ;; P-array and the S-boxes
+;;       (data [1 2 3 4]))
+;;   ;; encipher data in place
+;;   (blowfish-cipher-block data (car subkeys) (cdr subkeys))
+;;   ;; decipher in place
+;;   (blowfish-cipher-block data (car subkeys) (cdr subkeys) 'decrypt)
+;;   ;; data should now be back to its starting value
+;;   (assert (equal data [1 2 3 4])))
+
+;; note: the time taken to generate subkeys is quite substantial, but
+;; encryption and decryption afterwards is quite fast.
+
+;; keys are vectors of 16-bit integers, with the vector being a
+;; positive, even number of elements long.
+
+
+;;; Code:
+(require 'cl)
+
+;; blowfish is a 64-bit algorithm, which operates on 32-bit pieces.
+;; this code stores 32-bit numbers as vectors w/ 2 16-bit elements.
+
+;; helper functions
+(defsubst blowfish-xor (a b result)
+  (aset result 0 (logxor (aref a 0) (aref b 0)))
+  (aset result 1 (logxor (aref a 1) (aref b 1)))
+  (assert (and (< (aref result 0) (ash 1 16))
+	       (< (aref result 1) (ash 1 16))) nil
+	       ""))
+
+(defsubst blowfish-add (a b result)
+  (let* ((low (+ (aref a 1) (aref b 1)))
+	 (high (logand (+ (aref a 0) (aref b 0) (ash low -16))
+		       ?\xFFFF)))
+    (aset result 0 high)
+    (aset result 1 (logand low ?\xFFFF)))
+  (assert (and (< (aref result 0) (ash 1 16))
+	       (< (aref result 1) (ash 1 16))) nil
+	       ""))
+
+(defun blowfish-cipher-block (data p-array s-boxes &optional direction)
+  "encode or decode with the blowfish cipher, in place.
+first arg is vector of 4 16-bit words (MSB order).
+second arg is P-array to encrypt/decrypt with.
+third arg is S-boxes to encrypt/decrypt with.
+optional fourth arg is direction \(eq 'decrypt to decrypt\)."
+
+  ;; split the data into two 32 bit pieces (stored as 2 16-bit pieces
+  ;; each.)
+  (let ((xl (vector (aref data 0) (aref data 1)))
+	(xr (vector (aref data 2) (aref data 3)))
+        (reverse (eq direction 'decrypt)))
+    ;; 16 rounds
+    (dotimes (idx 16)
+      ;; mix in the p-array.  note the reverse order for decryption.
+      (let ((p-val (aref p-array (if reverse (- 17 idx) idx))))
+	(blowfish-xor xl p-val xl))
+      ;; apply F
+      (blowfish-f xl s-boxes xr)
+      ;; swap low and high 32 bits
+      (rotatef xl xr))
+
+    ;; undo the last swap
+    (rotatef xl xr)
+    ;; mixin last two elements of P-array
+    ;; (when comparing to section in AC 2nd Ed, note that this is 0
+    ;; indexed, and the reverse order for decryption.
+    (let ((p-val-16 (aref p-array (if reverse 1 16)))
+	  (p-val-17 (aref p-array (if reverse 0 17))))
+      (blowfish-xor xl p-val-17 xl)
+      (blowfish-xor xr p-val-16 xr))
+
+    ;; put the result back into the input vector
+    (aset data 0 (aref xl 0))
+    (aset data 1 (aref xl 1))
+    (aset data 2 (aref xr 0))
+    (aset data 3 (aref xr 1))
+    
+    ;; clean up
+    (fillarray xl 0)
+    (fillarray xr 0)))
+
+(defvar *blowfish-f-scratch* [0 0]
+  "scratch area for the blowfish-f function, to reduce allocation")
+
+(defun blowfish-f (x s-boxes dest)
+  "perform the blowfish F-function.  takes vector of two-16-bit
+numbers and S-boxes to use as args, and the destination to xor the
+result into.  uses *blowfish-f-scratch* to reduce allocation."
+  ;; S-boxes are indexed into via 8-bit pieces of X
+  (let* ((x0 (aref x 0))
+	 (Sa (aref (aref s-boxes 0) (ash x0 -8)))
+	 (Sb (aref (aref s-boxes 1) (logand x0 ?\xFF)))
+	 (x1 (aref x 1))
+	 (Sc (aref (aref s-boxes 2) (ash x1 -8)))
+	 (Sd (aref (aref s-boxes 3) (logand x1 ?\xFF))))
+
+    (blowfish-add Sa Sb *blowfish-f-scratch*)
+    (blowfish-xor Sc *blowfish-f-scratch* *blowfish-f-scratch*)
+    (blowfish-add Sd *blowfish-f-scratch* *blowfish-f-scratch*)
+    (blowfish-xor *blowfish-f-scratch* dest dest)))
+
+;; initialization constants for the P-array and S-boxes
+
+(defconst blowfish-s-box-inits
+  [
+   [
+    [?\xd131 ?\x0ba6] [?\x98df ?\xb5ac] [?\x2ffd ?\x72db] [?\xd01a ?\xdfb7]
+    [?\xb8e1 ?\xafed] [?\x6a26 ?\x7e96] [?\xba7c ?\x9045] [?\xf12c ?\x7f99]
+    [?\x24a1 ?\x9947] [?\xb391 ?\x6cf7] [?\x0801 ?\xf2e2] [?\x858e ?\xfc16]
+    [?\x6369 ?\x20d8] [?\x7157 ?\x4e69] [?\xa458 ?\xfea3] [?\xf493 ?\x3d7e]
+    [?\x0d95 ?\x748f] [?\x728e ?\xb658] [?\x718b ?\xcd58] [?\x8215 ?\x4aee]
+    [?\x7b54 ?\xa41d] [?\xc25a ?\x59b5] [?\x9c30 ?\xd539] [?\x2af2 ?\x6013]
+    [?\xc5d1 ?\xb023] [?\x2860 ?\x85f0] [?\xca41 ?\x7918] [?\xb8db ?\x38ef]
+    [?\x8e79 ?\xdcb0] [?\x603a ?\x180e] [?\x6c9e ?\x0e8b] [?\xb01e ?\x8a3e]
+    [?\xd715 ?\x77c1] [?\xbd31 ?\x4b27] [?\x78af ?\x2fda] [?\x5560 ?\x5c60]
+    [?\xe655 ?\x25f3] [?\xaa55 ?\xab94] [?\x5748 ?\x9862] [?\x63e8 ?\x1440]
+    [?\x55ca ?\x396a] [?\x2aab ?\x10b6] [?\xb4cc ?\x5c34] [?\x1141 ?\xe8ce]
+    [?\xa154 ?\x86af] [?\x7c72 ?\xe993] [?\xb3ee ?\x1411] [?\x636f ?\xbc2a]
+    [?\x2ba9 ?\xc55d] [?\x7418 ?\x31f6] [?\xce5c ?\x3e16] [?\x9b87 ?\x931e]
+    [?\xafd6 ?\xba33] [?\x6c24 ?\xcf5c] [?\x7a32 ?\x5381] [?\x2895 ?\x8677]
+    [?\x3b8f ?\x4898] [?\x6b4b ?\xb9af] [?\xc4bf ?\xe81b] [?\x6628 ?\x2193]
+    [?\x61d8 ?\x09cc] [?\xfb21 ?\xa991] [?\x487c ?\xac60] [?\x5dec ?\x8032]
+    [?\xef84 ?\x5d5d] [?\xe985 ?\x75b1] [?\xdc26 ?\x2302] [?\xeb65 ?\x1b88]
+    [?\x2389 ?\x3e81] [?\xd396 ?\xacc5] [?\x0f6d ?\x6ff3] [?\x83f4 ?\x4239]
+    [?\x2e0b ?\x4482] [?\xa484 ?\x2004] [?\x69c8 ?\xf04a] [?\x9e1f ?\x9b5e]
+    [?\x21c6 ?\x6842] [?\xf6e9 ?\x6c9a] [?\x670c ?\x9c61] [?\xabd3 ?\x88f0]
+    [?\x6a51 ?\xa0d2] [?\xd854 ?\x2f68] [?\x960f ?\xa728] [?\xab51 ?\x33a3]
+    [?\x6eef ?\x0b6c] [?\x137a ?\x3be4] [?\xba3b ?\xf050] [?\x7efb ?\x2a98]
+    [?\xa1f1 ?\x651d] [?\x39af ?\x0176] [?\x66ca ?\x593e] [?\x8243 ?\x0e88]
+    [?\x8cee ?\x8619] [?\x456f ?\x9fb4] [?\x7d84 ?\xa5c3] [?\x3b8b ?\x5ebe]
+    [?\xe06f ?\x75d8] [?\x85c1 ?\x2073] [?\x401a ?\x449f] [?\x56c1 ?\x6aa6]
+    [?\x4ed3 ?\xaa62] [?\x363f ?\x7706] [?\x1bfe ?\xdf72] [?\x429b ?\x023d]
+    [?\x37d0 ?\xd724] [?\xd00a ?\x1248] [?\xdb0f ?\xead3] [?\x49f1 ?\xc09b]
+    [?\x0753 ?\x72c9] [?\x8099 ?\x1b7b] [?\x25d4 ?\x79d8] [?\xf6e8 ?\xdef7]
+    [?\xe3fe ?\x501a] [?\xb679 ?\x4c3b] [?\x976c ?\xe0bd] [?\x04c0 ?\x06ba]
+    [?\xc1a9 ?\x4fb6] [?\x409f ?\x60c4] [?\x5e5c ?\x9ec2] [?\x196a ?\x2463]
+    [?\x68fb ?\x6faf] [?\x3e6c ?\x53b5] [?\x1339 ?\xb2eb] [?\x3b52 ?\xec6f]
+    [?\x6dfc ?\x511f] [?\x9b30 ?\x952c] [?\xcc81 ?\x4544] [?\xaf5e ?\xbd09]
+    [?\xbee3 ?\xd004] [?\xde33 ?\x4afd] [?\x660f ?\x2807] [?\x192e ?\x4bb3]
+    [?\xc0cb ?\xa857] [?\x45c8 ?\x740f] [?\xd20b ?\x5f39] [?\xb9d3 ?\xfbdb]
+    [?\x5579 ?\xc0bd] [?\x1a60 ?\x320a] [?\xd6a1 ?\x00c6] [?\x402c ?\x7279]
+    [?\x679f ?\x25fe] [?\xfb1f ?\xa3cc] [?\x8ea5 ?\xe9f8] [?\xdb32 ?\x22f8]
+    [?\x3c75 ?\x16df] [?\xfd61 ?\x6b15] [?\x2f50 ?\x1ec8] [?\xad05 ?\x52ab]
+    [?\x323d ?\xb5fa] [?\xfd23 ?\x8760] [?\x5331 ?\x7b48] [?\x3e00 ?\xdf82]
+    [?\x9e5c ?\x57bb] [?\xca6f ?\x8ca0] [?\x1a87 ?\x562e] [?\xdf17 ?\x69db]
+    [?\xd542 ?\xa8f6] [?\x287e ?\xffc3] [?\xac67 ?\x32c6] [?\x8c4f ?\x5573]
+    [?\x695b ?\x27b0] [?\xbbca ?\x58c8] [?\xe1ff ?\xa35d] [?\xb8f0 ?\x11a0]
+    [?\x10fa ?\x3d98] [?\xfd21 ?\x83b8] [?\x4afc ?\xb56c] [?\x2dd1 ?\xd35b]
+    [?\x9a53 ?\xe479] [?\xb6f8 ?\x4565] [?\xd28e ?\x49bc] [?\x4bfb ?\x9790]
+    [?\xe1dd ?\xf2da] [?\xa4cb ?\x7e33] [?\x62fb ?\x1341] [?\xcee4 ?\xc6e8]
+    [?\xef20 ?\xcada] [?\x3677 ?\x4c01] [?\xd07e ?\x9efe] [?\x2bf1 ?\x1fb4]
+    [?\x95db ?\xda4d] [?\xae90 ?\x9198] [?\xeaad ?\x8e71] [?\x6b93 ?\xd5a0]
+    [?\xd08e ?\xd1d0] [?\xafc7 ?\x25e0] [?\x8e3c ?\x5b2f] [?\x8e75 ?\x94b7]
+    [?\x8ff6 ?\xe2fb] [?\xf212 ?\x2b64] [?\x8888 ?\xb812] [?\x900d ?\xf01c]
+    [?\x4fad ?\x5ea0] [?\x688f ?\xc31c] [?\xd1cf ?\xf191] [?\xb3a8 ?\xc1ad]
+    [?\x2f2f ?\x2218] [?\xbe0e ?\x1777] [?\xea75 ?\x2dfe] [?\x8b02 ?\x1fa1]
+    [?\xe5a0 ?\xcc0f] [?\xb56f ?\x74e8] [?\x18ac ?\xf3d6] [?\xce89 ?\xe299]
+    [?\xb4a8 ?\x4fe0] [?\xfd13 ?\xe0b7] [?\x7cc4 ?\x3b81] [?\xd2ad ?\xa8d9]
+    [?\x165f ?\xa266] [?\x8095 ?\x7705] [?\x93cc ?\x7314] [?\x211a ?\x1477]
+    [?\xe6ad ?\x2065] [?\x77b5 ?\xfa86] [?\xc754 ?\x42f5] [?\xfb9d ?\x35cf]
+    [?\xebcd ?\xaf0c] [?\x7b3e ?\x89a0] [?\xd641 ?\x1bd3] [?\xae1e ?\x7e49]
+    [?\x0025 ?\x0e2d] [?\x2071 ?\xb35e] [?\x2268 ?\x00bb] [?\x57b8 ?\xe0af]
+    [?\x2464 ?\x369b] [?\xf009 ?\xb91e] [?\x5563 ?\x911d] [?\x59df ?\xa6aa]
+    [?\x78c1 ?\x4389] [?\xd95a ?\x537f] [?\x207d ?\x5ba2] [?\x02e5 ?\xb9c5]
+    [?\x8326 ?\x0376] [?\x6295 ?\xcfa9] [?\x11c8 ?\x1968] [?\x4e73 ?\x4a41]
+    [?\xb347 ?\x2dca] [?\x7b14 ?\xa94a] [?\x1b51 ?\x0052] [?\x9a53 ?\x2915]
+    [?\xd60f ?\x573f] [?\xbc9b ?\xc6e4] [?\x2b60 ?\xa476] [?\x81e6 ?\x7400]
+    [?\x08ba ?\x6fb5] [?\x571b ?\xe91f] [?\xf296 ?\xec6b] [?\x2a0d ?\xd915]
+    [?\xb663 ?\x6521] [?\xe7b9 ?\xf9b6] [?\xff34 ?\x052e] [?\xc585 ?\x5664]
+    [?\x53b0 ?\x2d5d] [?\xa99f ?\x8fa1] [?\x08ba ?\x4799] [?\x6e85 ?\x076a]
+    ]
+   [
+   [?\x4b7a ?\x70e9] [?\xb5b3 ?\x2944] [?\xdb75 ?\x092e] [?\xc419 ?\x2623]
+   [?\xad6e ?\xa6b0] [?\x49a7 ?\xdf7d] [?\x9cee ?\x60b8] [?\x8fed ?\xb266]
+   [?\xecaa ?\x8c71] [?\x699a ?\x17ff] [?\x5664 ?\x526c] [?\xc2b1 ?\x9ee1]
+   [?\x1936 ?\x02a5] [?\x7509 ?\x4c29] [?\xa059 ?\x1340] [?\xe418 ?\x3a3e]
+   [?\x3f54 ?\x989a] [?\x5b42 ?\x9d65] [?\x6b8f ?\xe4d6] [?\x99f7 ?\x3fd6]
+   [?\xa1d2 ?\x9c07] [?\xefe8 ?\x30f5] [?\x4d2d ?\x38e6] [?\xf025 ?\x5dc1]
+   [?\x4cdd ?\x2086] [?\x8470 ?\xeb26] [?\x6382 ?\xe9c6] [?\x021e ?\xcc5e]
+   [?\x0968 ?\x6b3f] [?\x3eba ?\xefc9] [?\x3c97 ?\x1814] [?\x6b6a ?\x70a1]
+   [?\x687f ?\x3584] [?\x52a0 ?\xe286] [?\xb79c ?\x5305] [?\xaa50 ?\x0737]
+   [?\x3e07 ?\x841c] [?\x7fde ?\xae5c] [?\x8e7d ?\x44ec] [?\x5716 ?\xf2b8]
+   [?\xb03a ?\xda37] [?\xf050 ?\x0c0d] [?\xf01c ?\x1f04] [?\x0200 ?\xb3ff]
+   [?\xae0c ?\xf51a] [?\x3cb5 ?\x74b2] [?\x2583 ?\x7a58] [?\xdc09 ?\x21bd]
+   [?\xd191 ?\x13f9] [?\x7ca9 ?\x2ff6] [?\x9432 ?\x4773] [?\x22f5 ?\x4701]
+   [?\x3ae5 ?\xe581] [?\x37c2 ?\xdadc] [?\xc8b5 ?\x7634] [?\x9af3 ?\xdda7]
+   [?\xa944 ?\x6146] [?\x0fd0 ?\x030e] [?\xecc8 ?\xc73e] [?\xa475 ?\x1e41]
+   [?\xe238 ?\xcd99] [?\x3bea ?\x0e2f] [?\x3280 ?\xbba1] [?\x183e ?\xb331]
+   [?\x4e54 ?\x8b38] [?\x4f6d ?\xb908] [?\x6f42 ?\x0d03] [?\xf60a ?\x04bf]
+   [?\x2cb8 ?\x1290] [?\x2497 ?\x7c79] [?\x5679 ?\xb072] [?\xbcaf ?\x89af]
+   [?\xde9a ?\x771f] [?\xd993 ?\x0810] [?\xb38b ?\xae12] [?\xdccf ?\x3f2e]
+   [?\x5512 ?\x721f] [?\x2e6b ?\x7124] [?\x501a ?\xdde6] [?\x9f84 ?\xcd87]
+   [?\x7a58 ?\x4718] [?\x7408 ?\xda17] [?\xbc9f ?\x9abc] [?\xe94b ?\x7d8c]
+   [?\xec7a ?\xec3a] [?\xdb85 ?\x1dfa] [?\x6309 ?\x4366] [?\xc464 ?\xc3d2]
+   [?\xef1c ?\x1847] [?\x3215 ?\xd908] [?\xdd43 ?\x3b37] [?\x24c2 ?\xba16]
+   [?\x12a1 ?\x4d43] [?\x2a65 ?\xc451] [?\x5094 ?\x0002] [?\x133a ?\xe4dd]
+   [?\x71df ?\xf89e] [?\x1031 ?\x4e55] [?\x81ac ?\x77d6] [?\x5f11 ?\x199b]
+   [?\x0435 ?\x56f1] [?\xd7a3 ?\xc76b] [?\x3c11 ?\x183b] [?\x5924 ?\xa509]
+   [?\xf28f ?\xe6ed] [?\x97f1 ?\xfbfa] [?\x9eba ?\xbf2c] [?\x1e15 ?\x3c6e]
+   [?\x86e3 ?\x4570] [?\xeae9 ?\x6fb1] [?\x860e ?\x5e0a] [?\x5a3e ?\x2ab3]
+   [?\x771f ?\xe71c] [?\x4e3d ?\x06fa] [?\x2965 ?\xdcb9] [?\x99e7 ?\x1d0f]
+   [?\x803e ?\x89d6] [?\x5266 ?\xc825] [?\x2e4c ?\xc978] [?\x9c10 ?\xb36a]
+   [?\xc615 ?\x0eba] [?\x94e2 ?\xea78] [?\xa5fc ?\x3c53] [?\x1e0a ?\x2df4]
+   [?\xf2f7 ?\x4ea7] [?\x361d ?\x2b3d] [?\x1939 ?\x260f] [?\x19c2 ?\x7960]
+   [?\x5223 ?\xa708] [?\xf713 ?\x12b6] [?\xebad ?\xfe6e] [?\xeac3 ?\x1f66]
+   [?\xe3bc ?\x4595] [?\xa67b ?\xc883] [?\xb17f ?\x37d1] [?\x018c ?\xff28]
+   [?\xc332 ?\xddef] [?\xbe6c ?\x5aa5] [?\x6558 ?\x2185] [?\x68ab ?\x9802]
+   [?\xeece ?\xa50f] [?\xdb2f ?\x953b] [?\x2aef ?\x7dad] [?\x5b6e ?\x2f84]
+   [?\x1521 ?\xb628] [?\x2907 ?\x6170] [?\xecdd ?\x4775] [?\x619f ?\x1510]
+   [?\x13cc ?\xa830] [?\xeb61 ?\xbd96] [?\x0334 ?\xfe1e] [?\xaa03 ?\x63cf]
+   [?\xb573 ?\x5c90] [?\x4c70 ?\xa239] [?\xd59e ?\x9e0b] [?\xcbaa ?\xde14]
+   [?\xeecc ?\x86bc] [?\x6062 ?\x2ca7] [?\x9cab ?\x5cab] [?\xb2f3 ?\x846e]
+   [?\x648b ?\x1eaf] [?\x19bd ?\xf0ca] [?\xa023 ?\x69b9] [?\x655a ?\xbb50]
+   [?\x4068 ?\x5a32] [?\x3c2a ?\xb4b3] [?\x319e ?\xe9d5] [?\xc021 ?\xb8f7]
+   [?\x9b54 ?\x0b19] [?\x875f ?\xa099] [?\x95f7 ?\x997e] [?\x623d ?\x7da8]
+   [?\xf837 ?\x889a] [?\x97e3 ?\x2d77] [?\x11ed ?\x935f] [?\x1668 ?\x1281]
+   [?\x0e35 ?\x8829] [?\xc7e6 ?\x1fd6] [?\x96de ?\xdfa1] [?\x7858 ?\xba99]
+   [?\x57f5 ?\x84a5] [?\x1b22 ?\x7263] [?\x9b83 ?\xc3ff] [?\x1ac2 ?\x4696]
+   [?\xcdb3 ?\x0aeb] [?\x532e ?\x3054] [?\x8fd9 ?\x48e4] [?\x6dbc ?\x3128]
+   [?\x58eb ?\xf2ef] [?\x34c6 ?\xffea] [?\xfe28 ?\xed61] [?\xee7c ?\x3c73]
+   [?\x5d4a ?\x14d9] [?\xe864 ?\xb7e3] [?\x4210 ?\x5d14] [?\x203e ?\x13e0]
+   [?\x45ee ?\xe2b6] [?\xa3aa ?\xabea] [?\xdb6c ?\x4f15] [?\xfacb ?\x4fd0]
+   [?\xc742 ?\xf442] [?\xef6a ?\xbbb5] [?\x654f ?\x3b1d] [?\x41cd ?\x2105]
+   [?\xd81e ?\x799e] [?\x8685 ?\x4dc7] [?\xe44b ?\x476a] [?\x3d81 ?\x6250]
+   [?\xcf62 ?\xa1f2] [?\x5b8d ?\x2646] [?\xfc88 ?\x83a0] [?\xc1c7 ?\xb6a3]
+   [?\x7f15 ?\x24c3] [?\x69cb ?\x7492] [?\x4784 ?\x8a0b] [?\x5692 ?\xb285]
+   [?\x095b ?\xbf00] [?\xad19 ?\x489d] [?\x1462 ?\xb174] [?\x2382 ?\x0e00]
+   [?\x5842 ?\x8d2a] [?\x0c55 ?\xf5ea] [?\x1dad ?\xf43e] [?\x233f ?\x7061]
+   [?\x3372 ?\xf092] [?\x8d93 ?\x7e41] [?\xd65f ?\xecf1] [?\x6c22 ?\x3bdb]
+   [?\x7cde ?\x3759] [?\xcbee ?\x7460] [?\x4085 ?\xf2a7] [?\xce77 ?\x326e]
+   [?\xa607 ?\x8084] [?\x19f8 ?\x509e] [?\xe8ef ?\xd855] [?\x61d9 ?\x9735]
+   [?\xa969 ?\xa7aa] [?\xc50c ?\x06c2] [?\x5a04 ?\xabfc] [?\x800b ?\xcadc]
+   [?\x9e44 ?\x7a2e] [?\xc345 ?\x3484] [?\xfdd5 ?\x6705] [?\x0e1e ?\x9ec9]
+   [?\xdb73 ?\xdbd3] [?\x1055 ?\x88cd] [?\x675f ?\xda79] [?\xe367 ?\x4340]
+   [?\xc5c4 ?\x3465] [?\x713e ?\x38d8] [?\x3d28 ?\xf89e] [?\xf16d ?\xff20]
+   [?\x153e ?\x21e7] [?\x8fb0 ?\x3d4a] [?\xe6e3 ?\x9f2b] [?\xdb83 ?\xadf7]
+   ]
+   [
+   [?\xe93d ?\x5a68] [?\x9481 ?\x40f7] [?\xf64c ?\x261c] [?\x9469 ?\x2934]
+   [?\x4115 ?\x20f7] [?\x7602 ?\xd4f7] [?\xbcf4 ?\x6b2e] [?\xd4a2 ?\x0068]
+   [?\xd408 ?\x2471] [?\x3320 ?\xf46a] [?\x43b7 ?\xd4b7] [?\x5000 ?\x61af]
+   [?\x1e39 ?\xf62e] [?\x9724 ?\x4546] [?\x1421 ?\x4f74] [?\xbf8b ?\x8840]
+   [?\x4d95 ?\xfc1d] [?\x96b5 ?\x91af] [?\x70f4 ?\xddd3] [?\x66a0 ?\x2f45]
+   [?\xbfbc ?\x09ec] [?\x03bd ?\x9785] [?\x7fac ?\x6dd0] [?\x31cb ?\x8504]
+   [?\x96eb ?\x27b3] [?\x55fd ?\x3941] [?\xda25 ?\x47e6] [?\xabca ?\x0a9a]
+   [?\x2850 ?\x7825] [?\x5304 ?\x29f4] [?\x0a2c ?\x86da] [?\xe9b6 ?\x6dfb]
+   [?\x68dc ?\x1462] [?\xd748 ?\x6900] [?\x680e ?\xc0a4] [?\x27a1 ?\x8dee]
+   [?\x4f3f ?\xfea2] [?\xe887 ?\xad8c] [?\xb58c ?\xe006] [?\x7af4 ?\xd6b6]
+   [?\xaace ?\x1e7c] [?\xd337 ?\x5fec] [?\xce78 ?\xa399] [?\x406b ?\x2a42]
+   [?\x20fe ?\x9e35] [?\xd9f3 ?\x85b9] [?\xee39 ?\xd7ab] [?\x3b12 ?\x4e8b]
+   [?\x1dc9 ?\xfaf7] [?\x4b6d ?\x1856] [?\x26a3 ?\x6631] [?\xeae3 ?\x97b2]
+   [?\x3a6e ?\xfa74] [?\xdd5b ?\x4332] [?\x6841 ?\xe7f7] [?\xca78 ?\x20fb]
+   [?\xfb0a ?\xf54e] [?\xd8fe ?\xb397] [?\x4540 ?\x56ac] [?\xba48 ?\x9527]
+   [?\x5553 ?\x3a3a] [?\x2083 ?\x8d87] [?\xfe6b ?\xa9b7] [?\xd096 ?\x954b]
+   [?\x55a8 ?\x67bc] [?\xa115 ?\x9a58] [?\xcca9 ?\x2963] [?\x99e1 ?\xdb33]
+   [?\xa62a ?\x4a56] [?\x3f31 ?\x25f9] [?\x5ef4 ?\x7e1c] [?\x9029 ?\x317c]
+   [?\xfdf8 ?\xe802] [?\x0427 ?\x2f70] [?\x80bb ?\x155c] [?\x0528 ?\x2ce3]
+   [?\x95c1 ?\x1548] [?\xe4c6 ?\x6d22] [?\x48c1 ?\x133f] [?\xc70f ?\x86dc]
+   [?\x07f9 ?\xc9ee] [?\x4104 ?\x1f0f] [?\x4047 ?\x79a4] [?\x5d88 ?\x6e17]
+   [?\x325f ?\x51eb] [?\xd59b ?\xc0d1] [?\xf2bc ?\xc18f] [?\x4111 ?\x3564]
+   [?\x257b ?\x7834] [?\x602a ?\x9c60] [?\xdff8 ?\xe8a3] [?\x1f63 ?\x6c1b]
+   [?\x0e12 ?\xb4c2] [?\x02e1 ?\x329e] [?\xaf66 ?\x4fd1] [?\xcad1 ?\x8115]
+   [?\x6b23 ?\x95e0] [?\x333e ?\x92e1] [?\x3b24 ?\x0b62] [?\xeebe ?\xb922]
+   [?\x85b2 ?\xa20e] [?\xe6ba ?\x0d99] [?\xde72 ?\x0c8c] [?\x2da2 ?\xf728]
+   [?\xd012 ?\x7845] [?\x95b7 ?\x94fd] [?\x647d ?\x0862] [?\xe7cc ?\xf5f0]
+   [?\x5449 ?\xa36f] [?\x877d ?\x48fa] [?\xc39d ?\xfd27] [?\xf33e ?\x8d1e]
+   [?\x0a47 ?\x6341] [?\x992e ?\xff74] [?\x3a6f ?\x6eab] [?\xf4f8 ?\xfd37]
+   [?\xa812 ?\xdc60] [?\xa1eb ?\xddf8] [?\x991b ?\xe14c] [?\xdb6e ?\x6b0d]
+   [?\xc67b ?\x5510] [?\x6d67 ?\x2c37] [?\x2765 ?\xd43b] [?\xdcd0 ?\xe804]
+   [?\xf129 ?\x0dc7] [?\xcc00 ?\xffa3] [?\xb539 ?\x0f92] [?\x690f ?\xed0b]
+   [?\x667b ?\x9ffb] [?\xcedb ?\x7d9c] [?\xa091 ?\xcf0b] [?\xd915 ?\x5ea3]
+   [?\xbb13 ?\x2f88] [?\x515b ?\xad24] [?\x7b94 ?\x79bf] [?\x763b ?\xd6eb]
+   [?\x3739 ?\x2eb3] [?\xcc11 ?\x5979] [?\x8026 ?\xe297] [?\xf42e ?\x312d]
+   [?\x6842 ?\xada7] [?\xc66a ?\x2b3b] [?\x1275 ?\x4ccc] [?\x782e ?\xf11c]
+   [?\x6a12 ?\x4237] [?\xb792 ?\x51e7] [?\x06a1 ?\xbbe6] [?\x4bfb ?\x6350]
+   [?\x1a6b ?\x1018] [?\x11ca ?\xedfa] [?\x3d25 ?\xbdd8] [?\xe2e1 ?\xc3c9]
+   [?\x4442 ?\x1659] [?\x0a12 ?\x1386] [?\xd90c ?\xec6e] [?\xd5ab ?\xea2a]
+   [?\x64af ?\x674e] [?\xda86 ?\xa85f] [?\xbebf ?\xe988] [?\x64e4 ?\xc3fe]
+   [?\x9dbc ?\x8057] [?\xf0f7 ?\xc086] [?\x6078 ?\x7bf8] [?\x6003 ?\x604d]
+   [?\xd1fd ?\x8346] [?\xf638 ?\x1fb0] [?\x7745 ?\xae04] [?\xd736 ?\xfccc]
+   [?\x8342 ?\x6b33] [?\xf01e ?\xab71] [?\xb080 ?\x4187] [?\x3c00 ?\x5e5f]
+   [?\x77a0 ?\x57be] [?\xbde8 ?\xae24] [?\x5546 ?\x4299] [?\xbf58 ?\x2e61]
+   [?\x4e58 ?\xf48f] [?\xf2dd ?\xfda2] [?\xf474 ?\xef38] [?\x8789 ?\xbdc2]
+   [?\x5366 ?\xf9c3] [?\xc8b3 ?\x8e74] [?\xb475 ?\xf255] [?\x46fc ?\xd9b9]
+   [?\x7aeb ?\x2661] [?\x8b1d ?\xdf84] [?\x846a ?\x0e79] [?\x915f ?\x95e2]
+   [?\x466e ?\x598e] [?\x20b4 ?\x5770] [?\x8cd5 ?\x5591] [?\xc902 ?\xde4c]
+   [?\xb90b ?\xace1] [?\xbb82 ?\x05d0] [?\x11a8 ?\x6248] [?\x7574 ?\xa99e]
+   [?\xb77f ?\x19b6] [?\xe0a9 ?\xdc09] [?\x662d ?\x09a1] [?\xc432 ?\x4633]
+   [?\xe85a ?\x1f02] [?\x09f0 ?\xbe8c] [?\x4a99 ?\xa025] [?\x1d6e ?\xfe10]
+   [?\x1ab9 ?\x3d1d] [?\x0ba5 ?\xa4df] [?\xa186 ?\xf20f] [?\x2868 ?\xf169]
+   [?\xdcb7 ?\xda83] [?\x5739 ?\x06fe] [?\xa1e2 ?\xce9b] [?\x4fcd ?\x7f52]
+   [?\x5011 ?\x5e01] [?\xa706 ?\x83fa] [?\xa002 ?\xb5c4] [?\x0de6 ?\xd027]
+   [?\x9af8 ?\x8c27] [?\x773f ?\x8641] [?\xc360 ?\x4c06] [?\x61a8 ?\x06b5]
+   [?\xf017 ?\x7a28] [?\xc0f5 ?\x86e0] [?\x0060 ?\x58aa] [?\x30dc ?\x7d62]
+   [?\x11e6 ?\x9ed7] [?\x2338 ?\xea63] [?\x53c2 ?\xdd94] [?\xc2c2 ?\x1634]
+   [?\xbbcb ?\xee56] [?\x90bc ?\xb6de] [?\xebfc ?\x7da1] [?\xce59 ?\x1d76]
+   [?\x6f05 ?\xe409] [?\x4b7c ?\x0188] [?\x3972 ?\x0a3d] [?\x7c92 ?\x7c24]
+   [?\x86e3 ?\x725f] [?\x724d ?\x9db9] [?\x1ac1 ?\x5bb4] [?\xd39e ?\xb8fc]
+   [?\xed54 ?\x5578] [?\x08fc ?\xa5b5] [?\xd83d ?\x7cd3] [?\x4dad ?\x0fc4]
+   [?\x1e50 ?\xef5e] [?\xb161 ?\xe6f8] [?\xa285 ?\x14d9] [?\x6c51 ?\x133c]
+   [?\x6fd5 ?\xc7e7] [?\x56e1 ?\x4ec4] [?\x362a ?\xbfce] [?\xddc6 ?\xc837]
+   [?\xd79a ?\x3234] [?\x9263 ?\x8212] [?\x670e ?\xfa8e] [?\x4060 ?\x00e0]
+   ]
+   [
+   [?\x3a39 ?\xce37] [?\xd3fa ?\xf5cf] [?\xabc2 ?\x7737] [?\x5ac5 ?\x2d1b]
+   [?\x5cb0 ?\x679e] [?\x4fa3 ?\x3742] [?\xd382 ?\x2740] [?\x99bc ?\x9bbe]
+   [?\xd511 ?\x8e9d] [?\xbf0f ?\x7315] [?\xd62d ?\x1c7e] [?\xc700 ?\xc47b]
+   [?\xb78c ?\x1b6b] [?\x21a1 ?\x9045] [?\xb26e ?\xb1be] [?\x6a36 ?\x6eb4]
+   [?\x5748 ?\xab2f] [?\xbc94 ?\x6e79] [?\xc6a3 ?\x76d2] [?\x6549 ?\xc2c8]
+   [?\x530f ?\xf8ee] [?\x468d ?\xde7d] [?\xd573 ?\x0a1d] [?\x4cd0 ?\x4dc6]
+   [?\x2939 ?\xbbdb] [?\xa9ba ?\x4650] [?\xac95 ?\x26e8] [?\xbe5e ?\xe304]
+   [?\xa1fa ?\xd5f0] [?\x6a2d ?\x519a] [?\x63ef ?\x8ce2] [?\x9a86 ?\xee22]
+   [?\xc089 ?\xc2b8] [?\x4324 ?\x2ef6] [?\xa51e ?\x03aa] [?\x9cf2 ?\xd0a4]
+   [?\x83c0 ?\x61ba] [?\x9be9 ?\x6a4d] [?\x8fe5 ?\x1550] [?\xba64 ?\x5bd6]
+   [?\x2826 ?\xa2f9] [?\xa73a ?\x3ae1] [?\x4ba9 ?\x9586] [?\xef55 ?\x62e9]
+   [?\xc72f ?\xefd3] [?\xf752 ?\xf7da] [?\x3f04 ?\x6f69] [?\x77fa ?\x0a59]
+   [?\x80e4 ?\xa915] [?\x87b0 ?\x8601] [?\x9b09 ?\xe6ad] [?\x3b3e ?\xe593]
+   [?\xe990 ?\xfd5a] [?\x9e34 ?\xd797] [?\x2cf0 ?\xb7d9] [?\x022b ?\x8b51]
+   [?\x96d5 ?\xac3a] [?\x017d ?\xa67d] [?\xd1cf ?\x3ed6] [?\x7c7d ?\x2d28]
+   [?\x1f9f ?\x25cf] [?\xadf2 ?\xb89b] [?\x5ad6 ?\xb472] [?\x5a88 ?\xf54c]
+   [?\xe029 ?\xac71] [?\xe019 ?\xa5e6] [?\x47b0 ?\xacfd] [?\xed93 ?\xfa9b]
+   [?\xe8d3 ?\xc48d] [?\x283b ?\x57cc] [?\xf8d5 ?\x6629] [?\x7913 ?\x2e28]
+   [?\x785f ?\x0191] [?\xed75 ?\x6055] [?\xf796 ?\x0e44] [?\xe3d3 ?\x5e8c]
+   [?\x1505 ?\x6dd4] [?\x88f4 ?\x6dba] [?\x03a1 ?\x6125] [?\x0564 ?\xf0bd]
+   [?\xc3eb ?\x9e15] [?\x3c90 ?\x57a2] [?\x9727 ?\x1aec] [?\xa93a ?\x072a]
+   [?\x1b3f ?\x6d9b] [?\x1e63 ?\x21f5] [?\xf59c ?\x66fb] [?\x26dc ?\xf319]
+   [?\x7533 ?\xd928] [?\xb155 ?\xfdf5] [?\x0356 ?\x3482] [?\x8aba ?\x3cbb]
+   [?\x2851 ?\x7711] [?\xc20a ?\xd9f8] [?\xabcc ?\x5167] [?\xccad ?\x925f]
+   [?\x4de8 ?\x1751] [?\x3830 ?\xdc8e] [?\x379d ?\x5862] [?\x9320 ?\xf991]
+   [?\xea7a ?\x90c2] [?\xfb3e ?\x7bce] [?\x5121 ?\xce64] [?\x774f ?\xbe32]
+   [?\xa8b6 ?\xe37e] [?\xc329 ?\x3d46] [?\x48de ?\x5369] [?\x6413 ?\xe680]
+   [?\xa2ae ?\x0810] [?\xdd6d ?\xb224] [?\x6985 ?\x2dfd] [?\x0907 ?\x2166]
+   [?\xb39a ?\x460a] [?\x6445 ?\xc0dd] [?\x586c ?\xdecf] [?\x1c20 ?\xc8ae]
+   [?\x5bbe ?\xf7dd] [?\x1b58 ?\x8d40] [?\xccd2 ?\x017f] [?\x6bb4 ?\xe3bb]
+   [?\xdda2 ?\x6a7e] [?\x3a59 ?\xff45] [?\x3e35 ?\x0a44] [?\xbcb4 ?\xcdd5]
+   [?\x72ea ?\xcea8] [?\xfa64 ?\x84bb] [?\x8d66 ?\x12ae] [?\xbf3c ?\x6f47]
+   [?\xd29b ?\xe463] [?\x542f ?\x5d9e] [?\xaec2 ?\x771b] [?\xf64e ?\x6370]
+   [?\x740e ?\x0d8d] [?\xe75b ?\x1357] [?\xf872 ?\x1671] [?\xaf53 ?\x7d5d]
+   [?\x4040 ?\xcb08] [?\x4eb4 ?\xe2cc] [?\x34d2 ?\x466a] [?\x0115 ?\xaf84]
+   [?\xe1b0 ?\x0428] [?\x9598 ?\x3a1d] [?\x06b8 ?\x9fb4] [?\xce6e ?\xa048]
+   [?\x6f3f ?\x3b82] [?\x3520 ?\xab82] [?\x011a ?\x1d4b] [?\x2772 ?\x27f8]
+   [?\x6115 ?\x60b1] [?\xe793 ?\x3fdc] [?\xbb3a ?\x792b] [?\x3445 ?\x25bd]
+   [?\xa088 ?\x39e1] [?\x51ce ?\x794b] [?\x2f32 ?\xc9b7] [?\xa01f ?\xbac9]
+   [?\xe01c ?\xc87e] [?\xbcc7 ?\xd1f6] [?\xcf01 ?\x11c3] [?\xa1e8 ?\xaac7]
+   [?\x1a90 ?\x8749] [?\xd44f ?\xbd9a] [?\xd0da ?\xdecb] [?\xd50a ?\xda38]
+   [?\x0339 ?\xc32a] [?\xc691 ?\x3667] [?\x8df9 ?\x317c] [?\xe0b1 ?\x2b4f]
+   [?\xf79e ?\x59b7] [?\x43f5 ?\xbb3a] [?\xf2d5 ?\x19ff] [?\x27d9 ?\x459c]
+   [?\xbf97 ?\x222c] [?\x15e6 ?\xfc2a] [?\x0f91 ?\xfc71] [?\x9b94 ?\x1525]
+   [?\xfae5 ?\x9361] [?\xceb6 ?\x9ceb] [?\xc2a8 ?\x6459] [?\x12ba ?\xa8d1]
+   [?\xb6c1 ?\x075e] [?\xe305 ?\x6a0c] [?\x10d2 ?\x5065] [?\xcb03 ?\xa442]
+   [?\xe0ec ?\x6e0e] [?\x1698 ?\xdb3b] [?\x4c98 ?\xa0be] [?\x3278 ?\xe964]
+   [?\x9f1f ?\x9532] [?\xe0d3 ?\x92df] [?\xd3a0 ?\x342b] [?\x8971 ?\xf21e]
+   [?\x1b0a ?\x7441] [?\x4ba3 ?\x348c] [?\xc5be ?\x7120] [?\xc376 ?\x32d8]
+   [?\xdf35 ?\x9f8d] [?\x9b99 ?\x2f2e] [?\xe60b ?\x6f47] [?\x0fe3 ?\xf11d]
+   [?\xe54c ?\xda54] [?\x1eda ?\xd891] [?\xce62 ?\x79cf] [?\xcd3e ?\x7e6f]
+   [?\x1618 ?\xb166] [?\xfd2c ?\x1d05] [?\x848f ?\xd2c5] [?\xf6fb ?\x2299]
+   [?\xf523 ?\xf357] [?\xa632 ?\x7623] [?\x93a8 ?\x3531] [?\x56cc ?\xcd02]
+   [?\xacf0 ?\x8162] [?\x5a75 ?\xebb5] [?\x6e16 ?\x3697] [?\x88d2 ?\x73cc]
+   [?\xde96 ?\x6292] [?\x81b9 ?\x49d0] [?\x4c50 ?\x901b] [?\x71c6 ?\x5614]
+   [?\xe6c6 ?\xc7bd] [?\x327a ?\x140a] [?\x45e1 ?\xd006] [?\xc3f2 ?\x7b9a]
+   [?\xc9aa ?\x53fd] [?\x62a8 ?\x0f00] [?\xbb25 ?\xbfe2] [?\x35bd ?\xd2f6]
+   [?\x7112 ?\x6905] [?\xb204 ?\x0222] [?\xb6cb ?\xcf7c] [?\xcd76 ?\x9c2b]
+   [?\x5311 ?\x3ec0] [?\x1640 ?\xe3d3] [?\x38ab ?\xbd60] [?\x2547 ?\xadf0]
+   [?\xba38 ?\x209c] [?\xf746 ?\xce76] [?\x77af ?\xa1c5] [?\x2075 ?\x6060]
+   [?\x85cb ?\xfe4e] [?\x8ae8 ?\x8dd8] [?\x7aaa ?\xf9b0] [?\x4cf9 ?\xaa7e]
+   [?\x1948 ?\xc25c] [?\x02fb ?\x8a8c] [?\x01c3 ?\x6ae4] [?\xd6eb ?\xe1f9]
+   [?\x90d4 ?\xf869] [?\xa65c ?\xdea0] [?\x3f09 ?\x252d] [?\xc208 ?\xe69f]
+   [?\xb74e ?\x6132] [?\xce77 ?\xe25b] [?\x578f ?\xdfe3] [?\x3ac3 ?\x72e6]
+   ]])
+
+(defconst blowfish-p-array-inits 
+  [
+   [?\x243f ?\x6a88] [?\x85a3 ?\x08d3] [?\x1319 ?\x8a2e] [?\x0370 ?\x7344]
+   [?\xa409 ?\x3822] [?\x299f ?\x31d0] [?\x082e ?\xfa98] [?\xec4e ?\x6c89]
+   [?\x4528 ?\x21e6] [?\x38d0 ?\x1377] [?\xbe54 ?\x66cf] [?\x34e9 ?\x0c6c]
+   [?\xc0ac ?\x29b7] [?\xc97c ?\x50dd] [?\x3f84 ?\xd5b5] [?\xb547 ?\x0917]
+   [?\x9216 ?\xd5d9] [?\x8979 ?\xfb1b]
+   ])
+
+(defun blowfish-generate-keys (key)
+  "given a key vector \(an even number of 16-bit integers\), returns
+the p-array and s-boxes for Blowfish encryption using that key, as a
+pair: \(P-array . S-boxes\)."
+  (let ((s-boxes (vector (make-vector 256 nil)
+			 (make-vector 256 nil)
+			 (make-vector 256 nil)
+			 (make-vector 256 nil)))
+	(p-array (make-vector 18 nil)))
+    ;; copy the initial values into the s-boxes
+    (dotimes (s 4)
+      (let ((s-box (aref s-boxes s))
+	    (inits (aref blowfish-s-box-inits s)))
+	(dotimes (idx 256)
+	  (aset s-box idx (copy-seq (aref inits idx))))))
+    ;; copy the initial values into the p-array
+    (dotimes (idx 18)
+      (aset p-array idx (copy-seq (aref blowfish-p-array-inits idx))))
+
+    ;; mix the key into the P-array
+    (let ((keylen (length key)))
+      (assert (and (>= keylen 2) (evenp keylen)) nil
+	      "Blowfish key must be a positive multiple of 2 elements long.")
+
+      (dotimes (idx 18)
+	(let* ((keyidx (mod (* 2 idx) keylen))
+	       (keyval (vector (aref key keyidx) 
+			       (aref key (1+ keyidx))))
+	       (p-entry (aref p-array idx)))
+	  (blowfish-xor p-entry keyval p-entry)
+	  ;; clean up
+	  (fillarray keyval 0))))
+
+    ;; begin the iterated filling of the P-array and S-boxes
+    (let ((data (vector 0 0 0 0)))
+      ;; fill the P-array
+      (do ((idx 0 (+ idx 2)))
+	  ((= idx 18))
+	;; encipher data w/ the current P-array and S-boxes
+	(blowfish-cipher-block data p-array s-boxes)
+	;; replace the next two P-array elements with the new data
+	(let ((Pa (aref p-array idx))
+	      (Pb (aref p-array (1+ idx))))
+	  (aset Pa 0 (aref data 0))
+	  (aset Pa 1 (aref data 1))
+	  (aset Pb 0 (aref data 2))
+	  (aset Pb 1 (aref data 3))))
+
+      ;; fill the S-boxes
+      (dotimes (s 4)
+	(do ((idx 0 (+ idx 2))
+	     (s-box (aref s-boxes s)))
+	    ((= idx 256))
+	  ;; encipher data w/ the current P-array and S-boxes
+	  (blowfish-cipher-block data p-array s-boxes)
+	  ;; replace the next two S-box elements with the new data
+	  (let ((Sa (aref s-box idx))
+		(Sb (aref s-box (1+ idx))))
+	    (aset Sa 0 (aref data 0))
+	    (aset Sa 1 (aref data 1))
+	    (aset Sb 0 (aref data 2))
+	    (aset Sb 1 (aref data 3)))))
+
+      ;; clean up
+      (fillarray data 0))
+      
+    ;; return the result
+    (cons p-array s-boxes)))
+;;;  des.el - Data Encryption Standard block cipher, including 3DES
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: DES, 3DES, oink, cipher, cypher, cryptography
+;; Created: 1998-04-01
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; this is not optimized at all, yet.  it uses vectors of boolean
+;; values.  changing it to use 16-bit integers instead might be
+;; faster, though the permutation functions will be quite a bit more
+;; confusing.
+
+;; this code was written using des-how-to.txt, by Matthew Fischer
+;; (mfischer@blue.weeg.uiowa.edu)
+
+;;; TODO:
+
+;; add DESX
+;; add DES/SK (anyone that knows what DES/SK is, please mail me)
+;; add DES with key-dependent S-boxes (a la Biham, see Schneier)
+
+;;; Code:
+
+(require 'cl)
+
+(defun hexstring-to-bitvec (string)
+  "convert a hexadecimal string into a MSB-first bit vector"
+  (let* ((strlen (length string))
+         (bitlen (* 4 strlen))
+         (bvec (make-vector bitlen nil)))
+    (do ((stridx 0 (1+ stridx))
+         (bitidx 0 (+ bitidx 4)))
+        ((= stridx strlen) bvec)
+      (let* ((char (aref string stridx))
+             (val (if (and (<= ?0 char)
+                           (<= char ?9))
+                      (- char ?0)
+                    (+ 10 (- (downcase char) ?a)))))
+        (dotimes (offset 4)
+          (when (/= 0 (logand val
+                              (ash 1 (- 3 offset))))
+            (aset bvec (+ bitidx offset) t)))))))
+
+(defun bitvec-to-hexstring (bitvec)
+  "convert an MSB-first bit vector into a hexadecimal string"
+  (let* ((bitlen (length bitvec))
+         (strlen (car (ceiling* bitlen 4)))
+         (string (make-string strlen ?0)))
+    (do ((stridx 0 (1+ stridx))
+         (bitidx 0 (+ bitidx 4)))
+        ((= stridx strlen) string)
+      (let ((val 0))
+        (dotimes (offset 4)
+          (let ((bidx (+ bitidx offset)))
+            (when (and (< bidx bitlen)
+                       (aref bitvec bidx))
+              (incf val (ash 1 (- 3 offset))))))
+        (aset string stridx (if (< val 10) 
+                                (+ ?0 val)
+                              (+ ?a (- val 10))))))))
+
+(defun des-permute (vec permute-vals)
+  "helper function for permutations in DES code"
+  (let* ((len (length permute-vals))
+         (outvec (make-vector len nil)))
+    (dotimes (offset len outvec)
+      (aset outvec offset (aref vec (aref permute-vals offset))))))
+
+;; note that these are 0-indexed.  most references list these as 1-indexed
+(defconst des-PC1-vals [56 48 40 32 24 16 8 0 57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 62 54 46 38 30 22 14 6 61 53 45 37 29 21 13 5 60 52 44 36 28 20 12 4 27 19 11 3])
+
+(defun des-PC1 (key)
+  "DES permuted choice #1.
+takes a 64-bit key and returns a 56-bit permuted key"
+  (assert (= (length key) 64) nil
+          "des-PC1: key must be 64 bits long")
+  (des-permute key des-PC1-vals))
+
+;; note that these are 0-indexed.  most references list these as 1-indexed
+(defconst des-PC2-vals [13 16 10 23 0 4 2 27 14 5 20 9 22 18 11 3 25 7 15 6 26 19 12 1 40 51 30 36 46 54 29 39 50 44 32 47 43 48 38 55 33 52 45 41 49 35 28 31])
+
+
+(defun des-PC2 (key)
+  "DES permuted choice #2.
+takes a 56-bit key and returns a 48-bit permuted key."
+  (assert (= (length key) 56) nil
+          "des-PC2: key must be 56 bits long")
+  (des-permute key des-PC2-vals))
+
+
+(defun des-<<< (vec shift)
+  "circular left shift VEC by SHIFT elements"
+  (let* ((len (length vec))
+         (outvec (make-vector len nil)))
+    (when (or (>= shift len)
+              (< shift 0))
+      (setq shift (mod shift len)))
+    (do ((out-idx 0 (1+ out-idx))
+         (in-idx shift (1+ in-idx)))
+        ((= in-idx len))
+      (aset outvec out-idx (aref vec in-idx)))
+    (do ((out-idx (- len shift) (1+ out-idx))
+         (in-idx 0 (1+ in-idx)))
+        ((= in-idx shift) outvec)
+      (aset outvec out-idx (aref vec in-idx)))))
+
+
+(defconst des-key-shifts [1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1])
+
+(defun des-compute-subkeys (key)
+  "computes the 16 48-bit subkeys from a 64-bit key"
+  (let* ((subkeys (make-vector 16 []))
+         (PC1 (des-PC1 key))
+         (C (subseq PC1 0 28))
+         (D (subseq PC1 28 56)))
+    ;; clean up
+    (fillarray PC1 nil)
+    ;; compute subkeys
+    (dotimes (count 16)
+      (let* ((new-C (des-<<< C (aref des-key-shifts count)))
+             (new-D (des-<<< D (aref des-key-shifts count)))
+             (CD (vconcat new-C new-D)))
+        (aset subkeys count (des-PC2 CD))
+        ;; clean up
+        (fillarray C nil)
+        (fillarray D nil)
+        ;; replace old with new
+        (setq C new-C)
+        (setq D new-D)))
+    (fillarray C nil)
+    (fillarray D nil)
+    subkeys))
+
+
+
+(defconst des-E-vals [31 0 1 2 3 4 3 4 5 6 7 8 7 8 9 10 11 12 11 12 13 14 15 16 15 16 17 18 19 20 19 20 21 22 23 24 23 24 25 26 27 28 27 28 29 30 31 0])
+
+(defun des-E (vec)
+  "perform the Expansion function on a 32-bit vector"
+  (assert (= (length vec) 32) nil
+          "des-E: vec must be 32 bits long")
+  (des-permute vec des-E-vals))
+
+(defun des-xor-in-place (vec1 vec2)
+  "XOR two bit vectors together, storing in the first"
+  (let ((len (length vec1)))
+    (assert (= len (length vec2)) nil
+            "des-xor: vec1 and vec2 must be of same length")
+    (dotimes (idx len vec1)
+      (aset vec1 idx (not (eq (aref vec1 idx)
+                              (aref vec2 idx)))))))
+
+(defun des-integer-to-bitvec (val)
+  "converts an integer to a 4-bit bit vector (used to construct S-boxes)"
+  (let ((out (make-vector 4 nil)))
+    (dotimes (shift 4 out)
+      (when (= 1 (logand 1 (ash val (- shift 3))))
+        (aset out shift t)))))
+        
+
+(defconst des-S-boxes-vals 
+  [[[14  4 13  1  2 15 11  8  3 10  6 12  5  9  0  7]
+    [ 0 15  7  4 14  2 13  1 10  6 12 11  9  5  3  8]
+    [ 4  1 14  8 13  6  2 11 15 12  9  7  3 10  5  0]
+    [15 12  8  2  4  9  1  7  5 11  3 14 10  0  6 13]]
+ 
+   [[15  1  8 14  6 11  3  4  9  7  2 13 12  0  5 10]
+    [ 3 13  4  7 15  2  8 14 12  0  1 10  6  9 11  5]
+    [ 0 14  7 11 10  4 13  1  5  8 12  6  9  3  2 15]
+    [13  8 10  1  3 15  4  2 11  6  7 12  0  5 14  9]]
+
+   [[10  0  9 14  6  3 15  5  1 13 12  7 11  4  2  8]
+    [13  7  0  9  3  4  6 10  2  8  5 14 12 11 15  1]
+    [13  6  4  9  8 15  3  0 11  1  2 12  5 10 14  7]
+    [ 1 10 13  0  6  9  8  7  4 15 14  3 11  5  2 12]]
+
+   [[ 7 13 14  3  0  6  9 10  1  2  8  5 11 12  4 15]
+    [13  8 11  5  6 15  0  3  4  7  2 12  1 10 14  9]
+    [10  6  9  0 12 11  7 13 15  1  3 14  5  2  8  4]
+    [ 3 15  0  6 10  1 13  8  9  4  5 11 12  7  2 14]]
+
+   [[ 2 12  4  1  7 10 11  6  8  5  3 15 13  0 14  9]
+    [14 11  2 12  4  7 13  1  5  0 15 10  3  9  8  6]
+    [ 4  2  1 11 10 13  7  8 15  9 12  5  6  3  0 14]
+    [11  8 12  7  1 14  2 13  6 15  0  9 10  4  5  3]]
+
+   [[12  1 10 15  9  2  6  8  0 13  3  4 14  7  5 11]
+    [10 15  4  2  7 12  9  5  6  1 13 14  0 11  3  8]
+    [ 9 14 15  5  2  8 12  3  7  0  4 10  1 13 11  6]
+    [ 4  3  2 12  9  5 15 10 11 14  1  7  6  0  8 13]]
+
+   [[ 4 11  2 14 15  0  8 13  3 12  9  7  5 10  6  1]
+    [13  0 11  7  4  9  1 10 14  3  5 12  2 15  8  6]
+    [ 1  4 11 13 12  3  7 14 10 15  6  8  0  5  9  2]
+    [ 6 11 13  8  1  4 10  7  9  5  0 15 14  2  3 12]]
+
+   [[13  2  8  4  6 15 11  1 10  9  3 14  5  0 12  7]
+    [ 1 15 13  8 10  3  7  4 12  5  6 11  0 14  9  2]
+    [ 7 11  4  1  9 12 14  2  0  6 10 13 15  3  5  8]
+    [ 2  1 14  7  4 10  8 13 15 12  9  0  3  5  6 11]]])
+
+(defconst des-S-boxes (map 'vector 
+                           #'(lambda (x) 
+                               (map 'vector
+                                    #'(lambda (y)
+                                        (map 'vector
+                                             #'des-integer-to-bitvec
+                                             y))
+                                    x))
+                           des-S-boxes-vals))
+
+(defun des-S (vec)
+  "do the S substitution on a 48-bit vector, returning a 32-bit vector"
+  (let ((temp-vecs (make-vector 8 nil)))
+    (do ((Sidx 0 (1+ Sidx))
+         (bitidx 0 (+ bitidx 6)))
+        ((= Sidx 8))
+      (let ((val1 (+ (if (aref vec (+ bitidx 0)) 2 0)
+                     (if (aref vec (+ bitidx 5)) 1 0)))
+            (val2 (+ (if (aref vec (+ bitidx 1)) 8 0)
+                     (if (aref vec (+ bitidx 2)) 4 0)
+                     (if (aref vec (+ bitidx 3)) 2 0)
+                     (if (aref vec (+ bitidx 4)) 1 0))))
+        (aset temp-vecs Sidx (aref (aref (aref des-S-boxes Sidx)
+                                         val1)
+                                   val2))))
+    (prog1
+        (apply #'vconcat (coerce temp-vecs 'list))
+      ;; clean up
+      (fillarray temp-vecs nil))))
+
+(defconst des-P-vals [15 6 19 20 28 11 27 16 0 14 22 25 4 17 30 9 1 7 23 13 31 26 2 8 18 12 29 5 21 10 3 24])
+
+(defun des-P (vec)
+  "perform the P permutation on a 32-bit vector"
+  (assert (= (length vec) 32) nil
+          "des-P: vec must be 32 bits long")
+  (des-permute vec des-P-vals))
+
+(defun des-f (vec key)
+  "perform the des f() function on 32-bit VEC and 48-bit KEY"
+  (let* ((E-vec (des-E vec))
+         (S-vec (des-S (des-xor-in-place E-vec key)))
+         (P-vec (des-P S-vec)))
+    (prog1
+        P-vec
+      ;; clean up
+      (fillarray E-vec nil)
+      (fillarray S-vec nil))))
+
+(defconst des-IP-vals [57 49 41 33 25 17 9 1 59 51 43 35 27 19 11 3 61 53 45 37 29 21 13 5 63 55 47 39 31 23 15 7 56 48 40 32 24 16 8 0 58 50 42 34 26 18 10 2 60 52 44 36 28 20 12 4 62 54 46 38 30 22 14 6])
+
+(defun des-IP (vec)
+  "perform the Initial Permutation on a 64-bit data vector"
+  (assert (= (length vec) 64) nil
+          "des-IP: vec must be 64 bits long")
+  (des-permute vec des-IP-vals))
+
+
+(defconst des-IP-inv-vals [39 7 47 15 55 23 63 31 38 6 46 14 54 22 62 30 37 5 45 13 53 21 61 29 36 4 44 12 52 20 60 28 35 3 43 11 51 19 59 27 34 2 42 10 50 18 58 26 33 1 41 9 49 17 57 25 32 0 40 8 48 16 56 24])
+
+(defun des-IP-inv (vec)
+  "perform the inverse of the Initial Permutation on a 64-bit data vector"
+  (assert (= (length vec) 64) nil
+          "des-IP-inv: vec must be 64 bits long")
+  (des-permute vec des-IP-inv-vals))
+
+(defun des-cipher-block (vec subkeys &optional reverse)
+  "perform the DES cipher on a 64-bit VEC using SUBKEYS.
+if optional third arg REVERSE is true, decrypts."
+  (let* ((IP (des-IP vec))
+         (L (subseq IP 0 32))
+         (R (subseq IP 32 64)))
+    ;; clean up
+    (fillarray IP nil)
+
+    (dotimes (count 16)
+      (let ((f-R (des-f R (aref subkeys (if reverse (- 15 count) count))))
+            (old-R R)
+            (old-L L))
+        (setq L old-R)
+        (setq R (des-xor-in-place old-L f-R))
+        ;; clean up
+        (fillarray f-R nil)))
+
+    (let ((RL (vconcat R L)))
+      (prog1
+          (des-IP-inv RL)
+        ;; clean up
+        (fillarray RL nil)
+        (fillarray R nil)
+        (fillarray L nil)))))
+
+(defun des-triple-des (data subkeys1 subkeys2 subkeys3 &optional reverse)
+  "perform the triple-DES encryption on DATA with three sets of subkeys.
+if optional fifth arg REVERSE is true, decrypts."
+  (if (not reverse)
+      (let* ((E1 (des-cipher-block data subkeys1))
+             (E2 (des-cipher-block E1 subkeys2 t))
+             (E3 (des-cipher-block E2 subkeys3)))
+        ;; clean up
+        (fillarray E1 nil)
+        (fillarray E2 nil)
+        E3)
+
+    (let* ((D1 (des-cipher-block data subkeys3 t))
+           (D2 (des-cipher-block D1 subkeys2))
+           (D3 (des-cipher-block D2 subkeys1 t)))
+      ;; clean up
+      (fillarray D1 nil)
+      (fillarray D2 nil)
+      D3)))
+;;;  idea.el -- block cipher
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: IDEA, oink, cipher, cypher, cryptography
+;; Created: 1998-04-01
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; this code probably isn't as efficient as it could be.
+;; neither am i, though.
+
+;;; Code:
+
+(require 'cl)
+
+;; multiplication mod (2^16)+1, chopped to 16 bits
+;; works by splitting multiplicand into two 8 bit parts
+;; note that an argument of 0 is treated as if it were 2^16
+(defun idea-mul (a b)
+  (if (or (= a 0)
+          (= b 0))
+      (logand (- ?\x10001 a b) ?\xffff)
+
+    ;; split a into 8 bit pieces
+    (let* ((low (logand a ?\xff))
+           (high (ash a -8)))
+
+      ;; multiply low and high parts by b
+      (setq low (* low b))
+      (setq high (* high b))
+
+      ;; add overlapped bits of high and low, store in low
+      (setq low (+ low (ash (logand ?\xff high) 8)))
+      
+      ;; shift high so high and low do not overlap
+      (setq high (+ (ash high -8) (ash low -16)))
+      (setq low (logand low ?\xffff))
+
+      ;; product is now (+ (ash high 16) low)
+      
+      ;; optimized mod operation
+      (setq low (- low high))
+      (if (<= low 0)
+          (logand (+ low ?\x10001) ?\xffff)
+        (logand low ?\xffff)))))
+
+;; multiplicative inverse, mod (2^16)+1 (which is prime)
+;; uses extended Euclid algorithm
+(defun idea-mul-inv (x)
+  (if (= x 0)
+      0
+    ;; calculate am + bn = d, d = greatest common divisor of m,n.
+    ;; if m is prime, then b and n are multiplicative inverses
+    (let ((m ?\x10001)
+          (n x)
+          (a 0)
+          (b 1)
+          (not-done t))
+      (while not-done
+        (let ((r (mod m n))
+              (q (/ m n))
+              (temp b))
+          (if (= r 0)
+              (setq not-done nil)
+            (progn
+              (setq m n)
+              (setq n r)
+              (setq b (- a (* q b)))
+              (setq a temp)))))
+      (if (< b 0)
+          (logand (+ b ?\x10001) ?\xffff)
+        (logand b ?\xffff)))))
+
+
+(defconst *idea-rounds* 8)
+(defconst *idea-subkey-number* 52)
+
+;; generate internal encryption keys from an external key
+(defun idea-encrypt-subkeys (key &optional xor-safe)
+  "generate the IDEA-subkeys from a 128-bit (8 element vector of
+16-bit values).  optional second arg controls XORing with 0x0dae to
+prevent \"weak\" keys from being generated.  return vector of 52
+16-bit numbers."
+
+  ;; sanity check
+  (assert (= (length key) 8) nil
+	  "idea-encrypt-subkeys: first arg must be of length 8")
+
+  (let ((subkeys (make-vector *idea-subkey-number* 0)))
+
+    (dotimes (idx 8)
+      (aset subkeys idx (aref key idx)))
+
+    (do ((idx 8 (1+ idx)))
+	((= idx *idea-subkey-number*))
+
+      (let* ((idx1 (if (= 0 (mod (1+ idx) 8))
+		       (- idx 15)
+		     (- idx 7)))
+	     (idx2 (if (< (mod (+ idx 2) 8) 2)
+		       (- idx 14)
+		     (- idx 6))))
+	(aset subkeys idx (logand ?\xffff
+				  (logior (ash (aref subkeys idx1) 9)
+					  (ash (aref subkeys idx2)
+					       -7))))))
+    (when xor-safe
+      (dotimes (idx *idea-subkey-number*)
+	(aset subkeys idx (logxor ?\x0dae (aref subkeys idx)))))
+
+    subkeys))
+
+(defun idea-decrypt-subkeys (enc-subkeys)
+  "generate IDEA decryptions subkeys from the encryption subkeys"
+  (let ((dec-subkeys (make-vector *idea-subkey-number* 0))
+	(in-idx 0))
+    (flet ((next-subkey ()
+	      (prog1
+		  (aref enc-subkeys in-idx)
+		(incf in-idx))))
+
+      (let ((idx (* 6 *idea-rounds*)))
+	(aset dec-subkeys (+ idx 0) (idea-mul-inv (next-subkey)))
+	(aset dec-subkeys (+ idx 1) (logand ?\xffff (- (next-subkey))))
+	(aset dec-subkeys (+ idx 2) (logand ?\xffff (- (next-subkey))))
+	(aset dec-subkeys (+ idx 3) (idea-mul-inv (next-subkey))))
+
+      (do ((idx (* 6 (1- *idea-rounds*)) (- idx 6)))
+	  ((< idx 0))
+	(aset dec-subkeys (+ idx 4) (next-subkey))
+	(aset dec-subkeys (+ idx 5) (next-subkey))
+	(aset dec-subkeys (+ idx 0) (idea-mul-inv (next-subkey)))
+	
+	(if (= 0 idx)
+	    (progn
+	      (aset dec-subkeys (+ idx 1) (logand ?\xffff (- (next-subkey))))
+	      (aset dec-subkeys (+ idx 2) (logand ?\xffff (- (next-subkey)))))
+	  (progn
+	    (aset dec-subkeys (+ idx 2) (logand ?\xffff (- (next-subkey))))
+	    (aset dec-subkeys (+ idx 1) (logand ?\xffff (- (next-subkey))))))
+	
+	(aset dec-subkeys (+ idx 3) (idea-mul-inv (next-subkey)))))
+    dec-subkeys))
+
+;; encrypt a 64-bit block of data (4 16-bit words), using the subkeys
+;; provided, in place 
+(defun idea-cipher-block (data subkeys)
+  (let ((word0 (aref data 0))
+        (word1 (aref data 1))
+        (word2 (aref data 2))
+        (word3 (aref data 3))
+        (idx 0)
+	(key-idx 0)
+        t1 t2)
+    (flet ((next-subkey ()
+	      (prog1
+		  (aref subkeys key-idx)
+		(incf key-idx))))
+
+      (dotimes (idx *idea-rounds*)
+	(setq word0 (idea-mul word0 (next-subkey)))
+	(setq word1 (logand ?\xffff (+ word1 (next-subkey))))
+	(setq word2 (logand ?\xffff (+ word2 (next-subkey))))
+	(setq word3 (idea-mul word3 (next-subkey)))
+	
+	(setq t2 (idea-mul (logxor word0 word2) 
+			   (next-subkey)))
+	(setq t1 (idea-mul (logand ?\xffff (+ t2 (logxor word1 word3)))
+			   (next-subkey)))
+	(setq t2 (logand ?\xffff (+ t1 t2)))
+	
+	(setq word0 (logxor word0 t1))
+	(setq word3 (logxor word3 t2))
+	
+	(setq t2 (logxor t2 word1))
+	(setq word1 (logxor word2 t1))
+	(setq word2 t2))
+      
+      (setq word0 (idea-mul word0 (next-subkey)))
+      (setq word2 (logand ?\xffff (+ word2 (next-subkey))))
+      (setq word1 (logand ?\xffff (+ word1 (next-subkey))))
+      (setq word3 (idea-mul word3 (next-subkey))))
+      
+    ;; word 1 and 2 are swapped before output
+    (aset data 0 word0)
+    (aset data 1 word2)
+    (aset data 2 word1)
+    (aset data 3 word3)))
+
+(defun idea-cbc-encode (data subkeys &optional IV)
+  "encrypts its first argument, a vector of 16-bit ints, with the keys
+in its second argument, using the IV in the optional third argument
+(which is prepended to the output vector).  if IV is nil, it is taken
+as \[0 0 0 0\] and not prepended to the output.
+returns a vector of 16-bit ints."
+  (let* ((len (length data))
+	 (out-vec (make-vector (if IV (+ len 4) len) 0))
+	 (temp-vec (make-vector 4 0)))
+
+    ;; sanity checks
+    (assert (zerop (mod len 4)) nil
+	    "idea-cbc-encode: length of data must be a multiple of 4")
+    (when IV
+      (assert (= 4 (length IV)) nil 
+	      "idea-cbc-encode: length of IV must be 4"))
+    (assert (= *idea-subkey-number* (length subkeys)) nil
+	    "idea-cbc-encode: there must be %d subkeys"
+	    *idea-subkey-number*)
+
+    ;; write IV into output and temp-vec, if present
+    (when IV
+      (dotimes (idx 4)
+	(aset temp-vec idx (aref IV idx))
+	(aset out-vec idx (aref IV idx))))
+
+    ;; encrypt the rest of the input in CBC mode
+    (do ((in-idx 0 (+ in-idx 4))
+	 (out-idx (if IV 4 0) (+ out-idx 4)))
+	((= in-idx len))
+
+      (dotimes (offset 4)
+	;; XOR the current plaintext block and previous ciphertext
+	;; block (which is in temp-vec) into temp-vec.  (if no IV was
+	;; given, then temp-vec will be all zeroes.)
+	(aset temp-vec offset (logxor (aref data (+ in-idx offset))
+				      (aref temp-vec offset))))
+
+      ;; encrypt temp-vec in place
+      (idea-cipher-block temp-vec subkeys)
+      
+      ;; write temp-vec into the output
+      (dotimes (offset 4)
+        (aset out-vec (+ out-idx offset) (aref temp-vec offset))))
+
+    ;; clean up 
+    (fillarray temp-vec 0)
+
+    out-vec))
+
+(defun idea-cbc-decode (data subkeys &optional no-iv)
+  "decrypts its first argument, a vector of 16-bit ints, with the keys
+in its second argument.  third argument, if non-nil, indicates that
+the data does not have an IV prepended, and that the IV should be
+taken as \[0 0 0 0\].
+returns a vector of 16-bit ints."
+  (let* ((len (length data))
+         (out-vec (make-vector (max 0 (if no-iv len (- len 4))) 0))
+         (temp-vec (make-vector 4 0))
+	 (cur-block (make-vector 4 0))
+	 (prev-block (make-vector 4 0)))
+    
+    ;; sanity checks
+    (assert (zerop (mod len 4)) nil
+	    "idea-cbc-decode: length of data must be a multiple of 4")
+    (unless no-iv
+      (assert (> len 0) nil
+	      "idea-cbc-decode: length of data must be at least 4"))
+    (assert (= *idea-subkey-number* (length subkeys)) nil
+	    "idea-cbc-decode: there must be %d subkeys"
+	    *idea-subkey-number*)
+    
+    ;; set up the feedback block
+    (unless no-iv
+      (dotimes (offset 4)
+	(aset prev-block offset (aref data offset))))
+
+    ;; decrypt the input in CBC mode
+    (do ((in-idx (if no-iv 0 4) (+ in-idx 4))
+	 (out-idx 0 (+ out-idx 4)))
+	((= in-idx len))
+
+      ;; copy the ciphertext block into temp-vec and cur-block
+      (dotimes (offset 4)
+	(let ((x (aref data (+ in-idx offset))))
+	  (aset temp-vec offset x)
+	  (aset cur-block offset x)))
+
+      ;; decrypt temp-vec in place with the keys
+      (idea-cipher-block temp-vec subkeys)
+
+      (dotimes (offset 4)
+	;; XOR the output of the cipher with the previous ciphertext
+	;; block, storing the result in the output
+	(aset out-vec 
+	      (+ out-idx offset)
+	      (logxor (aref temp-vec offset)
+		      (aref prev-block offset)))
+	;; move cur-block into prev-block
+	(aset prev-block offset (aref cur-block offset))))
+
+    ;; clean up
+    (fillarray temp-vec 0)
+    (fillarray prev-block 0)
+    (fillarray cur-block 0)
+
+    out-vec))
+
+(defun idea-package-transform (data key)
+  "perform the idea-cbc package transform on DATA using KEY.
+all arguments are vectors of 16-bit integers.  DATA should be 4*n
+elements long, KEY should be 8 elements.  no IV is used to seed the
+CBC, since the key is (supposedly) random.
+
+package transform is:
+  m <= \(idea-cbc data key\)
+  k <= key
+  k[i%8] <= \(logxor k[i%8] m[i]\) ;; i from 0 to \(length m\)
+  output <= \(append m k\)"
+
+  (let* ((subkeys (idea-encrypt-subkeys key))
+         (enc-data (idea-cbc-encode data subkeys))
+         (enc-len (length enc-data))
+         ;; m is enc-data with the key appended
+         (m-len (+ enc-len 8))
+         (m (make-vector m-len 0))
+         ;; scratch space for the key
+         (k (make-vector 8 0)))
+    
+    ;; copy key into k
+    (dotimes (key-idx 8)
+      (aset k key-idx (aref key key-idx)))
+
+    ;; XOR the k with the blocks of enc-data
+    (do ((idx 0 (1+ idx))
+         (key-idx 0 (% (1+ key-idx) 8)))
+        ((= idx enc-len))
+      (aset k key-idx (logxor (aref k key-idx)
+                              (aref enc-data idx))))
+
+    ;; copy the encoded data into m
+    (dotimes (idx enc-len)
+      (aset m idx (aref enc-data idx)))
+
+    ;; copy k into the final elements of m
+    (dotimes (key-idx 8)
+      (aset m (+ enc-len key-idx) (aref k key-idx)))
+
+    ;; clean up
+    (fillarray enc-data 0)
+    (fillarray subkeys 0)
+    (fillarray k 0)
+    
+    m))
+
+
+(defun idea-package-untransform (data)
+  "reverse the idea-cbc package transform on DATA.  see the
+documentation for idea-package-transform for an explanation of the
+transform that this function undoes."
+
+  ;; decode m, allocate space for encrypted message and key
+  (let* ((len (length data))
+         (enc-len (- len 8))
+         (enc-data (make-vector enc-len 0))
+         (key (make-vector 8 0)))
+    
+    ;; extract enc-data
+    (dotimes (idx enc-len)
+      (aset enc-data idx (aref data idx)))
+
+    ;; extract the XORed key
+    (dotimes (key-idx 8)
+      (aset key key-idx (aref data (+ enc-len key-idx))))
+
+    ;; XOR the key with the blocks of enc-data
+    (do ((idx 0 (1+ idx))
+         (key-idx 0 (% (1+ key-idx) 8)))
+        ((= idx enc-len))
+      (aset key key-idx (logxor (aref key key-idx)
+                                (aref enc-data idx))))
+
+    ;; generate the decryption keys
+    (let* ((enc-subkeys (idea-encrypt-subkeys key))
+           (dec-subkeys (idea-decrypt-subkeys enc-subkeys)))
+      
+      ;; extract the result and clean up
+      (prog1
+	  ;; no IV sent included in package transform
+          (idea-cbc-decode enc-data dec-subkeys t)
+        (fillarray enc-data 0)
+        (fillarray key 0)
+        (fillarray enc-subkeys 0)
+        (fillarray dec-subkeys 0)))))
+
+(provide 'idea)
+;;;  md5-old.el -- MD5 message digest algorithm
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: MD5, message digest
+;; Created: 1998-04-27
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; this is a slower, more clear, version of md5.el.  it's based on md5-old.el
+
+;;; Code:
+(require 'cl)
+
+(defun md5 (string)
+  "return the md5 hash of a string, as a 128 bit string"
+  (let* ((length (length string))
+	 ;; md5 requires the message be padded to a length of 512*k +
+	 ;; 64 (bits).  confusion source: we're working with bytes.
+	 ;; padding is always done.
+	 ;; 512 bits = 64 bytes, 64 bits = 8 bytes
+	 (next-512 (+ 64 (logand (+ length 8) (lognot 63))))
+	 (pad-bytes (- next-512 length 8))
+	 (pad-string (make-string pad-bytes 0))
+	 (len-string (make-string 8 0)))
+    ;; message is constructed as:
+    ;; original-message | pad | length-in-bits
+    ;; pad is 10000... (bitwise)
+    ;; length-in-bits is length before padding, and is 64 bits long
+
+    ;; fill in the single bit of the pad
+    (aset pad-string 0 (ash 1 7))
+
+    ;; there's a slim chance of overflow when multiplying the length
+    ;; by 8 to get the length in bits.  to avoid this, do some
+    ;; slightly hairier math when writing the length into len-string.
+    ;; also, it has to be LSB-first.  be still my aching brain.
+
+    ;; LSB sucks.
+
+    ;; only do the first 4 bytes, even though supposedly there are 8.
+    ;; 32 bit emacsen think that (ash 40 -37) => 1
+    ;; (supposed to be fixed in future releases)
+    (dotimes (idx 4)
+      (aset len-string idx (logand ?\xff
+				   (ash length (- 3 (* idx 8))))))
+    
+    (md5-vector
+     (md5-string-to-32bit-vec
+      (concat string pad-string len-string)))))
+
+(defun md5-string-to-32bit-vec (string)
+  ;; emacs doesn't actually have 32 bits, in most implementations.
+  ;; 32 bit numbers are represented as a pair of 16 bit numbers
+
+  ;; 4 chars per 32 bit number, in LSB-first!
+  (let* ((veclen (/ (length string) 4))
+	 (vec (make-vector veclen nil))
+	 (stridx 0))
+    (dotimes (vecidx veclen)
+      ;; MD5 integers are (hi . lo) 16 bit words
+      (aset vec vecidx (cons (+ (ash (aref string (+ stridx 3)) 8)
+				(aref string (+ stridx 2)))
+			     (+ (ash (aref string (+ stridx 1)) 8)
+				(aref string (+ stridx 0)))))
+      (incf stridx 4))
+
+    vec))
+
+(defsubst md5-f2 (x y z)
+  (logior (logand x y)
+	  (logand (lognot x)
+		  z)))
+
+(defsubst md5-g2 (x y z)
+  (logior (logand x z)
+	  (logand y (lognot z))))
+
+(defsubst md5-h2 (x y z)
+  (logxor x y z))
+
+(defsubst md5-i2 (x y z)
+  (logxor y
+	  (logior x
+		  ;; this is normally a lognot, but that would set
+		  ;; high bits, and there's no logand to clear them.
+		  (logxor z ?\xffff))))
+
+(defsubst md5-f (x y z)
+  (cons (md5-f2 (car x) (car y) (car z))
+	(md5-f2 (cdr x) (cdr y) (cdr z))))
+
+(defsubst md5-g (x y z)
+  (cons (md5-g2 (car x) (car y) (car z))
+	(md5-g2 (cdr x) (cdr y) (cdr z))))
+
+(defsubst md5-h (x y z)
+  (cons (md5-h2 (car x) (car y) (car z))
+	(md5-h2 (cdr x) (cdr y) (cdr z))))
+
+(defsubst md5-i (x y z)
+  (cons (md5-i2 (car x) (car y) (car z))
+	(md5-i2 (cdr x) (cdr y) (cdr z))))
+
+(defsubst md5<<< (val shift)
+  "circular shift md5 32 bit int VAL by SHIFT bits"
+  (let ((a (car val))
+	(b (cdr val)))
+
+    ;; shifts greater than 16 need to be handled by a swap, then a
+    ;; smaller shift
+    (when (> shift 16)
+      (rotatef a b)
+      (decf shift 16))
+
+    (cons (logand ?\xffff (logior (ash a shift) (ash b (- shift 16))))
+	  (logand ?\xffff (logior (ash b shift) (ash a (- shift 16)))))))
+
+(defsubst md5+ (&rest args)
+  ;; enough room to just add without carry checks
+  (let* ((lo (apply #'+ (mapcar #'cdr args)))
+	 (hi (+ (ash lo -16) (apply #'+ (mapcar #'car args)))))
+    (cons (logand ?\xffff hi)
+	  (logand ?\xffff lo))))
+
+;; array of values for i=[1..64] => floor(2^32 * abs(sin(i)))
+(defconst md5-t
+
+  [(?\xd76a . ?\xa478)
+   (?\xe8c7 . ?\xb756)
+   (?\x2420 . ?\x70db)
+   (?\xc1bd . ?\xceee)
+   (?\xf57c . ?\x0faf)
+   (?\x4787 . ?\xc62a)
+   (?\xa830 . ?\x4613)
+   (?\xfd46 . ?\x9501)
+   (?\x6980 . ?\x98d8)
+   (?\x8b44 . ?\xf7af)
+   (?\xffff . ?\x5bb1)
+   (?\x895c . ?\xd7be)
+   (?\x6b90 . ?\x1122)
+   (?\xfd98 . ?\x7193)
+   (?\xa679 . ?\x438e)
+   (?\x49b4 . ?\x0821)
+
+   (?\xf61e . ?\x2562)
+   (?\xc040 . ?\xb340)
+   (?\x265e . ?\x5a51)
+   (?\xe9b6 . ?\xc7aa)
+   (?\xd62f . ?\x105d)
+   (?\x0244 . ?\x1453)
+   (?\xd8a1 . ?\xe681)
+   (?\xe7d3 . ?\xfbc8)
+   (?\x21e1 . ?\xcde6)
+   (?\xc337 . ?\x07d6)
+   (?\xf4d5 . ?\x0d87)
+   (?\x455a . ?\x14ed)
+   (?\xa9e3 . ?\xe905)
+   (?\xfcef . ?\xa3f8)
+   (?\x676f . ?\x02d9)
+   (?\x8d2a . ?\x4c8a)
+
+   (?\xfffa . ?\x3942)
+   (?\x8771 . ?\xf681)
+   (?\x6d9d . ?\x6122)
+   (?\xfde5 . ?\x380c)
+   (?\xa4be . ?\xea44)
+   (?\x4bde . ?\xcfa9)
+   (?\xf6bb . ?\x4b60)
+   (?\xbebf . ?\xbc70)
+   (?\x289b . ?\x7ec6)
+   (?\xeaa1 . ?\x27fa)
+   (?\xd4ef . ?\x3085)
+   (?\x0488 . ?\x1d05)
+   (?\xd9d4 . ?\xd039)
+   (?\xe6db . ?\x99e5)
+   (?\x1fa2 . ?\x7cf8)
+   (?\xc4ac . ?\x5665)
+
+   (?\xf429 . ?\x2244)
+   (?\x432a . ?\xff97)
+   (?\xab94 . ?\x23a7)
+   (?\xfc93 . ?\xa039)
+   (?\x655b . ?\x59c3)
+   (?\x8f0c . ?\xcc92)
+   (?\xffef . ?\xf47d)
+   (?\x8584 . ?\x5dd1)
+   (?\x6fa8 . ?\x7e4f)
+   (?\xfe2c . ?\xe6e0)
+   (?\xa301 . ?\x4314)
+   (?\x4e08 . ?\x11a1)
+   (?\xf753 . ?\x7e82)
+   (?\xbd3a . ?\xf235)
+   (?\x2ad7 . ?\xd2bb)
+   (?\xeb86 . ?\xd391)])
+
+(eval-and-compile
+  (defun md5-rewrite (fun w x y z vec-idx shift)
+    "helper function for md5-vector, below.  ugly coding practice,
+having a macro-rewriter elsewhere, but the indentation was getting a
+bit out of control.
+NB: vec, v-offset, and t-idx below must be defined where the macro is
+called!" 
+    `(setq ,w (md5+ ,x
+		    (md5<<< (md5+ ,w
+				  ,(list fun x y z)
+				  (aref vec (+ v-offset ,vec-idx))
+				  (aref md5-t t-idx))
+			    ,shift)))))
+
+
+(defun md5-vector (vec)
+  ;; initialize the chaining variables
+  (let ((a (cons ?\x6745 ?\x2301))
+	(b (cons ?\xefcd ?\xab89))
+	(c (cons ?\x98ba ?\xdcfe))
+	(d (cons ?\x1032 ?\x5476))
+	(v-offset 0))
+
+    (dotimes (count (/ (length vec) 16))
+      (let ((AA a) (BB b) (CC c) (DD d)
+	    (t-idx 0))
+	(macrolet
+	    ((f (v1 v2 v3 v4 v-idx shift)
+		`(progn
+		   ,(md5-rewrite 'md5-f v1 v2 v3 v4 v-idx shift)
+		   (incf t-idx))))
+
+	  (f a b c d  0  7) (f d a b c  1 12) (f c d a b  2 17) (f b c d a  3 22)
+	  (f a b c d  4  7) (f d a b c  5 12) (f c d a b  6 17) (f b c d a  7 22)
+	  (f a b c d  8  7) (f d a b c  9 12) (f c d a b 10 17) (f b c d a 11 22)
+	  (f a b c d 12  7) (f d a b c 13 12) (f c d a b 14 17) (f b c d a 15 22))
+
+	(macrolet
+	    ((g (v1 v2 v3 v4 v-idx shift)
+		`(progn
+		   ,(md5-rewrite 'md5-g v1 v2 v3 v4 v-idx shift)
+		   (incf t-idx))))
+
+	  (g a b c d  1  5) (g d a b c  6  9) (g c d a b 11 14) (g b c d a  0 20)
+	  (g a b c d  5  5) (g d a b c 10  9) (g c d a b 15 14) (g b c d a  4 20)
+	  (g a b c d  9  5) (g d a b c 14  9) (g c d a b  3 14) (g b c d a  8 20)
+	  (g a b c d 13  5) (g d a b c  2  9) (g c d a b  7 14) (g b c d a 12 20))
+
+	(macrolet
+	    ((h (v1 v2 v3 v4 v-idx shift)
+		`(progn
+		   ,(md5-rewrite 'md5-h v1 v2 v3 v4 v-idx shift)
+		   (incf t-idx))))
+
+	  (h a b c d  5  4) (h d a b c  8 11) (h c d a b 11 16) (h b c d a 14 23)
+	  (h a b c d  1  4) (h d a b c  4 11) (h c d a b  7 16) (h b c d a 10 23)
+	  (h a b c d 13  4) (h d a b c  0 11) (h c d a b  3 16) (h b c d a  6 23)
+	  (h a b c d  9  4) (h d a b c 12 11) (h c d a b 15 16) (h b c d a  2 23))
+
+	(macrolet
+	    ((i (v1 v2 v3 v4 v-idx shift)
+		`(progn
+		   ,(md5-rewrite `md5-i v1 v2 v3 v4 v-idx shift)
+		   (incf t-idx))))
+
+	  (i a b c d  0  6) (i d a b c  7 10) (i c d a b 14 15) (i b c d a  5 21)
+	  (i a b c d 12  6) (i d a b c  3 10) (i c d a b 10 15) (i b c d a  1 21)
+	  (i a b c d  8  6) (i d a b c 15 10) (i c d a b  6 15) (i b c d a 13 21)
+	  (i a b c d  4  6) (i d a b c 11 10) (i c d a b  2 15) (i b c d a  9 21))
+
+	(setq a (md5+ AA a)
+	      b (md5+ BB b)
+	      c (md5+ CC c)
+	      d (md5+ DD d)))
+
+      (incf v-offset 16))
+
+    ;; swap back from LSB-first.  i feel ill.
+    (mapconcat #'(lambda (x) (format "%02x%02x" (logand ?\xff x) (ash x -8)))
+	       (list (cdr a) (car a)
+		     (cdr b) (car b)
+		     (cdr c) (car c)
+		     (cdr d) (car d))
+	       "")))
+
+(provide 'md5)
+;;;  md5.el -- MD5 message digest algorithm
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: MD5, message digest
+;; Created: 1998-04-27
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; this is an implementation of the MD5 hashing algorithm as described
+;; in RFC 1321.  Applied Cryptography, by Bruce Schneier, was used as
+;; a reference, but it should be noted that the initialization values
+;; for the chaining vectors in that book are in byte-reversed order,
+;; as of the 4th printing.  the mixin constants are correct, though.
+;;
+;; this code might be somewhat confusing at first (or second).  two
+;; sources of confusion are likely: the fact that MD5 works in least
+;; significant byte order on the data, and that this code represents
+;; 32 bit numbers as two 16 bit numbers (most emacsen not being able
+;; to go past 27 bits).
+;;
+;; this code was first written to appear as close to the format in the
+;; RFC, then adjusted to take advantage of the patterns in the message
+;; index (v-idx, below, in md5-vectors).  originally, numbers were
+;; passed around and operated on as pairs, but the algorithm can be
+;; (and has been) made to operate independently on the two 16-bit
+;; halves of the numbers, combining both halves only when doing adds
+;; and circular shifts.  this keeps consing to a minimum (almost
+;; none), and roughly doubles the speed compared to the equivalent
+;; algorithm operating on numbers as pairs.
+;;
+;; it also provides for greater security when hashing sensistive
+;; strings, since less data is created and left for the GC to clean
+;; up.
+;;
+;; there should be a file called md5-old.el accompanying this file.
+;; it is the original, slow, consful version of this code, and is
+;; (hopefully) easier to understand.
+
+(require 'cl)
+
+(defun md5 (string)
+  "return the md5 hash of a string, as a 128 bit string"
+  (let* ((length (length string))
+	 ;; md5 requires the message be padded to a length of 512*k +
+	 ;; 64 (bits).  confusion source: we're working with bytes.
+	 ;; padding is always done.
+	 ;; 512 bits = 64 bytes, 64 bits = 8 bytes
+	 (next-512 (+ 64 (logand (+ length 8) (lognot 63))))
+	 (pad-bytes (- next-512 length 8))
+	 (pad-string (make-string pad-bytes 0))
+	 (len-string (make-string 8 0)))
+    ;; message is constructed as:
+    ;; original-message | pad | length-in-bits
+    ;; pad is 10000... (bitwise)
+    ;; length-in-bits is length before padding, and is 64 bits long
+
+    ;; fill in the single bit of the pad
+    (aset pad-string 0 (ash 1 7))
+
+    ;; there's a slim chance of overflow when multiplying the length
+    ;; by 8 to get the length in bits.  to avoid this, do some
+    ;; slightly hairier math when writing the length into len-string.
+    ;; also, it has to be LSB-first.  be still my aching brain.
+
+    ;; LSB sucks.
+
+    ;; only do the first 4 bytes, even though supposedly there are 8.
+    ;; 32 bit emacsen think that (ash 40 -37) => 1
+    ;; (supposed to be fixed in future releases)
+    (dotimes (idx 4)
+      (aset len-string idx (logand ?\xff
+				   (ash length (- 3 (* idx 8))))))
+    
+
+    (let* ((concat-string (concat string pad-string len-string))
+           (vecs (md5-string-to-32bit-vecs concat-string))) 
+      (prog1
+          (md5-vectors (car vecs) (cdr vecs))
+        ;; clear out the concat-string and vectors, in case they are
+        ;; sensitive
+        (fillarray concat-string ?0)
+	(fillarray (car vecs) 0)
+	(fillarray (cdr vecs) 0)))))
+
+(defun md5-string-to-32bit-vecs (string)
+  "turn a string into 32 bit numbers, with high and low 16bit halves
+in different vectors.
+returned as \(cons vec-hi vec-lo\)."
+  ;; emacs doesn't actually have 32 bits, in most implementations.
+  ;; 32 bit numbers are represented as a pair of 16 bit numbers.
+
+  ;; 4 chars per 32 bit number, in LSB-first!
+  (let* ((veclen (/ (length string) 4))
+	 (vec-hi (make-vector veclen 0))
+	 (vec-lo (make-vector veclen 0))
+	 (stridx 0))
+    (dotimes (vecidx veclen)
+      ;; MD5 integers are kept as two 16 bit words
+      ;; note the LSB magic/annoyance
+      (aset vec-hi vecidx (+ (ash (aref string (+ stridx 3)) 8)
+			     (aref string (+ stridx 2))))
+      (aset vec-lo vecidx (+ (ash (aref string (+ stridx 1)) 8)
+			     (aref string (+ stridx 0))))
+      (incf stridx 4))
+
+    (cons vec-hi vec-lo)))
+
+;; array of values for i=[1..64] => floor(2^32 * abs(sin(i)))
+;; broken into two arrays, hi values and low
+(defconst md5-t-hi
+  [?\xd76a ?\xe8c7 ?\x2420 ?\xc1bd 
+           ?\xf57c ?\x4787 ?\xa830 ?\xfd46
+           ?\x6980 ?\x8b44 ?\xffff ?\x895c 
+           ?\x6b90 ?\xfd98 ?\xa679 ?\x49b4
+           ?\xf61e ?\xc040 ?\x265e ?\xe9b6 
+           ?\xd62f ?\x0244 ?\xd8a1 ?\xe7d3
+           ?\x21e1 ?\xc337 ?\xf4d5 ?\x455a 
+           ?\xa9e3 ?\xfcef ?\x676f ?\x8d2a
+           ?\xfffa ?\x8771 ?\x6d9d ?\xfde5 
+           ?\xa4be ?\x4bde ?\xf6bb ?\xbebf
+           ?\x289b ?\xeaa1 ?\xd4ef ?\x0488 
+           ?\xd9d4 ?\xe6db ?\x1fa2 ?\xc4ac
+           ?\xf429 ?\x432a ?\xab94 ?\xfc93 
+           ?\x655b ?\x8f0c ?\xffef ?\x8584
+           ?\x6fa8 ?\xfe2c ?\xa301 ?\x4e08 
+           ?\xf753 ?\xbd3a ?\x2ad7 ?\xeb86])
+
+(defconst md5-t-lo
+  [?\xa478 ?\xb756 ?\x70db ?\xceee
+           ?\x0faf ?\xc62a ?\x4613 ?\x9501
+           ?\x98d8 ?\xf7af ?\x5bb1 ?\xd7be
+           ?\x1122 ?\x7193 ?\x438e ?\x0821
+           ?\x2562 ?\xb340 ?\x5a51 ?\xc7aa
+           ?\x105d ?\x1453 ?\xe681 ?\xfbc8
+           ?\xcde6 ?\x07d6 ?\x0d87 ?\x14ed
+           ?\xe905 ?\xa3f8 ?\x02d9 ?\x4c8a
+           ?\x3942 ?\xf681 ?\x6122 ?\x380c 
+           ?\xea44 ?\xcfa9 ?\x4b60 ?\xbc70
+           ?\x7ec6 ?\x27fa ?\x3085 ?\x1d05 
+           ?\xd039 ?\x99e5 ?\x7cf8 ?\x5665
+           ?\x2244 ?\xff97 ?\x23a7 ?\xa039
+           ?\x59c3 ?\xcc92 ?\xf47d ?\x5dd1
+           ?\x7e4f ?\xe6e0 ?\x4314 ?\x11a1
+           ?\x7e82 ?\xf235 ?\xd2bb ?\xd391])
+
+
+(eval-when-compile
+  (defun md5<<< (val-hi val-lo shift)
+    "macro to circular shift val-(hi,lo)  by SHIFT bits"
+    ;; shifts greater than 16 need to be handled by a swap, then a
+    ;; smaller shift
+    (if (>= shift 16)
+	(progn
+	  (decf shift 16)
+	  (if (= shift 0)
+	      `(rotatef ,val-hi ,val-lo)
+	    ;; swapped shift
+	    `(let ((a (logand ?\xffff (logior (ash ,val-lo ,shift) (ash ,val-hi ,(- shift 16)))))
+		   (b (logand ?\xffff (logior (ash ,val-hi ,shift) (ash ,val-lo ,(- shift 16))))))
+	       (setq ,val-hi a
+		     ,val-lo b))))
+      `(let ((a (logand ?\xffff (logior (ash ,val-hi ,shift) (ash ,val-lo ,(- shift 16)))))
+	     (b (logand ?\xffff (logior (ash ,val-lo ,shift) (ash ,val-hi ,(- shift 16))))))
+	 (setq ,val-hi a
+	       ,val-lo b)))))
+
+
+(eval-when-compile
+  (defun md5-f (x y z)
+    `(logior (logand ,x ,y)
+             (logand (lognot ,x)
+                     ,z))))
+
+(eval-when-compile
+  (defun md5-g (x y z)
+    `(logior (logand ,x ,z)
+             (logand ,y (lognot ,z)))))
+
+(eval-when-compile
+  (defun md5-h (x y z)
+    `(logxor ,x ,y ,z)))
+
+(eval-when-compile
+  (defun md5-i (x y z)
+    `(logxor ,y
+             (logior ,x
+                     ;; this is normally a lognot, but that would set
+                     ;; high bits, and there's no logand to clear them.
+                     (logxor ,z ?\xffff)))))
+
+  
+(eval-when-compile
+  (defun md5-rewrite (fun w x y z shift)
+    "consing reduced form of md5 common step.
+requires v-offset, v-idx, vec-hi, vec-lo, t-idx to be defined at
+calling point." 
+    (flet ((add-lo (x)
+		   (intern (concat (symbol-name x) "-lo")))
+	   (add-hi (x)
+		   (intern (concat (symbol-name x) "-hi"))))
+      
+      (let ((w-hi (add-hi w)) (w-lo (add-lo w))
+	    (x-hi (add-hi x)) (x-lo (add-lo x))
+	    (y-hi (add-hi y)) (y-lo (add-lo y))
+	    (z-hi (add-hi z)) (z-lo (add-lo z)))
+
+	`(progn
+	   (setq ,w-hi (+ ,w-hi
+			  ,(funcall fun x-hi y-hi z-hi)
+			  (aref vec-hi (+ v-offset v-idx))
+			  (aref md5-t-hi t-idx))
+		 ,w-lo (+ ,w-lo
+			  ,(funcall fun x-lo y-lo z-lo)
+			  (aref vec-lo (+ v-offset v-idx))
+			  (aref md5-t-lo t-idx)))
+
+	   (setq ,w-hi (logand ?\xffff 
+			       (+ ,w-hi 
+				  (ash ,w-lo -16))))
+	   (setq ,w-lo (logand ?\xffff ,w-lo))
+
+	   ,(md5<<< w-hi w-lo shift)
+
+	   (incf ,w-lo ,x-lo)
+
+	   (setq ,w-hi (logand ?\xffff 
+			       (+ ,w-hi
+				  ,x-hi
+				  (ash ,w-lo -16))))
+	   (setq ,w-lo (logand ?\xffff ,w-lo))
+
+	   (incf t-idx))))))
+
+(defun md5-vectors (vec-hi vec-lo)
+  ;; initialize the chaining variables
+  (let ((a-hi ?\x6745) (a-lo ?\x2301)
+	(b-hi ?\xefcd) (b-lo ?\xab89)
+	(c-hi ?\x98ba) (c-lo ?\xdcfe)
+	(d-hi ?\x1032) (d-lo ?\x5476)
+	(v-offset 0))
+    
+    (dotimes (count (/ (length vec-hi) 16))
+      (let ((AA-hi a-hi) (BB-hi b-hi) (CC-hi c-hi) (DD-hi d-hi)
+	    (AA-lo a-lo) (BB-lo b-lo) (CC-lo c-lo) (DD-lo d-lo)
+	    (t-idx 0)
+	    v-idx)
+	(macrolet
+	    ((f (v1 v2 v3 v4 shift)
+		`(prog1
+		     ,(md5-rewrite 'md5-f v1 v2 v3 v4 shift)
+		   (incf v-idx))))
+                
+	  (setq v-idx 0)
+	  (dotimes (count 4)
+	    (f a b c d 7)
+	    (f d a b c 12)
+	    (f c d a b 17)
+	    (f b c d a 22)))
+
+	(macrolet
+	    ((g (v1 v2 v3 v4 shift)
+		`(prog1
+		     ,(md5-rewrite 'md5-g v1 v2 v3 v4 shift)
+		   (setq v-idx (logand ?\xf (+ v-idx 5))))))
+
+	  (setq v-idx 1)
+	  (dotimes (count 4)
+	    (g a b c d 5)
+	    (g d a b c 9)
+	    (g c d a b 14)
+	    (g b c d a 20)))
+
+	(macrolet
+	    ((h (v1 v2 v3 v4 shift)
+		`(prog1
+		     ,(md5-rewrite 'md5-h v1 v2 v3 v4 shift)
+		   (setq v-idx (logand ?\xf (+ v-idx 3))))))
+	
+	  (setq v-idx 5)
+	  (dotimes (count 4)
+	    (h a b c d 4)
+	    (h d a b c 11)
+	    (h c d a b 16)
+	    (h b c d a 23)))
+
+	(macrolet
+	    ((i (v1 v2 v3 v4 shift)
+		`(prog1
+		     ,(md5-rewrite 'md5-i v1 v2 v3 v4 shift)
+		   (setq v-idx (logand ?\xf (+ v-idx 7))))))
+	
+	  (setq v-idx 0)
+	  (dotimes (count 4)
+	    (i a b c d 6)
+	    (i d a b c 10)
+	    (i c d a b 15)
+	    (i b c d a 21)))
+
+
+	(setq a-lo (+ AA-lo a-lo)
+	      b-lo (+ BB-lo b-lo)
+	      c-lo (+ CC-lo c-lo)
+	      d-lo (+ DD-lo d-lo))
+	
+	(setq a-hi (logand ?\xffff
+			   (+ AA-hi a-hi
+			      (ash a-lo -16)))
+	      b-hi (logand ?\xffff
+			   (+ BB-hi b-hi
+			      (ash b-lo -16)))
+	      c-hi (logand ?\xffff
+			   (+ CC-hi c-hi
+			      (ash c-lo -16)))
+	      d-hi (logand ?\xffff
+			   (+ DD-hi d-hi
+			      (ash d-lo -16))))
+
+	(setq a-lo (logand ?\xffff a-lo)
+	      b-lo (logand ?\xffff b-lo)
+	      c-lo (logand ?\xffff c-lo)
+	      d-lo (logand ?\xffff d-lo))
+	
+
+	(incf v-offset 16)))
+    
+    
+    ;; write out LSB-first.  i feel ill.
+    (mapconcat #'(lambda (x) (format "%02x%02x" (logand ?\xff x) (ash x -8)))
+               (list 
+                a-lo a-hi
+                b-lo b-hi
+                c-lo c-hi
+                d-lo d-hi)
+               "")))
+
+;; clean up the namespace
+(eval-when-compile
+  (fmakunbound 'md5-rewrite)
+  (fmakunbound 'md5<<<)
+  (fmakunbound 'md5-f)
+  (fmakunbound 'md5-g)
+  (fmakunbound 'md5-h)
+  (fmakunbound 'md5-i))
+
+(provide 'md5)
+(crypto
+  (standards-version 0.1
+   version VERSION
+   author-version AUTHOR_VERSION
+   date DATE
+   build-date BUILD_DATE
+   maintainer MAINTAINER
+   distribution xemacs
+   priority low
+   category CATEGORY
+   dump nil
+   description "Crypto functionality in Emacs Lisp."
+   filename FILENAME
+   md5sum MD5SUM
+   size SIZE
+   provides (ascii-armor blowfish des idea rander rc16 sha1)
+   requires (REQUIRES)
+   type regular
+))
+;;;  paranoid.el -- even more paranoid password prompter
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: password, comint
+;; Created: 1998-05-20
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+;;; Commentary:
+
+;; taken from comint.el, so it doesn't have to be loaded in its
+;; entirety, and made a little more paranoid.
+
+;; (defun comint-read-noecho (prompt &optional stars) ...)
+(defun prompt-paranoidly (prompt)
+
+  "Read a single line of text from user without echoing, and return
+it.  Prompt with argument PROMPT, a string.  Input ends with RET, LFD,
+or ESC.  DEL or C-h rubs out.  C-u kills line.  C-g aborts (if
+`inhibit-quit' is set because e.g. this function was called from a
+process filter and C-g is pressed, this function returns nil rather
+than a string).
+
+Note that the keystrokes comprising the text can still be recovered
+\(temporarily) with \\[view-lossage].  Some people find this worrysome.
+Once the caller uses the password, it can erase the password
+by doing \(fillarray STRING 0)."
+  (let ((ans "")
+	(newans nil)
+	(c 0)
+	(echo-keystrokes 0)
+	(cursor-in-echo-area t)
+	(message-log-max nil)
+	(done nil))
+    (while (not done)
+      (message "%s" prompt)
+      ;; Use this instead of `read-char' to avoid "Non-character input-event".
+      (setq c (read-char-exclusive))
+      (cond ((= c ?\C-g)
+	     ;; This function may get called from a process filter, where
+	     ;; inhibit-quit is set.  In later versions of emacs read-char
+	     ;; may clear quit-flag itself and return C-g.  That would make
+	     ;; it impossible to quit this loop in a simple way, so
+	     ;; re-enable it here (for backward-compatibility the check for
+	     ;; quit-flag below would still be necessary, so this seems
+	     ;; like the simplest way to do things).
+	     (fillarray ans 0)
+	     (setq quit-flag t
+		   done t))
+	    ((or (= c ?\r) (= c ?\n) (= c ?\e))
+	     (setq done t))
+	    ((= c ?\C-u)
+	     (fillarray ans 0)
+	     (setq ans ""))
+	    ((and (/= c ?\b) (/= c ?\177))
+	     (setq newans (concat ans (char-to-string c)))
+	     (fillarray ans 0)
+	     (setq ans newans))
+	    ((> (length ans) 0)
+	     (setq newans (substring ans 0 -1))
+	     (fillarray ans 0)
+	     (setq ans newans))))
+    (if quit-flag
+        ;; Emulate a true quit, except that we have to return a value.
+        (prog1
+            (setq quit-flag nil)
+          (message "Quit")
+          (beep t))
+      (message "")
+      ans)))
+
+(provide 'paranoid)
+;;;  rander.el -- possibly better random numbers, using rc16 as a RNG
+
+;; Copyright (C) 1998 Ray Jones
+
+;; Author: Ray Jones, rjones@pobox.com
+;; Keywords: RNG, rc4, rc16, stream cipher
+;; Created: 1998-04-14
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program; if not, you can either send email to this
+;; program's maintainer or write to: The Free Software Foundation,
+;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
+
+
+(require 'cl)
+(require 'rc16)
+
+(defvar *rander-file* (expand-file-name "~/.emacs.rander"))
+(defvar *rander-file-length* 512)
+
+;;; Initialization of the random state
+
+;; generate a string with random information in it
+(defun rander-noise-string ()
+  (concat
+   ;; randomness from before
+   (if (file-readable-p *rander-file*)
+       (let ((buf nil))
+	 (unwind-protect
+	     (progn
+	       (setq buf (generate-new-buffer "randerdata"))
+	       (save-excursion
+		 (set-buffer buf)
+		 (insert-file-contents-literally *rander-file*)
+		 (buffer-string)))
+	   (if buf
+	       (let ((kill-buffer-hook nil))
+		 (kill-buffer buf))))))
+
+   ;; allocation randomness
+   (if (boundp 'cons-cells-consed)
+       (apply 'concat 
+              (mapcar 'int-to-string 
+                      (list cons-cells-consed
+                            floats-consed
+                            intervals-consed
+                            misc-objects-consed
+                            string-chars-consed
+                            symbols-consed
+                            vector-cells-consed)))
+       "")
+   
+   ;; time randomness
+   (apply 'concat (mapcar 'int-to-string (current-time)))
+   
+   ;; process randomness
+   (int-to-string (emacs-pid))))
+
+
+;;; Mixin keypress randomness, on the fly
+
+;; don't use this if your (current-time) is not fine grained in the
+;; microseconds.  or if your computer is particularly slow, and the
+;; pre-command-hook stuff slows it down (unlikely).
+(defvar *rander-use-keypress* t)
+;; this number shouldn't be too high, as a call to (rander16) will
+;; have to mixin up to this many values before actually returning
+(defvar *rander-keypress-count* 128)
+(defvar *rander-keypress-timings* 
+  (and *rander-use-keypress*
+       (make-vector *rander-keypress-count* 0)))
+(defvar *rander-keypress-have* 0)
+
+(defun rander-store-key-time ()
+  "store keypress timings until we have filled the keypress timings buffer"
+  (when (< *rander-keypress-have* *rander-keypress-count*)
+    (aset *rander-keypress-timings* 
+          *rander-keypress-have* 
+          (nth 2 (current-time)))
+    (incf *rander-keypress-have*)))
+
+(if *rander-use-keypress*
+    (add-hook 'pre-command-hook 'rander-store-key-time))
+
+;;; main source of randomness, the rc16 generator
+(defvar *rander-initialized* nil)
+(defvar *rander-rc16-context* nil)
+
+(defun rander-init ()
+  (setq *rander-rc16-context* (rc16-create-context))
+  (rc16-set-key *rander-rc16-context* (rander-noise-string))
+  (add-hook 'kill-emacs-hook 'rander-write-file)
+  (setq *rander-initialized* t))
+
+(defun rander16 ()
+  (if (not *rander-initialized*)
+      (rander-init))
+  (when (and *rander-use-keypress*
+             (not (zerop *rander-keypress-have*)))
+    ;; mixin all the keypresses we have stored to this point
+    (dotimes (idx *rander-keypress-have*)
+      (rc16-mixin *rander-rc16-context*
+                  (aref *rander-keypress-timings* idx)))
+    ;; reset the buffer
+    (setq *rander-keypress-have* 0))
+
+  ;; return a random value
+  (rc16-short *rander-rc16-context*))
+
+(defun rander-write-file ()
+  "write out a seed file for the next time rander is used.  called at
+the exit of emacs."  
+  (let ((buf nil))
+    (unwind-protect
+        (progn
+          (setq buf (generate-new-buffer "randerdata"))
+          (save-excursion
+            (set-buffer buf)
+            (dotimes (count *rander-file-length*)
+              (insert (logand ?\xff (rander16))))
+	    (let ((backup-inhibited t))
+	      (write-file *rander-file*))))
+      (if buf
+          (let ((kill-buffer-hook nil))
+            (kill-buffer buf))))))
+
+(provide 'rander)