nullprogram.com/blog/2009/04/26/
I have previously talked about arcfour
and CipherSaber and provided
implementations in C. For fun, I made an implementation of arcfour in
Emacs lisp (elisp), and built upon that to make a CipherSaber
implementation in elisp. Check it out with Git,
git clone git://github.com/skeeto/arcfour.git
If you don't have Git (yet), you can follow that link to use the web
interface. The relevant files are arcfour.el
and
ciphersaber.el
. There are some test vectors in there that
I won't show here. Here is the arcfour implementation,
(defun rc4-init-state ()
"Initialize the arcfour state vector."
(interactive)
(setq rc4-state (make-vector 256 0))
(setq rc4-i 0)
(setq rc4-j 0)
(let (i)
(dotimes (i 256 rc4-state)
(aset rc4-state i i))))
(defun rc4-swap (i j)
"Swap two elements in the state vector."
(let ((temp (aref rc4-state i)))
(aset rc4-state i (aref rc4-state j))
(aset rc4-state j temp)))
(defun rc4-key-sched (key)
"Arcfour key-scheduler: initialize state from key."
(interactive "sEnter key: ")
(let ((j 0) i)
(dotimes (i 256 rc4-state)
(setq j (% (+ j
(aref rc4-state i)
(aref key (% i (length key)))) 256))
(rc4-swap i j))))
(defun rc4-gen-byte ()
"Generate a single byte."
(interactive)
(setq rc4-i (% (1+ rc4-i) 256))
(setq rc4-j (% (+ rc4-j (aref rc4-state rc4-i)) 256))
(rc4-swap rc4-i rc4-j)
(aref rc4-state (% (+ (aref rc4-state rc4-i)
(aref rc4-state rc4-j)) 256)))
For the sake of simplicity it uses some global variables to store the
cipher state. It would be better if the state was returned as a list,
continuation, or closure. That way we could run a bunch of different
ciphers at the same time.
And this provides interactive functions so that they can be called by
a user right on the buffer being used, with M-x rc4-buffer
.
(defun rc4-region (start end key)
"Encrypt/decrypt region with arcfour using given key."
(interactive "r\nsEnter key: ")
(rc4-init-state)
(rc4-key-sched key)
(save-excursion
(let (c)
(goto-char start)
(while (< (point) end)
(setq c (char-after))
(delete-char 1)
(insert-char (logxor c (rc4-gen-byte)) 1)))))
(defun rc4-buffer (key)
"Encrypt/decrypt entire buffer with arcfour."
(interactive "sEnter key: ")
(rc4-region (point-min) (point-max) key))
You may run into encoding issues with encrypted regions. The
CipherSaber implementation below gets around this problem by turning
off multi-byte encoding with set-buffer-multibyte
.
In ciphersaber.el
we apply these functions. The
CipherSaber functions can be called with M-x
cs-encrypt-buffer
and M-x cs-decrypt-buffer
. Note
that this is only CipherSaber-1, and I leave CipherSaber-2 as an
exercise for the reader :-P.
(defun cs-encrypt-buffer (key)
"Encrypt buffer with CipherSaber-1."
(interactive "sEnter key: ")
(set-buffer-multibyte nil)
(let* ((iv (cs-generate-iv))
(cs-key (concat key iv)))
(rc4-buffer cs-key)
(beginning-of-buffer)
(insert iv)))
(defun cs-decrypt-buffer (key)
"Decrypt buffer with CipherSaber-1."
(interactive "sEnter key: ")
(let* ((iv (cs-retrieve-iv))
(cs-key (concat key iv)))
(rc4-buffer cs-key)))
(defun cs-generate-iv ()
"Generate a 10-byte initialization vector."
(let ((iv "") i)
(dotimes (i 10 iv)
(setq iv (concat iv (char-to-string (random 256)))))))
(defun cs-retrieve-iv ()
"Remove initialization vector from buffer and return it."
(beginning-of-buffer)
(let ((iv "") i)
(dotimes (i 10 iv)
(setq iv (concat iv (char-to-string (char-after))))
(delete-char 1))))
I didn't bother with save-excursion
because I didn't
think it would be important where the point is in the middle of an
encrypted file. Feel free to add it, though!
These functions could be used to make a minor mode to transparently
encrypt and decrypt CipherSaber files. It could also be modified to
take advantage of Emacs' batch mode to handle CipherSaber
processing right from the shell. But those are other projects!