Coverage report: /home/ellis/comp/ext/ironclad/src/ciphers/chacha.lisp
Kind | Covered | All | % |
expression | 0 | 221 | 0.0 |
branch | 0 | 14 | 0.0 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; chacha.lisp --implementation of the ChaCha stream cipher
4
(declaim (type (simple-octet-vector 16) chacha-sigma chacha-tau))
6
#.(coerce (map 'vector #'char-code "expand 32-byte k") 'simple-octet-vector))
9
#.(coerce (map 'vector #'char-code "expand 16-byte k") 'simple-octet-vector))
11
(deftype chacha-state () '(simple-array (unsigned-byte 32) (16)))
12
(deftype chacha-keystream-buffer () '(simple-octet-vector 64))
14
(declaim (inline chacha-core))
15
(defun chacha-core (n-rounds buffer state)
16
(declare (type chacha-keystream-buffer buffer))
17
(declare (type chacha-state state))
18
(declare (optimize speed))
19
#+(and x86-64 ironclad-assembly)
20
(x-chacha-core n-rounds buffer state)
21
#-(and sbcl x86-64 ironclad-assembly)
22
(let ((x (make-array 16 :element-type '(unsigned-byte 32))))
23
(declare (dynamic-extent x))
25
(macrolet ((combine (x y shift)
26
`(rol32 (logxor ,x ,y) ,shift))
29
(quarter-round (y0 y1 y2 y3)
30
`(setf (ref ,y0) (mod32+ (ref ,y0) (ref ,y1))
31
(ref ,y3) (combine (ref ,y3) (ref ,y0) 16)
32
(ref ,y2) (mod32+ (ref ,y2) (ref ,y3))
33
(ref ,y1) (combine (ref ,y1) (ref ,y2) 12)
34
(ref ,y0) (mod32+ (ref ,y0) (ref ,y1))
35
(ref ,y3) (combine (ref ,y3) (ref ,y0) 8)
36
(ref ,y2) (mod32+ (ref ,y2) (ref ,y3))
37
(ref ,y1) (combine (ref ,y1) (ref ,y2) 7))))
39
(quarter-round 0 4 8 12)
40
(quarter-round 1 5 9 13)
41
(quarter-round 2 6 10 14)
42
(quarter-round 3 7 11 15)
44
(quarter-round 0 5 10 15)
45
(quarter-round 1 6 11 12)
46
(quarter-round 2 7 8 13)
47
(quarter-round 3 4 9 14))
49
(setf (ub32ref/le buffer (* i 4))
50
(mod32+ (aref x i) (aref state i))))))
53
(defun chacha/8-core (buffer state)
54
(declare (type chacha-keystream-buffer buffer))
55
(declare (type chacha-state state))
56
(chacha-core 4 buffer state))
58
(defun chacha/12-core (buffer state)
59
(declare (type chacha-keystream-buffer buffer))
60
(declare (type chacha-state state))
61
(chacha-core 6 buffer state))
63
(defun chacha/20-core (buffer state)
64
(declare (type chacha-keystream-buffer buffer))
65
(declare (type chacha-state state))
66
(chacha-core 10 buffer state))
68
(defclass chacha (stream-cipher)
69
((state :reader chacha-state
70
:initform (make-array 16 :element-type '(unsigned-byte 32)
73
(counter-size :accessor chacha-counter-size
76
(keystream-buffer :reader chacha-keystream-buffer
77
:initform (make-array 64 :element-type '(unsigned-byte 8))
78
:type chacha-keystream-buffer)
79
(keystream-buffer-remaining :accessor chacha-keystream-buffer-remaining
82
(core-function :reader chacha-core-function
83
:initarg :core-function
85
(:default-initargs :core-function #'chacha/20-core))
87
(defclass chacha/12 (chacha)
89
(:default-initargs :core-function #'chacha/12-core))
91
(defclass chacha/8 (chacha)
93
(:default-initargs :core-function #'chacha/8-core))
95
(defun chacha-keyify (cipher key)
96
(declare (type chacha cipher))
97
(let ((state (chacha-state cipher)))
98
(declare (type chacha-state state))
99
(multiple-value-bind (constants offset)
100
(if (= (length key) 16)
101
(values chacha-tau 0)
102
(values chacha-sigma 16))
103
(setf (aref state 4) (ub32ref/le key 0)
104
(aref state 5) (ub32ref/le key 4)
105
(aref state 6) (ub32ref/le key 8)
106
(aref state 7) (ub32ref/le key 12))
107
(setf (aref state 8) (ub32ref/le key (+ offset 0))
108
(aref state 9) (ub32ref/le key (+ offset 4))
109
(aref state 10) (ub32ref/le key (+ offset 8))
110
(aref state 11) (ub32ref/le key (+ offset 12)))
111
(setf (aref state 0) (ub32ref/le constants 0)
112
(aref state 1) (ub32ref/le constants 4)
113
(aref state 2) (ub32ref/le constants 8)
114
(aref state 3) (ub32ref/le constants 12))
117
(defmethod shared-initialize :after ((cipher chacha) slot-names
120
(initialization-vector nil iv-p)
122
(declare (ignore initargs key key-p iv-p))
123
(setf (chacha-keystream-buffer-remaining cipher) 0)
124
(when initialization-vector
125
(when (< (length initialization-vector) 8)
126
(error 'invalid-initialization-vector
127
:cipher (class-name (class-of cipher))
129
(let ((state (chacha-state cipher)))
130
(declare (type chacha-state state))
131
(case (length initialization-vector)
133
;; 32-bit counter and 96-bit nonce of the RFC 8439 variant
134
(setf (chacha-counter-size cipher) 1)
135
(setf (aref state 12) 0
136
(aref state 13) (ub32ref/le initialization-vector 0)
137
(aref state 14) (ub32ref/le initialization-vector 4)
138
(aref state 15) (ub32ref/le initialization-vector 8)))
140
;; 64-bit counter and 64-bit nonce of the original algorithm
141
(setf (chacha-counter-size cipher) 2)
142
(setf (aref state 12) 0
144
(aref state 14) (ub32ref/le initialization-vector 0)
145
(aref state 15) (ub32ref/le initialization-vector 4))))))
148
(defmethod schedule-key ((cipher chacha) key)
149
(chacha-keyify cipher key)
152
(define-stream-cryptor chacha
153
(let ((state (chacha-state context))
154
(keystream-buffer (chacha-keystream-buffer context))
155
(keystream-buffer-remaining (chacha-keystream-buffer-remaining context))
156
(core-function (chacha-core-function context)))
157
(declare (type chacha-state state)
158
(type chacha-keystream-buffer keystream-buffer)
159
(type (integer 0 64) keystream-buffer-remaining)
160
(type function core-function))
161
(unless (zerop length)
162
(unless (zerop keystream-buffer-remaining)
163
(let ((size (min length keystream-buffer-remaining)))
164
(declare (type (integer 0 64) size))
165
(xor-block size keystream-buffer (- 64 keystream-buffer-remaining)
166
plaintext plaintext-start
167
ciphertext ciphertext-start)
168
(decf keystream-buffer-remaining size)
170
(incf ciphertext-start size)
171
(incf plaintext-start size)))
172
(unless (zerop length)
174
(funcall core-function keystream-buffer state)
175
(when (zerop (setf (aref state 12)
176
(mod32+ (aref state 12) 1)))
177
(setf (aref state 13) (mod32+ (aref state 13) 1)))
179
(xor-block length keystream-buffer 0 plaintext plaintext-start
180
ciphertext ciphertext-start)
181
(setf (chacha-keystream-buffer-remaining context) (- 64 length))
182
(return-from chacha-crypt (values)))
183
(xor-block 64 keystream-buffer 0 plaintext plaintext-start
184
ciphertext ciphertext-start)
186
(incf ciphertext-start 64)
187
(incf plaintext-start 64)))
188
(setf (chacha-keystream-buffer-remaining context) keystream-buffer-remaining))
193
(:crypt-function chacha-crypt)
194
(:key-length (:fixed 16 32)))
198
(:crypt-function chacha-crypt)
199
(:key-length (:fixed 16 32)))
203
(:crypt-function chacha-crypt)
204
(:key-length (:fixed 16 32)))