Coverage report: /home/ellis/comp/ext/ironclad/src/ciphers/rc6.lisp
Kind | Covered | All | % |
expression | 0 | 1132 | 0.0 |
branch | 0 | 2 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;;; rc6.lisp -- implementation of the RC6 block cipher
4
(defconstant +rc6/32-p+ #xb7e15163)
5
(defconstant +rc6/32-q+ #x9e3779b9)
7
(deftype rc6-n-rounds () '(mod 256))
9
(defclass rc6 (cipher 16-byte-block-mixin)
10
((n-rounds :reader n-rounds :initarg :n-rounds :type rc6-n-rounds)
11
(round-keys :accessor round-keys
12
:type (simple-array (unsigned-byte 32) (*))))
13
(:default-initargs :n-rounds 20))
15
;;; The code generated by these functions produces lots of compiler
16
;;; notes under SBCL, but the resulting disassembly looks pretty good.
17
;;; I don't know where the notes originate from...
18
(eval-when (:compile-toplevel :load-toplevel :execute)
19
(defun generate-unrolled-rc6-encryption (n-rounds)
20
(let* ((orig-vars (list 'a 'b 'c 'd))
21
(vars (setf (cdr (last orig-vars)) orig-vars)))
22
(loop for i from 2 upto (* n-rounds 2) by 2
23
for (a b c d) on vars by #'cdr
24
collect `(let ((v (rol32 (mod32* ,b
26
(ldb (byte 32 0) (sb-vm::%lea ,b ,b 1 1))
28
(mod32+ (mod32ash ,b 1) 1)) 5))
31
(ldb (byte 32 0) (sb-vm::%lea ,d ,d 1 1))
33
(mod32+ (mod32ash ,d 1) 1)) 5)))
34
(declare (type (unsigned-byte 32) u v))
35
(setf ,a (mod32+ (rol32 (logxor ,a v) (mod u 32))
37
,c (mod32+ (rol32 (logxor ,c u) (mod v 32))
38
(aref round-keys ,(1+ i))))) into forms
39
finally (return `(let ((round-keys (round-keys context)))
40
(declare (type (simple-array (unsigned-byte 32) (,(+ (* n-rounds 2) 4))) round-keys))
41
(with-words ((a b c d) plaintext plaintext-start :big-endian nil)
42
(setf b (mod32+ b (aref round-keys 0))
43
d (mod32+ d (aref round-keys 1)))
45
(setf a (mod32+ a (aref round-keys (+ (* 2 ,n-rounds) 2)))
46
c (mod32+ c (aref round-keys (+ (* 2 ,n-rounds) 3))))
47
(store-words ciphertext ciphertext-start a b c d)))))))
49
(defun generate-unrolled-rc6-decryption (n-rounds)
50
(let* ((orig-vars (list 'd 'a 'b 'c))
51
(vars (setf (cdr (last orig-vars)) orig-vars)))
52
(loop for i from (* n-rounds 2) downto 2 by 2
53
for (a b c d) on vars by #'cdddr
54
collect `(let ((u (rol32 (mod32* ,d
56
(ldb (byte 32 0) (sb-vm::%lea ,d ,d 1 1))
58
(mod32+ (mod32ash ,d 1) 1)) 5))
61
(ldb (byte 32 0) (sb-vm::%lea ,b ,b 1 1))
63
(mod32+ (mod32ash ,b 1) 1)) 5)))
64
(declare (type (unsigned-byte 32) u v))
65
(setf ,c (logxor (ror32 (mod32- ,c (aref round-keys ,(1+ i)))
67
,a (logxor (ror32 (mod32- ,a (aref round-keys ,i))
68
(mod u 32)) v))) into forms
69
finally (return `(let ((round-keys (round-keys context)))
70
(declare (type (simple-array (unsigned-byte 32) (,(+ (* n-rounds 2) 4))) round-keys))
71
(with-words ((a b c d) ciphertext ciphertext-start :big-endian nil)
72
(setf c (mod32- c (aref round-keys (+ (* 2 ,n-rounds) 3)))
73
a (mod32- a (aref round-keys (+ (* 2 ,n-rounds) 2))))
75
(setf d (mod32- d (aref round-keys 1))
76
b (mod32- b (aref round-keys 0)))
77
(store-words plaintext plaintext-start a b c d))))))))
79
(define-block-encryptor rc6 16
80
#.(generate-unrolled-rc6-encryption 20))
82
(define-block-decryptor rc6 16
83
#.(generate-unrolled-rc6-decryption 20))
85
(defun rc6-expand-key (key n-rounds)
86
(declare (type (simple-array (unsigned-byte 8) (*)) key))
87
(declare (type rc6-n-rounds n-rounds))
88
(let* ((n-round-keys (* 2 (+ n-rounds 2)))
89
(round-keys (make-array n-round-keys :element-type '(unsigned-byte 32)))
90
(expanded-key (make-array 256 :element-type '(unsigned-byte 8)
92
(n-expanded-key-words (ceiling (length key) 4))
93
(l (make-array 64 :element-type '(unsigned-byte 32))))
94
(declare (dynamic-extent expanded-key l))
95
(declare (type (simple-array (unsigned-byte 8) (256)) expanded-key))
96
(declare (type (simple-array (unsigned-byte 32) (64)) l))
97
(declare (type (simple-array (unsigned-byte 32) (*)) round-keys))
98
;; convert the key into a sequence of (unsigned-byte 32). this way
99
;; is somewhat slow and consy, but it's easily shown to be correct.
100
(replace expanded-key key)
101
(loop for i from 0 below 64 do
102
(setf (aref l i) (ub32ref/le expanded-key (* i 4))))
103
;; initialize the round keys
104
(loop initially (setf (aref round-keys 0) +rc6/32-p+)
105
for i from 1 below n-round-keys do
106
(setf (aref round-keys i) (mod32+ (aref round-keys (1- i)) +rc6/32-q+)))
107
;; mix in the user's key
108
(do ((k (* 3 (max n-expanded-key-words n-round-keys)) (1- k))
111
(i 0 (mod (1+ i) n-round-keys))
112
(j 0 (mod (1+ j) n-expanded-key-words)))
113
((<= k 0) round-keys)
114
(declare (type (unsigned-byte 32) a b))
115
(setf a (rol32 (mod32+ (aref round-keys i) (mod32+ a b)) 3))
116
(setf (aref round-keys i) a)
117
(setf b (let ((x (mod32+ a b)))
118
(declare (type (unsigned-byte 32) x))
119
(rol32 (mod32+ (aref l j) x) (mod x 32))))
120
(setf (aref l j) b))))
122
(defmethod schedule-key ((cipher rc6) key)
123
(let* ((n-rounds (n-rounds cipher))
124
(round-keys (rc6-expand-key key n-rounds)))
125
(setf (round-keys cipher) round-keys)
129
(:encrypt-function rc6-encrypt-block)
130
(:decrypt-function rc6-decrypt-block)
132
(:key-length (:variable 1 255 1)))