1 | /* $NetBSD: cgd_crypto.c,v 1.13 2015/04/25 12:55:04 riastradh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2002 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Roland C. Dowdeswell. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Crypto Framework For cgd.c |
34 | * |
35 | * This framework is temporary and awaits a more complete |
36 | * kernel wide crypto implementation. |
37 | */ |
38 | |
39 | #include <sys/cdefs.h> |
40 | __KERNEL_RCSID(0, "$NetBSD: cgd_crypto.c,v 1.13 2015/04/25 12:55:04 riastradh Exp $" ); |
41 | |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/malloc.h> |
45 | |
46 | #include <dev/cgd_crypto.h> |
47 | |
48 | #include <crypto/rijndael/rijndael-api-fst.h> |
49 | #include <crypto/des/des.h> |
50 | #include <crypto/blowfish/blowfish.h> |
51 | |
52 | #ifdef DIAGNOSTIC |
53 | #define DIAGPANIC(x) panic x |
54 | #else |
55 | #define DIAGPANIC(x) |
56 | #endif |
57 | |
58 | /* |
59 | * The general framework provides only one generic function. |
60 | * It takes the name of an algorith and returns a struct cryptfuncs * |
61 | * for it. It is up to the initialisation routines of the algorithm |
62 | * to check key size and block size. |
63 | */ |
64 | |
65 | static cfunc_init cgd_cipher_aes_init; |
66 | static cfunc_destroy cgd_cipher_aes_destroy; |
67 | static cfunc_cipher cgd_cipher_aes_cbc; |
68 | |
69 | static cfunc_init cgd_cipher_3des_init; |
70 | static cfunc_destroy cgd_cipher_3des_destroy; |
71 | static cfunc_cipher cgd_cipher_3des_cbc; |
72 | |
73 | static cfunc_init cgd_cipher_bf_init; |
74 | static cfunc_destroy cgd_cipher_bf_destroy; |
75 | static cfunc_cipher cgd_cipher_bf_cbc; |
76 | |
77 | static const struct cryptfuncs cf[] = { |
78 | { |
79 | .cf_name = "aes-cbc" , |
80 | .cf_init = cgd_cipher_aes_init, |
81 | .cf_destroy = cgd_cipher_aes_destroy, |
82 | .cf_cipher = cgd_cipher_aes_cbc, |
83 | }, |
84 | { |
85 | .cf_name = "3des-cbc" , |
86 | .cf_init = cgd_cipher_3des_init, |
87 | .cf_destroy = cgd_cipher_3des_destroy, |
88 | .cf_cipher = cgd_cipher_3des_cbc, |
89 | }, |
90 | { |
91 | .cf_name = "blowfish-cbc" , |
92 | .cf_init = cgd_cipher_bf_init, |
93 | .cf_destroy = cgd_cipher_bf_destroy, |
94 | .cf_cipher = cgd_cipher_bf_cbc, |
95 | }, |
96 | }; |
97 | const struct cryptfuncs * |
98 | cryptfuncs_find(const char *alg) |
99 | { |
100 | |
101 | for (size_t i = 0; i < __arraycount(cf); i++) |
102 | if (strcmp(cf[i].cf_name, alg) == 0) |
103 | return &cf[i]; |
104 | |
105 | return NULL; |
106 | } |
107 | |
108 | typedef void (*cipher_func)(void *, void *, const void *, size_t); |
109 | |
110 | static void |
111 | cgd_cipher_uio_cbc(void *privdata, cipher_func cipher, |
112 | struct uio *dstuio, struct uio *srcuio); |
113 | |
114 | /* |
115 | * cgd_cipher_uio_cbc takes a simple cbc cipher and iterates |
116 | * it over two struct uio's. It presumes that the cipher function |
117 | * that is passed to it keeps the IV state between calls. |
118 | * |
119 | * We assume that the caller has ensured that each segment is evenly |
120 | * divisible by the block size, which for the cgd is a valid assumption. |
121 | * If we were to make this code more generic, we might need to take care |
122 | * of this case, either by issuing an error or copying the data. |
123 | */ |
124 | |
125 | static void |
126 | cgd_cipher_uio_cbc(void *privdata, cipher_func cipher, |
127 | struct uio *dstuio, struct uio *srcuio) |
128 | { |
129 | const struct iovec *dst; |
130 | const struct iovec *src; |
131 | int dstnum; |
132 | int dstoff = 0; |
133 | int srcnum; |
134 | int srcoff = 0; |
135 | |
136 | dst = dstuio->uio_iov; |
137 | dstnum = dstuio->uio_iovcnt; |
138 | src = srcuio->uio_iov; |
139 | srcnum = srcuio->uio_iovcnt; |
140 | for (;;) { |
141 | int l = MIN(dst->iov_len - dstoff, src->iov_len - srcoff); |
142 | u_int8_t *d = (u_int8_t *)dst->iov_base + dstoff; |
143 | const u_int8_t *s = (const u_int8_t *)src->iov_base + srcoff; |
144 | |
145 | cipher(privdata, d, s, l); |
146 | |
147 | dstoff += l; |
148 | srcoff += l; |
149 | /* |
150 | * We assume that {dst,src} == {dst,src}->iov_len, |
151 | * because it should not be possible for it not to be. |
152 | */ |
153 | if (dstoff == dst->iov_len) { |
154 | dstoff = 0; |
155 | dstnum--; |
156 | dst++; |
157 | } |
158 | if (srcoff == src->iov_len) { |
159 | srcoff = 0; |
160 | srcnum--; |
161 | src++; |
162 | } |
163 | if (!srcnum || !dstnum) |
164 | break; |
165 | } |
166 | } |
167 | |
168 | /* |
169 | * AES Framework |
170 | */ |
171 | |
172 | /* |
173 | * NOTE: we do not store the blocksize in here, because it is not |
174 | * variable [yet], we hardcode the blocksize to 16 (128 bits). |
175 | */ |
176 | |
177 | struct aes_privdata { |
178 | keyInstance ap_enckey; |
179 | keyInstance ap_deckey; |
180 | }; |
181 | |
182 | struct aes_encdata { |
183 | keyInstance *ae_key; /* key for this direction */ |
184 | u_int8_t ae_iv[16]; /* Initialization Vector */ |
185 | }; |
186 | |
187 | static void * |
188 | cgd_cipher_aes_init(size_t keylen, const void *key, size_t *blocksize) |
189 | { |
190 | struct aes_privdata *ap; |
191 | |
192 | if (!blocksize) |
193 | return NULL; |
194 | if (keylen != 128 && keylen != 192 && keylen != 256) |
195 | return NULL; |
196 | if (*blocksize == (size_t)-1) |
197 | *blocksize = 128; |
198 | if (*blocksize != 128) |
199 | return NULL; |
200 | ap = malloc(sizeof(*ap), M_DEVBUF, 0); |
201 | if (!ap) |
202 | return NULL; |
203 | rijndael_makeKey(&ap->ap_enckey, DIR_ENCRYPT, keylen, key); |
204 | rijndael_makeKey(&ap->ap_deckey, DIR_DECRYPT, keylen, key); |
205 | return ap; |
206 | } |
207 | |
208 | static void |
209 | cgd_cipher_aes_destroy(void *data) |
210 | { |
211 | struct aes_privdata *apd = data; |
212 | |
213 | explicit_memset(apd, 0, sizeof(*apd)); |
214 | free(apd, M_DEVBUF); |
215 | } |
216 | |
217 | static void |
218 | aes_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len) |
219 | { |
220 | struct aes_encdata *ae = privdata; |
221 | cipherInstance cipher; |
222 | |
223 | rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv); |
224 | rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst); |
225 | (void)memcpy(ae->ae_iv, (u_int8_t *)dst + (len - 16), 16); |
226 | } |
227 | |
228 | static void |
229 | aes_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len) |
230 | { |
231 | struct aes_encdata *ae = privdata; |
232 | cipherInstance cipher; |
233 | |
234 | rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv); |
235 | rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst); |
236 | (void)memcpy(ae->ae_iv, (const u_int8_t *)src + (len - 16), 16); |
237 | } |
238 | |
239 | static void |
240 | cgd_cipher_aes_cbc(void *privdata, struct uio *dstuio, |
241 | struct uio *srcuio, const void *iv, int dir) |
242 | { |
243 | struct aes_privdata *apd = privdata; |
244 | struct aes_encdata encd; |
245 | |
246 | (void)memcpy(encd.ae_iv, iv, 16); |
247 | switch (dir) { |
248 | case CGD_CIPHER_ENCRYPT: |
249 | encd.ae_key = &apd->ap_enckey; |
250 | cgd_cipher_uio_cbc(&encd, aes_cbc_enc_int, dstuio, srcuio); |
251 | break; |
252 | case CGD_CIPHER_DECRYPT: |
253 | encd.ae_key = &apd->ap_deckey; |
254 | cgd_cipher_uio_cbc(&encd, aes_cbc_dec_int, dstuio, srcuio); |
255 | break; |
256 | default: |
257 | DIAGPANIC(("%s: unrecognised direction %d" , __func__, dir)); |
258 | } |
259 | } |
260 | |
261 | /* |
262 | * 3DES Framework |
263 | */ |
264 | |
265 | struct c3des_privdata { |
266 | des_key_schedule cp_key1; |
267 | des_key_schedule cp_key2; |
268 | des_key_schedule cp_key3; |
269 | }; |
270 | |
271 | struct c3des_encdata { |
272 | des_key_schedule *ce_key1; |
273 | des_key_schedule *ce_key2; |
274 | des_key_schedule *ce_key3; |
275 | u_int8_t ce_iv[8]; |
276 | }; |
277 | |
278 | static void * |
279 | cgd_cipher_3des_init(size_t keylen, const void *key, size_t *blocksize) |
280 | { |
281 | struct c3des_privdata *cp; |
282 | int error = 0; |
283 | des_cblock *block; |
284 | |
285 | if (!blocksize) |
286 | return NULL; |
287 | if (*blocksize == (size_t)-1) |
288 | *blocksize = 64; |
289 | if (keylen != (DES_KEY_SZ * 3 * 8) || *blocksize != 64) |
290 | return NULL; |
291 | cp = malloc(sizeof(*cp), M_DEVBUF, 0); |
292 | if (!cp) |
293 | return NULL; |
294 | block = __UNCONST(key); |
295 | error = des_key_sched(block, cp->cp_key1); |
296 | error |= des_key_sched(block + 1, cp->cp_key2); |
297 | error |= des_key_sched(block + 2, cp->cp_key3); |
298 | if (error) { |
299 | explicit_memset(cp, 0, sizeof(*cp)); |
300 | free(cp, M_DEVBUF); |
301 | return NULL; |
302 | } |
303 | return cp; |
304 | } |
305 | |
306 | static void |
307 | cgd_cipher_3des_destroy(void *data) |
308 | { |
309 | struct c3des_privdata *cp = data; |
310 | |
311 | explicit_memset(cp, 0, sizeof(*cp)); |
312 | free(cp, M_DEVBUF); |
313 | } |
314 | |
315 | static void |
316 | c3des_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len) |
317 | { |
318 | struct c3des_encdata *ce = privdata; |
319 | |
320 | des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2, |
321 | *ce->ce_key3, (des_cblock *)ce->ce_iv, 1); |
322 | (void)memcpy(ce->ce_iv, (const u_int8_t *)dst + (len - 8), 8); |
323 | } |
324 | |
325 | static void |
326 | c3des_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len) |
327 | { |
328 | struct c3des_encdata *ce = privdata; |
329 | |
330 | des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2, |
331 | *ce->ce_key3, (des_cblock *)ce->ce_iv, 0); |
332 | (void)memcpy(ce->ce_iv, (const u_int8_t *)src + (len - 8), 8); |
333 | } |
334 | |
335 | static void |
336 | cgd_cipher_3des_cbc(void *privdata, struct uio *dstuio, |
337 | struct uio *srcuio, const void *iv, int dir) |
338 | { |
339 | struct c3des_privdata *cp = privdata; |
340 | struct c3des_encdata ce; |
341 | |
342 | (void)memcpy(ce.ce_iv, iv, 8); |
343 | ce.ce_key1 = &cp->cp_key1; |
344 | ce.ce_key2 = &cp->cp_key2; |
345 | ce.ce_key3 = &cp->cp_key3; |
346 | switch (dir) { |
347 | case CGD_CIPHER_ENCRYPT: |
348 | cgd_cipher_uio_cbc(&ce, c3des_cbc_enc_int, dstuio, srcuio); |
349 | break; |
350 | case CGD_CIPHER_DECRYPT: |
351 | cgd_cipher_uio_cbc(&ce, c3des_cbc_dec_int, dstuio, srcuio); |
352 | break; |
353 | default: |
354 | DIAGPANIC(("%s: unrecognised direction %d" , __func__, dir)); |
355 | } |
356 | } |
357 | |
358 | /* |
359 | * Blowfish Framework |
360 | */ |
361 | |
362 | struct bf_privdata { |
363 | BF_KEY bp_key; |
364 | }; |
365 | |
366 | struct bf_encdata { |
367 | BF_KEY *be_key; |
368 | u_int8_t be_iv[8]; |
369 | }; |
370 | |
371 | static void * |
372 | cgd_cipher_bf_init(size_t keylen, const void *key, size_t *blocksize) |
373 | { |
374 | struct bf_privdata *bp; |
375 | |
376 | if (!blocksize) |
377 | return NULL; |
378 | if (keylen < 40 || keylen > 448 || (keylen % 8 != 0)) |
379 | return NULL; |
380 | if (*blocksize == (size_t)-1) |
381 | *blocksize = 64; |
382 | if (*blocksize != 64) |
383 | return NULL; |
384 | bp = malloc(sizeof(*bp), M_DEVBUF, 0); |
385 | if (!bp) |
386 | return NULL; |
387 | BF_set_key(&bp->bp_key, keylen / 8, key); |
388 | return bp; |
389 | } |
390 | |
391 | static void |
392 | cgd_cipher_bf_destroy(void *data) |
393 | { |
394 | struct bf_privdata *bp = data; |
395 | |
396 | explicit_memset(bp, 0, sizeof(*bp)); |
397 | free(bp, M_DEVBUF); |
398 | } |
399 | |
400 | static void |
401 | bf_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len) |
402 | { |
403 | struct bf_encdata *be = privdata; |
404 | |
405 | BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 1); |
406 | (void)memcpy(be->be_iv, (u_int8_t *)dst + (len - 8), 8); |
407 | } |
408 | |
409 | static void |
410 | bf_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len) |
411 | { |
412 | struct bf_encdata *be = privdata; |
413 | |
414 | BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 0); |
415 | (void)memcpy(be->be_iv, (const u_int8_t *)src + (len - 8), 8); |
416 | } |
417 | |
418 | static void |
419 | cgd_cipher_bf_cbc(void *privdata, struct uio *dstuio, |
420 | struct uio *srcuio, const void *iv, int dir) |
421 | { |
422 | struct bf_privdata *bp = privdata; |
423 | struct bf_encdata be; |
424 | |
425 | (void)memcpy(be.be_iv, iv, 8); |
426 | be.be_key = &bp->bp_key; |
427 | switch (dir) { |
428 | case CGD_CIPHER_ENCRYPT: |
429 | cgd_cipher_uio_cbc(&be, bf_cbc_enc_int, dstuio, srcuio); |
430 | break; |
431 | case CGD_CIPHER_DECRYPT: |
432 | cgd_cipher_uio_cbc(&be, bf_cbc_dec_int, dstuio, srcuio); |
433 | break; |
434 | default: |
435 | DIAGPANIC(("%s: unrecognised direction %d" , __func__, dir)); |
436 | } |
437 | |
438 | } |
439 | |