xref: /netbsd/sys/dev/cgd_crypto.c (revision c4a72b64)
1 /* $NetBSD: cgd_crypto.c,v 1.1 2002/10/04 18:22:35 elric 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.1 2002/10/04 18:22:35 elric 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 	free(apd, M_DEVBUF);
206 }
207 
208 void
209 aes_cbc_enc_int(void *privdata, void *dst, void *src, int len)
210 {
211 	struct aes_encdata	*ae = (void *)privdata;
212 	cipherInstance		 cipher;
213 
214 	rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
215 	rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst);
216 	memcpy(ae->ae_iv, (u_int8_t *)dst + (len - 16), 16);
217 }
218 
219 void
220 aes_cbc_dec_int(void *privdata, void *dst, void *src, int len)
221 {
222 	struct aes_encdata	*ae = (void *)privdata;
223 	cipherInstance		 cipher;
224 
225 	rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
226 	rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst);
227 	memcpy(ae->ae_iv, (u_int8_t *)src + (len - 16), 16);
228 }
229 
230 void
231 cgd_cipher_aes_cbc(caddr_t privdata, struct uio *dstuio,
232 	struct uio *srcuio, caddr_t iv, int dir)
233 {
234 	struct aes_privdata	*apd = (void *)privdata;
235 	struct aes_encdata	 encd;
236 
237 	memcpy(encd.ae_iv, iv, 16);
238 	switch (dir) {
239 	case CGD_CIPHER_ENCRYPT:
240 		encd.ae_key = &apd->ap_enckey;
241 		cgd_cipher_uio_cbc(&encd, aes_cbc_enc_int, dstuio, srcuio);
242 		break;
243 	case CGD_CIPHER_DECRYPT:
244 		encd.ae_key = &apd->ap_deckey;
245 		cgd_cipher_uio_cbc(&encd, aes_cbc_dec_int, dstuio, srcuio);
246 		break;
247 	default:
248 		DIAGPANIC("cgd_cipher_aes_cbc: unrecgnised direction");
249 	}
250 }
251 
252 /*
253  * 3DES Framework
254  */
255 
256 #include <crypto/des/des.h>
257 
258 cfunc_init	cgd_cipher_3des_init;
259 cfunc_destroy	cgd_cipher_3des_destroy;
260 cfunc_cipher	cgd_cipher_3des_cbc;
261 
262 struct cryptfuncs cgd_3des_funcs = {
263 	cgd_cipher_3des_init,
264 	cgd_cipher_3des_destroy,
265 	cgd_cipher_3des_cbc,
266 };
267 
268 struct c3des_privdata {
269 	des_key_schedule	cp_key1;
270 	des_key_schedule	cp_key2;
271 	des_key_schedule	cp_key3;
272 };
273 
274 static void	c3des_cbc_enc_int(void *, void *, void *, int);
275 static void	c3des_cbc_dec_int(void *, void *, void *, int);
276 
277 struct c3des_encdata {
278 	des_key_schedule	*ce_key1;
279 	des_key_schedule	*ce_key2;
280 	des_key_schedule	*ce_key3;
281 	u_int8_t		ce_iv[8];
282 };
283 
284 caddr_t
285 cgd_cipher_3des_init(int keylen, caddr_t key, int *blocksize)
286 {
287 	struct	c3des_privdata *cp;
288 	int	error = 0;
289 
290 printf("cgd_cipher_3des_init: enter (keylen=%d, blocksize=%d)\n",
291 keylen, *blocksize);
292 	if (!blocksize)
293 		return NULL;
294 	if (*blocksize == -1)
295 		*blocksize = 64;
296 	if (keylen != (DES_KEY_SZ * 3 * 8) || *blocksize != 64)
297 		return NULL;
298 printf("cgd_cipher_3des_init: about to malloc (keylen=%d, blocksize=%d)\n",
299 keylen, *blocksize);
300 	cp = malloc(sizeof(*cp), M_DEVBUF, 0);
301 	if (!cp)
302 		return NULL;
303 printf("cgd_cipher_3des_init: successfully malloc'ed\n");
304 	error  = des_key_sched((des_cblock *)key, cp->cp_key1);
305 	error |= des_key_sched((des_cblock *)key + 1, cp->cp_key2);
306 	error |= des_key_sched((des_cblock *)key + 2, cp->cp_key3);
307 printf("cgd_cipher_3des_init: did the des_key_sched, error=%d\n", error);
308 	if (error) {
309 		free(cp, M_DEVBUF);
310 		return NULL;
311 	}
312 	return (caddr_t)cp;
313 }
314 
315 void
316 cgd_cipher_3des_destroy(caddr_t data)
317 {
318 	struct c3des_privdata *cp = (void *)data;
319 
320 	free(cp, M_DEVBUF);
321 }
322 
323 static void
324 c3des_cbc_enc_int(void *privdata, void *dst, void *src, int len)
325 {
326 	struct	c3des_encdata *ce = (void *)privdata;
327 
328 	des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
329 	    *ce->ce_key3, (des_cblock *)ce->ce_iv, 1);
330 	memcpy(ce->ce_iv, (u_int8_t *)dst + (len - 8), 8);
331 }
332 
333 static void
334 c3des_cbc_dec_int(void *privdata, void *dst, void *src, int len)
335 {
336 	struct	c3des_encdata *ce = (void *)privdata;
337 
338 	des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
339 	    *ce->ce_key3, (des_cblock *)ce->ce_iv, 0);
340 	memcpy(ce->ce_iv, (u_int8_t *)src + (len - 8), 8);
341 }
342 
343 void
344 cgd_cipher_3des_cbc(caddr_t privdata, struct uio *dstuio,
345 	struct uio *srcuio, caddr_t iv, int dir)
346 {
347 	struct	c3des_privdata *cp = (void *)privdata;
348 	struct	c3des_encdata ce;
349 
350 	memcpy(ce.ce_iv, iv, 8);
351 	ce.ce_key1 = &cp->cp_key1;
352 	ce.ce_key2 = &cp->cp_key2;
353 	ce.ce_key3 = &cp->cp_key3;
354 	switch (dir) {
355 	case CGD_CIPHER_ENCRYPT:
356 		cgd_cipher_uio_cbc(&ce, c3des_cbc_enc_int, dstuio, srcuio);
357 		break;
358 	case CGD_CIPHER_DECRYPT:
359 		cgd_cipher_uio_cbc(&ce, c3des_cbc_dec_int, dstuio, srcuio);
360 		break;
361 	default:
362 		DIAGPANIC("cgd_cipher_3des_cbc: unrecognised direction");
363 	}
364 }
365 
366 /*
367  * Blowfish Framework
368  */
369 
370 #include <crypto/blowfish/blowfish.h>
371 
372 cfunc_init	cgd_cipher_bf_init;
373 cfunc_destroy	cgd_cipher_bf_destroy;
374 cfunc_cipher	cgd_cipher_bf_cbc;
375 
376 struct cryptfuncs cgd_BF_funcs = {
377 	cgd_cipher_bf_init,
378 	cgd_cipher_bf_destroy,
379 	cgd_cipher_bf_cbc,
380 };
381 
382 static void	bf_cbc_enc_int(void *, void *, void *, int);
383 static void	bf_cbc_dec_int(void *, void *, void *, int);
384 
385 struct bf_privdata {
386 	BF_KEY	bp_key;
387 };
388 
389 struct bf_encdata {
390 	BF_KEY		*be_key;
391 	u_int8_t	 be_iv[8];
392 };
393 
394 caddr_t
395 cgd_cipher_bf_init(int keylen, caddr_t key, int *blocksize)
396 {
397 	struct	bf_privdata *bp;
398 
399 	if (!blocksize)
400 		return NULL;
401 	if (keylen < 40 || keylen > 448)
402 		return NULL;
403 	if (*blocksize == -1)
404 		*blocksize = 64;
405 	if (*blocksize != 64)
406 		return NULL;
407 	bp = malloc(sizeof(*bp), M_DEVBUF, 0);
408 	if (!bp)
409 		return NULL;
410 	BF_set_key(&bp->bp_key, keylen, key);
411 	return (caddr_t)bp;
412 }
413 
414 void
415 cgd_cipher_bf_destroy(caddr_t data)
416 {
417 	struct	bf_privdata *bp = (void *)data;
418 
419 	free(bp, M_DEVBUF);
420 }
421 
422 void
423 bf_cbc_enc_int(void *privdata, void *dst, void *src, int len)
424 {
425 	struct	bf_encdata *be = (void *)privdata;
426 
427 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 1);
428 	memcpy(be->be_iv, (u_int8_t *)dst + (len - 8), 8);
429 }
430 
431 void
432 bf_cbc_dec_int(void *privdata, void *dst, void *src, int len)
433 {
434 	struct	bf_encdata *be = (void *)privdata;
435 
436 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 0);
437 	memcpy(be->be_iv, (u_int8_t *)src + (len - 8), 8);
438 }
439 
440 void
441 cgd_cipher_bf_cbc(caddr_t privdata, struct uio *dstuio,
442 	struct uio *srcuio, caddr_t iv, int dir)
443 {
444 	struct	bf_privdata *bp = (void *)privdata;
445 	struct	bf_encdata be;
446 
447 	memcpy(be.be_iv, iv, 8);
448 	be.be_key = &bp->bp_key;
449 	switch (dir) {
450 	case CGD_CIPHER_ENCRYPT:
451 		cgd_cipher_uio_cbc(&be, bf_cbc_enc_int, dstuio, srcuio);
452 		break;
453 	case CGD_CIPHER_DECRYPT:
454 		cgd_cipher_uio_cbc(&be, bf_cbc_dec_int, dstuio, srcuio);
455 		break;
456 	default:
457 		DIAGPANIC("cgd_cipher_bf_cbc: unrecognised direction");
458 	}
459 
460 }
461