;;; -*- Mode:LISP; Package:(CRYPT GLOBAL); Readtable:ZL; Base:10 -*- ;; This program implements the ;; Proposed Federal Information Processing ;; Data Encryption Standard. ;; See Federal Register, March 17, 1975 (40FR12134) (defmacro define-array (name dimlist &optional contents) (let ((v (intern (string-append "*" name "*"))) (l (mapcar #'(lambda (ignore) (gentemp "i")) dimlist))) `(progn 'compile (defparameter ,v (char-array-init ',dimlist ',contents)) (defmacro ,name ,l (list 'aref ',v ,@l))))) (defun char-array-init (dimlist contents) (let ((a (if (not (numberp (car dimlist))) (make-array (length contents)) (make-array dimlist)))) (fillarray a (if (not contents) (list 0) contents)) a)) ;; Initial permutation, (define-array IP (NIL) (58 50 42 34 26 18 10 2 60 52 44 36 28 20 12 4 62 54 46 38 30 22 14 6 64 56 48 40 32 24 16 8 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)) ;; Final permutation, FP = IP^(-1) (define-array FP (NIL) (40 8 48 16 56 24 64 32 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)) ;; Permuted-choice 1 from the key bits ;; to yield C and D. ;; Note that bits 8,16... are left out: ;; They are intended for a parity check. (define-array PC1_C (NIL) (57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 27 19 11 3 60 52 44 36)) (define-array PC1_D (NIL) (63 55 47 39 31 23 15 7 62 54 46 38 30 22 14 6 61 53 45 37 29 21 13 5 28 20 12 4)) ;; Sequence of shifts used for the key schedule. (define-array shifts (NIL) (1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 1)) ;; Permuted-choice 2, to pick out the bits from ;; the CD array that generate the key schedule. (define-array PC2_C (NIL) (14 17 11 24 1 5 3 28 15 6 21 10 23 19 12 4 26 8 16 7 27 20 13 2)) (define-array PC2_D (NIL) (41 52 31 37 47 55 30 40 51 45 33 48 44 49 39 56 34 53 46 42 50 36 29 32)) ;; The C and D arrays used to calculate the key schedule. (define-array C (28)) (define-array D (28)) ;; The key schedule. ;; Generated from the key. (define-array ks (16 48)) ;; Set up the key schedule from the key. (defun setkey (key &aux temp) (macrolet ((key (index) `(aref key ,index))) ;; First, generate C and D by permuting ;; the key. The low order bit of each ;; 8-bit char is not used, so C and D are only 28 ;; bits apiece. (dotimes (i 28) (setf (c i) (key (1- (pc1_c i)))) (setf (d i) (key (1- (pc1_d i))))) ;; To generate Ki, rotate C and D according ;; to schedule and pick up a permutation ;; using PC2. (dotimes (i 16) ;; rotate. (dotimes (k (shifts i)) (setq temp (c 0)) (dotimes (j 26) (setf (c j) (c (1+ j)))) (setf (c 27) temp) (setq temp (d 0)) (dotimes (j 26) (setf (d j) (d (1+ j)))) (setf (d 27) temp)) ;; get Ki. Note C and D are concatenated. (dotimes (j 14) (setf (ks i j) (c (- (pc2_c j) 1))) (setf (ks i (+ j 24)) (d (- (pc2_d j) 28 1))))))) ;; The E bit-selection table. (define-array EB (48)) (define-array e (NIL) (32 1 2 3 4 5 4 5 6 7 8 9 8 9 10 11 12 13 12 13 14 15 16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29 30 31 32 1)) ;; The 8 selection functions. ;; For some reason, they give a 0-origin ;; index, unlike everything else. (define-array S (8 64) (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 )) ;; P is a permutation on the selected combination ;; of the current L and key. (define-array p (nil) (16 7 20 21 29 12 28 17 1 15 23 26 5 18 31 10 2 8 24 14 32 27 3 9 19 13 30 6 22 11 4 25)) ;; The current block, divided into 2 halves. (define-array l (64)) (define-array r (64)) (define-array templ (32)) (define-array f (32)) ;; The combination of the key and the input, before selection. (define-array pres (48)) ;; The payoff: encrypt a block. (defun encrypt (block edflag &aux temp i k) (macrolet ((block (index) `(aref block ,index))) (dotimes (j 64) (setf (l j) (block (- (ip j) 1)))) ;; Perform an encryption operation 16 times. (dotimes (ii 16) ;; Set direction (if edflag (setq i (- 15 ii)) (setq i ii)) ;; Save the R array, ;; which will be the new L. (dotimes (j 32) (setf (templ j) (r j))) ;; Expand R to 48 bits using the E selector; ;; exclusive-or with the current key bits. (dotimes (j 48) (setf (pres j) (logxor (r (- (e j) 1)) (ks i j)))) ;; The pre-select bits are now considered ;; in 8 groups of 6 bits each. ;; The 8 selection functions map these ;; 6-bit quantities into 4-bit quantities ;; and the results permuted ;; to make an f(R, K). ;; The indexing into the selection functions ;; is peculiar; it could be simplified by ;; rewriting the tables. (dotimes (j 8) (setq temp (* 6 j)) (setq k (s j (+ (ash (pres (+ temp 0)) 5) (ash (pres (+ temp 1)) 3) (ash (pres (+ temp 2)) 2) (ash (pres (+ temp 3)) 1) (ash (pres (+ temp 4)) 0) (ash (pres (+ temp 5)) 4)))) (setq temp (* 4 j)) (setf (f (+ temp 0)) (logand (ash k -3) 1)) (setf (f (+ temp 1)) (logand (ash k -2) 1)) (setf (f (+ temp 2)) (logand (ash k -1) 1)) (setf (f (+ temp 3)) (logand (ash k -0) 1))) ;; The new R is L ^ f(R, K). ;; The f here has to be permuted first, though. (dotimes (j 32) (setf (r j) (logxor (l j) (f (- (p j) 1))))) ;; Finally, the new L (the original R) ;; is copied back. (dotimes (j 32) (setf (l j) (templ j)))) ;; The output L and R are reversed. (dotimes (j 32) (setq temp (l j)) (setf (l j) (r j)) (setf (r j) temp)) ;; The final output ;; gets the inverse permutation of the very original. (dotimes (j 64) (setf (block j) (l (- (fp j) 1)))))) (define-array bblock (66)) (define-array iobuf (16)) (defun crypt (pw salt &aux c temp) (macrolet ((pw (index) `(aref pw ,index)) (salt (index) `(aref salt ,index))) (dotimes (i 65) (setf (bblock i) 0)) (do ((i 0) (pwi 0 (1+ pwi)) (n (length pw))) ((or (= pwi n) (= i 64))) (setq c (pw pwi)) (dotimes (j 7) (setf (bblock i) (logand (ash c (- j 6)) 1)) (incf i)) (incf i)) (setkey *bblock*) (dotimes (i 65) (setf (bblock i) 0)) (dotimes (i 48) (setf (eb i) (e i))) (dotimes (i 2) (setq c (salt i)) (setf (iobuf i) c) (if (> c #.(char-code #\Z)) (setq c (- c 6))) (if (> c #.(char-code #\9)) (setq c (- c 7))) (setq c (- c #.(char-code #\.))) (dotimes (j 6) (when (not (zerop (logand (ash c (- j)) 1))) (setq temp (eb (+ (* 6 i) j))) (setf (eb (+ (* 6 i) j)) (eb (+ (* 6 i) j 24))) (setf (eb (+ (* 6 i) j 24)) temp)))) (dotimes (i 25) (encrypt *bblock* nil)) (dotimes (i 11) (setq c 0) (dotimes (j 6) (setq c (ash c 1)) (setq c (logior c (bblock (+ (* 6 i) j)))) (setq c (+ c #.(char-code #\.))) (if (> c #\9) (setq c (+ c 7))) (if (> c #\Z) (setq c (+ c 6))) (setf (iobuf (+ i 2)) c))) ; (setf (iobuf (+ i 2)) 0) (if (= (iobuf 1) 0) (setf (iobuf 1) (iobuf 0))) *iobuf*))