]> git.proxmox.com Git - mirror_zfs.git/blob - module/icp/algs/aes/aes_impl.c
Remove bcopy(), bzero(), bcmp()
[mirror_zfs.git] / module / icp / algs / aes / aes_impl.c
1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/zfs_context.h>
26 #include <sys/crypto/icp.h>
27 #include <sys/crypto/spi.h>
28 #include <sys/simd.h>
29 #include <modes/modes.h>
30 #include <aes/aes_impl.h>
31
32 /*
33 * Initialize AES encryption and decryption key schedules.
34 *
35 * Parameters:
36 * cipherKey User key
37 * keyBits AES key size (128, 192, or 256 bits)
38 * keysched AES key schedule to be initialized, of type aes_key_t.
39 * Allocated by aes_alloc_keysched().
40 */
41 void
42 aes_init_keysched(const uint8_t *cipherKey, uint_t keyBits, void *keysched)
43 {
44 const aes_impl_ops_t *ops = aes_impl_get_ops();
45 aes_key_t *newbie = keysched;
46 uint_t keysize, i, j;
47 union {
48 uint64_t ka64[4];
49 uint32_t ka32[8];
50 } keyarr;
51
52 switch (keyBits) {
53 case 128:
54 newbie->nr = 10;
55 break;
56
57 case 192:
58 newbie->nr = 12;
59 break;
60
61 case 256:
62 newbie->nr = 14;
63 break;
64
65 default:
66 /* should never get here */
67 return;
68 }
69 keysize = CRYPTO_BITS2BYTES(keyBits);
70
71 /*
72 * Generic C implementation requires byteswap for little endian
73 * machines, various accelerated implementations for various
74 * architectures may not.
75 */
76 if (!ops->needs_byteswap) {
77 /* no byteswap needed */
78 if (IS_P2ALIGNED(cipherKey, sizeof (uint64_t))) {
79 for (i = 0, j = 0; j < keysize; i++, j += 8) {
80 /* LINTED: pointer alignment */
81 keyarr.ka64[i] = *((uint64_t *)&cipherKey[j]);
82 }
83 } else {
84 memcpy(keyarr.ka32, cipherKey, keysize);
85 }
86 } else {
87 /* byte swap */
88 for (i = 0, j = 0; j < keysize; i++, j += 4) {
89 keyarr.ka32[i] =
90 htonl(*(uint32_t *)(void *)&cipherKey[j]);
91 }
92 }
93
94 ops->generate(newbie, keyarr.ka32, keyBits);
95 newbie->ops = ops;
96
97 /*
98 * Note: if there are systems that need the AES_64BIT_KS type in the
99 * future, move setting key schedule type to individual implementations
100 */
101 newbie->type = AES_32BIT_KS;
102 }
103
104
105 /*
106 * Encrypt one block using AES.
107 * Align if needed and (for x86 32-bit only) byte-swap.
108 *
109 * Parameters:
110 * ks Key schedule, of type aes_key_t
111 * pt Input block (plain text)
112 * ct Output block (crypto text). Can overlap with pt
113 */
114 int
115 aes_encrypt_block(const void *ks, const uint8_t *pt, uint8_t *ct)
116 {
117 aes_key_t *ksch = (aes_key_t *)ks;
118 const aes_impl_ops_t *ops = ksch->ops;
119
120 if (IS_P2ALIGNED2(pt, ct, sizeof (uint32_t)) && !ops->needs_byteswap) {
121 /* LINTED: pointer alignment */
122 ops->encrypt(&ksch->encr_ks.ks32[0], ksch->nr,
123 /* LINTED: pointer alignment */
124 (uint32_t *)pt, (uint32_t *)ct);
125 } else {
126 uint32_t buffer[AES_BLOCK_LEN / sizeof (uint32_t)];
127
128 /* Copy input block into buffer */
129 if (ops->needs_byteswap) {
130 buffer[0] = htonl(*(uint32_t *)(void *)&pt[0]);
131 buffer[1] = htonl(*(uint32_t *)(void *)&pt[4]);
132 buffer[2] = htonl(*(uint32_t *)(void *)&pt[8]);
133 buffer[3] = htonl(*(uint32_t *)(void *)&pt[12]);
134 } else
135 memcpy(&buffer, pt, AES_BLOCK_LEN);
136
137 ops->encrypt(&ksch->encr_ks.ks32[0], ksch->nr, buffer, buffer);
138
139 /* Copy result from buffer to output block */
140 if (ops->needs_byteswap) {
141 *(uint32_t *)(void *)&ct[0] = htonl(buffer[0]);
142 *(uint32_t *)(void *)&ct[4] = htonl(buffer[1]);
143 *(uint32_t *)(void *)&ct[8] = htonl(buffer[2]);
144 *(uint32_t *)(void *)&ct[12] = htonl(buffer[3]);
145 } else
146 memcpy(ct, &buffer, AES_BLOCK_LEN);
147 }
148 return (CRYPTO_SUCCESS);
149 }
150
151
152 /*
153 * Decrypt one block using AES.
154 * Align and byte-swap if needed.
155 *
156 * Parameters:
157 * ks Key schedule, of type aes_key_t
158 * ct Input block (crypto text)
159 * pt Output block (plain text). Can overlap with pt
160 */
161 int
162 aes_decrypt_block(const void *ks, const uint8_t *ct, uint8_t *pt)
163 {
164 aes_key_t *ksch = (aes_key_t *)ks;
165 const aes_impl_ops_t *ops = ksch->ops;
166
167 if (IS_P2ALIGNED2(ct, pt, sizeof (uint32_t)) && !ops->needs_byteswap) {
168 /* LINTED: pointer alignment */
169 ops->decrypt(&ksch->decr_ks.ks32[0], ksch->nr,
170 /* LINTED: pointer alignment */
171 (uint32_t *)ct, (uint32_t *)pt);
172 } else {
173 uint32_t buffer[AES_BLOCK_LEN / sizeof (uint32_t)];
174
175 /* Copy input block into buffer */
176 if (ops->needs_byteswap) {
177 buffer[0] = htonl(*(uint32_t *)(void *)&ct[0]);
178 buffer[1] = htonl(*(uint32_t *)(void *)&ct[4]);
179 buffer[2] = htonl(*(uint32_t *)(void *)&ct[8]);
180 buffer[3] = htonl(*(uint32_t *)(void *)&ct[12]);
181 } else
182 memcpy(&buffer, ct, AES_BLOCK_LEN);
183
184 ops->decrypt(&ksch->decr_ks.ks32[0], ksch->nr, buffer, buffer);
185
186 /* Copy result from buffer to output block */
187 if (ops->needs_byteswap) {
188 *(uint32_t *)(void *)&pt[0] = htonl(buffer[0]);
189 *(uint32_t *)(void *)&pt[4] = htonl(buffer[1]);
190 *(uint32_t *)(void *)&pt[8] = htonl(buffer[2]);
191 *(uint32_t *)(void *)&pt[12] = htonl(buffer[3]);
192 } else
193 memcpy(pt, &buffer, AES_BLOCK_LEN);
194 }
195 return (CRYPTO_SUCCESS);
196 }
197
198
199 /*
200 * Allocate key schedule for AES.
201 *
202 * Return the pointer and set size to the number of bytes allocated.
203 * Memory allocated must be freed by the caller when done.
204 *
205 * Parameters:
206 * size Size of key schedule allocated, in bytes
207 * kmflag Flag passed to kmem_alloc(9F); ignored in userland.
208 */
209 void *
210 aes_alloc_keysched(size_t *size, int kmflag)
211 {
212 aes_key_t *keysched;
213
214 keysched = (aes_key_t *)kmem_alloc(sizeof (aes_key_t), kmflag);
215 if (keysched != NULL) {
216 *size = sizeof (aes_key_t);
217 return (keysched);
218 }
219 return (NULL);
220 }
221
222 /* AES implementation that contains the fastest methods */
223 static aes_impl_ops_t aes_fastest_impl = {
224 .name = "fastest"
225 };
226
227 /* All compiled in implementations */
228 static const aes_impl_ops_t *aes_all_impl[] = {
229 &aes_generic_impl,
230 #if defined(__x86_64)
231 &aes_x86_64_impl,
232 #endif
233 #if defined(__x86_64) && defined(HAVE_AES)
234 &aes_aesni_impl,
235 #endif
236 };
237
238 /* Indicate that benchmark has been completed */
239 static boolean_t aes_impl_initialized = B_FALSE;
240
241 /* Select aes implementation */
242 #define IMPL_FASTEST (UINT32_MAX)
243 #define IMPL_CYCLE (UINT32_MAX-1)
244
245 #define AES_IMPL_READ(i) (*(volatile uint32_t *) &(i))
246
247 static uint32_t icp_aes_impl = IMPL_FASTEST;
248 static uint32_t user_sel_impl = IMPL_FASTEST;
249
250 /* Hold all supported implementations */
251 static size_t aes_supp_impl_cnt = 0;
252 static aes_impl_ops_t *aes_supp_impl[ARRAY_SIZE(aes_all_impl)];
253
254 /*
255 * Returns the AES operations for encrypt/decrypt/key setup. When a
256 * SIMD implementation is not allowed in the current context, then
257 * fallback to the fastest generic implementation.
258 */
259 const aes_impl_ops_t *
260 aes_impl_get_ops(void)
261 {
262 if (!kfpu_allowed())
263 return (&aes_generic_impl);
264
265 const aes_impl_ops_t *ops = NULL;
266 const uint32_t impl = AES_IMPL_READ(icp_aes_impl);
267
268 switch (impl) {
269 case IMPL_FASTEST:
270 ASSERT(aes_impl_initialized);
271 ops = &aes_fastest_impl;
272 break;
273 case IMPL_CYCLE:
274 /* Cycle through supported implementations */
275 ASSERT(aes_impl_initialized);
276 ASSERT3U(aes_supp_impl_cnt, >, 0);
277 static size_t cycle_impl_idx = 0;
278 size_t idx = (++cycle_impl_idx) % aes_supp_impl_cnt;
279 ops = aes_supp_impl[idx];
280 break;
281 default:
282 ASSERT3U(impl, <, aes_supp_impl_cnt);
283 ASSERT3U(aes_supp_impl_cnt, >, 0);
284 if (impl < ARRAY_SIZE(aes_all_impl))
285 ops = aes_supp_impl[impl];
286 break;
287 }
288
289 ASSERT3P(ops, !=, NULL);
290
291 return (ops);
292 }
293
294 /*
295 * Initialize all supported implementations.
296 */
297 void
298 aes_impl_init(void)
299 {
300 aes_impl_ops_t *curr_impl;
301 int i, c;
302
303 /* Move supported implementations into aes_supp_impls */
304 for (i = 0, c = 0; i < ARRAY_SIZE(aes_all_impl); i++) {
305 curr_impl = (aes_impl_ops_t *)aes_all_impl[i];
306
307 if (curr_impl->is_supported())
308 aes_supp_impl[c++] = (aes_impl_ops_t *)curr_impl;
309 }
310 aes_supp_impl_cnt = c;
311
312 /*
313 * Set the fastest implementation given the assumption that the
314 * hardware accelerated version is the fastest.
315 */
316 #if defined(__x86_64)
317 #if defined(HAVE_AES)
318 if (aes_aesni_impl.is_supported()) {
319 memcpy(&aes_fastest_impl, &aes_aesni_impl,
320 sizeof (aes_fastest_impl));
321 } else
322 #endif
323 {
324 memcpy(&aes_fastest_impl, &aes_x86_64_impl,
325 sizeof (aes_fastest_impl));
326 }
327 #else
328 memcpy(&aes_fastest_impl, &aes_generic_impl,
329 sizeof (aes_fastest_impl));
330 #endif
331
332 strlcpy(aes_fastest_impl.name, "fastest", AES_IMPL_NAME_MAX);
333
334 /* Finish initialization */
335 atomic_swap_32(&icp_aes_impl, user_sel_impl);
336 aes_impl_initialized = B_TRUE;
337 }
338
339 static const struct {
340 char *name;
341 uint32_t sel;
342 } aes_impl_opts[] = {
343 { "cycle", IMPL_CYCLE },
344 { "fastest", IMPL_FASTEST },
345 };
346
347 /*
348 * Function sets desired aes implementation.
349 *
350 * If we are called before init(), user preference will be saved in
351 * user_sel_impl, and applied in later init() call. This occurs when module
352 * parameter is specified on module load. Otherwise, directly update
353 * icp_aes_impl.
354 *
355 * @val Name of aes implementation to use
356 * @param Unused.
357 */
358 int
359 aes_impl_set(const char *val)
360 {
361 int err = -EINVAL;
362 char req_name[AES_IMPL_NAME_MAX];
363 uint32_t impl = AES_IMPL_READ(user_sel_impl);
364 size_t i;
365
366 /* sanitize input */
367 i = strnlen(val, AES_IMPL_NAME_MAX);
368 if (i == 0 || i >= AES_IMPL_NAME_MAX)
369 return (err);
370
371 strlcpy(req_name, val, AES_IMPL_NAME_MAX);
372 while (i > 0 && isspace(req_name[i-1]))
373 i--;
374 req_name[i] = '\0';
375
376 /* Check mandatory options */
377 for (i = 0; i < ARRAY_SIZE(aes_impl_opts); i++) {
378 if (strcmp(req_name, aes_impl_opts[i].name) == 0) {
379 impl = aes_impl_opts[i].sel;
380 err = 0;
381 break;
382 }
383 }
384
385 /* check all supported impl if init() was already called */
386 if (err != 0 && aes_impl_initialized) {
387 /* check all supported implementations */
388 for (i = 0; i < aes_supp_impl_cnt; i++) {
389 if (strcmp(req_name, aes_supp_impl[i]->name) == 0) {
390 impl = i;
391 err = 0;
392 break;
393 }
394 }
395 }
396
397 if (err == 0) {
398 if (aes_impl_initialized)
399 atomic_swap_32(&icp_aes_impl, impl);
400 else
401 atomic_swap_32(&user_sel_impl, impl);
402 }
403
404 return (err);
405 }
406
407 #if defined(_KERNEL) && defined(__linux__)
408
409 static int
410 icp_aes_impl_set(const char *val, zfs_kernel_param_t *kp)
411 {
412 return (aes_impl_set(val));
413 }
414
415 static int
416 icp_aes_impl_get(char *buffer, zfs_kernel_param_t *kp)
417 {
418 int i, cnt = 0;
419 char *fmt;
420 const uint32_t impl = AES_IMPL_READ(icp_aes_impl);
421
422 ASSERT(aes_impl_initialized);
423
424 /* list mandatory options */
425 for (i = 0; i < ARRAY_SIZE(aes_impl_opts); i++) {
426 fmt = (impl == aes_impl_opts[i].sel) ? "[%s] " : "%s ";
427 cnt += sprintf(buffer + cnt, fmt, aes_impl_opts[i].name);
428 }
429
430 /* list all supported implementations */
431 for (i = 0; i < aes_supp_impl_cnt; i++) {
432 fmt = (i == impl) ? "[%s] " : "%s ";
433 cnt += sprintf(buffer + cnt, fmt, aes_supp_impl[i]->name);
434 }
435
436 return (cnt);
437 }
438
439 module_param_call(icp_aes_impl, icp_aes_impl_set, icp_aes_impl_get,
440 NULL, 0644);
441 MODULE_PARM_DESC(icp_aes_impl, "Select aes implementation.");
442 #endif