Coverage report: /home/ellis/comp/ext/ironclad/src/macs/gmac.lisp

KindCoveredAll%
expression0506 0.0
branch046 0.0
Key
Not instrumented
Conditionalized out
Executed
Not executed
 
Both branches taken
One branch taken
Neither branch taken
1
 ;;;; gmac.lisp -- GMAC message authentication code
2
 ;; See nistspecialpublication800-38d.pdf about GCM and GMAC.
3
 (in-package :crypto)
4
 
5
 (defclass gmac (mac)
6
   ((accumulator :accessor gmac-accumulator
7
                 :initform (make-array 16 :element-type '(unsigned-byte 8))
8
                 :type (simple-array (unsigned-byte 8) (16)))
9
    (key :accessor gmac-key
10
         :type (or null
11
                   (simple-array (unsigned-byte 8) (16))
12
                   (simple-array (unsigned-byte 64) (128 2 2))))
13
    (total-length :accessor gmac-total-length
14
                  :initform 0
15
                  :type (unsigned-byte 64))
16
    (cipher :accessor gmac-cipher
17
            :initform nil)
18
    (j0 :accessor gmac-j0
19
        :type (simple-array (unsigned-byte 8) (16)))
20
    (iv :accessor gmac-iv
21
        :initform (make-array 16 :element-type '(unsigned-byte 8))
22
        :type (simple-array (unsigned-byte 8) (16)))
23
    (buffer :accessor gmac-buffer
24
            :initform (make-array 16 :element-type '(unsigned-byte 8))
25
            :type (simple-array (unsigned-byte 8) (16)))
26
    (buffer-length :accessor gmac-buffer-length
27
                   :initform 0
28
                   :type (integer 0 16))))
29
 
30
 (defun make-gmac (key cipher-name initialization-vector)
31
   (unless (member (length key) (key-lengths cipher-name))
32
     (error 'invalid-mac-parameter
33
            :mac-name 'gmac
34
            :message "The key length is not compatible with the cipher"))
35
   (unless (= (block-length cipher-name) 16)
36
     (error 'invalid-mac-parameter
37
            :mac-name 'gmac
38
            :message "GMAC only supports 128-bit block ciphers"))
39
   (make-instance 'gmac
40
                  :key key
41
                  :cipher-name cipher-name
42
                  :initialization-vector initialization-vector))
43
 
44
 (declaim (inline gmac-swap-16))
45
 (defun gmac-swap-16 (data)
46
   (declare (type (simple-array (unsigned-byte 8) (16)) data)
47
            (optimize (speed 3) (space 0) (safety 0) (debug 0)))
48
   (let ((x (ub64ref/be data 8)))
49
     (declare (type (unsigned-byte 64) x))
50
     (setf (ub64ref/le data 8) (ub64ref/be data 0)
51
           (ub64ref/le data 0) x))
52
   (values))
53
 
54
 (defun ghash (h x)
55
   (multiple-value-bind (q r) (floor (length x) 16)
56
     (assert (zerop r))
57
     (let ((z (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0))
58
           (i 0))
59
       (if #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
60
           #-(and x86-64 ironclad-assembly) nil
61
           (let ((y (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0)))
62
             (dotimes (j q)
63
               (replace y x :start2 i)
64
               (ironclad::gmac-swap-16 y)
65
               (ironclad::xor-block 16 z 0 y 0 z 0)
66
               (ironclad::gmac-mul z h)
67
               (incf i 16))
68
             (ironclad::gmac-swap-16 z))
69
           (dotimes (j q)
70
             (ironclad::xor-block 16 z 0 x i z 0)
71
             (ironclad::gmac-mul z h)
72
             (incf i 16)))
73
       z)))
74
 
75
 (defun j0 (h iv)
76
   (labels ((pad (n)
77
              (make-array (- (* 16 (ceiling n 16)) n)
78
                          :element-type '(unsigned-byte 8)
79
                          :initial-element 0))
80
            (ac (a c)
81
              (let ((an (length a))
82
                    (cn (length c)))
83
                (concatenate '(simple-array (unsigned-byte 8) (*))
84
                             a
85
                             (pad an)
86
                             c
87
                             (pad cn)
88
                             (integer-to-octets (* 8 an) :n-bits 64)
89
                             (integer-to-octets (* 8 cn) :n-bits 64)))))
90
     (let* ((n (length iv))
91
            (n*8 (* 8 n)))
92
       (cond
93
         ((= 12 n)
94
          (concatenate '(simple-array (unsigned-byte 8) (16)) iv #(0 0 0 1)))
95
         ((< 0 n*8 #.(expt 2 64))
96
          (ghash h (ac nil iv)))
97
         (t
98
          (error 'invalid-mac-parameter
99
                 :mac-name 'gmac
100
                 :message "iv size not in range 0<|iv|<2^64 bits"))))))
101
 
102
 (defmethod shared-initialize :after ((mac gmac) slot-names &rest initargs &key key cipher-name initialization-vector &allow-other-keys)
103
   (declare (ignore slot-names initargs)
104
            (type (simple-array (unsigned-byte 8) (*)) key))
105
   (when (and cipher-name (/= (block-length cipher-name) 16))
106
     (error 'invalid-mac-parameter
107
            :mac-name 'gmac
108
            :message "GMAC only supports 128-bit block ciphers"))
109
   (if #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
110
       #-(and x86-64 ironclad-assembly) nil
111
       (let ((cipher (if (or cipher-name (null (gmac-cipher mac)))
112
                         (make-cipher cipher-name :key key :mode :ecb)
113
                         (reinitialize-instance (gmac-cipher mac) :key key :mode :ecb)))
114
             (hkey (make-array 16 :element-type '(unsigned-byte 8)))
115
             (iv (gmac-iv mac)))
116
         (declare (type (simple-array (unsigned-byte 8) (16)) hkey))
117
         (setf (gmac-key mac) hkey
118
               (gmac-total-length mac) 0
119
               (gmac-buffer-length mac) 0
120
               (gmac-cipher mac) cipher)
121
         (fill (gmac-accumulator mac) 0)
122
         (fill hkey 0)
123
         (encrypt-in-place cipher hkey)
124
         (gmac-swap-16 hkey)
125
         (let ((j0 (j0 hkey initialization-vector)))
126
           (setf (gmac-j0 mac) j0)
127
           (replace iv j0))
128
         (encrypt-in-place cipher iv)
129
         mac)
130
       (let ((table (make-array '(128 2 2) :element-type '(unsigned-byte 64)
131
                                           :initial-element 0))
132
             (cipher (if cipher-name
133
                         (make-cipher cipher-name :key key :mode :ecb)
134
                         (gmac-cipher mac)))
135
             (iv (gmac-iv mac))
136
             (hkey (make-array 16 :element-type '(unsigned-byte 8)
137
                                  :initial-element 0)))
138
         (declare (type (simple-array (unsigned-byte 64) (128 2 2)) table)
139
                  (type (simple-array (unsigned-byte 8) (16)) hkey)
140
                  (dynamic-extent hkey))
141
         (setf (gmac-key mac) table
142
               (gmac-total-length mac) 0
143
               (gmac-buffer-length mac) 0
144
               (gmac-cipher mac) cipher)
145
         (fill (gmac-accumulator mac) 0)
146
         (encrypt-in-place cipher hkey)
147
 
148
         (setf (aref table 0 1 0) (ub64ref/be hkey 0)
149
               (aref table 0 1 1) (ub64ref/be hkey 8))
150
         (dotimes (i 127)
151
           (let ((c (if (logbitp 0 (aref table i 1 1)) #xe100000000000000 0)))
152
             (declare (type (unsigned-byte 64) c))
153
             (setf (aref table (1+ i) 1 1) (logior (mod64ash (aref table i 1 1) -1)
154
                                                   (mod64ash (aref table i 1 0) 63))
155
                   (aref table (1+ i) 1 0) (logxor (mod64ash (aref table i 1 0) -1) c))))
156
         (let ((j0 (j0 table initialization-vector)))
157
           (setf (gmac-j0 mac) j0)
158
           (replace iv j0))
159
         (encrypt-in-place cipher iv)
160
         mac)))
161
 
162
 (defun gmac-mul (accumulator key)
163
   (declare (type (simple-array (unsigned-byte 8) (16)) accumulator)
164
            (optimize (speed 3) (space 0) (safety 0) (debug 0)))
165
   (if #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
166
       #-(and x86-64 ironclad-assembly) nil
167
       #+(and x86-64 ironclad-assembly) (gmac-mul-fast accumulator key)
168
       #-(and x86-64 ironclad-assembly) nil
169
       (let ((x 0)
170
             (z0 0)
171
             (z1 0)
172
             (b 0))
173
         (declare (type (simple-array (unsigned-byte 64) (128 2 2)) key)
174
                  (type (unsigned-byte 8) x)
175
                  (type (unsigned-byte 64) z0 z1)
176
                  (type bit b))
177
         (dotimes-unrolled (i 16)
178
           (setf x (aref accumulator i))
179
           (dotimes-unrolled (j 8)
180
             (setf b (logand (ash x (- j 7)) 1)
181
                   z0 (logxor z0 (aref key (+ (* i 8) j) b 0))
182
                   z1 (logxor z1 (aref key (+ (* i 8) j) b 1)))))
183
         (setf (ub64ref/be accumulator 0) z0
184
               (ub64ref/be accumulator 8) z1)))
185
   (values))
186
 
187
 (defun update-gmac (mac data &key (start 0) (end (length data)))
188
   (declare (type (simple-array (unsigned-byte 8) (*)) data)
189
            (type index start end)
190
            (optimize (speed 3) (space 0) (safety 0) (debug 0)))
191
   (let ((accumulator (gmac-accumulator mac))
192
         (key (gmac-key mac))
193
         (total-length (gmac-total-length mac))
194
         (buffer (gmac-buffer mac))
195
         (buffer-length (gmac-buffer-length mac))
196
         (remaining (- end start)))
197
     (declare (type (simple-array (unsigned-byte 8) (16)) accumulator buffer)
198
              (type (unsigned-byte 64) total-length)
199
              (type (integer 0 16) buffer-length)
200
              (type index remaining))
201
 
202
     ;; Fill the buffer with new data if necessary
203
     (when (plusp buffer-length)
204
       (let ((n (min remaining (- 16 buffer-length))))
205
         (declare (type (integer 0 16) n))
206
         (replace buffer data
207
                  :start1 buffer-length
208
                  :start2 start
209
                  :end2 (+ start n))
210
         (incf buffer-length n)
211
         (incf start n)
212
         (decf remaining n)))
213
 
214
     ;; Process the buffer
215
     (when (= buffer-length 16)
216
       (when #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
217
             #-(and x86-64 ironclad-assembly) nil
218
         (gmac-swap-16 buffer))
219
       (xor-block 16 accumulator 0 buffer 0 accumulator 0)
220
       (gmac-mul accumulator key)
221
       (incf total-length 16)
222
       (setf buffer-length 0))
223
 
224
     ;; Process the data
225
     (if #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
226
         #-(and x86-64 ironclad-assembly) nil
227
         (loop while (> remaining 16) do
228
           (setf (ub64ref/le buffer 8) (ub64ref/be data start)
229
                 (ub64ref/le buffer 0) (ub64ref/be data (+ start 8)))
230
           (xor-block 16 accumulator 0 buffer 0 accumulator 0)
231
           (gmac-mul accumulator key)
232
           (incf total-length 16)
233
           (incf start 16)
234
           (decf remaining 16))
235
         (loop while (> remaining 16) do
236
           (xor-block 16 accumulator 0 data start accumulator 0)
237
           (gmac-mul accumulator key)
238
           (incf total-length 16)
239
           (incf start 16)
240
           (decf remaining 16)))
241
 
242
     ;; Put the remaining data in the buffer
243
     (when (plusp remaining)
244
       (replace buffer data :start1 0 :start2 start :end2 end)
245
       (setf buffer-length remaining))
246
 
247
     ;; Save the state
248
     (setf (gmac-total-length mac) total-length
249
           (gmac-buffer-length mac) buffer-length)
250
     (values)))
251
 
252
 (defun gmac-digest (mac &optional (encrypted-data-length 0))
253
   (let ((accumulator (copy-seq (gmac-accumulator mac)))
254
         (key (gmac-key mac))
255
         (total-length (gmac-total-length mac))
256
         (iv (copy-seq (gmac-iv mac)))
257
         (buffer (copy-seq (gmac-buffer mac)))
258
         (buffer-length (gmac-buffer-length mac)))
259
     (declare (type (simple-array (unsigned-byte 8) (16)) accumulator buffer iv)
260
              (type (unsigned-byte 64) total-length)
261
              (type (integer 0 16) buffer-length))
262
 
263
     ;; Process the buffer
264
     (when (plusp buffer-length)
265
       (fill buffer 0 :start buffer-length)
266
       (when #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
267
             #-(and x86-64 ironclad-assembly) nil
268
         (gmac-swap-16 buffer))
269
       (xor-block 16 accumulator 0 buffer 0 accumulator 0)
270
       (gmac-mul accumulator key)
271
       (incf total-length buffer-length))
272
 
273
     ;; Padding
274
     (if #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
275
         #-(and x86-64 ironclad-assembly) nil
276
         (setf (ub64ref/le buffer 0) (mod64* 8 encrypted-data-length)
277
               (ub64ref/le buffer 8) (mod64* 8 (- total-length encrypted-data-length)))
278
         (setf (ub64ref/be buffer 0) (mod64* 8 (- total-length encrypted-data-length))
279
               (ub64ref/be buffer 8) (mod64* 8 encrypted-data-length)))
280
     (xor-block 16 accumulator 0 buffer 0 accumulator 0)
281
     (gmac-mul accumulator key)
282
 
283
     ;; Produce the tag
284
     (when #+(and x86-64 ironclad-assembly) (pclmulqdq-supported-p)
285
           #-(and x86-64 ironclad-assembly) nil
286
       (gmac-swap-16 accumulator))
287
     (xor-block 16 accumulator 0 iv 0 accumulator 0)
288
     accumulator))
289
 
290
 (defmac gmac
291
         make-gmac
292
         update-gmac
293
         gmac-digest)