lisp-encryption-practice/vigenere.lisp

64 lines
2.4 KiB
Common Lisp

;; vigenere.lisp - Simple implementation of a Vigenere cipher.
;;
;; This file is free software under the terms of the GPL3 license. You can find
;; a copy of the license at: https://www.gnu.org/licenses/gpl-3.0.en.html
(defpackage vigenere
(:use :cl)
(:export
:+vigenere-alphabet+ :+vigenere-inverse-alphabet+ :vigenere-letter-char
:vigenere-char-letter :vigenere-add :vigenere-encrypt :vigenere-invert-char
:vigenere-decrypt))
(in-package vigenere)
(defparameter +vigenere-alphabet+
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789."
"Alphabet for use in `vigenere-encrypt'.")
(defparameter +vigenere-inverse-alphabet+
(loop with alph = (make-array 123 :initial-element 0)
for i below (length +vigenere-alphabet+)
for char = (aref +vigenere-alphabet+ i)
do (setf (aref alph (char-code char)) i)
finally (return alph))
"Inverse lookup table for `vigenere-encrypt'.")
(defun vigenere-letter-char (letter)
"Convert LETTER to a Lisp char object."
(aref +vigenere-alphabet+ letter))
(defun vigenere-char-letter (char)
"Convert a Lisp char object CHAR to a letter."
(aref +vigenere-inverse-alphabet+ (char-code char)))
(defun vigenere-add (elem by)
"Add ELEM and BY under the modulo (length `+vigenere-alphabet+')"
(mod (+ elem by) (length +vigenere-alphabet+)))
(defun vigenere-encrypt (plain key)
"Encrypt PLAIN using a vigenere cipher. This works by shifting each element of
PLAIN by each consecutive elements of KEY, wrapping around if there are no more
elements left in KEY."
(let ((done (make-array (length plain))))
(dotimes (i (length plain) (map 'string 'vigenere-letter-char
done))
(setf (aref done i)
(vigenere-add (vigenere-char-letter (aref plain i))
(vigenere-char-letter
(aref key (mod i (length key)))))))))
(defun vigenere-invert-char (char)
"Invert CHAR. That is, return the character that will invert the effect that
CHAR had during encryption."
(let ((letter (vigenere-char-letter char)))
(vigenere-letter-char (- (length +vigenere-alphabet+) letter))))
(defun vigenere-decrypt (cipher key)
"Decrypt CIPHER using a vigenere cipher, with the key KEY."
(vigenere-encrypt cipher (map 'string 'vigenere-invert-char key)))
;; Local Variables:
;; jinx-local-words: "vigenere"
;; End: