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