Coverage report: /home/ellis/comp/ext/ironclad/src/ciphers/rc6.lisp

KindCoveredAll%
expression01132 0.0
branch02 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
2
 (in-package :ironclad)
3
 
4
 (defconstant +rc6/32-p+ #xb7e15163)
5
 (defconstant +rc6/32-q+ #x9e3779b9)
6
 
7
 (deftype rc6-n-rounds () '(mod 256))
8
 
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))
14
 
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
25
                                            #+x86
26
                                            (ldb (byte 32 0) (sb-vm::%lea ,b ,b 1 1))
27
                                            #-x86
28
                                            (mod32+ (mod32ash ,b 1) 1)) 5))
29
                          (u (rol32 (mod32* ,d
30
                                            #+x86
31
                                            (ldb (byte 32 0) (sb-vm::%lea ,d ,d 1 1))
32
                                            #-x86
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))
36
                               (aref round-keys ,i))
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)))
44
                               ,@forms
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)))))))
48
 
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
55
                                            #+x86
56
                                            (ldb (byte 32 0) (sb-vm::%lea ,d ,d 1 1))
57
                                            #-x86
58
                                            (mod32+ (mod32ash ,d 1) 1)) 5))
59
                          (v (rol32 (mod32* ,b
60
                                            #+x86
61
                                            (ldb (byte 32 0) (sb-vm::%lea ,b ,b 1 1))
62
                                            #-x86
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)))
66
                                             (mod v 32)) u)
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))))
74
                             ,@forms
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))))))))
78
 
79
 (define-block-encryptor rc6 16
80
   #.(generate-unrolled-rc6-encryption 20))
81
 
82
 (define-block-decryptor rc6 16
83
   #.(generate-unrolled-rc6-decryption 20))
84
 
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)
91
                                      :initial-element 0))
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))
109
          (a 0)
110
          (b 0)
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))))
121
 
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)
126
     cipher))
127
 
128
 (defcipher rc6
129
   (:encrypt-function rc6-encrypt-block)
130
   (:decrypt-function rc6-decrypt-block)
131
   (:block-length 16)
132
   (:key-length (:variable 1 255 1)))