viper -- Update and prettify package-info.in provides.
[packages] / xemacs-packages / ecrypto / blowfish.el
1 ;;;  blowfish.el -- block cipher
2
3 ;; Copyright (C) 1998 Ray Jones
4
5 ;; Author: Ray Jones, rjones@pobox.com
6 ;; Keywords: Blowfish, Schneier, oink, cipher, cypher, cryptography
7 ;; Created: 1998-04-01
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13 ;;
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18 ;;
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with this program; if not, you can either send email to this
21 ;; program's maintainer or write to: The Free Software Foundation,
22 ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
23
24 ;;; Commentary:
25
26 ;; this code is Bruce Schneier's Blowfish encryption algorithm.  it is
27 ;; fast, license-free, unpatented, and beleived secure.  it takes a
28 ;; key of length 32-448 bits.  it works on 64-bit blocks.  further
29 ;; information is available in Applied Cryptography by Schneier or at
30 ;; http://www.counterpane.com/blowfish.html
31
32 ;; to use, given a key:
33 ;;
34 ;; (let ((subkeys (blowfish-generate-keys key)) ;; returns a pair, the
35 ;;                                              ;; P-array and the S-boxes
36 ;;       (data [1 2 3 4]))
37 ;;   ;; encipher data in place
38 ;;   (blowfish-cipher-block data (car subkeys) (cdr subkeys))
39 ;;   ;; decipher in place
40 ;;   (blowfish-cipher-block data (car subkeys) (cdr subkeys) 'decrypt)
41 ;;   ;; data should now be back to its starting value
42 ;;   (assert (equal data [1 2 3 4])))
43
44 ;; note: the time taken to generate subkeys is quite substantial, but
45 ;; encryption and decryption afterwards is quite fast.
46
47 ;; keys are vectors of 16-bit integers, with the vector being a
48 ;; positive, even number of elements long.
49
50
51 ;;; Code:
52 (require 'cl)
53
54 ;; blowfish is a 64-bit algorithm, which operates on 32-bit pieces.
55 ;; this code stores 32-bit numbers as vectors w/ 2 16-bit elements.
56
57 ;; helper functions
58 (defsubst blowfish-xor (a b result)
59   (aset result 0 (logxor (aref a 0) (aref b 0)))
60   (aset result 1 (logxor (aref a 1) (aref b 1)))
61   (assert (and (< (aref result 0) (ash 1 16))
62                (< (aref result 1) (ash 1 16))) nil
63                ""))
64
65 (defsubst blowfish-add (a b result)
66   (let* ((low (+ (aref a 1) (aref b 1)))
67          (high (logand (+ (aref a 0) (aref b 0) (ash low -16))
68                        #xFFFF)))
69     (aset result 0 high)
70     (aset result 1 (logand low #xFFFF)))
71   (assert (and (< (aref result 0) (ash 1 16))
72                (< (aref result 1) (ash 1 16))) nil
73                ""))
74
75 (defun blowfish-cipher-block (data p-array s-boxes &optional direction)
76   "encode or decode with the blowfish cipher, in place.
77 first arg is vector of 4 16-bit words (MSB order).
78 second arg is P-array to encrypt/decrypt with.
79 third arg is S-boxes to encrypt/decrypt with.
80 optional fourth arg is direction \(eq 'decrypt to decrypt\)."
81
82   ;; split the data into two 32 bit pieces (stored as 2 16-bit pieces
83   ;; each.)
84   (let ((xl (vector (aref data 0) (aref data 1)))
85         (xr (vector (aref data 2) (aref data 3)))
86         (reverse (eq direction 'decrypt)))
87     ;; 16 rounds
88     (dotimes (idx 16)
89       ;; mix in the p-array.  note the reverse order for decryption.
90       (let ((p-val (aref p-array (if reverse (- 17 idx) idx))))
91         (blowfish-xor xl p-val xl))
92       ;; apply F
93       (blowfish-f xl s-boxes xr)
94       ;; swap low and high 32 bits
95       (rotatef xl xr))
96
97     ;; undo the last swap
98     (rotatef xl xr)
99     ;; mixin last two elements of P-array
100     ;; (when comparing to section in AC 2nd Ed, note that this is 0
101     ;; indexed, and the reverse order for decryption.
102     (let ((p-val-16 (aref p-array (if reverse 1 16)))
103           (p-val-17 (aref p-array (if reverse 0 17))))
104       (blowfish-xor xl p-val-17 xl)
105       (blowfish-xor xr p-val-16 xr))
106
107     ;; put the result back into the input vector
108     (aset data 0 (aref xl 0))
109     (aset data 1 (aref xl 1))
110     (aset data 2 (aref xr 0))
111     (aset data 3 (aref xr 1))
112     
113     ;; clean up
114     (fillarray xl 0)
115     (fillarray xr 0)))
116
117 (defvar *blowfish-f-scratch* [0 0]
118   "scratch area for the blowfish-f function, to reduce allocation")
119
120 (defun blowfish-f (x s-boxes dest)
121   "perform the blowfish F-function.  takes vector of two-16-bit
122 numbers and S-boxes to use as args, and the destination to xor the
123 result into.  uses *blowfish-f-scratch* to reduce allocation."
124   ;; S-boxes are indexed into via 8-bit pieces of X
125   (let* ((x0 (aref x 0))
126          (Sa (aref (aref s-boxes 0) (ash x0 -8)))
127          (Sb (aref (aref s-boxes 1) (logand x0 #xFF)))
128          (x1 (aref x 1))
129          (Sc (aref (aref s-boxes 2) (ash x1 -8)))
130          (Sd (aref (aref s-boxes 3) (logand x1 #xFF))))
131
132     (blowfish-add Sa Sb *blowfish-f-scratch*)
133     (blowfish-xor Sc *blowfish-f-scratch* *blowfish-f-scratch*)
134     (blowfish-add Sd *blowfish-f-scratch* *blowfish-f-scratch*)
135     (blowfish-xor *blowfish-f-scratch* dest dest)))
136
137 ;; initialization constants for the P-array and S-boxes
138
139 (defconst blowfish-s-box-inits
140   [
141    [
142     [#xd131 #x0ba6] [#x98df #xb5ac] [#x2ffd #x72db] [#xd01a #xdfb7]
143     [#xb8e1 #xafed] [#x6a26 #x7e96] [#xba7c #x9045] [#xf12c #x7f99]
144     [#x24a1 #x9947] [#xb391 #x6cf7] [#x0801 #xf2e2] [#x858e #xfc16]
145     [#x6369 #x20d8] [#x7157 #x4e69] [#xa458 #xfea3] [#xf493 #x3d7e]
146     [#x0d95 #x748f] [#x728e #xb658] [#x718b #xcd58] [#x8215 #x4aee]
147     [#x7b54 #xa41d] [#xc25a #x59b5] [#x9c30 #xd539] [#x2af2 #x6013]
148     [#xc5d1 #xb023] [#x2860 #x85f0] [#xca41 #x7918] [#xb8db #x38ef]
149     [#x8e79 #xdcb0] [#x603a #x180e] [#x6c9e #x0e8b] [#xb01e #x8a3e]
150     [#xd715 #x77c1] [#xbd31 #x4b27] [#x78af #x2fda] [#x5560 #x5c60]
151     [#xe655 #x25f3] [#xaa55 #xab94] [#x5748 #x9862] [#x63e8 #x1440]
152     [#x55ca #x396a] [#x2aab #x10b6] [#xb4cc #x5c34] [#x1141 #xe8ce]
153     [#xa154 #x86af] [#x7c72 #xe993] [#xb3ee #x1411] [#x636f #xbc2a]
154     [#x2ba9 #xc55d] [#x7418 #x31f6] [#xce5c #x3e16] [#x9b87 #x931e]
155     [#xafd6 #xba33] [#x6c24 #xcf5c] [#x7a32 #x5381] [#x2895 #x8677]
156     [#x3b8f #x4898] [#x6b4b #xb9af] [#xc4bf #xe81b] [#x6628 #x2193]
157     [#x61d8 #x09cc] [#xfb21 #xa991] [#x487c #xac60] [#x5dec #x8032]
158     [#xef84 #x5d5d] [#xe985 #x75b1] [#xdc26 #x2302] [#xeb65 #x1b88]
159     [#x2389 #x3e81] [#xd396 #xacc5] [#x0f6d #x6ff3] [#x83f4 #x4239]
160     [#x2e0b #x4482] [#xa484 #x2004] [#x69c8 #xf04a] [#x9e1f #x9b5e]
161     [#x21c6 #x6842] [#xf6e9 #x6c9a] [#x670c #x9c61] [#xabd3 #x88f0]
162     [#x6a51 #xa0d2] [#xd854 #x2f68] [#x960f #xa728] [#xab51 #x33a3]
163     [#x6eef #x0b6c] [#x137a #x3be4] [#xba3b #xf050] [#x7efb #x2a98]
164     [#xa1f1 #x651d] [#x39af #x0176] [#x66ca #x593e] [#x8243 #x0e88]
165     [#x8cee #x8619] [#x456f #x9fb4] [#x7d84 #xa5c3] [#x3b8b #x5ebe]
166     [#xe06f #x75d8] [#x85c1 #x2073] [#x401a #x449f] [#x56c1 #x6aa6]
167     [#x4ed3 #xaa62] [#x363f #x7706] [#x1bfe #xdf72] [#x429b #x023d]
168     [#x37d0 #xd724] [#xd00a #x1248] [#xdb0f #xead3] [#x49f1 #xc09b]
169     [#x0753 #x72c9] [#x8099 #x1b7b] [#x25d4 #x79d8] [#xf6e8 #xdef7]
170     [#xe3fe #x501a] [#xb679 #x4c3b] [#x976c #xe0bd] [#x04c0 #x06ba]
171     [#xc1a9 #x4fb6] [#x409f #x60c4] [#x5e5c #x9ec2] [#x196a #x2463]
172     [#x68fb #x6faf] [#x3e6c #x53b5] [#x1339 #xb2eb] [#x3b52 #xec6f]
173     [#x6dfc #x511f] [#x9b30 #x952c] [#xcc81 #x4544] [#xaf5e #xbd09]
174     [#xbee3 #xd004] [#xde33 #x4afd] [#x660f #x2807] [#x192e #x4bb3]
175     [#xc0cb #xa857] [#x45c8 #x740f] [#xd20b #x5f39] [#xb9d3 #xfbdb]
176     [#x5579 #xc0bd] [#x1a60 #x320a] [#xd6a1 #x00c6] [#x402c #x7279]
177     [#x679f #x25fe] [#xfb1f #xa3cc] [#x8ea5 #xe9f8] [#xdb32 #x22f8]
178     [#x3c75 #x16df] [#xfd61 #x6b15] [#x2f50 #x1ec8] [#xad05 #x52ab]
179     [#x323d #xb5fa] [#xfd23 #x8760] [#x5331 #x7b48] [#x3e00 #xdf82]
180     [#x9e5c #x57bb] [#xca6f #x8ca0] [#x1a87 #x562e] [#xdf17 #x69db]
181     [#xd542 #xa8f6] [#x287e #xffc3] [#xac67 #x32c6] [#x8c4f #x5573]
182     [#x695b #x27b0] [#xbbca #x58c8] [#xe1ff #xa35d] [#xb8f0 #x11a0]
183     [#x10fa #x3d98] [#xfd21 #x83b8] [#x4afc #xb56c] [#x2dd1 #xd35b]
184     [#x9a53 #xe479] [#xb6f8 #x4565] [#xd28e #x49bc] [#x4bfb #x9790]
185     [#xe1dd #xf2da] [#xa4cb #x7e33] [#x62fb #x1341] [#xcee4 #xc6e8]
186     [#xef20 #xcada] [#x3677 #x4c01] [#xd07e #x9efe] [#x2bf1 #x1fb4]
187     [#x95db #xda4d] [#xae90 #x9198] [#xeaad #x8e71] [#x6b93 #xd5a0]
188     [#xd08e #xd1d0] [#xafc7 #x25e0] [#x8e3c #x5b2f] [#x8e75 #x94b7]
189     [#x8ff6 #xe2fb] [#xf212 #x2b64] [#x8888 #xb812] [#x900d #xf01c]
190     [#x4fad #x5ea0] [#x688f #xc31c] [#xd1cf #xf191] [#xb3a8 #xc1ad]
191     [#x2f2f #x2218] [#xbe0e #x1777] [#xea75 #x2dfe] [#x8b02 #x1fa1]
192     [#xe5a0 #xcc0f] [#xb56f #x74e8] [#x18ac #xf3d6] [#xce89 #xe299]
193     [#xb4a8 #x4fe0] [#xfd13 #xe0b7] [#x7cc4 #x3b81] [#xd2ad #xa8d9]
194     [#x165f #xa266] [#x8095 #x7705] [#x93cc #x7314] [#x211a #x1477]
195     [#xe6ad #x2065] [#x77b5 #xfa86] [#xc754 #x42f5] [#xfb9d #x35cf]
196     [#xebcd #xaf0c] [#x7b3e #x89a0] [#xd641 #x1bd3] [#xae1e #x7e49]
197     [#x0025 #x0e2d] [#x2071 #xb35e] [#x2268 #x00bb] [#x57b8 #xe0af]
198     [#x2464 #x369b] [#xf009 #xb91e] [#x5563 #x911d] [#x59df #xa6aa]
199     [#x78c1 #x4389] [#xd95a #x537f] [#x207d #x5ba2] [#x02e5 #xb9c5]
200     [#x8326 #x0376] [#x6295 #xcfa9] [#x11c8 #x1968] [#x4e73 #x4a41]
201     [#xb347 #x2dca] [#x7b14 #xa94a] [#x1b51 #x0052] [#x9a53 #x2915]
202     [#xd60f #x573f] [#xbc9b #xc6e4] [#x2b60 #xa476] [#x81e6 #x7400]
203     [#x08ba #x6fb5] [#x571b #xe91f] [#xf296 #xec6b] [#x2a0d #xd915]
204     [#xb663 #x6521] [#xe7b9 #xf9b6] [#xff34 #x052e] [#xc585 #x5664]
205     [#x53b0 #x2d5d] [#xa99f #x8fa1] [#x08ba #x4799] [#x6e85 #x076a]
206     ]
207    [
208    [#x4b7a #x70e9] [#xb5b3 #x2944] [#xdb75 #x092e] [#xc419 #x2623]
209    [#xad6e #xa6b0] [#x49a7 #xdf7d] [#x9cee #x60b8] [#x8fed #xb266]
210    [#xecaa #x8c71] [#x699a #x17ff] [#x5664 #x526c] [#xc2b1 #x9ee1]
211    [#x1936 #x02a5] [#x7509 #x4c29] [#xa059 #x1340] [#xe418 #x3a3e]
212    [#x3f54 #x989a] [#x5b42 #x9d65] [#x6b8f #xe4d6] [#x99f7 #x3fd6]
213    [#xa1d2 #x9c07] [#xefe8 #x30f5] [#x4d2d #x38e6] [#xf025 #x5dc1]
214    [#x4cdd #x2086] [#x8470 #xeb26] [#x6382 #xe9c6] [#x021e #xcc5e]
215    [#x0968 #x6b3f] [#x3eba #xefc9] [#x3c97 #x1814] [#x6b6a #x70a1]
216    [#x687f #x3584] [#x52a0 #xe286] [#xb79c #x5305] [#xaa50 #x0737]
217    [#x3e07 #x841c] [#x7fde #xae5c] [#x8e7d #x44ec] [#x5716 #xf2b8]
218    [#xb03a #xda37] [#xf050 #x0c0d] [#xf01c #x1f04] [#x0200 #xb3ff]
219    [#xae0c #xf51a] [#x3cb5 #x74b2] [#x2583 #x7a58] [#xdc09 #x21bd]
220    [#xd191 #x13f9] [#x7ca9 #x2ff6] [#x9432 #x4773] [#x22f5 #x4701]
221    [#x3ae5 #xe581] [#x37c2 #xdadc] [#xc8b5 #x7634] [#x9af3 #xdda7]
222    [#xa944 #x6146] [#x0fd0 #x030e] [#xecc8 #xc73e] [#xa475 #x1e41]
223    [#xe238 #xcd99] [#x3bea #x0e2f] [#x3280 #xbba1] [#x183e #xb331]
224    [#x4e54 #x8b38] [#x4f6d #xb908] [#x6f42 #x0d03] [#xf60a #x04bf]
225    [#x2cb8 #x1290] [#x2497 #x7c79] [#x5679 #xb072] [#xbcaf #x89af]
226    [#xde9a #x771f] [#xd993 #x0810] [#xb38b #xae12] [#xdccf #x3f2e]
227    [#x5512 #x721f] [#x2e6b #x7124] [#x501a #xdde6] [#x9f84 #xcd87]
228    [#x7a58 #x4718] [#x7408 #xda17] [#xbc9f #x9abc] [#xe94b #x7d8c]
229    [#xec7a #xec3a] [#xdb85 #x1dfa] [#x6309 #x4366] [#xc464 #xc3d2]
230    [#xef1c #x1847] [#x3215 #xd908] [#xdd43 #x3b37] [#x24c2 #xba16]
231    [#x12a1 #x4d43] [#x2a65 #xc451] [#x5094 #x0002] [#x133a #xe4dd]
232    [#x71df #xf89e] [#x1031 #x4e55] [#x81ac #x77d6] [#x5f11 #x199b]
233    [#x0435 #x56f1] [#xd7a3 #xc76b] [#x3c11 #x183b] [#x5924 #xa509]
234    [#xf28f #xe6ed] [#x97f1 #xfbfa] [#x9eba #xbf2c] [#x1e15 #x3c6e]
235    [#x86e3 #x4570] [#xeae9 #x6fb1] [#x860e #x5e0a] [#x5a3e #x2ab3]
236    [#x771f #xe71c] [#x4e3d #x06fa] [#x2965 #xdcb9] [#x99e7 #x1d0f]
237    [#x803e #x89d6] [#x5266 #xc825] [#x2e4c #xc978] [#x9c10 #xb36a]
238    [#xc615 #x0eba] [#x94e2 #xea78] [#xa5fc #x3c53] [#x1e0a #x2df4]
239    [#xf2f7 #x4ea7] [#x361d #x2b3d] [#x1939 #x260f] [#x19c2 #x7960]
240    [#x5223 #xa708] [#xf713 #x12b6] [#xebad #xfe6e] [#xeac3 #x1f66]
241    [#xe3bc #x4595] [#xa67b #xc883] [#xb17f #x37d1] [#x018c #xff28]
242    [#xc332 #xddef] [#xbe6c #x5aa5] [#x6558 #x2185] [#x68ab #x9802]
243    [#xeece #xa50f] [#xdb2f #x953b] [#x2aef #x7dad] [#x5b6e #x2f84]
244    [#x1521 #xb628] [#x2907 #x6170] [#xecdd #x4775] [#x619f #x1510]
245    [#x13cc #xa830] [#xeb61 #xbd96] [#x0334 #xfe1e] [#xaa03 #x63cf]
246    [#xb573 #x5c90] [#x4c70 #xa239] [#xd59e #x9e0b] [#xcbaa #xde14]
247    [#xeecc #x86bc] [#x6062 #x2ca7] [#x9cab #x5cab] [#xb2f3 #x846e]
248    [#x648b #x1eaf] [#x19bd #xf0ca] [#xa023 #x69b9] [#x655a #xbb50]
249    [#x4068 #x5a32] [#x3c2a #xb4b3] [#x319e #xe9d5] [#xc021 #xb8f7]
250    [#x9b54 #x0b19] [#x875f #xa099] [#x95f7 #x997e] [#x623d #x7da8]
251    [#xf837 #x889a] [#x97e3 #x2d77] [#x11ed #x935f] [#x1668 #x1281]
252    [#x0e35 #x8829] [#xc7e6 #x1fd6] [#x96de #xdfa1] [#x7858 #xba99]
253    [#x57f5 #x84a5] [#x1b22 #x7263] [#x9b83 #xc3ff] [#x1ac2 #x4696]
254    [#xcdb3 #x0aeb] [#x532e #x3054] [#x8fd9 #x48e4] [#x6dbc #x3128]
255    [#x58eb #xf2ef] [#x34c6 #xffea] [#xfe28 #xed61] [#xee7c #x3c73]
256    [#x5d4a #x14d9] [#xe864 #xb7e3] [#x4210 #x5d14] [#x203e #x13e0]
257    [#x45ee #xe2b6] [#xa3aa #xabea] [#xdb6c #x4f15] [#xfacb #x4fd0]
258    [#xc742 #xf442] [#xef6a #xbbb5] [#x654f #x3b1d] [#x41cd #x2105]
259    [#xd81e #x799e] [#x8685 #x4dc7] [#xe44b #x476a] [#x3d81 #x6250]
260    [#xcf62 #xa1f2] [#x5b8d #x2646] [#xfc88 #x83a0] [#xc1c7 #xb6a3]
261    [#x7f15 #x24c3] [#x69cb #x7492] [#x4784 #x8a0b] [#x5692 #xb285]
262    [#x095b #xbf00] [#xad19 #x489d] [#x1462 #xb174] [#x2382 #x0e00]
263    [#x5842 #x8d2a] [#x0c55 #xf5ea] [#x1dad #xf43e] [#x233f #x7061]
264    [#x3372 #xf092] [#x8d93 #x7e41] [#xd65f #xecf1] [#x6c22 #x3bdb]
265    [#x7cde #x3759] [#xcbee #x7460] [#x4085 #xf2a7] [#xce77 #x326e]
266    [#xa607 #x8084] [#x19f8 #x509e] [#xe8ef #xd855] [#x61d9 #x9735]
267    [#xa969 #xa7aa] [#xc50c #x06c2] [#x5a04 #xabfc] [#x800b #xcadc]
268    [#x9e44 #x7a2e] [#xc345 #x3484] [#xfdd5 #x6705] [#x0e1e #x9ec9]
269    [#xdb73 #xdbd3] [#x1055 #x88cd] [#x675f #xda79] [#xe367 #x4340]
270    [#xc5c4 #x3465] [#x713e #x38d8] [#x3d28 #xf89e] [#xf16d #xff20]
271    [#x153e #x21e7] [#x8fb0 #x3d4a] [#xe6e3 #x9f2b] [#xdb83 #xadf7]
272    ]
273    [
274    [#xe93d #x5a68] [#x9481 #x40f7] [#xf64c #x261c] [#x9469 #x2934]
275    [#x4115 #x20f7] [#x7602 #xd4f7] [#xbcf4 #x6b2e] [#xd4a2 #x0068]
276    [#xd408 #x2471] [#x3320 #xf46a] [#x43b7 #xd4b7] [#x5000 #x61af]
277    [#x1e39 #xf62e] [#x9724 #x4546] [#x1421 #x4f74] [#xbf8b #x8840]
278    [#x4d95 #xfc1d] [#x96b5 #x91af] [#x70f4 #xddd3] [#x66a0 #x2f45]
279    [#xbfbc #x09ec] [#x03bd #x9785] [#x7fac #x6dd0] [#x31cb #x8504]
280    [#x96eb #x27b3] [#x55fd #x3941] [#xda25 #x47e6] [#xabca #x0a9a]
281    [#x2850 #x7825] [#x5304 #x29f4] [#x0a2c #x86da] [#xe9b6 #x6dfb]
282    [#x68dc #x1462] [#xd748 #x6900] [#x680e #xc0a4] [#x27a1 #x8dee]
283    [#x4f3f #xfea2] [#xe887 #xad8c] [#xb58c #xe006] [#x7af4 #xd6b6]
284    [#xaace #x1e7c] [#xd337 #x5fec] [#xce78 #xa399] [#x406b #x2a42]
285    [#x20fe #x9e35] [#xd9f3 #x85b9] [#xee39 #xd7ab] [#x3b12 #x4e8b]
286    [#x1dc9 #xfaf7] [#x4b6d #x1856] [#x26a3 #x6631] [#xeae3 #x97b2]
287    [#x3a6e #xfa74] [#xdd5b #x4332] [#x6841 #xe7f7] [#xca78 #x20fb]
288    [#xfb0a #xf54e] [#xd8fe #xb397] [#x4540 #x56ac] [#xba48 #x9527]
289    [#x5553 #x3a3a] [#x2083 #x8d87] [#xfe6b #xa9b7] [#xd096 #x954b]
290    [#x55a8 #x67bc] [#xa115 #x9a58] [#xcca9 #x2963] [#x99e1 #xdb33]
291    [#xa62a #x4a56] [#x3f31 #x25f9] [#x5ef4 #x7e1c] [#x9029 #x317c]
292    [#xfdf8 #xe802] [#x0427 #x2f70] [#x80bb #x155c] [#x0528 #x2ce3]
293    [#x95c1 #x1548] [#xe4c6 #x6d22] [#x48c1 #x133f] [#xc70f #x86dc]
294    [#x07f9 #xc9ee] [#x4104 #x1f0f] [#x4047 #x79a4] [#x5d88 #x6e17]
295    [#x325f #x51eb] [#xd59b #xc0d1] [#xf2bc #xc18f] [#x4111 #x3564]
296    [#x257b #x7834] [#x602a #x9c60] [#xdff8 #xe8a3] [#x1f63 #x6c1b]
297    [#x0e12 #xb4c2] [#x02e1 #x329e] [#xaf66 #x4fd1] [#xcad1 #x8115]
298    [#x6b23 #x95e0] [#x333e #x92e1] [#x3b24 #x0b62] [#xeebe #xb922]
299    [#x85b2 #xa20e] [#xe6ba #x0d99] [#xde72 #x0c8c] [#x2da2 #xf728]
300    [#xd012 #x7845] [#x95b7 #x94fd] [#x647d #x0862] [#xe7cc #xf5f0]
301    [#x5449 #xa36f] [#x877d #x48fa] [#xc39d #xfd27] [#xf33e #x8d1e]
302    [#x0a47 #x6341] [#x992e #xff74] [#x3a6f #x6eab] [#xf4f8 #xfd37]
303    [#xa812 #xdc60] [#xa1eb #xddf8] [#x991b #xe14c] [#xdb6e #x6b0d]
304    [#xc67b #x5510] [#x6d67 #x2c37] [#x2765 #xd43b] [#xdcd0 #xe804]
305    [#xf129 #x0dc7] [#xcc00 #xffa3] [#xb539 #x0f92] [#x690f #xed0b]
306    [#x667b #x9ffb] [#xcedb #x7d9c] [#xa091 #xcf0b] [#xd915 #x5ea3]
307    [#xbb13 #x2f88] [#x515b #xad24] [#x7b94 #x79bf] [#x763b #xd6eb]
308    [#x3739 #x2eb3] [#xcc11 #x5979] [#x8026 #xe297] [#xf42e #x312d]
309    [#x6842 #xada7] [#xc66a #x2b3b] [#x1275 #x4ccc] [#x782e #xf11c]
310    [#x6a12 #x4237] [#xb792 #x51e7] [#x06a1 #xbbe6] [#x4bfb #x6350]
311    [#x1a6b #x1018] [#x11ca #xedfa] [#x3d25 #xbdd8] [#xe2e1 #xc3c9]
312    [#x4442 #x1659] [#x0a12 #x1386] [#xd90c #xec6e] [#xd5ab #xea2a]
313    [#x64af #x674e] [#xda86 #xa85f] [#xbebf #xe988] [#x64e4 #xc3fe]
314    [#x9dbc #x8057] [#xf0f7 #xc086] [#x6078 #x7bf8] [#x6003 #x604d]
315    [#xd1fd #x8346] [#xf638 #x1fb0] [#x7745 #xae04] [#xd736 #xfccc]
316    [#x8342 #x6b33] [#xf01e #xab71] [#xb080 #x4187] [#x3c00 #x5e5f]
317    [#x77a0 #x57be] [#xbde8 #xae24] [#x5546 #x4299] [#xbf58 #x2e61]
318    [#x4e58 #xf48f] [#xf2dd #xfda2] [#xf474 #xef38] [#x8789 #xbdc2]
319    [#x5366 #xf9c3] [#xc8b3 #x8e74] [#xb475 #xf255] [#x46fc #xd9b9]
320    [#x7aeb #x2661] [#x8b1d #xdf84] [#x846a #x0e79] [#x915f #x95e2]
321    [#x466e #x598e] [#x20b4 #x5770] [#x8cd5 #x5591] [#xc902 #xde4c]
322    [#xb90b #xace1] [#xbb82 #x05d0] [#x11a8 #x6248] [#x7574 #xa99e]
323    [#xb77f #x19b6] [#xe0a9 #xdc09] [#x662d #x09a1] [#xc432 #x4633]
324    [#xe85a #x1f02] [#x09f0 #xbe8c] [#x4a99 #xa025] [#x1d6e #xfe10]
325    [#x1ab9 #x3d1d] [#x0ba5 #xa4df] [#xa186 #xf20f] [#x2868 #xf169]
326    [#xdcb7 #xda83] [#x5739 #x06fe] [#xa1e2 #xce9b] [#x4fcd #x7f52]
327    [#x5011 #x5e01] [#xa706 #x83fa] [#xa002 #xb5c4] [#x0de6 #xd027]
328    [#x9af8 #x8c27] [#x773f #x8641] [#xc360 #x4c06] [#x61a8 #x06b5]
329    [#xf017 #x7a28] [#xc0f5 #x86e0] [#x0060 #x58aa] [#x30dc #x7d62]
330    [#x11e6 #x9ed7] [#x2338 #xea63] [#x53c2 #xdd94] [#xc2c2 #x1634]
331    [#xbbcb #xee56] [#x90bc #xb6de] [#xebfc #x7da1] [#xce59 #x1d76]
332    [#x6f05 #xe409] [#x4b7c #x0188] [#x3972 #x0a3d] [#x7c92 #x7c24]
333    [#x86e3 #x725f] [#x724d #x9db9] [#x1ac1 #x5bb4] [#xd39e #xb8fc]
334    [#xed54 #x5578] [#x08fc #xa5b5] [#xd83d #x7cd3] [#x4dad #x0fc4]
335    [#x1e50 #xef5e] [#xb161 #xe6f8] [#xa285 #x14d9] [#x6c51 #x133c]
336    [#x6fd5 #xc7e7] [#x56e1 #x4ec4] [#x362a #xbfce] [#xddc6 #xc837]
337    [#xd79a #x3234] [#x9263 #x8212] [#x670e #xfa8e] [#x4060 #x00e0]
338    ]
339    [
340    [#x3a39 #xce37] [#xd3fa #xf5cf] [#xabc2 #x7737] [#x5ac5 #x2d1b]
341    [#x5cb0 #x679e] [#x4fa3 #x3742] [#xd382 #x2740] [#x99bc #x9bbe]
342    [#xd511 #x8e9d] [#xbf0f #x7315] [#xd62d #x1c7e] [#xc700 #xc47b]
343    [#xb78c #x1b6b] [#x21a1 #x9045] [#xb26e #xb1be] [#x6a36 #x6eb4]
344    [#x5748 #xab2f] [#xbc94 #x6e79] [#xc6a3 #x76d2] [#x6549 #xc2c8]
345    [#x530f #xf8ee] [#x468d #xde7d] [#xd573 #x0a1d] [#x4cd0 #x4dc6]
346    [#x2939 #xbbdb] [#xa9ba #x4650] [#xac95 #x26e8] [#xbe5e #xe304]
347    [#xa1fa #xd5f0] [#x6a2d #x519a] [#x63ef #x8ce2] [#x9a86 #xee22]
348    [#xc089 #xc2b8] [#x4324 #x2ef6] [#xa51e #x03aa] [#x9cf2 #xd0a4]
349    [#x83c0 #x61ba] [#x9be9 #x6a4d] [#x8fe5 #x1550] [#xba64 #x5bd6]
350    [#x2826 #xa2f9] [#xa73a #x3ae1] [#x4ba9 #x9586] [#xef55 #x62e9]
351    [#xc72f #xefd3] [#xf752 #xf7da] [#x3f04 #x6f69] [#x77fa #x0a59]
352    [#x80e4 #xa915] [#x87b0 #x8601] [#x9b09 #xe6ad] [#x3b3e #xe593]
353    [#xe990 #xfd5a] [#x9e34 #xd797] [#x2cf0 #xb7d9] [#x022b #x8b51]
354    [#x96d5 #xac3a] [#x017d #xa67d] [#xd1cf #x3ed6] [#x7c7d #x2d28]
355    [#x1f9f #x25cf] [#xadf2 #xb89b] [#x5ad6 #xb472] [#x5a88 #xf54c]
356    [#xe029 #xac71] [#xe019 #xa5e6] [#x47b0 #xacfd] [#xed93 #xfa9b]
357    [#xe8d3 #xc48d] [#x283b #x57cc] [#xf8d5 #x6629] [#x7913 #x2e28]
358    [#x785f #x0191] [#xed75 #x6055] [#xf796 #x0e44] [#xe3d3 #x5e8c]
359    [#x1505 #x6dd4] [#x88f4 #x6dba] [#x03a1 #x6125] [#x0564 #xf0bd]
360    [#xc3eb #x9e15] [#x3c90 #x57a2] [#x9727 #x1aec] [#xa93a #x072a]
361    [#x1b3f #x6d9b] [#x1e63 #x21f5] [#xf59c #x66fb] [#x26dc #xf319]
362    [#x7533 #xd928] [#xb155 #xfdf5] [#x0356 #x3482] [#x8aba #x3cbb]
363    [#x2851 #x7711] [#xc20a #xd9f8] [#xabcc #x5167] [#xccad #x925f]
364    [#x4de8 #x1751] [#x3830 #xdc8e] [#x379d #x5862] [#x9320 #xf991]
365    [#xea7a #x90c2] [#xfb3e #x7bce] [#x5121 #xce64] [#x774f #xbe32]
366    [#xa8b6 #xe37e] [#xc329 #x3d46] [#x48de #x5369] [#x6413 #xe680]
367    [#xa2ae #x0810] [#xdd6d #xb224] [#x6985 #x2dfd] [#x0907 #x2166]
368    [#xb39a #x460a] [#x6445 #xc0dd] [#x586c #xdecf] [#x1c20 #xc8ae]
369    [#x5bbe #xf7dd] [#x1b58 #x8d40] [#xccd2 #x017f] [#x6bb4 #xe3bb]
370    [#xdda2 #x6a7e] [#x3a59 #xff45] [#x3e35 #x0a44] [#xbcb4 #xcdd5]
371    [#x72ea #xcea8] [#xfa64 #x84bb] [#x8d66 #x12ae] [#xbf3c #x6f47]
372    [#xd29b #xe463] [#x542f #x5d9e] [#xaec2 #x771b] [#xf64e #x6370]
373    [#x740e #x0d8d] [#xe75b #x1357] [#xf872 #x1671] [#xaf53 #x7d5d]
374    [#x4040 #xcb08] [#x4eb4 #xe2cc] [#x34d2 #x466a] [#x0115 #xaf84]
375    [#xe1b0 #x0428] [#x9598 #x3a1d] [#x06b8 #x9fb4] [#xce6e #xa048]
376    [#x6f3f #x3b82] [#x3520 #xab82] [#x011a #x1d4b] [#x2772 #x27f8]
377    [#x6115 #x60b1] [#xe793 #x3fdc] [#xbb3a #x792b] [#x3445 #x25bd]
378    [#xa088 #x39e1] [#x51ce #x794b] [#x2f32 #xc9b7] [#xa01f #xbac9]
379    [#xe01c #xc87e] [#xbcc7 #xd1f6] [#xcf01 #x11c3] [#xa1e8 #xaac7]
380    [#x1a90 #x8749] [#xd44f #xbd9a] [#xd0da #xdecb] [#xd50a #xda38]
381    [#x0339 #xc32a] [#xc691 #x3667] [#x8df9 #x317c] [#xe0b1 #x2b4f]
382    [#xf79e #x59b7] [#x43f5 #xbb3a] [#xf2d5 #x19ff] [#x27d9 #x459c]
383    [#xbf97 #x222c] [#x15e6 #xfc2a] [#x0f91 #xfc71] [#x9b94 #x1525]
384    [#xfae5 #x9361] [#xceb6 #x9ceb] [#xc2a8 #x6459] [#x12ba #xa8d1]
385    [#xb6c1 #x075e] [#xe305 #x6a0c] [#x10d2 #x5065] [#xcb03 #xa442]
386    [#xe0ec #x6e0e] [#x1698 #xdb3b] [#x4c98 #xa0be] [#x3278 #xe964]
387    [#x9f1f #x9532] [#xe0d3 #x92df] [#xd3a0 #x342b] [#x8971 #xf21e]
388    [#x1b0a #x7441] [#x4ba3 #x348c] [#xc5be #x7120] [#xc376 #x32d8]
389    [#xdf35 #x9f8d] [#x9b99 #x2f2e] [#xe60b #x6f47] [#x0fe3 #xf11d]
390    [#xe54c #xda54] [#x1eda #xd891] [#xce62 #x79cf] [#xcd3e #x7e6f]
391    [#x1618 #xb166] [#xfd2c #x1d05] [#x848f #xd2c5] [#xf6fb #x2299]
392    [#xf523 #xf357] [#xa632 #x7623] [#x93a8 #x3531] [#x56cc #xcd02]
393    [#xacf0 #x8162] [#x5a75 #xebb5] [#x6e16 #x3697] [#x88d2 #x73cc]
394    [#xde96 #x6292] [#x81b9 #x49d0] [#x4c50 #x901b] [#x71c6 #x5614]
395    [#xe6c6 #xc7bd] [#x327a #x140a] [#x45e1 #xd006] [#xc3f2 #x7b9a]
396    [#xc9aa #x53fd] [#x62a8 #x0f00] [#xbb25 #xbfe2] [#x35bd #xd2f6]
397    [#x7112 #x6905] [#xb204 #x0222] [#xb6cb #xcf7c] [#xcd76 #x9c2b]
398    [#x5311 #x3ec0] [#x1640 #xe3d3] [#x38ab #xbd60] [#x2547 #xadf0]
399    [#xba38 #x209c] [#xf746 #xce76] [#x77af #xa1c5] [#x2075 #x6060]
400    [#x85cb #xfe4e] [#x8ae8 #x8dd8] [#x7aaa #xf9b0] [#x4cf9 #xaa7e]
401    [#x1948 #xc25c] [#x02fb #x8a8c] [#x01c3 #x6ae4] [#xd6eb #xe1f9]
402    [#x90d4 #xf869] [#xa65c #xdea0] [#x3f09 #x252d] [#xc208 #xe69f]
403    [#xb74e #x6132] [#xce77 #xe25b] [#x578f #xdfe3] [#x3ac3 #x72e6]
404    ]])
405
406 (defconst blowfish-p-array-inits 
407   [
408    [#x243f #x6a88] [#x85a3 #x08d3] [#x1319 #x8a2e] [#x0370 #x7344]
409    [#xa409 #x3822] [#x299f #x31d0] [#x082e #xfa98] [#xec4e #x6c89]
410    [#x4528 #x21e6] [#x38d0 #x1377] [#xbe54 #x66cf] [#x34e9 #x0c6c]
411    [#xc0ac #x29b7] [#xc97c #x50dd] [#x3f84 #xd5b5] [#xb547 #x0917]
412    [#x9216 #xd5d9] [#x8979 #xfb1b]
413    ])
414
415 (defun blowfish-generate-keys (key)
416   "given a key vector \(an even number of 16-bit integers\), returns
417 the p-array and s-boxes for Blowfish encryption using that key, as a
418 pair: \(P-array . S-boxes\)."
419   (let ((s-boxes (vector (make-vector 256 nil)
420                          (make-vector 256 nil)
421                          (make-vector 256 nil)
422                          (make-vector 256 nil)))
423         (p-array (make-vector 18 nil)))
424     ;; copy the initial values into the s-boxes
425     (dotimes (s 4)
426       (let ((s-box (aref s-boxes s))
427             (inits (aref blowfish-s-box-inits s)))
428         (dotimes (idx 256)
429           (aset s-box idx (copy-seq (aref inits idx))))))
430     ;; copy the initial values into the p-array
431     (dotimes (idx 18)
432       (aset p-array idx (copy-seq (aref blowfish-p-array-inits idx))))
433
434     ;; mix the key into the P-array
435     (let ((keylen (length key)))
436       (assert (and (>= keylen 2) (evenp keylen)) nil
437               "Blowfish key must be a positive multiple of 2 elements long.")
438
439       (dotimes (idx 18)
440         (let* ((keyidx (mod (* 2 idx) keylen))
441                (keyval (vector (aref key keyidx) 
442                                (aref key (1+ keyidx))))
443                (p-entry (aref p-array idx)))
444           (blowfish-xor p-entry keyval p-entry)
445           ;; clean up
446           (fillarray keyval 0))))
447
448     ;; begin the iterated filling of the P-array and S-boxes
449     (let ((data (vector 0 0 0 0)))
450       ;; fill the P-array
451       (do ((idx 0 (+ idx 2)))
452           ((= idx 18))
453         ;; encipher data w/ the current P-array and S-boxes
454         (blowfish-cipher-block data p-array s-boxes)
455         ;; replace the next two P-array elements with the new data
456         (let ((Pa (aref p-array idx))
457               (Pb (aref p-array (1+ idx))))
458           (aset Pa 0 (aref data 0))
459           (aset Pa 1 (aref data 1))
460           (aset Pb 0 (aref data 2))
461           (aset Pb 1 (aref data 3))))
462
463       ;; fill the S-boxes
464       (dotimes (s 4)
465         (do ((idx 0 (+ idx 2))
466              (s-box (aref s-boxes s)))
467             ((= idx 256))
468           ;; encipher data w/ the current P-array and S-boxes
469           (blowfish-cipher-block data p-array s-boxes)
470           ;; replace the next two S-box elements with the new data
471           (let ((Sa (aref s-box idx))
472                 (Sb (aref s-box (1+ idx))))
473             (aset Sa 0 (aref data 0))
474             (aset Sa 1 (aref data 1))
475             (aset Sb 0 (aref data 2))
476             (aset Sb 1 (aref data 3)))))
477
478       ;; clean up
479       (fillarray data 0))
480       
481     ;; return the result
482     (cons p-array s-boxes)))