diff --git a/ironclad.asd b/ironclad.asd index 4846d72..c33c959 100644 --- a/ironclad.asd +++ b/ironclad.asd @@ -78,6 +78,7 @@ (:file "tea" :depends-on ("cipher")) (:file "xtea" :depends-on ("cipher")) (:file "cast5" :depends-on ("cipher")) + (:file "serpent" :depends-on ("cipher")) ;; stream ciphers (:file "arcfour" :depends-on ("cipher")) (:file "salsa20" :depends-on ("cipher")) @@ -283,6 +284,7 @@ (:test-vector-file "tea") (:test-vector-file "xtea") (:test-vector-file "cast5") + (:test-vector-file "serpent") ;; modes (:test-vector-file "cbc") (:test-vector-file "ctr") diff --git a/src/ciphers/serpent.lisp b/src/ciphers/serpent.lisp new file mode 100644 index 0000000..0d8e502 --- /dev/null +++ b/src/ciphers/serpent.lisp @@ -0,0 +1,630 @@ +;;;; -*- mode: lisp; indent-tabs-mode: nil -*- +;;;; serpent.lisp -- implementation of the Serpent block cipher + +(in-package :crypto) + + +;;; S-Boxes + +(defmacro serpent-sbox0 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r3 (logxor ,r3 ,r0) + ,t0 ,r1 + ,r1 (logand ,r1 ,r3) + ,t0 (logxor ,t0 ,r2) + ,r1 (logxor ,r1 ,r0) + ,r0 (logior ,r0 ,r3) + ,r0 (logxor ,r0 ,t0) + ,t0 (logxor ,t0 ,r3) + ,r3 (logxor ,r3 ,r2) + ,r2 (logior ,r2 ,r1) + ,r2 (logxor ,r2 ,t0) + ,t0 (mod32lognot ,t0) + ,t0 (logior ,t0 ,r1) + ,r1 (logxor ,r1 ,r3) + ,r1 (logxor ,r1 ,t0) + ,r3 (logior ,r3 ,r0) + ,r1 (logxor ,r1 ,r3) + ,t0 (logxor ,t0 ,r3) + ,o0 ,r1 + ,o1 ,t0 + ,o2 ,r2 + ,o3 ,r0)) + +(defmacro serpent-sbox0-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r2 (mod32lognot ,r2) + ,t0 ,r1 + ,r1 (logior ,r1 ,r0) + ,t0 (mod32lognot ,t0) + ,r1 (logxor ,r1 ,r2) + ,r2 (logior ,r2 ,t0) + ,r1 (logxor ,r1 ,r3) + ,r0 (logxor ,r0 ,t0) + ,r2 (logxor ,r2 ,r0) + ,r0 (logand ,r0 ,r3) + ,t0 (logxor ,t0 ,r0) + ,r0 (logior ,r0 ,r1) + ,r0 (logxor ,r0 ,r2) + ,r3 (logxor ,r3 ,t0) + ,r2 (logxor ,r2 ,r1) + ,r3 (logxor ,r3 ,r0) + ,r3 (logxor ,r3 ,r1) + ,r2 (logand ,r2 ,r3) + ,t0 (logxor ,t0 ,r2) + ,o0 ,r0 + ,o1 ,t0 + ,o2 ,r1 + ,o3 ,r3)) + +(defmacro serpent-sbox1 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r0 (mod32lognot ,r0) + ,r2 (mod32lognot ,r2) + ,t0 ,r0 + ,r0 (logand ,r0 ,r1) + ,r2 (logxor ,r0 ,r2) + ,r0 (logior ,r0 ,r3) + ,r3 (logxor ,r3 ,r2) + ,r1 (logxor ,r1 ,r0) + ,r0 (logxor ,r0 ,t0) + ,t0 (logior ,t0 ,r1) + ,r1 (logxor ,r1 ,r3) + ,r2 (logior ,r2 ,r0) + ,r2 (logand ,r2 ,t0) + ,r0 (logxor ,r0 ,r1) + ,r1 (logand ,r1 ,r2) + ,r1 (logxor ,r1 ,r0) + ,r0 (logand ,r0 ,r2) + ,r0 (logxor ,r0 ,t0) + ,o0 ,r2 + ,o1 ,r0 + ,o2 ,r3 + ,o3 ,r1)) + +(defmacro serpent-sbox1-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r1 + ,r1 (logxor ,r1 ,r3) + ,r3 (logand ,r3 ,r1) + ,t0 (logxor ,t0 ,r2) + ,r3 (logxor ,r3 ,r0) + ,r0 (logior ,r0 ,r1) + ,r2 (logxor ,r2 ,r3) + ,r0 (logxor ,r0 ,t0) + ,r0 (logior ,r0 ,r2) + ,r1 (logxor ,r1 ,r3) + ,r0 (logxor ,r0 ,r1) + ,r1 (logior ,r1 ,r3) + ,r1 (logxor ,r1 ,r0) + ,t0 (mod32lognot ,t0) + ,t0 (logxor ,t0 ,r1) + ,r1 (logior ,r1 ,r0) + ,r1 (logxor ,r1 ,r0) + ,r1 (logior ,r1 ,t0) + ,r3 (logxor ,r3 ,r1) + ,o0 ,t0 + ,o1 ,r0 + ,o2 ,r3 + ,o3 ,r2)) + +(defmacro serpent-sbox2 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r0 + ,r0 (logand ,r0 ,r2) + ,r0 (logxor ,r0 ,r3) + ,r2 (logxor ,r2 ,r1) + ,r2 (logxor ,r2 ,r0) + ,r3 (logior ,r3 ,t0) + ,r3 (logxor ,r3 ,r1) + ,t0 (logxor ,t0 ,r2) + ,r1 ,r3 + ,r3 (logior ,r3 ,t0) + ,r3 (logxor ,r3 ,r0) + ,r0 (logand ,r0 ,r1) + ,t0 (logxor ,t0 ,r0) + ,r1 (logxor ,r1 ,r3) + ,r1 (logxor ,r1 ,t0) + ,t0 (mod32lognot ,t0) + ,o0 ,r2 + ,o1 ,r3 + ,o2 ,r1 + ,o3 ,t0)) + +(defmacro serpent-sbox2-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r2 (logxor ,r2 ,r3) + ,r3 (logxor ,r3 ,r0) + ,t0 ,r3 + ,r3 (logand ,r3 ,r2) + ,r3 (logxor ,r3 ,r1) + ,r1 (logior ,r1 ,r2) + ,r1 (logxor ,r1 ,t0) + ,t0 (logand ,t0 ,r3) + ,r2 (logxor ,r2 ,r3) + ,t0 (logand ,t0 ,r0) + ,t0 (logxor ,t0 ,r2) + ,r2 (logand ,r2 ,r1) + ,r2 (logior ,r2 ,r0) + ,r3 (mod32lognot ,r3) + ,r2 (logxor ,r2 ,r3) + ,r0 (logxor ,r0 ,r3) + ,r0 (logand ,r0 ,r1) + ,r3 (logxor ,r3 ,t0) + ,r3 (logxor ,r3 ,r0) + ,o0 ,r1 + ,o1 ,t0 + ,o2 ,r2 + ,o3 ,r3)) + +(defmacro serpent-sbox3 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r0 + ,r0 (logior ,r0 ,r3) + ,r3 (logxor ,r3 ,r1) + ,r1 (logand ,r1 ,t0) + ,t0 (logxor ,t0 ,r2) + ,r2 (logxor ,r2 ,r3) + ,r3 (logand ,r3 ,r0) + ,t0 (logior ,t0 ,r1) + ,r3 (logxor ,r3 ,t0) + ,r0 (logxor ,r0 ,r1) + ,t0 (logand ,t0 ,r0) + ,r1 (logxor ,r1 ,r3) + ,t0 (logxor ,t0 ,r2) + ,r1 (logior ,r1 ,r0) + ,r1 (logxor ,r1 ,r2) + ,r0 (logxor ,r0 ,r3) + ,r2 ,r1 + ,r1 (logior ,r1 ,r3) + ,r1 (logxor ,r1 ,r0) + ,o0 ,r1 + ,o1 ,r2 + ,o2 ,r3 + ,o3 ,t0)) + +(defmacro serpent-sbox3-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r2 + ,r2 (logxor ,r2 ,r1) + ,r0 (logxor ,r0 ,r2) + ,t0 (logand ,t0 ,r2) + ,t0 (logxor ,t0 ,r0) + ,r0 (logand ,r0 ,r1) + ,r1 (logxor ,r1 ,r3) + ,r3 (logior ,r3 ,t0) + ,r2 (logxor ,r2 ,r3) + ,r0 (logxor ,r0 ,r3) + ,r1 (logxor ,r1 ,t0) + ,r3 (logand ,r3 ,r2) + ,r3 (logxor ,r3 ,r1) + ,r1 (logxor ,r1 ,r0) + ,r1 (logior ,r1 ,r2) + ,r0 (logxor ,r0 ,r3) + ,r1 (logxor ,r1 ,t0) + ,r0 (logxor ,r0 ,r1) + ,o0 ,r2 + ,o1 ,r1 + ,o2 ,r3 + ,o3 ,r0)) + +(defmacro serpent-sbox4 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r1 (logxor ,r1 ,r3) + ,r3 (mod32lognot ,r3) + ,r2 (logxor ,r2 ,r3) + ,r3 (logxor ,r3 ,r0) + ,t0 ,r1 + ,r1 (logand ,r1 ,r3) + ,r1 (logxor ,r1 ,r2) + ,t0 (logxor ,t0 ,r3) + ,r0 (logxor ,r0 ,t0) + ,r2 (logand ,r2 ,t0) + ,r2 (logxor ,r2 ,r0) + ,r0 (logand ,r0 ,r1) + ,r3 (logxor ,r3 ,r0) + ,t0 (logior ,t0 ,r1) + ,t0 (logxor ,t0 ,r0) + ,r0 (logior ,r0 ,r3) + ,r0 (logxor ,r0 ,r2) + ,r2 (logand ,r2 ,r3) + ,r0 (mod32lognot ,r0) + ,t0 (logxor ,t0 ,r2) + ,o0 ,r1 + ,o1 ,t0 + ,o2 ,r0 + ,o3 ,r3)) + +(defmacro serpent-sbox4-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r2 + ,r2 (logand ,r2 ,r3) + ,r2 (logxor ,r2 ,r1) + ,r1 (logior ,r1 ,r3) + ,r1 (logand ,r1 ,r0) + ,t0 (logxor ,t0 ,r2) + ,t0 (logxor ,t0 ,r1) + ,r1 (logand ,r1 ,r2) + ,r0 (mod32lognot ,r0) + ,r3 (logxor ,r3 ,t0) + ,r1 (logxor ,r1 ,r3) + ,r3 (logand ,r3 ,r0) + ,r3 (logxor ,r3 ,r2) + ,r0 (logxor ,r0 ,r1) + ,r2 (logand ,r2 ,r0) + ,r3 (logxor ,r3 ,r0) + ,r2 (logxor ,r2 ,t0) + ,r2 (logior ,r2 ,r3) + ,r3 (logxor ,r3 ,r0) + ,r2 (logxor ,r2 ,r1) + ,o0 ,r0 + ,o1 ,r3 + ,o2 ,r2 + ,o3 ,t0)) + +(defmacro serpent-sbox5 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r0 (logxor ,r0 ,r1) + ,r1 (logxor ,r1 ,r3) + ,r3 (mod32lognot ,r3) + ,t0 ,r1 + ,r1 (logand ,r1 ,r0) + ,r2 (logxor ,r2 ,r3) + ,r1 (logxor ,r1 ,r2) + ,r2 (logior ,r2 ,t0) + ,t0 (logxor ,t0 ,r3) + ,r3 (logand ,r3 ,r1) + ,r3 (logxor ,r3 ,r0) + ,t0 (logxor ,t0 ,r1) + ,t0 (logxor ,t0 ,r2) + ,r2 (logxor ,r2 ,r0) + ,r0 (logand ,r0 ,r3) + ,r2 (mod32lognot ,r2) + ,r0 (logxor ,r0 ,t0) + ,t0 (logior ,t0 ,r3) + ,r2 (logxor ,r2 ,t0) + ,o0 ,r1 + ,o1 ,r3 + ,o2 ,r0 + ,o3 ,r2)) + +(defmacro serpent-sbox5-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r1 (mod32lognot ,r1) + ,t0 ,r3 + ,r2 (logxor ,r2 ,r1) + ,r3 (logior ,r3 ,r0) + ,r3 (logxor ,r3 ,r2) + ,r2 (logior ,r2 ,r1) + ,r2 (logand ,r2 ,r0) + ,t0 (logxor ,t0 ,r3) + ,r2 (logxor ,r2 ,t0) + ,t0 (logior ,t0 ,r0) + ,t0 (logxor ,t0 ,r1) + ,r1 (logand ,r1 ,r2) + ,r1 (logxor ,r1 ,r3) + ,t0 (logxor ,t0 ,r2) + ,r3 (logand ,r3 ,t0) + ,t0 (logxor ,t0 ,r1) + ,r3 (logxor ,r3 ,t0) + ,t0 (mod32lognot ,t0) + ,r3 (logxor ,r3 ,r0) + ,o0 ,r1 + ,o1 ,t0 + ,o2 ,r3 + ,o3 ,r2)) + +(defmacro serpent-sbox6 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r2 (mod32lognot ,r2) + ,t0 ,r3 + ,r3 (logand ,r3 ,r0) + ,r0 (logxor ,r0 ,t0) + ,r3 (logxor ,r3 ,r2) + ,r2 (logior ,r2 ,t0) + ,r1 (logxor ,r1 ,r3) + ,r2 (logxor ,r2 ,r0) + ,r0 (logior ,r0 ,r1) + ,r2 (logxor ,r2 ,r1) + ,t0 (logxor ,t0 ,r0) + ,r0 (logior ,r0 ,r3) + ,r0 (logxor ,r0 ,r2) + ,t0 (logxor ,t0 ,r3) + ,t0 (logxor ,t0 ,r0) + ,r3 (mod32lognot ,r3) + ,r2 (logand ,r2 ,t0) + ,r2 (logxor ,r2 ,r3) + ,o0 ,r0 + ,o1 ,r1 + ,o2 ,t0 + ,o3 ,r2)) + +(defmacro serpent-sbox6-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,r0 (logxor ,r0 ,r2) + ,t0 ,r2 + ,r2 (logand ,r2 ,r0) + ,t0 (logxor ,t0 ,r3) + ,r2 (mod32lognot ,r2) + ,r3 (logxor ,r3 ,r1) + ,r2 (logxor ,r2 ,r3) + ,t0 (logior ,t0 ,r0) + ,r0 (logxor ,r0 ,r2) + ,r3 (logxor ,r3 ,t0) + ,t0 (logxor ,t0 ,r1) + ,r1 (logand ,r1 ,r3) + ,r1 (logxor ,r1 ,r0) + ,r0 (logxor ,r0 ,r3) + ,r0 (logior ,r0 ,r2) + ,r3 (logxor ,r3 ,r1) + ,t0 (logxor ,t0 ,r0) + ,o0 ,r1 + ,o1 ,r2 + ,o2 ,t0 + ,o3 ,r3)) + +(defmacro serpent-sbox7 (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r1 + ,r1 (logior ,r1 ,r2) + ,r1 (logxor ,r1 ,r3) + ,t0 (logxor ,t0 ,r2) + ,r2 (logxor ,r2 ,r1) + ,r3 (logior ,r3 ,t0) + ,r3 (logand ,r3 ,r0) + ,t0 (logxor ,t0 ,r2) + ,r3 (logxor ,r3 ,r1) + ,r1 (logior ,r1 ,t0) + ,r1 (logxor ,r1 ,r0) + ,r0 (logior ,r0 ,t0) + ,r0 (logxor ,r0 ,r2) + ,r1 (logxor ,r1 ,t0) + ,r2 (logxor ,r2 ,r1) + ,r1 (logand ,r1 ,r0) + ,r1 (logxor ,r1 ,t0) + ,r2 (mod32lognot ,r2) + ,r2 (logior ,r2 ,r0) + ,t0 (logxor ,t0 ,r2) + ,o0 ,t0 + ,o1 ,r3 + ,o2 ,r1 + ,o3 ,r0)) + +(defmacro serpent-sbox7-inverse (r0 r1 r2 r3 o0 o1 o2 o3 t0) + `(setf ,t0 ,r2 + ,r2 (logxor ,r2 ,r0) + ,r0 (logand ,r0 ,r3) + ,t0 (logior ,t0 ,r3) + ,r2 (mod32lognot ,r2) + ,r3 (logxor ,r3 ,r1) + ,r1 (logior ,r1 ,r0) + ,r0 (logxor ,r0 ,r2) + ,r2 (logand ,r2 ,t0) + ,r3 (logand ,r3 ,t0) + ,r1 (logxor ,r1 ,r2) + ,r2 (logxor ,r2 ,r0) + ,r0 (logior ,r0 ,r2) + ,t0 (logxor ,t0 ,r1) + ,r0 (logxor ,r0 ,r3) + ,r3 (logxor ,r3 ,t0) + ,t0 (logior ,t0 ,r0) + ,r3 (logxor ,r3 ,r2) + ,t0 (logxor ,t0 ,r2) + ,o0 ,r3 + ,o1 ,r0 + ,o2 ,r1 + ,o3 ,t0)) + + +;;; Linear transformation + +(defmacro serpent-linear-transformation (r0 r1 r2 r3) + `(setf ,r0 (rol32 ,r0 13) + ,r2 (rol32 ,r2 3) + ,r1 (logxor ,r1 ,r0 ,r2) + ,r3 (logxor ,r3 ,r2 (mod32ash ,r0 3)) + ,r1 (rol32 ,r1 1) + ,r3 (rol32 ,r3 7) + ,r0 (logxor ,r0 ,r1 ,r3) + ,r2 (logxor ,r2 ,r3 (mod32ash ,r1 7)) + ,r0 (rol32 ,r0 5) + ,r2 (rol32 ,r2 22))) + +(defmacro serpent-linear-transformation-inverse (r0 r1 r2 r3) + `(setf ,r2 (rol32 ,r2 10) + ,r0 (rol32 ,r0 27) + ,r2 (logxor ,r2 ,r3 (mod32ash ,r1 7)) + ,r0 (logxor ,r0 ,r1 ,r3) + ,r3 (rol32 ,r3 25) + ,r1 (rol32 ,r1 31) + ,r3 (logxor ,r3 ,r2 (mod32ash ,r0 3)) + ,r1 (logxor ,r1 ,r0 ,r2) + ,r2 (rol32 ,r2 29) + ,r0 (rol32 ,r0 19))) + + +;;; Key schedule + +(defconstant +serpent-phi+ #x9e3779b9) + +(defclass serpent (cipher 16-byte-block-mixin) + ((subkeys :accessor serpent-subkeys + :type (simple-array (unsigned-byte 32) (33 4))))) + +(defun serpent-pad-key (key) + (let ((padded-key (make-array 8 :element-type '(unsigned-byte 32))) + (len (floor (length key) 4))) + (dotimes (i len) + (setf (aref padded-key i) (ub32ref/le key (* i 4)))) + (when (< len 8) + (setf (aref padded-key len) 1) + (loop for i from (1+ len) below 8 + do (setf (aref padded-key i) 0))) + padded-key)) + +(defun serpent-generate-subkeys (key) + (declare (type (simple-array (unsigned-byte 32) (8)) key) + (optimize (speed 3) (space 0) (safety 0) (debug 0))) + (let ((subkeys (make-array '(33 4) :element-type '(unsigned-byte 32))) + (w (copy-seq key)) + (ws (make-array 4 :element-type '(unsigned-byte 32))) + (wt (make-array 4 :element-type '(unsigned-byte 32))) + (t0 0) + (t1 0) + (t2 0) + (t3 0) + (t4 0)) + (declare (type (simple-array (unsigned-byte 32) (33 4)) subkeys) + (type (simple-array (unsigned-byte 32) (8)) w) + (type (simple-array (unsigned-byte 32) (4)) ws wt) + (type (unsigned-byte 32) t0 t1 t2 t3 t4)) + (macrolet ((expand-key4 (wo r) + `(setf (aref ,wo 0) (rol32 (logxor (aref w ,(mod (+ r 0) 8)) + (aref w ,(mod (+ r 3) 8)) + (aref w ,(mod (+ r 5) 8)) + (aref w ,(mod (+ r 7) 8)) + +serpent-phi+ + ,(+ r 0)) + 11) + (aref w ,(mod (+ r 0) 8)) (aref ,wo 0) + (aref ,wo 1) (rol32 (logxor (aref w ,(mod (+ r 1) 8)) + (aref w ,(mod (+ r 4) 8)) + (aref w ,(mod (+ r 6) 8)) + (aref w ,(mod (+ r 0) 8)) + +serpent-phi+ + ,(+ r 1)) + 11) + (aref w ,(mod (+ r 1) 8)) (aref ,wo 1) + (aref ,wo 2) (rol32 (logxor (aref w ,(mod (+ r 2) 8)) + (aref w ,(mod (+ r 5) 8)) + (aref w ,(mod (+ r 7) 8)) + (aref w ,(mod (+ r 1) 8)) + +serpent-phi+ + ,(+ r 2)) + 11) + (aref w ,(mod (+ r 2) 8)) (aref ,wo 2) + (aref ,wo 3) (rol32 (logxor (aref w ,(mod (+ r 3) 8)) + (aref w ,(mod (+ r 6) 8)) + (aref w ,(mod (+ r 0) 8)) + (aref w ,(mod (+ r 2) 8)) + +serpent-phi+ + ,(+ r 3)) + 11) + (aref w ,(mod (+ r 3) 8)) (aref ,wo 3))) + + (make-subkeys () + (loop for i from 0 to 15 + for sbox-a = (read-from-string (format nil "serpent-sbox~d" (mod (- 3 (* 2 i)) 8))) + for sbox-b = (read-from-string (format nil "serpent-sbox~d" (mod (- 2 (* 2 i)) 8))) + append (list `(expand-key4 ws ,(* 8 i)) + `(expand-key4 wt ,(+ (* 8 i) 4)) + `(setf t0 (aref ws 0) + t1 (aref ws 1) + t2 (aref ws 2) + t3 (aref ws 3)) + `(,sbox-a t0 t1 t2 t3 (aref ws 0) (aref ws 1) (aref ws 2) (aref ws 3) t4) + `(setf (aref subkeys ,(* 2 i) 0) (aref ws 0) + (aref subkeys ,(* 2 i) 1) (aref ws 1) + (aref subkeys ,(* 2 i) 2) (aref ws 2) + (aref subkeys ,(* 2 i) 3) (aref ws 3)) + `(setf t0 (aref wt 0) + t1 (aref wt 1) + t2 (aref wt 2) + t3 (aref wt 3)) + `(,sbox-b t0 t1 t2 t3 (aref wt 0) (aref wt 1) (aref wt 2) (aref wt 3) t4) + `(setf (aref subkeys ,(1+ (* 2 i)) 0) (aref wt 0) + (aref subkeys ,(1+ (* 2 i)) 1) (aref wt 1) + (aref subkeys ,(1+ (* 2 i)) 2) (aref wt 2) + (aref subkeys ,(1+ (* 2 i)) 3) (aref wt 3))) + into forms + finally (return `(progn ,@forms))))) + + (make-subkeys) + (expand-key4 ws 128) + (setf t0 (aref ws 0) + t1 (aref ws 1) + t2 (aref ws 2) + t3 (aref ws 3)) + (serpent-sbox3 t0 t1 t2 t3 (aref ws 0) (aref ws 1) (aref ws 2) (aref ws 3) t4) + (setf (aref subkeys 32 0) (aref ws 0) + (aref subkeys 32 1) (aref ws 1) + (aref subkeys 32 2) (aref ws 2) + (aref subkeys 32 3) (aref ws 3)) + + subkeys))) + +(defmethod schedule-key ((cipher serpent) key) + (setf (serpent-subkeys cipher) (serpent-generate-subkeys (serpent-pad-key key))) + cipher) + + +;;; Rounds + +(define-block-encryptor serpent 16 + (let ((subkeys (serpent-subkeys context)) + (t0 0) + (t1 0) + (t2 0) + (t3 0) + (t4 0)) + (declare (type (simple-array (unsigned-byte 32) (33 4)) subkeys) + (type (unsigned-byte 32) t0 t1 t2 t3 t4)) + (with-words ((b0 b1 b2 b3) plaintext plaintext-start :big-endian nil :size 4) + (macrolet ((serpent-rounds () + (loop for i from 0 to 30 + for sbox = (read-from-string (format nil "serpent-sbox~d" (mod i 8))) + append (list `(setf t0 (logxor b0 (aref subkeys ,i 0)) + t1 (logxor b1 (aref subkeys ,i 1)) + t2 (logxor b2 (aref subkeys ,i 2)) + t3 (logxor b3 (aref subkeys ,i 3))) + `(,sbox t0 t1 t2 t3 b0 b1 b2 b3 t4) + `(serpent-linear-transformation b0 b1 b2 b3)) + into forms + finally (return `(progn ,@forms))))) + + ;; Regular rounds + (serpent-rounds) + + ;; Last round + (setf b0 (logxor b0 (aref subkeys 31 0)) + b1 (logxor b1 (aref subkeys 31 1)) + b2 (logxor b2 (aref subkeys 31 2)) + b3 (logxor b3 (aref subkeys 31 3))) + (serpent-sbox7 b0 b1 b2 b3 t0 t1 t2 t3 t4) + (setf b0 (logxor t0 (aref subkeys 32 0)) + b1 (logxor t1 (aref subkeys 32 1)) + b2 (logxor t2 (aref subkeys 32 2)) + b3 (logxor t3 (aref subkeys 32 3))) + + (store-words ciphertext ciphertext-start b0 b1 b2 b3) + (values))))) + +(define-block-decryptor serpent 16 + (let ((subkeys (serpent-subkeys context)) + (t0 0) + (t1 0) + (t2 0) + (t3 0) + (t4 0)) + (declare (type (simple-array (unsigned-byte 32) (33 4)) subkeys) + (type (unsigned-byte 32) t0 t1 t2 t3 t4)) + (with-words ((b0 b1 b2 b3) ciphertext ciphertext-start :big-endian nil :size 4) + (macrolet ((serpent-rounds-inverse () + (loop for i from 30 downto 0 + for sbox-inverse = (read-from-string (format nil "serpent-sbox~d-inverse" (mod i 8))) + append (list `(serpent-linear-transformation-inverse b0 b1 b2 b3) + `(,sbox-inverse b0 b1 b2 b3 t0 t1 t2 t3 t4) + `(setf b0 (logxor t0 (aref subkeys ,i 0)) + b1 (logxor t1 (aref subkeys ,i 1)) + b2 (logxor t2 (aref subkeys ,i 2)) + b3 (logxor t3 (aref subkeys ,i 3)))) + into forms + finally (return `(progn ,@forms))))) + + ;; First inverse round + (setf b0 (logxor b0 (aref subkeys 32 0)) + b1 (logxor b1 (aref subkeys 32 1)) + b2 (logxor b2 (aref subkeys 32 2)) + b3 (logxor b3 (aref subkeys 32 3))) + (serpent-sbox7-inverse b0 b1 b2 b3 t0 t1 t2 t3 t4) + (setf b0 (logxor t0 (aref subkeys 31 0)) + b1 (logxor t1 (aref subkeys 31 1)) + b2 (logxor t2 (aref subkeys 31 2)) + b3 (logxor t3 (aref subkeys 31 3))) + + ;; Regular inverse rounds + (serpent-rounds-inverse) + + (store-words plaintext plaintext-start b0 b1 b2 b3) + (values))))) + +(defcipher serpent + (:encrypt-function serpent-encrypt-block) + (:decrypt-function serpent-decrypt-block) + (:block-length 16) + (:key-length (:fixed 16 24 32))) diff --git a/src/package.lisp b/src/package.lisp index 9156181..2e26660 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -100,7 +100,8 @@ ;; supported block ciphers (:export #:blowfish #:tea #:xtea #:square #:rc2 #:rc5 #:rc6 #:des #:3des #:aes #:twofish #:cast5 #:idea #:misty1 #:null - #:threefish256 #:threefish512 #:threefish1024) + #:threefish256 #:threefish512 #:threefish1024 + #:serpent) ;; supported stream ciphers (:export #:arcfour #:salsa20 #:salsa20/12 #:salsa20/8 #:chacha #:chacha/12 #:chacha/8)) diff --git a/testing/test-vectors/serpent.testvec b/testing/test-vectors/serpent.testvec new file mode 100644 index 0000000..5af4ef2 --- /dev/null +++ b/testing/test-vectors/serpent.testvec @@ -0,0 +1,53 @@ +;;;; Serpent test vectors + +;;; Some tests from NESSIE + +;;; 128-bit key + +(:ecb-mode-test #h"00000000000000000000000000000000" #h"00000000000000000000000000000000" #h"3620B17AE6A993D09618B8768266BAE9") +(:ecb-mode-test #h"80000000000000000000000000000000" #h"00000000000000000000000000000000" #h"264E5481EFF42A4606ABDA06C0BFDA3D") +(:ecb-mode-test #h"40000000000000000000000000000000" #h"00000000000000000000000000000000" #h"4A231B3BC727993407AC6EC8350E8524") +(:ecb-mode-test #h"08000000000000000000000000000000" #h"00000000000000000000000000000000" #h"34B355520DF861F3F5C66A2379FBDA15") +(:ecb-mode-test #h"01010101010101010101010101010101" #h"01010101010101010101010101010101" #h"5107E36DBE81D9996D1EF7F3656FFC63") +(:ecb-mode-test #h"02020202020202020202020202020202" #h"02020202020202020202020202020202" #h"1AE5355487F88F824B6462B45C4C6AA5") +(:ecb-mode-test #h"10101010101010101010101010101010" #h"10101010101010101010101010101010" #h"185EFBCD1AC2EFF75CF764F05CFAFD33") +(:ecb-mode-test #h"11111111111111111111111111111111" #h"11111111111111111111111111111111" #h"F84F5C8EEEA4D3527F734428F4B3AED6") +(:ecb-mode-test #h"12121212121212121212121212121212" #h"12121212121212121212121212121212" #h"933E63A78E6AA1216A1B1CE2559D42BF") +(:ecb-mode-test #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"BD2DBD2EB4193A2773CDB9906A34376D") +(:ecb-mode-test #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"2DEE675B6B7401367DA2A80FB44B8065") +(:ecb-mode-test #h"000102030405060708090A0B0C0D0E0F" #h"00112233445566778899AABBCCDDEEFF" #h"563E2CF8740A27C164804560391E9B27") +(:ecb-mode-test #h"2BD6459F82C5B300952C49104881FF48" #h"EA024714AD5C4D84EA024714AD5C4D84" #h"92D7F8EF2C36C53409F275902F06539F") + + +;;; 192-bit key + +(:ecb-mode-test #h"000000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"A583EF976A292B406BBD5DC8256B0442") +(:ecb-mode-test #h"800000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"9E274EAD9B737BB21EFCFCA548602689") +(:ecb-mode-test #h"400000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"92FC8E510399E46A041BF365E7B3AE82") +(:ecb-mode-test #h"080000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"257A79F891BB8D0C13FEEF1ACC264214") +(:ecb-mode-test #h"010101010101010101010101010101010101010101010101" #h"01010101010101010101010101010101" #h"3C30CC53B1408BF333B85DD1C6632A29") +(:ecb-mode-test #h"020202020202020202020202020202020202020202020202" #h"02020202020202020202020202020202" #h"9CCCE11543D31C4527860F2411FC6435") +(:ecb-mode-test #h"101010101010101010101010101010101010101010101010" #h"10101010101010101010101010101010" #h"8FF90E91ECA31C767C88B5FBA1AC885A") +(:ecb-mode-test #h"111111111111111111111111111111111111111111111111" #h"11111111111111111111111111111111" #h"5A591008778D540E22648F7146360682") +(:ecb-mode-test #h"121212121212121212121212121212121212121212121212" #h"12121212121212121212121212121212" #h"7CC04EDE1EC605160B5F23265B5A074C") +(:ecb-mode-test #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"9B89376FB4EE9D5AFBDA22D1F67E7155") +(:ecb-mode-test #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"08FC09BD2580A3FFBC8453FAF21417C0") +(:ecb-mode-test #h"000102030405060708090A0B0C0D0E0F1011121314151617" #h"00112233445566778899AABBCCDDEEFF" #h"6AB816C82DE53B93005008AFA2246A02") +(:ecb-mode-test #h"2BD6459F82C5B300952C49104881FF482BD6459F82C5B300" #h"EA024714AD5C4D84EA024714AD5C4D84" #h"827B18C2678A239DFC5512842000E204") + + +;;; 256-bit key + +(:ecb-mode-test #h"0000000000000000000000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"49672BA898D98DF95019180445491089") +(:ecb-mode-test #h"8000000000000000000000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"A223AA1288463C0E2BE38EBD825616C0") +(:ecb-mode-test #h"4000000000000000000000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"EAE1D405570174DF7DF2F9966D509159") +(:ecb-mode-test #h"0800000000000000000000000000000000000000000000000000000000000000" #h"00000000000000000000000000000000" #h"EC9D6557EED58E6CF89A746BBDB6C9B7") +(:ecb-mode-test #h"0101010101010101010101010101010101010101010101010101010101010101" #h"01010101010101010101010101010101" #h"EC9723B15B2A6489F84C4524FFFC2748") +(:ecb-mode-test #h"0202020202020202020202020202020202020202020202020202020202020202" #h"02020202020202020202020202020202" #h"1187F485538514476184E567DA0421C7") +(:ecb-mode-test #h"1010101010101010101010101010101010101010101010101010101010101010" #h"10101010101010101010101010101010" #h"0058F8E377AA222F712C2479F4A562AF") +(:ecb-mode-test #h"1111111111111111111111111111111111111111111111111111111111111111" #h"11111111111111111111111111111111" #h"A482EAA5D5771F2FDB2EA1A5F141B9E2") +(:ecb-mode-test #h"1212121212121212121212121212121212121212121212121212121212121212" #h"12121212121212121212121212121212" #h"34C9A82AFA5AF48071F5F7BC90C1BC85") +(:ecb-mode-test #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C" #h"052C775722AFEF0010C5795C521B9D25") +(:ecb-mode-test #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" #h"6AC7579D9377845A816CA6D758F3FEFF") +(:ecb-mode-test #h"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" #h"00112233445566778899AABBCCDDEEFF" #h"2868B7A2D28ECD5E4FDEFAC3C4330074") +(:ecb-mode-test #h"2BD6459F82C5B300952C49104881FF482BD6459F82C5B300952C49104881FF48" #h"EA024714AD5C4D84EA024714AD5C4D84" #h"3E507730776B93FDEA661235E1DD99F0")