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

KindCoveredAll%
expression0202 0.0
branch06 0.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;;; rc5.lisp -- implementation of the RC5 encryption algorithm from RFC 2040
2
 (in-package :ironclad)
3
 
4
 ;;; RC5 is technically a parameterized cipher admitting a variable
5
 ;;; number of rounds.  This implementation expose a method of selecting
6
 ;;; the number of rounds to be used (`n-rounds' &key parameter in
7
 ;;; CREATE-RC5-CONTEXT), but none of the upper-level machinery actually
8
 ;;; uses this parameter.  In a small overhaul of the MAKE-CIPHER
9
 ;;; functionality in Ironclad, it would be nice to change this state of
10
 ;;; affairs.  12 was the number of rounds suggested initially, but RC5
11
 ;;; with 12 rounds is susceptible to a differential plaintext attack.
12
 ;;; OpenSSL supports 12 or 16 as the number of rounds (with no error
13
 ;;; checking, natch).
14
 ;;;
15
 ;;; See also the TODO file.
16
 (defconstant +rc5/32-p+ #xb7e15163)
17
 (defconstant +rc5/32-q+ #x9e3779b9)
18
 
19
 (defconstant +rc5-w+ 32)
20
 (defconstant +rc5-ww+ 4)
21
 (defconstant +rc5-b+ 64)
22
 (defconstant +rc5-bb+ 8)
23
 
24
 (deftype rc5-n-rounds () '(mod 256))
25
 (deftype rc5-round-keys () '(simple-array (unsigned-byte 32) (*)))
26
 
27
 (defclass rc5 (cipher 8-byte-block-mixin)
28
   ((n-rounds :reader n-rounds :initarg :n-rounds :type rc5-n-rounds)
29
    (round-keys :accessor round-keys
30
                :type (simple-array (unsigned-byte 32) (*))))
31
   (:default-initargs :n-rounds 12))
32
 
33
 (define-block-encryptor rc5 8
34
   (let ((n-rounds (n-rounds context))
35
         (round-keys (round-keys context)))
36
     (declare (type rc5-n-rounds n-rounds))
37
     (declare (type rc5-round-keys round-keys))
38
     (with-words ((a b) plaintext plaintext-start :big-endian nil)
39
       (setf a (mod32+ a (aref round-keys 0))
40
             b (mod32+ b (aref round-keys 1)))
41
       (do ((i 1 (1+ i)))
42
           ((> i n-rounds)
43
            (store-words ciphertext ciphertext-start a b))
44
         (setf a (logxor a b))
45
         (setf a (mod32+ (rol32 a (mod b 32)) (aref round-keys (* i 2))))
46
         (setf b (logxor b a))
47
         (setf b (mod32+ (rol32 b (mod a 32)) (aref round-keys (1+ (* i 2)))))))))
48
 
49
 (define-block-decryptor rc5 8
50
   (let ((n-rounds (n-rounds context))
51
         (round-keys (round-keys context)))
52
     (declare (type rc5-n-rounds n-rounds))
53
     (declare (type rc5-round-keys round-keys))
54
     (with-words ((a b) ciphertext ciphertext-start :big-endian nil)
55
       (do ((i n-rounds (1- i)))
56
           ((<= i 0)
57
            (setf b (mod32- b (aref round-keys 1))
58
                  a (mod32- a (aref round-keys 0)))
59
            (store-words plaintext plaintext-start a b))
60
         (setf b (rol32 (mod32- b (aref round-keys (1+ (* i 2))))
61
                        (mod (- 32 (mod a 32)) 32)))
62
         (setf b (logxor b a))
63
         (setf a (rol32 (mod32- a (aref round-keys (* i 2)))
64
                        (mod (- 32 (mod b 32)) 32)))
65
         (setf a (logxor a b))))))
66
 
67
 (defun rc5-expand-key (key n-rounds)
68
   (declare (type (simple-array (unsigned-byte 8) (*)) key))
69
   (declare (type rc5-n-rounds n-rounds))
70
   (let* ((n-round-keys (* 2 (1+ n-rounds)))
71
          (round-keys (make-array n-round-keys :element-type '(unsigned-byte 32)))
72
          (expanded-key (make-array 256 :element-type '(unsigned-byte 8)
73
                                      :initial-element 0))
74
          (n-expanded-key-words (ceiling (length key) 4))
75
          (l (make-array 64 :element-type '(unsigned-byte 32))))
76
     (declare (dynamic-extent expanded-key l))
77
     (declare (type (simple-array (unsigned-byte 8) (256)) expanded-key))
78
     (declare (type (simple-array (unsigned-byte 32) (64)) l))
79
     (declare (type (simple-array (unsigned-byte 32) (*)) round-keys))
80
     ;; convert the key into a sequence of (unsigned-byte 32).  this way
81
     ;; is somewhat slow and consy, but it's easily shown to be correct.
82
     (replace expanded-key key)
83
     (loop for i from 0 below 64 do
84
           (setf (aref l i) (ub32ref/le expanded-key (* i 4))))
85
     ;; initialize the round keys
86
     (loop initially (setf (aref round-keys 0) +rc5/32-p+)
87
       for i from 1 below n-round-keys do
88
       (setf (aref round-keys i) (mod32+ (aref round-keys (1- i)) +rc5/32-q+)))
89
     ;; mix in the user's key
90
     (do ((k (* 3 (max n-expanded-key-words n-round-keys)) (1- k))
91
          (a 0)
92
          (b 0)
93
          (i 0 (mod (1+ i) n-round-keys))
94
          (j 0 (mod (1+ j) n-expanded-key-words)))
95
         ((<= k 0) round-keys)
96
       (declare (type (unsigned-byte 32) a b))
97
       (setf a (rol32 (mod32+ (aref round-keys i) (mod32+ a b)) 3))
98
       (setf (aref round-keys i) a)
99
       (setf b (let ((x (mod32+ a b)))
100
                 (declare (type (unsigned-byte 32) x))
101
                 (rol32 (mod32+ (aref l j) x) (mod x 32))))
102
       (setf (aref l j) b))))
103
 
104
 (defmethod schedule-key ((cipher rc5) key)
105
   (let* ((n-rounds (n-rounds cipher))
106
          (round-keys (rc5-expand-key key n-rounds)))
107
     (setf (round-keys cipher) round-keys)
108
     cipher))
109
 
110
 (defcipher rc5
111
   (:encrypt-function rc5-encrypt-block)
112
   (:decrypt-function rc5-decrypt-block)
113
   (:block-length 8)
114
   (:key-length (:variable 1 255 1)))