aes_via.c revision 1.2 1 1.2 riastrad /* $NetBSD: aes_via.c,v 1.2 2020/06/29 23:41:35 riastradh Exp $ */
2 1.1 riastrad
3 1.1 riastrad /*-
4 1.1 riastrad * Copyright (c) 2020 The NetBSD Foundation, Inc.
5 1.1 riastrad * All rights reserved.
6 1.1 riastrad *
7 1.1 riastrad * Redistribution and use in source and binary forms, with or without
8 1.1 riastrad * modification, are permitted provided that the following conditions
9 1.1 riastrad * are met:
10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright
11 1.1 riastrad * notice, this list of conditions and the following disclaimer.
12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the
14 1.1 riastrad * documentation and/or other materials provided with the distribution.
15 1.1 riastrad *
16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE.
27 1.1 riastrad */
28 1.1 riastrad
29 1.1 riastrad #include <sys/cdefs.h>
30 1.2 riastrad __KERNEL_RCSID(1, "$NetBSD: aes_via.c,v 1.2 2020/06/29 23:41:35 riastradh Exp $");
31 1.1 riastrad
32 1.1 riastrad #include <sys/types.h>
33 1.1 riastrad #include <sys/evcnt.h>
34 1.1 riastrad #include <sys/systm.h>
35 1.1 riastrad
36 1.1 riastrad #include <crypto/aes/aes.h>
37 1.1 riastrad #include <crypto/aes/aes_bear.h>
38 1.1 riastrad
39 1.1 riastrad #include <x86/cpufunc.h>
40 1.1 riastrad #include <x86/cpuvar.h>
41 1.1 riastrad #include <x86/fpu.h>
42 1.1 riastrad #include <x86/specialreg.h>
43 1.1 riastrad #include <x86/via_padlock.h>
44 1.1 riastrad
45 1.1 riastrad static void
46 1.1 riastrad aesvia_reload_keys(void)
47 1.1 riastrad {
48 1.1 riastrad
49 1.1 riastrad asm volatile("pushf; popf");
50 1.1 riastrad }
51 1.1 riastrad
52 1.1 riastrad static uint32_t
53 1.1 riastrad aesvia_keylen_cw0(unsigned nrounds)
54 1.1 riastrad {
55 1.1 riastrad
56 1.1 riastrad /*
57 1.1 riastrad * Determine the control word bits for the key size / number of
58 1.1 riastrad * rounds. For AES-128, the hardware can do key expansion on
59 1.1 riastrad * the fly; for AES-192 and AES-256, software must do it.
60 1.1 riastrad */
61 1.1 riastrad switch (nrounds) {
62 1.1 riastrad case AES_128_NROUNDS:
63 1.1 riastrad return C3_CRYPT_CWLO_KEY128;
64 1.1 riastrad case AES_192_NROUNDS:
65 1.1 riastrad return C3_CRYPT_CWLO_KEY192 | C3_CRYPT_CWLO_KEYGEN_SW;
66 1.1 riastrad case AES_256_NROUNDS:
67 1.1 riastrad return C3_CRYPT_CWLO_KEY256 | C3_CRYPT_CWLO_KEYGEN_SW;
68 1.1 riastrad default:
69 1.1 riastrad panic("invalid AES nrounds: %u", nrounds);
70 1.1 riastrad }
71 1.1 riastrad }
72 1.1 riastrad
73 1.1 riastrad static void
74 1.1 riastrad aesvia_setenckey(struct aesenc *enc, const uint8_t *key, uint32_t nrounds)
75 1.1 riastrad {
76 1.1 riastrad size_t key_len;
77 1.1 riastrad
78 1.1 riastrad switch (nrounds) {
79 1.1 riastrad case AES_128_NROUNDS:
80 1.1 riastrad enc->aese_aes.aes_rk[0] = le32dec(key + 4*0);
81 1.1 riastrad enc->aese_aes.aes_rk[1] = le32dec(key + 4*1);
82 1.1 riastrad enc->aese_aes.aes_rk[2] = le32dec(key + 4*2);
83 1.1 riastrad enc->aese_aes.aes_rk[3] = le32dec(key + 4*3);
84 1.1 riastrad return;
85 1.1 riastrad case AES_192_NROUNDS:
86 1.1 riastrad key_len = 24;
87 1.1 riastrad break;
88 1.1 riastrad case AES_256_NROUNDS:
89 1.1 riastrad key_len = 32;
90 1.1 riastrad break;
91 1.1 riastrad default:
92 1.1 riastrad panic("invalid AES nrounds: %u", nrounds);
93 1.1 riastrad }
94 1.1 riastrad br_aes_ct_keysched_stdenc(enc->aese_aes.aes_rk, key, key_len);
95 1.1 riastrad }
96 1.1 riastrad
97 1.1 riastrad static void
98 1.1 riastrad aesvia_setdeckey(struct aesdec *dec, const uint8_t *key, uint32_t nrounds)
99 1.1 riastrad {
100 1.1 riastrad size_t key_len;
101 1.1 riastrad
102 1.1 riastrad switch (nrounds) {
103 1.1 riastrad case AES_128_NROUNDS:
104 1.1 riastrad dec->aesd_aes.aes_rk[0] = le32dec(key + 4*0);
105 1.1 riastrad dec->aesd_aes.aes_rk[1] = le32dec(key + 4*1);
106 1.1 riastrad dec->aesd_aes.aes_rk[2] = le32dec(key + 4*2);
107 1.1 riastrad dec->aesd_aes.aes_rk[3] = le32dec(key + 4*3);
108 1.1 riastrad return;
109 1.1 riastrad case AES_192_NROUNDS:
110 1.1 riastrad key_len = 24;
111 1.1 riastrad break;
112 1.1 riastrad case AES_256_NROUNDS:
113 1.1 riastrad key_len = 32;
114 1.1 riastrad break;
115 1.1 riastrad default:
116 1.1 riastrad panic("invalid AES nrounds: %u", nrounds);
117 1.1 riastrad }
118 1.1 riastrad br_aes_ct_keysched_stddec(dec->aesd_aes.aes_rk, key, key_len);
119 1.1 riastrad }
120 1.1 riastrad
121 1.1 riastrad static inline void
122 1.2 riastrad aesvia_encN(const struct aesenc *enc, const uint8_t in[static 16],
123 1.2 riastrad uint8_t out[static 16], size_t nblocks, uint32_t cw0)
124 1.1 riastrad {
125 1.1 riastrad const uint32_t cw[4] __aligned(16) = {
126 1.1 riastrad [0] = (cw0
127 1.1 riastrad | C3_CRYPT_CWLO_ALG_AES
128 1.1 riastrad | C3_CRYPT_CWLO_ENCRYPT
129 1.1 riastrad | C3_CRYPT_CWLO_NORMAL),
130 1.1 riastrad };
131 1.1 riastrad
132 1.1 riastrad KASSERT(((uintptr_t)enc & 0xf) == 0);
133 1.1 riastrad KASSERT(((uintptr_t)in & 0xf) == 0);
134 1.1 riastrad KASSERT(((uintptr_t)out & 0xf) == 0);
135 1.1 riastrad
136 1.1 riastrad asm volatile("rep xcryptecb"
137 1.1 riastrad : "+c"(nblocks), "+S"(in), "+D"(out)
138 1.1 riastrad : "b"(enc), "d"(cw)
139 1.1 riastrad : "memory", "cc");
140 1.1 riastrad }
141 1.1 riastrad
142 1.1 riastrad static inline void
143 1.2 riastrad aesvia_decN(const struct aesdec *dec, const uint8_t in[static 16],
144 1.2 riastrad uint8_t out[static 16], size_t nblocks, uint32_t cw0)
145 1.1 riastrad {
146 1.1 riastrad const uint32_t cw[4] __aligned(16) = {
147 1.1 riastrad [0] = (cw0
148 1.1 riastrad | C3_CRYPT_CWLO_ALG_AES
149 1.1 riastrad | C3_CRYPT_CWLO_DECRYPT
150 1.1 riastrad | C3_CRYPT_CWLO_NORMAL),
151 1.1 riastrad };
152 1.1 riastrad
153 1.1 riastrad KASSERT(((uintptr_t)dec & 0xf) == 0);
154 1.1 riastrad KASSERT(((uintptr_t)in & 0xf) == 0);
155 1.1 riastrad KASSERT(((uintptr_t)out & 0xf) == 0);
156 1.1 riastrad
157 1.1 riastrad asm volatile("rep xcryptecb"
158 1.1 riastrad : "+c"(nblocks), "+S"(in), "+D"(out)
159 1.1 riastrad : "b"(dec), "d"(cw)
160 1.1 riastrad : "memory", "cc");
161 1.1 riastrad }
162 1.1 riastrad
163 1.1 riastrad static struct evcnt enc_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
164 1.1 riastrad NULL, "aesvia", "enc aligned");
165 1.1 riastrad EVCNT_ATTACH_STATIC(enc_aligned_evcnt);
166 1.1 riastrad static struct evcnt enc_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
167 1.1 riastrad NULL, "aesvia", "dec unaligned");
168 1.1 riastrad EVCNT_ATTACH_STATIC(enc_unaligned_evcnt);
169 1.1 riastrad
170 1.1 riastrad static void
171 1.1 riastrad aesvia_enc(const struct aesenc *enc, const uint8_t in[static 16],
172 1.1 riastrad uint8_t out[static 16], uint32_t nrounds)
173 1.1 riastrad {
174 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
175 1.1 riastrad
176 1.1 riastrad fpu_kern_enter();
177 1.1 riastrad aesvia_reload_keys();
178 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out) & 0xf) == 0 &&
179 1.1 riastrad ((uintptr_t)in & 0xff0) != 0xff0) {
180 1.1 riastrad enc_aligned_evcnt.ev_count++;
181 1.2 riastrad aesvia_encN(enc, in, out, 1, cw0);
182 1.1 riastrad } else {
183 1.1 riastrad enc_unaligned_evcnt.ev_count++;
184 1.1 riastrad /*
185 1.1 riastrad * VIA requires 16-byte/128-bit alignment, and
186 1.1 riastrad * xcrypt-ecb reads one block past the one we're
187 1.1 riastrad * working on -- which may go past the end of the page
188 1.1 riastrad * into unmapped territory. Use a bounce buffer if
189 1.1 riastrad * either constraint is violated.
190 1.1 riastrad */
191 1.1 riastrad uint8_t inbuf[16] __aligned(16);
192 1.1 riastrad uint8_t outbuf[16] __aligned(16);
193 1.1 riastrad
194 1.1 riastrad memcpy(inbuf, in, 16);
195 1.2 riastrad aesvia_encN(enc, inbuf, outbuf, 1, cw0);
196 1.1 riastrad memcpy(out, outbuf, 16);
197 1.1 riastrad
198 1.1 riastrad explicit_memset(inbuf, 0, sizeof inbuf);
199 1.1 riastrad explicit_memset(outbuf, 0, sizeof outbuf);
200 1.1 riastrad }
201 1.1 riastrad fpu_kern_leave();
202 1.1 riastrad }
203 1.1 riastrad
204 1.1 riastrad static struct evcnt dec_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
205 1.1 riastrad NULL, "aesvia", "dec aligned");
206 1.1 riastrad EVCNT_ATTACH_STATIC(dec_aligned_evcnt);
207 1.1 riastrad static struct evcnt dec_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
208 1.1 riastrad NULL, "aesvia", "dec unaligned");
209 1.1 riastrad EVCNT_ATTACH_STATIC(dec_unaligned_evcnt);
210 1.1 riastrad
211 1.1 riastrad static void
212 1.1 riastrad aesvia_dec(const struct aesdec *dec, const uint8_t in[static 16],
213 1.1 riastrad uint8_t out[static 16], uint32_t nrounds)
214 1.1 riastrad {
215 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
216 1.1 riastrad
217 1.1 riastrad fpu_kern_enter();
218 1.1 riastrad aesvia_reload_keys();
219 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out) & 0xf) == 0 &&
220 1.1 riastrad ((uintptr_t)in & 0xff0) != 0xff0) {
221 1.1 riastrad dec_aligned_evcnt.ev_count++;
222 1.2 riastrad aesvia_decN(dec, in, out, 1, cw0);
223 1.1 riastrad } else {
224 1.1 riastrad dec_unaligned_evcnt.ev_count++;
225 1.1 riastrad /*
226 1.1 riastrad * VIA requires 16-byte/128-bit alignment, and
227 1.1 riastrad * xcrypt-ecb reads one block past the one we're
228 1.1 riastrad * working on -- which may go past the end of the page
229 1.1 riastrad * into unmapped territory. Use a bounce buffer if
230 1.1 riastrad * either constraint is violated.
231 1.1 riastrad */
232 1.1 riastrad uint8_t inbuf[16] __aligned(16);
233 1.1 riastrad uint8_t outbuf[16] __aligned(16);
234 1.1 riastrad
235 1.1 riastrad memcpy(inbuf, in, 16);
236 1.2 riastrad aesvia_decN(dec, inbuf, outbuf, 1, cw0);
237 1.1 riastrad memcpy(out, outbuf, 16);
238 1.1 riastrad
239 1.1 riastrad explicit_memset(inbuf, 0, sizeof inbuf);
240 1.1 riastrad explicit_memset(outbuf, 0, sizeof outbuf);
241 1.1 riastrad }
242 1.1 riastrad fpu_kern_leave();
243 1.1 riastrad }
244 1.1 riastrad
245 1.1 riastrad static inline void
246 1.2 riastrad aesvia_cbc_encN(const struct aesenc *enc, const uint8_t in[static 16],
247 1.1 riastrad uint8_t out[static 16], size_t nblocks, uint8_t **ivp, uint32_t cw0)
248 1.1 riastrad {
249 1.1 riastrad const uint32_t cw[4] __aligned(16) = {
250 1.1 riastrad [0] = (cw0
251 1.1 riastrad | C3_CRYPT_CWLO_ALG_AES
252 1.1 riastrad | C3_CRYPT_CWLO_ENCRYPT
253 1.1 riastrad | C3_CRYPT_CWLO_NORMAL),
254 1.1 riastrad };
255 1.1 riastrad
256 1.1 riastrad KASSERT(((uintptr_t)enc & 0xf) == 0);
257 1.1 riastrad KASSERT(((uintptr_t)in & 0xf) == 0);
258 1.1 riastrad KASSERT(((uintptr_t)out & 0xf) == 0);
259 1.1 riastrad KASSERT(((uintptr_t)*ivp & 0xf) == 0);
260 1.1 riastrad
261 1.1 riastrad /*
262 1.1 riastrad * Register effects:
263 1.1 riastrad * - Counts nblocks down to zero.
264 1.1 riastrad * - Advances in by nblocks (units of blocks).
265 1.1 riastrad * - Advances out by nblocks (units of blocks).
266 1.1 riastrad * - Updates *ivp to point at the last block of out.
267 1.1 riastrad */
268 1.1 riastrad asm volatile("rep xcryptcbc"
269 1.1 riastrad : "+c"(nblocks), "+S"(in), "+D"(out), "+a"(*ivp)
270 1.1 riastrad : "b"(enc), "d"(cw)
271 1.1 riastrad : "memory", "cc");
272 1.1 riastrad }
273 1.1 riastrad
274 1.1 riastrad static inline void
275 1.2 riastrad aesvia_cbc_decN(const struct aesdec *dec, const uint8_t in[static 16],
276 1.1 riastrad uint8_t out[static 16], size_t nblocks, uint8_t iv[static 16],
277 1.1 riastrad uint32_t cw0)
278 1.1 riastrad {
279 1.1 riastrad const uint32_t cw[4] __aligned(16) = {
280 1.1 riastrad [0] = (cw0
281 1.1 riastrad | C3_CRYPT_CWLO_ALG_AES
282 1.1 riastrad | C3_CRYPT_CWLO_DECRYPT
283 1.1 riastrad | C3_CRYPT_CWLO_NORMAL),
284 1.1 riastrad };
285 1.1 riastrad
286 1.1 riastrad KASSERT(((uintptr_t)dec & 0xf) == 0);
287 1.1 riastrad KASSERT(((uintptr_t)in & 0xf) == 0);
288 1.1 riastrad KASSERT(((uintptr_t)out & 0xf) == 0);
289 1.1 riastrad KASSERT(((uintptr_t)iv & 0xf) == 0);
290 1.1 riastrad
291 1.1 riastrad /*
292 1.1 riastrad * Register effects:
293 1.1 riastrad * - Counts nblocks down to zero.
294 1.1 riastrad * - Advances in by nblocks (units of blocks).
295 1.1 riastrad * - Advances out by nblocks (units of blocks).
296 1.1 riastrad * Memory side effects:
297 1.1 riastrad * - Writes what was the last block of in at the address iv.
298 1.1 riastrad */
299 1.1 riastrad asm volatile("rep xcryptcbc"
300 1.1 riastrad : "+c"(nblocks), "+S"(in), "+D"(out)
301 1.1 riastrad : "a"(iv), "b"(dec), "d"(cw)
302 1.1 riastrad : "memory", "cc");
303 1.1 riastrad }
304 1.1 riastrad
305 1.1 riastrad static inline void
306 1.1 riastrad xor128(void *x, const void *a, const void *b)
307 1.1 riastrad {
308 1.1 riastrad uint32_t *x32 = x;
309 1.1 riastrad const uint32_t *a32 = a;
310 1.1 riastrad const uint32_t *b32 = b;
311 1.1 riastrad
312 1.1 riastrad x32[0] = a32[0] ^ b32[0];
313 1.1 riastrad x32[1] = a32[1] ^ b32[1];
314 1.1 riastrad x32[2] = a32[2] ^ b32[2];
315 1.1 riastrad x32[3] = a32[3] ^ b32[3];
316 1.1 riastrad }
317 1.1 riastrad
318 1.1 riastrad static struct evcnt cbcenc_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
319 1.1 riastrad NULL, "aesvia", "cbcenc aligned");
320 1.1 riastrad EVCNT_ATTACH_STATIC(cbcenc_aligned_evcnt);
321 1.1 riastrad static struct evcnt cbcenc_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
322 1.1 riastrad NULL, "aesvia", "cbcenc unaligned");
323 1.1 riastrad EVCNT_ATTACH_STATIC(cbcenc_unaligned_evcnt);
324 1.1 riastrad
325 1.1 riastrad static void
326 1.1 riastrad aesvia_cbc_enc(const struct aesenc *enc, const uint8_t in[static 16],
327 1.1 riastrad uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
328 1.1 riastrad uint32_t nrounds)
329 1.1 riastrad {
330 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
331 1.1 riastrad
332 1.1 riastrad KASSERT(nbytes % 16 == 0);
333 1.1 riastrad if (nbytes == 0)
334 1.1 riastrad return;
335 1.1 riastrad
336 1.1 riastrad fpu_kern_enter();
337 1.1 riastrad aesvia_reload_keys();
338 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out | (uintptr_t)iv) & 0xf) == 0) {
339 1.1 riastrad cbcenc_aligned_evcnt.ev_count++;
340 1.1 riastrad uint8_t *ivp = iv;
341 1.2 riastrad aesvia_cbc_encN(enc, in, out, nbytes/16, &ivp, cw0);
342 1.1 riastrad memcpy(iv, ivp, 16);
343 1.1 riastrad } else {
344 1.1 riastrad cbcenc_unaligned_evcnt.ev_count++;
345 1.1 riastrad uint8_t cv[16] __aligned(16);
346 1.1 riastrad uint8_t tmp[16] __aligned(16);
347 1.1 riastrad
348 1.1 riastrad memcpy(cv, iv, 16);
349 1.1 riastrad for (; nbytes; nbytes -= 16, in += 16, out += 16) {
350 1.1 riastrad memcpy(tmp, in, 16);
351 1.1 riastrad xor128(tmp, tmp, cv);
352 1.2 riastrad aesvia_encN(enc, tmp, cv, 1, cw0);
353 1.1 riastrad memcpy(out, cv, 16);
354 1.1 riastrad }
355 1.1 riastrad memcpy(iv, cv, 16);
356 1.1 riastrad }
357 1.1 riastrad fpu_kern_leave();
358 1.1 riastrad }
359 1.1 riastrad
360 1.1 riastrad static struct evcnt cbcdec_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
361 1.1 riastrad NULL, "aesvia", "cbcdec aligned");
362 1.1 riastrad EVCNT_ATTACH_STATIC(cbcdec_aligned_evcnt);
363 1.1 riastrad static struct evcnt cbcdec_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
364 1.1 riastrad NULL, "aesvia", "cbcdec unaligned");
365 1.1 riastrad EVCNT_ATTACH_STATIC(cbcdec_unaligned_evcnt);
366 1.1 riastrad
367 1.1 riastrad static void
368 1.1 riastrad aesvia_cbc_dec(const struct aesdec *dec, const uint8_t in[static 16],
369 1.1 riastrad uint8_t out[static 16], size_t nbytes, uint8_t iv[static 16],
370 1.1 riastrad uint32_t nrounds)
371 1.1 riastrad {
372 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
373 1.1 riastrad
374 1.1 riastrad KASSERT(nbytes % 16 == 0);
375 1.1 riastrad if (nbytes == 0)
376 1.1 riastrad return;
377 1.1 riastrad
378 1.1 riastrad fpu_kern_enter();
379 1.1 riastrad aesvia_reload_keys();
380 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out | (uintptr_t)iv) & 0xf) == 0) {
381 1.1 riastrad cbcdec_aligned_evcnt.ev_count++;
382 1.2 riastrad aesvia_cbc_decN(dec, in, out, nbytes/16, iv, cw0);
383 1.1 riastrad } else {
384 1.1 riastrad cbcdec_unaligned_evcnt.ev_count++;
385 1.1 riastrad uint8_t iv0[16] __aligned(16);
386 1.1 riastrad uint8_t cv[16] __aligned(16);
387 1.1 riastrad uint8_t tmp[16] __aligned(16);
388 1.1 riastrad
389 1.1 riastrad memcpy(iv0, iv, 16);
390 1.1 riastrad memcpy(cv, in + nbytes - 16, 16);
391 1.1 riastrad memcpy(iv, cv, 16);
392 1.1 riastrad
393 1.1 riastrad for (;;) {
394 1.2 riastrad aesvia_decN(dec, cv, tmp, 1, cw0);
395 1.1 riastrad if ((nbytes -= 16) == 0)
396 1.1 riastrad break;
397 1.1 riastrad memcpy(cv, in + nbytes - 16, 16);
398 1.1 riastrad xor128(tmp, tmp, cv);
399 1.1 riastrad memcpy(out + nbytes, tmp, 16);
400 1.1 riastrad }
401 1.1 riastrad
402 1.1 riastrad xor128(tmp, tmp, iv0);
403 1.1 riastrad memcpy(out, tmp, 16);
404 1.1 riastrad explicit_memset(tmp, 0, sizeof tmp);
405 1.1 riastrad }
406 1.1 riastrad fpu_kern_leave();
407 1.1 riastrad }
408 1.1 riastrad
409 1.1 riastrad static inline void
410 1.1 riastrad aesvia_xts_update(uint32_t *t0, uint32_t *t1, uint32_t *t2, uint32_t *t3)
411 1.1 riastrad {
412 1.1 riastrad uint32_t s0, s1, s2, s3;
413 1.1 riastrad
414 1.1 riastrad s0 = *t0 >> 31;
415 1.1 riastrad s1 = *t1 >> 31;
416 1.1 riastrad s2 = *t2 >> 31;
417 1.1 riastrad s3 = *t3 >> 31;
418 1.1 riastrad *t0 = (*t0 << 1) ^ (-s3 & 0x87);
419 1.1 riastrad *t1 = (*t1 << 1) ^ s0;
420 1.1 riastrad *t2 = (*t2 << 1) ^ s1;
421 1.1 riastrad *t3 = (*t3 << 1) ^ s2;
422 1.1 riastrad }
423 1.1 riastrad
424 1.1 riastrad static int
425 1.1 riastrad aesvia_xts_update_selftest(void)
426 1.1 riastrad {
427 1.1 riastrad static const struct {
428 1.1 riastrad uint32_t in[4], out[4];
429 1.1 riastrad } cases[] = {
430 1.1 riastrad { {1}, {2} },
431 1.1 riastrad { {0x80000000U,0,0,0}, {0,1,0,0} },
432 1.1 riastrad { {0,0x80000000U,0,0}, {0,0,1,0} },
433 1.1 riastrad { {0,0,0x80000000U,0}, {0,0,0,1} },
434 1.1 riastrad { {0,0,0,0x80000000U}, {0x87,0,0,0} },
435 1.1 riastrad { {0,0x80000000U,0,0x80000000U}, {0x87,0,1,0} },
436 1.1 riastrad };
437 1.1 riastrad unsigned i;
438 1.1 riastrad uint32_t t0, t1, t2, t3;
439 1.1 riastrad
440 1.1 riastrad for (i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) {
441 1.1 riastrad t0 = cases[i].in[0];
442 1.1 riastrad t1 = cases[i].in[1];
443 1.1 riastrad t2 = cases[i].in[2];
444 1.1 riastrad t3 = cases[i].in[3];
445 1.1 riastrad aesvia_xts_update(&t0, &t1, &t2, &t3);
446 1.1 riastrad if (t0 != cases[i].out[0] ||
447 1.1 riastrad t1 != cases[i].out[1] ||
448 1.1 riastrad t2 != cases[i].out[2] ||
449 1.1 riastrad t3 != cases[i].out[3])
450 1.1 riastrad return -1;
451 1.1 riastrad }
452 1.1 riastrad
453 1.1 riastrad /* Success! */
454 1.1 riastrad return 0;
455 1.1 riastrad }
456 1.1 riastrad
457 1.1 riastrad static struct evcnt xtsenc_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
458 1.1 riastrad NULL, "aesvia", "xtsenc aligned");
459 1.1 riastrad EVCNT_ATTACH_STATIC(xtsenc_aligned_evcnt);
460 1.1 riastrad static struct evcnt xtsenc_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
461 1.1 riastrad NULL, "aesvia", "xtsenc unaligned");
462 1.1 riastrad EVCNT_ATTACH_STATIC(xtsenc_unaligned_evcnt);
463 1.1 riastrad
464 1.1 riastrad static void
465 1.1 riastrad aesvia_xts_enc(const struct aesenc *enc, const uint8_t in[static 16],
466 1.1 riastrad uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
467 1.1 riastrad uint32_t nrounds)
468 1.1 riastrad {
469 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
470 1.1 riastrad uint32_t t[4];
471 1.1 riastrad
472 1.1 riastrad KASSERT(nbytes % 16 == 0);
473 1.1 riastrad
474 1.1 riastrad memcpy(t, tweak, 16);
475 1.1 riastrad
476 1.1 riastrad fpu_kern_enter();
477 1.1 riastrad aesvia_reload_keys();
478 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out) & 0xf) == 0) {
479 1.1 riastrad xtsenc_aligned_evcnt.ev_count++;
480 1.1 riastrad unsigned lastblock = 0;
481 1.2 riastrad uint32_t buf[8*4] __aligned(16);
482 1.1 riastrad
483 1.1 riastrad /*
484 1.1 riastrad * Make sure the last block is not the last block of a
485 1.1 riastrad * page. (Note that we store the AES input in `out' as
486 1.1 riastrad * a temporary buffer, rather than reading it directly
487 1.1 riastrad * from `in', since we have to combine the tweak
488 1.1 riastrad * first.)
489 1.1 riastrad */
490 1.1 riastrad lastblock = 16*(((uintptr_t)(out + nbytes) & 0xfff) == 0);
491 1.1 riastrad nbytes -= lastblock;
492 1.1 riastrad
493 1.2 riastrad /*
494 1.2 riastrad * Handle an odd number of initial blocks so we can
495 1.2 riastrad * process the rest in eight-block (128-byte) chunks.
496 1.2 riastrad */
497 1.2 riastrad if (nbytes % 128) {
498 1.2 riastrad unsigned nbytes128 = nbytes % 128;
499 1.2 riastrad
500 1.2 riastrad nbytes -= nbytes128;
501 1.2 riastrad for (; nbytes128; nbytes128 -= 16, in += 16, out += 16)
502 1.2 riastrad {
503 1.2 riastrad xor128(out, in, t);
504 1.2 riastrad aesvia_encN(enc, out, out, 1, cw0);
505 1.2 riastrad xor128(out, out, t);
506 1.2 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
507 1.2 riastrad }
508 1.2 riastrad }
509 1.2 riastrad
510 1.2 riastrad /* Process eight blocks at a time. */
511 1.2 riastrad for (; nbytes; nbytes -= 128, in += 128, out += 128) {
512 1.2 riastrad unsigned i;
513 1.2 riastrad for (i = 0; i < 8; i++) {
514 1.2 riastrad memcpy(buf + 4*i, t, 16);
515 1.2 riastrad xor128(out + 4*i, in + 4*i, t);
516 1.2 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
517 1.2 riastrad }
518 1.2 riastrad aesvia_encN(enc, out, out, 8, cw0);
519 1.2 riastrad for (i = 0; i < 8; i++)
520 1.2 riastrad xor128(out + 4*i, in + 4*i, buf + 4*i);
521 1.1 riastrad }
522 1.1 riastrad
523 1.1 riastrad /* Handle the last block of a page, if necessary. */
524 1.1 riastrad if (lastblock) {
525 1.1 riastrad xor128(buf, in, t);
526 1.2 riastrad aesvia_encN(enc, (const void *)buf, out, 1, cw0);
527 1.1 riastrad }
528 1.2 riastrad
529 1.2 riastrad explicit_memset(buf, 0, sizeof buf);
530 1.1 riastrad } else {
531 1.1 riastrad xtsenc_unaligned_evcnt.ev_count++;
532 1.1 riastrad uint8_t buf[16] __aligned(16);
533 1.1 riastrad
534 1.1 riastrad for (; nbytes; nbytes -= 16, in += 16, out += 16) {
535 1.1 riastrad memcpy(buf, in, 16);
536 1.1 riastrad xor128(buf, buf, t);
537 1.2 riastrad aesvia_encN(enc, buf, buf, 1, cw0);
538 1.1 riastrad xor128(buf, buf, t);
539 1.1 riastrad memcpy(out, buf, 16);
540 1.1 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
541 1.1 riastrad }
542 1.1 riastrad
543 1.1 riastrad explicit_memset(buf, 0, sizeof buf);
544 1.1 riastrad }
545 1.1 riastrad fpu_kern_leave();
546 1.1 riastrad
547 1.1 riastrad memcpy(tweak, t, 16);
548 1.1 riastrad explicit_memset(t, 0, sizeof t);
549 1.1 riastrad }
550 1.1 riastrad
551 1.1 riastrad static struct evcnt xtsdec_aligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
552 1.1 riastrad NULL, "aesvia", "xtsdec aligned");
553 1.1 riastrad EVCNT_ATTACH_STATIC(xtsdec_aligned_evcnt);
554 1.1 riastrad static struct evcnt xtsdec_unaligned_evcnt = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
555 1.1 riastrad NULL, "aesvia", "xtsdec unaligned");
556 1.1 riastrad EVCNT_ATTACH_STATIC(xtsdec_unaligned_evcnt);
557 1.1 riastrad
558 1.1 riastrad static void
559 1.1 riastrad aesvia_xts_dec(const struct aesdec *dec, const uint8_t in[static 16],
560 1.1 riastrad uint8_t out[static 16], size_t nbytes, uint8_t tweak[static 16],
561 1.1 riastrad uint32_t nrounds)
562 1.1 riastrad {
563 1.1 riastrad const uint32_t cw0 = aesvia_keylen_cw0(nrounds);
564 1.1 riastrad uint32_t t[4];
565 1.1 riastrad
566 1.1 riastrad KASSERT(nbytes % 16 == 0);
567 1.1 riastrad
568 1.1 riastrad memcpy(t, tweak, 16);
569 1.1 riastrad
570 1.1 riastrad fpu_kern_enter();
571 1.1 riastrad aesvia_reload_keys();
572 1.1 riastrad if ((((uintptr_t)in | (uintptr_t)out) & 0xf) == 0) {
573 1.1 riastrad xtsdec_aligned_evcnt.ev_count++;
574 1.1 riastrad unsigned lastblock = 0;
575 1.2 riastrad uint32_t buf[8*4] __aligned(16);
576 1.1 riastrad
577 1.1 riastrad /*
578 1.1 riastrad * Make sure the last block is not the last block of a
579 1.1 riastrad * page. (Note that we store the AES input in `out' as
580 1.1 riastrad * a temporary buffer, rather than reading it directly
581 1.1 riastrad * from `in', since we have to combine the tweak
582 1.1 riastrad * first.)
583 1.1 riastrad */
584 1.1 riastrad lastblock = 16*(((uintptr_t)(out + nbytes) & 0xfff) == 0);
585 1.1 riastrad nbytes -= lastblock;
586 1.1 riastrad
587 1.2 riastrad /*
588 1.2 riastrad * Handle an odd number of initial blocks so we can
589 1.2 riastrad * process the rest in eight-block (128-byte) chunks.
590 1.2 riastrad */
591 1.2 riastrad if (nbytes % 128) {
592 1.2 riastrad unsigned nbytes128 = nbytes % 128;
593 1.2 riastrad
594 1.2 riastrad nbytes -= nbytes128;
595 1.2 riastrad for (; nbytes128; nbytes128 -= 16, in += 16, out += 16)
596 1.2 riastrad {
597 1.2 riastrad xor128(out, in, t);
598 1.2 riastrad aesvia_decN(dec, out, out, 1, cw0);
599 1.2 riastrad xor128(out, out, t);
600 1.2 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
601 1.2 riastrad }
602 1.2 riastrad }
603 1.2 riastrad
604 1.2 riastrad /* Process eight blocks at a time. */
605 1.2 riastrad for (; nbytes; nbytes -= 128, in += 128, out += 128) {
606 1.2 riastrad unsigned i;
607 1.2 riastrad for (i = 0; i < 8; i++) {
608 1.2 riastrad memcpy(buf + 4*i, t, 16);
609 1.2 riastrad xor128(out + 4*i, in + 4*i, t);
610 1.2 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
611 1.2 riastrad }
612 1.2 riastrad aesvia_decN(dec, out, out, 8, cw0);
613 1.2 riastrad for (i = 0; i < 8; i++)
614 1.2 riastrad xor128(out + 4*i, in + 4*i, buf + 4*i);
615 1.1 riastrad }
616 1.1 riastrad
617 1.1 riastrad /* Handle the last block of a page, if necessary. */
618 1.1 riastrad if (lastblock) {
619 1.1 riastrad xor128(buf, in, t);
620 1.2 riastrad aesvia_decN(dec, (const void *)buf, out, 1, cw0);
621 1.1 riastrad }
622 1.2 riastrad
623 1.2 riastrad explicit_memset(buf, 0, sizeof buf);
624 1.1 riastrad } else {
625 1.1 riastrad xtsdec_unaligned_evcnt.ev_count++;
626 1.1 riastrad uint8_t buf[16] __aligned(16);
627 1.1 riastrad
628 1.1 riastrad for (; nbytes; nbytes -= 16, in += 16, out += 16) {
629 1.1 riastrad memcpy(buf, in, 16);
630 1.1 riastrad xor128(buf, buf, t);
631 1.2 riastrad aesvia_decN(dec, buf, buf, 1, cw0);
632 1.1 riastrad xor128(buf, buf, t);
633 1.1 riastrad memcpy(out, buf, 16);
634 1.1 riastrad aesvia_xts_update(&t[0], &t[1], &t[2], &t[3]);
635 1.1 riastrad }
636 1.1 riastrad
637 1.1 riastrad explicit_memset(buf, 0, sizeof buf);
638 1.1 riastrad }
639 1.1 riastrad fpu_kern_leave();
640 1.1 riastrad
641 1.1 riastrad memcpy(tweak, t, 16);
642 1.1 riastrad explicit_memset(t, 0, sizeof t);
643 1.1 riastrad }
644 1.1 riastrad
645 1.1 riastrad static int
646 1.1 riastrad aesvia_probe(void)
647 1.1 riastrad {
648 1.1 riastrad
649 1.1 riastrad /* Verify that the CPU advertises VIA ACE support. */
650 1.1 riastrad if ((cpu_feature[4] & CPUID_VIA_HAS_ACE) == 0)
651 1.1 riastrad return -1;
652 1.1 riastrad
653 1.1 riastrad /* Verify that our XTS tweak update logic works. */
654 1.1 riastrad if (aesvia_xts_update_selftest())
655 1.1 riastrad return -1;
656 1.1 riastrad
657 1.1 riastrad /* Success! */
658 1.1 riastrad return 0;
659 1.1 riastrad }
660 1.1 riastrad
661 1.1 riastrad struct aes_impl aes_via_impl = {
662 1.1 riastrad .ai_name = "VIA ACE",
663 1.1 riastrad .ai_probe = aesvia_probe,
664 1.1 riastrad .ai_setenckey = aesvia_setenckey,
665 1.1 riastrad .ai_setdeckey = aesvia_setdeckey,
666 1.1 riastrad .ai_enc = aesvia_enc,
667 1.1 riastrad .ai_dec = aesvia_dec,
668 1.1 riastrad .ai_cbc_enc = aesvia_cbc_enc,
669 1.1 riastrad .ai_cbc_dec = aesvia_cbc_dec,
670 1.1 riastrad .ai_xts_enc = aesvia_xts_enc,
671 1.1 riastrad .ai_xts_dec = aesvia_xts_dec,
672 1.1 riastrad };
673