Home | History | Annotate | Line # | Download | only in dev
cgd_crypto.c revision 1.3
      1 /* $NetBSD: cgd_crypto.c,v 1.3 2004/03/18 10:42:08 dan 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 2004/03/18 10:42:08 dan 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 	if (!blocksize)
    291 		return NULL;
    292 	if (*blocksize == -1)
    293 		*blocksize = 64;
    294 	if (keylen != (DES_KEY_SZ * 3 * 8) || *blocksize != 64)
    295 		return NULL;
    296 	cp = malloc(sizeof(*cp), M_DEVBUF, 0);
    297 	if (!cp)
    298 		return NULL;
    299 	error  = des_key_sched((des_cblock *)key, cp->cp_key1);
    300 	error |= des_key_sched((des_cblock *)key + 1, cp->cp_key2);
    301 	error |= des_key_sched((des_cblock *)key + 2, cp->cp_key3);
    302 	if (error) {
    303 		free(cp, M_DEVBUF);
    304 		return NULL;
    305 	}
    306 	return (caddr_t)cp;
    307 }
    308 
    309 void
    310 cgd_cipher_3des_destroy(caddr_t data)
    311 {
    312 	struct c3des_privdata *cp = (void *)data;
    313 
    314 	free(cp, M_DEVBUF);
    315 }
    316 
    317 static void
    318 c3des_cbc_enc_int(void *privdata, void *dst, void *src, int len)
    319 {
    320 	struct	c3des_encdata *ce = (void *)privdata;
    321 
    322 	des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
    323 	    *ce->ce_key3, (des_cblock *)ce->ce_iv, 1);
    324 	memcpy(ce->ce_iv, (u_int8_t *)dst + (len - 8), 8);
    325 }
    326 
    327 static void
    328 c3des_cbc_dec_int(void *privdata, void *dst, void *src, int len)
    329 {
    330 	struct	c3des_encdata *ce = (void *)privdata;
    331 
    332 	des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
    333 	    *ce->ce_key3, (des_cblock *)ce->ce_iv, 0);
    334 	memcpy(ce->ce_iv, (u_int8_t *)src + (len - 8), 8);
    335 }
    336 
    337 void
    338 cgd_cipher_3des_cbc(caddr_t privdata, struct uio *dstuio,
    339 	struct uio *srcuio, caddr_t iv, int dir)
    340 {
    341 	struct	c3des_privdata *cp = (void *)privdata;
    342 	struct	c3des_encdata ce;
    343 
    344 	memcpy(ce.ce_iv, iv, 8);
    345 	ce.ce_key1 = &cp->cp_key1;
    346 	ce.ce_key2 = &cp->cp_key2;
    347 	ce.ce_key3 = &cp->cp_key3;
    348 	switch (dir) {
    349 	case CGD_CIPHER_ENCRYPT:
    350 		cgd_cipher_uio_cbc(&ce, c3des_cbc_enc_int, dstuio, srcuio);
    351 		break;
    352 	case CGD_CIPHER_DECRYPT:
    353 		cgd_cipher_uio_cbc(&ce, c3des_cbc_dec_int, dstuio, srcuio);
    354 		break;
    355 	default:
    356 		DIAGPANIC("cgd_cipher_3des_cbc: unrecognised direction");
    357 	}
    358 }
    359 
    360 /*
    361  * Blowfish Framework
    362  */
    363 
    364 #include <crypto/blowfish/blowfish.h>
    365 
    366 cfunc_init	cgd_cipher_bf_init;
    367 cfunc_destroy	cgd_cipher_bf_destroy;
    368 cfunc_cipher	cgd_cipher_bf_cbc;
    369 
    370 struct cryptfuncs cgd_BF_funcs = {
    371 	cgd_cipher_bf_init,
    372 	cgd_cipher_bf_destroy,
    373 	cgd_cipher_bf_cbc,
    374 };
    375 
    376 static void	bf_cbc_enc_int(void *, void *, void *, int);
    377 static void	bf_cbc_dec_int(void *, void *, void *, int);
    378 
    379 struct bf_privdata {
    380 	BF_KEY	bp_key;
    381 };
    382 
    383 struct bf_encdata {
    384 	BF_KEY		*be_key;
    385 	u_int8_t	 be_iv[8];
    386 };
    387 
    388 caddr_t
    389 cgd_cipher_bf_init(int keylen, caddr_t key, int *blocksize)
    390 {
    391 	struct	bf_privdata *bp;
    392 
    393 	if (!blocksize)
    394 		return NULL;
    395 	if (keylen < 40 || keylen > 448 || (keylen % 8 != 0))
    396 		return NULL;
    397 	if (*blocksize == -1)
    398 		*blocksize = 64;
    399 	if (*blocksize != 64)
    400 		return NULL;
    401 	bp = malloc(sizeof(*bp), M_DEVBUF, 0);
    402 	if (!bp)
    403 		return NULL;
    404 	BF_set_key(&bp->bp_key, keylen / 8, key);
    405 	return (caddr_t)bp;
    406 }
    407 
    408 void
    409 cgd_cipher_bf_destroy(caddr_t data)
    410 {
    411 	struct	bf_privdata *bp = (void *)data;
    412 
    413 	free(bp, M_DEVBUF);
    414 }
    415 
    416 void
    417 bf_cbc_enc_int(void *privdata, void *dst, void *src, int len)
    418 {
    419 	struct	bf_encdata *be = (void *)privdata;
    420 
    421 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 1);
    422 	memcpy(be->be_iv, (u_int8_t *)dst + (len - 8), 8);
    423 }
    424 
    425 void
    426 bf_cbc_dec_int(void *privdata, void *dst, void *src, int len)
    427 {
    428 	struct	bf_encdata *be = (void *)privdata;
    429 
    430 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 0);
    431 	memcpy(be->be_iv, (u_int8_t *)src + (len - 8), 8);
    432 }
    433 
    434 void
    435 cgd_cipher_bf_cbc(caddr_t privdata, struct uio *dstuio,
    436 	struct uio *srcuio, caddr_t iv, int dir)
    437 {
    438 	struct	bf_privdata *bp = (void *)privdata;
    439 	struct	bf_encdata be;
    440 
    441 	memcpy(be.be_iv, iv, 8);
    442 	be.be_key = &bp->bp_key;
    443 	switch (dir) {
    444 	case CGD_CIPHER_ENCRYPT:
    445 		cgd_cipher_uio_cbc(&be, bf_cbc_enc_int, dstuio, srcuio);
    446 		break;
    447 	case CGD_CIPHER_DECRYPT:
    448 		cgd_cipher_uio_cbc(&be, bf_cbc_dec_int, dstuio, srcuio);
    449 		break;
    450 	default:
    451 		DIAGPANIC("cgd_cipher_bf_cbc: unrecognised direction");
    452 	}
    453 
    454 }
    455