Home | History | Annotate | Line # | Download | only in dev
cgd_crypto.c revision 1.6
      1 /* $NetBSD: cgd_crypto.c,v 1.6 2006/12/01 15:52:55 christos 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.6 2006/12/01 15:52:55 christos 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(const 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 *, size_t);
     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 *, size_t);
    177 static void	aes_cbc_dec_int(void *, void *, void *, size_t);
    178 
    179 void *
    180 cgd_cipher_aes_init(size_t keylen, void *key, size_t *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 == (size_t)-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 ap;
    198 }
    199 
    200 void
    201 cgd_cipher_aes_destroy(void *data)
    202 {
    203 	struct aes_privdata *apd = data;
    204 
    205 	(void)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, size_t len)
    211 {
    212 	struct aes_encdata	*ae = 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 	(void)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, size_t len)
    222 {
    223 	struct aes_encdata	*ae = 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 	(void)memcpy(ae->ae_iv, (u_int8_t *)src + (len - 16), 16);
    229 }
    230 
    231 void
    232 cgd_cipher_aes_cbc(void *privdata, struct uio *dstuio,
    233     struct uio *srcuio, void *iv, int dir)
    234 {
    235 	struct aes_privdata	*apd = privdata;
    236 	struct aes_encdata	 encd;
    237 
    238 	(void)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(("%s: unrecognised direction %d", __FUNCTION__, dir));
    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 *, size_t);
    276 static void	c3des_cbc_dec_int(void *, void *, void *, size_t);
    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 void *
    286 cgd_cipher_3des_init(size_t keylen, void *key, size_t *blocksize)
    287 {
    288 	struct	c3des_privdata *cp;
    289 	int	error = 0;
    290 
    291 	if (!blocksize)
    292 		return NULL;
    293 	if (*blocksize == (size_t)-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 		(void)memset(cp, 0, sizeof(*cp));
    305 		free(cp, M_DEVBUF);
    306 		return NULL;
    307 	}
    308 	return cp;
    309 }
    310 
    311 void
    312 cgd_cipher_3des_destroy(void *data)
    313 {
    314 	struct c3des_privdata *cp = data;
    315 
    316 	(void)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, size_t len)
    322 {
    323 	struct	c3des_encdata *ce = 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 	(void)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, size_t len)
    332 {
    333 	struct	c3des_encdata *ce = 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 	(void)memcpy(ce->ce_iv, (u_int8_t *)src + (len - 8), 8);
    338 }
    339 
    340 void
    341 cgd_cipher_3des_cbc(void *privdata, struct uio *dstuio,
    342 	struct uio *srcuio, void *iv, int dir)
    343 {
    344 	struct	c3des_privdata *cp = privdata;
    345 	struct	c3des_encdata ce;
    346 
    347 	(void)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(("%s: unrecognised direction %d", __FUNCTION__, dir));
    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 *, size_t);
    380 static void	bf_cbc_dec_int(void *, void *, void *, size_t);
    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 void *
    392 cgd_cipher_bf_init(size_t keylen, void *key, size_t *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 == (size_t)-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 bp;
    409 }
    410 
    411 void
    412 cgd_cipher_bf_destroy(void *data)
    413 {
    414 	struct	bf_privdata *bp = data;
    415 
    416 	(void)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, size_t len)
    422 {
    423 	struct	bf_encdata *be = privdata;
    424 
    425 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 1);
    426 	(void)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, size_t len)
    431 {
    432 	struct	bf_encdata *be = privdata;
    433 
    434 	BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 0);
    435 	(void)memcpy(be->be_iv, (u_int8_t *)src + (len - 8), 8);
    436 }
    437 
    438 void
    439 cgd_cipher_bf_cbc(void *privdata, struct uio *dstuio,
    440     struct uio *srcuio, void *iv, int dir)
    441 {
    442 	struct	bf_privdata *bp = privdata;
    443 	struct	bf_encdata be;
    444 
    445 	(void)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(("%s: unrecognised direction %d", __FUNCTION__, dir));
    456 	}
    457 
    458 }
    459