I've been trying to teach myself lisp for a while now. Below is
some lisp code to encrypt a message using the RC4 algorithm. It
is basically a literal translation of the C code for RC4 encryption
available on the internet. It produces the same results as the
test vectors given with the C code, so I believe it is correct.
What I'd like to know is, is there a 'better' way to write this.
Something that looks less like C code.
I'm not trying to squeeze maximum performance out of this, it's just
an exercise.
(defun make-new-rc4-codebook (key)
"Return an RC4 codebook initialized with key.
Key is 1 to 256 8 bit integers"
(let
((codebook (make-array '(256) :initial-element 0))
(index1 0)
(index2 0)
(tmp 0)
(key-length (length key)))
(do ((n 0 (+ 1 n)))
((= n 256) nil)
(setf (aref codebook n) n))
(do ((n 0 (+ 1 n)))
((= n 256) codebook)
(setf index2 (mod (+ (aref key index1) (aref codebook n) index2) 256))
(setf tmp (aref codebook n))
(setf (aref codebook n) (aref codebook index2))
(setf (aref codebook index2) tmp)
(setf index1 (mod (+ 1 index1) key-length)))))
(defun rc4-crypt (key msg)
"Encrypt msg using rc4 algorithm with key given"
(let ((codebook (make-new-rc4-codebook key))
(x 0)
(y 0)
(tmp nil))
(do ((n 0 (+ 1 n)))
((= n (length msg)) msg)
(setf y (mod (+ (setf tmp (aref codebook (setf x (mod (+ x 1)
256))))
y)
256))
(setf (aref codebook x) (aref codebook y))
(setf (aref codebook y) tmp)
(setf (aref msg n) (mod (logxor (aref msg n)
(aref codebook (mod (+ (aref codebook x)
(aref codebook y))
256)))
256)))))
(defun run-tests ()
"Run the tests"
;; Test vector 0
;; Key: 0x01 0x23 0x45 0x67 0x89 0xab 0xcd 0xef
;; Input: 0x01 0x23 0x45 0x67 0x89 0xab 0xcd 0xef
;; 0 Output: 0x75 0xb7 0x87 0x80 0x99 0xe0 0xc5 0x96
(let ((key (make-array '(8)
:initial-contents '(#x1 #x23 #x45 #x67 #x89 #xab #xcd #xef)))
(msg (make-array '(8)
:initial-contents '(#x1 #x23 #x45 #x67 #x89 #xab #xcd #xef)))
(*print-base* 16))
(print "key")
(print key)
(print "Input msg")
(print msg)
(print "output msg")
(print (rc4-crypt key msg))
;; Test vector 1
;; Key: 0x01 0x23 0x45 0x67 0x89 0xab 0xcd 0xef
;; Input: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
;; 0 Output: 0x74 0x94 0xc2 0xe7 0x10 0x4b 0x08 0x79
(setf key (make-array '(8)
:initial-contents '(#x1 #x23 #x45 #x67 #x89 #xab #xcd #xef)))
(setf msg (make-array '(8)
:initial-contents '(0 0 0 0 0 0 0 0)))
(print "key")
(print key)
(print "Input msg")
(print msg)
(print "output msg")
(print (rc4-crypt key msg))
;; Test vector 2
;; Key: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
;; Input: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
;; 0 Output: 0xde 0x18 0x89 0x41 0xa3 0x37 0x5d 0x3a
(setf key (make-array '(8) :initial-contents '(0 0 0 0 0 0 0 0)))
(setf msg (make-array '(8) :initial-contents '(0 0 0 0 0 0 0 0)))
(print "key")
(print key)
(print "Input msg")
(print msg)
(print "output msg")
(print (rc4-crypt key msg))))
> Hi all,
>
> I've been trying to teach myself lisp for a while now. Below is
> some lisp code to encrypt a message using the RC4 algorithm. It
> is basically a literal translation of the C code for RC4 encryption
> available on the internet. It produces the same results as the
> test vectors given with the C code, so I believe it is correct.
>
> What I'd like to know is, is there a 'better' way to write this.
> Something that looks less like C code.
Maybe there is. You could use some more built-in functionality
like DOTIMES, LOOP and ROTATEF. Example:
(defun make-new-rc4-codebook (key)
"Return an RC4 codebook initialized with key.
Key is 1 to 256 8 bit integers"
(let ((codebook (make-array '(256) :initial-element 0))
(key-length (length key)))
(dotimes (n 256)
(setf (aref codebook n) n))
(loop for n below 256
for index1 = 0 then (mod (1+ index1) key-length)
with index2 = 0
do (setf index2 (mod (+ (aref key index1)
(aref codebook n)
index2)
256))
do (rotatef (aref codebook n) (aref codebook index2)))
codebook))
But this really doesn't change that much.
> (defun run-tests ()
> "Run the tests"
For experimenting with algorithms it is sometimes
quite handy to use a regression tester.
; deftest NAME FORM &rest VALUES
(rt:deftest "test1"
(rc4-crypt (make-array '(8) :initial-contents '(#x1 #x23 #x45 #x67 #x89 #xab #xcd #xef))
(make-array '(8) :initial-contents '(#x1 #x23 #x45 #x67 #x89 #xab #xcd #xef)))
#(#x75 #xb7 #x87 #x80 #x99 #xe0 #xc5 #x96))
(rt:do-tests)
You would need to modify the "RT" regression tester from
the CMU Lisp archive for your purpose.
--
Rainer Joswig, Hamburg, Germany
Email: mailto:jos...@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/