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