All pastes #1179692 Raw Edit

rc4.lisp

public text v1 · immutable
#1179692 ·published 2008-08-20 14:57 UTC
rendered paste body
;; Common Lisp RC4 implementation as an exercise
;; Released in the Public Domain.

;; TODO:
;; - Attempt to specialize methods afterwards for other objects than strings
;; - Attempt to cleanup code further
;; - Write with-key-init or such macro
;; - Write stream-type functions for it


(declaim (optimize (speed 3) (safety 1))
	 (inline -key-init)
	 (inline key-random)
	 (inline key-random-add))


(defpackage :mm-rc4
  (:use :cl)
  (:nicknames :rc4)
  (:export
   #:key-init
   #:key-random-add
   #:key-random
   #:key-destroy))


(in-package :rc4)


(defclass rc4-type ()
  ((x
    :type fixnum
    :accessor key-x
    :initform 0)
   (y
    :type fixnum
    :accessor key-y
    :initform 0)
   (state
    :type (simple-array fixnum (256))
    :accessor key-state
    :initform (make-array 256 :element-type 'fixnum :initial-element 0))))


(defgeneric -key-init (key))

(defmethod -key-init ((k rc4-type))
  (setf (key-x k) 0)
  (setf (key-y k) 0)
  (loop
     for i from 0 to 255
     do (setf (aref (the (simple-array fixnum (256)) (key-state k)) i) i)))


(defgeneric key-init (key data discard))

(defmethod key-init ((k rc4-type) (s string) (discard fixnum))
  (-key-init k)
  (key-random-add k s discard))


(defgeneric key-random-add (key data discard))

(defmethod key-random-add ((k rc4-type) (s string) (discard fixnum))
  (let ((y 0) (si 0) (slen (length s)))
    (with-accessors ((sa key-state)) k
      (declare (type fixnum y si slen)
	       (type (simple-array fixnum (256)) sa)
	       (type (simple-array character (*)) s))
      (loop
	 for x from 0 to 255
	 do (progn
	      (setf
	       y (logand (+ y (aref sa x) (char-code (char s si))) #Xff)
	       si (mod (1+ si) slen))
	      (psetf (aref sa x) (aref sa y)
		     (aref sa y) (aref sa x))))))
  (loop
     repeat discard
     do (key-random k)))


(defgeneric key-random (key))

(defmethod key-random ((k rc4-type))
  (with-accessors ((sa key-state) (kx key-x) (ky key-y)) k
    (declare (type fixnum kx ky)
	     (type (simple-array fixnum (256)) sa))
    (setf
     kx (logand (1+ kx) #Xff)
     ky (logand (+ ky (aref sa kx)) #Xff))
    (psetf (aref sa kx) (aref sa ky)
	   (aref sa ky) (aref sa kx))
    (aref sa (logand (+ (aref sa kx) (aref sa ky)) #Xff))))


(defgeneric key-encode (k s))

;; XXX This would fail with length == 0!
;; Also, now only supports destructive mode.
(defmethod key-encode ((k rc4-type) (s string))
  (let ((slen (1- (length s))))
    (declare (type fixnum slen)
	     (type (simple-array character (*)) s))
    (loop
       for i from 0 to slen
       do (setf (char s i)
		(code-char
		 (logxor (char-code (char s i))
			 (the fixnum (key-random k)))))))
  s)


(defgeneric key-destroy (k))

(defmethod key-destroy ((k rc4-type))
  (setf (key-x k) 0)
  (setf (key-y k) 0)
  (loop
     for i from (the fixnum 0) to 255
     do (setf (aref (the (simple-array fixnum (256)) (key-state k)) i) 0)))



(defvar *k*)
(setf *k* (make-instance 'rc4-type))
(key-init *k* "This is a test" 3072)
;;(key-destroy *k*)