2017-01-02 17:28:29 +03:00
|
|
|
/* $NetBSD: cgd_crypto.c,v 1.15 2017/01/02 14:28:29 alnsn Exp $ */
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
/*-
|
|
|
|
* Copyright (c) 2002 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Roland C. Dowdeswell.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Crypto Framework For cgd.c
|
|
|
|
*
|
|
|
|
* This framework is temporary and awaits a more complete
|
|
|
|
* kernel wide crypto implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
2017-01-02 17:28:29 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: cgd_crypto.c,v 1.15 2017/01/02 14:28:29 alnsn Exp $");
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
|
|
|
|
#include <dev/cgd_crypto.h>
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
#include <crypto/rijndael/rijndael-api-fst.h>
|
|
|
|
#include <crypto/des/des.h>
|
|
|
|
#include <crypto/blowfish/blowfish.h>
|
|
|
|
|
2002-10-04 22:22:35 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
2006-12-01 18:52:55 +03:00
|
|
|
#define DIAGPANIC(x) panic x
|
2002-10-04 22:22:35 +04:00
|
|
|
#else
|
|
|
|
#define DIAGPANIC(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The general framework provides only one generic function.
|
|
|
|
* It takes the name of an algorith and returns a struct cryptfuncs *
|
|
|
|
* for it. It is up to the initialisation routines of the algorithm
|
|
|
|
* to check key size and block size.
|
|
|
|
*/
|
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static cfunc_init cgd_cipher_aes_cbc_init;
|
|
|
|
static cfunc_destroy cgd_cipher_aes_cbc_destroy;
|
|
|
|
static cfunc_cipher cgd_cipher_aes_cbc;
|
|
|
|
static cfunc_cipher_prep cgd_cipher_aes_cbc_prep;
|
2012-12-05 06:23:20 +04:00
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static cfunc_init cgd_cipher_aes_xts_init;
|
|
|
|
static cfunc_destroy cgd_cipher_aes_xts_destroy;
|
|
|
|
static cfunc_cipher cgd_cipher_aes_xts;
|
|
|
|
static cfunc_cipher_prep cgd_cipher_aes_xts_prep;
|
2012-12-05 06:23:20 +04:00
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static cfunc_init cgd_cipher_3des_init;
|
|
|
|
static cfunc_destroy cgd_cipher_3des_destroy;
|
|
|
|
static cfunc_cipher cgd_cipher_3des_cbc;
|
|
|
|
static cfunc_cipher_prep cgd_cipher_3des_cbc_prep;
|
|
|
|
|
|
|
|
static cfunc_init cgd_cipher_bf_init;
|
|
|
|
static cfunc_destroy cgd_cipher_bf_destroy;
|
|
|
|
static cfunc_cipher cgd_cipher_bf_cbc;
|
|
|
|
static cfunc_cipher_prep cgd_cipher_bf_cbc_prep;
|
2012-12-05 06:23:20 +04:00
|
|
|
|
|
|
|
static const struct cryptfuncs cf[] = {
|
2016-12-11 03:20:49 +03:00
|
|
|
{
|
|
|
|
.cf_name = "aes-xts",
|
|
|
|
.cf_init = cgd_cipher_aes_xts_init,
|
|
|
|
.cf_destroy = cgd_cipher_aes_xts_destroy,
|
|
|
|
.cf_cipher = cgd_cipher_aes_xts,
|
|
|
|
.cf_cipher_prep = cgd_cipher_aes_xts_prep,
|
|
|
|
},
|
2012-12-05 06:23:20 +04:00
|
|
|
{
|
|
|
|
.cf_name = "aes-cbc",
|
2016-12-11 03:20:49 +03:00
|
|
|
.cf_init = cgd_cipher_aes_cbc_init,
|
|
|
|
.cf_destroy = cgd_cipher_aes_cbc_destroy,
|
2012-12-05 06:23:20 +04:00
|
|
|
.cf_cipher = cgd_cipher_aes_cbc,
|
2016-12-11 03:20:49 +03:00
|
|
|
.cf_cipher_prep = cgd_cipher_aes_cbc_prep,
|
2012-12-05 06:23:20 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cf_name = "3des-cbc",
|
|
|
|
.cf_init = cgd_cipher_3des_init,
|
|
|
|
.cf_destroy = cgd_cipher_3des_destroy,
|
|
|
|
.cf_cipher = cgd_cipher_3des_cbc,
|
2016-12-11 03:20:49 +03:00
|
|
|
.cf_cipher_prep = cgd_cipher_3des_cbc_prep,
|
2012-12-05 06:23:20 +04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.cf_name = "blowfish-cbc",
|
|
|
|
.cf_init = cgd_cipher_bf_init,
|
|
|
|
.cf_destroy = cgd_cipher_bf_destroy,
|
|
|
|
.cf_cipher = cgd_cipher_bf_cbc,
|
2016-12-11 03:20:49 +03:00
|
|
|
.cf_cipher_prep = cgd_cipher_bf_cbc_prep,
|
2012-12-05 06:23:20 +04:00
|
|
|
},
|
|
|
|
};
|
|
|
|
const struct cryptfuncs *
|
2006-12-01 18:52:55 +03:00
|
|
|
cryptfuncs_find(const char *alg)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
for (size_t i = 0; i < __arraycount(cf); i++)
|
|
|
|
if (strcmp(cf[i].cf_name, alg) == 0)
|
|
|
|
return &cf[i];
|
|
|
|
|
2002-10-04 22:22:35 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-01-22 02:00:08 +03:00
|
|
|
typedef void (*cipher_func)(void *, void *, const void *, size_t);
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(void *privdata, cipher_func cipher,
|
2002-10-04 22:22:35 +04:00
|
|
|
struct uio *dstuio, struct uio *srcuio);
|
|
|
|
|
|
|
|
/*
|
2016-12-11 03:20:49 +03:00
|
|
|
* cgd_cipher_uio takes a simple cbc or xts cipher and iterates
|
2002-10-04 22:22:35 +04:00
|
|
|
* it over two struct uio's. It presumes that the cipher function
|
|
|
|
* that is passed to it keeps the IV state between calls.
|
|
|
|
*
|
|
|
|
* We assume that the caller has ensured that each segment is evenly
|
|
|
|
* divisible by the block size, which for the cgd is a valid assumption.
|
|
|
|
* If we were to make this code more generic, we might need to take care
|
|
|
|
* of this case, either by issuing an error or copying the data.
|
|
|
|
*/
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(void *privdata, cipher_func cipher,
|
2006-12-01 18:52:55 +03:00
|
|
|
struct uio *dstuio, struct uio *srcuio)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2015-04-25 15:55:04 +03:00
|
|
|
const struct iovec *dst;
|
|
|
|
const struct iovec *src;
|
2002-10-04 22:22:35 +04:00
|
|
|
int dstnum;
|
|
|
|
int dstoff = 0;
|
|
|
|
int srcnum;
|
|
|
|
int srcoff = 0;
|
|
|
|
|
|
|
|
dst = dstuio->uio_iov;
|
|
|
|
dstnum = dstuio->uio_iovcnt;
|
|
|
|
src = srcuio->uio_iov;
|
|
|
|
srcnum = srcuio->uio_iovcnt;
|
|
|
|
for (;;) {
|
|
|
|
int l = MIN(dst->iov_len - dstoff, src->iov_len - srcoff);
|
|
|
|
u_int8_t *d = (u_int8_t *)dst->iov_base + dstoff;
|
2015-04-25 15:55:04 +03:00
|
|
|
const u_int8_t *s = (const u_int8_t *)src->iov_base + srcoff;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
cipher(privdata, d, s, l);
|
|
|
|
|
|
|
|
dstoff += l;
|
|
|
|
srcoff += l;
|
|
|
|
/*
|
|
|
|
* We assume that {dst,src} == {dst,src}->iov_len,
|
|
|
|
* because it should not be possible for it not to be.
|
|
|
|
*/
|
|
|
|
if (dstoff == dst->iov_len) {
|
|
|
|
dstoff = 0;
|
|
|
|
dstnum--;
|
|
|
|
dst++;
|
|
|
|
}
|
|
|
|
if (srcoff == src->iov_len) {
|
|
|
|
srcoff = 0;
|
|
|
|
srcnum--;
|
|
|
|
src++;
|
|
|
|
}
|
|
|
|
if (!srcnum || !dstnum)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* AES Framework
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: we do not store the blocksize in here, because it is not
|
|
|
|
* variable [yet], we hardcode the blocksize to 16 (128 bits).
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct aes_privdata {
|
|
|
|
keyInstance ap_enckey;
|
|
|
|
keyInstance ap_deckey;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct aes_encdata {
|
|
|
|
keyInstance *ae_key; /* key for this direction */
|
2017-01-02 17:28:29 +03:00
|
|
|
u_int8_t ae_iv[CGD_AES_BLOCK_SIZE]; /* Initialization Vector */
|
2002-10-04 22:22:35 +04:00
|
|
|
};
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void *
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_aes_cbc_init(size_t keylen, const void *key, size_t *blocksize)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
|
|
|
struct aes_privdata *ap;
|
|
|
|
|
|
|
|
if (!blocksize)
|
|
|
|
return NULL;
|
|
|
|
if (keylen != 128 && keylen != 192 && keylen != 256)
|
|
|
|
return NULL;
|
2006-12-01 18:52:55 +03:00
|
|
|
if (*blocksize == (size_t)-1)
|
2002-10-04 22:22:35 +04:00
|
|
|
*blocksize = 128;
|
|
|
|
if (*blocksize != 128)
|
|
|
|
return NULL;
|
|
|
|
ap = malloc(sizeof(*ap), M_DEVBUF, 0);
|
|
|
|
if (!ap)
|
|
|
|
return NULL;
|
|
|
|
rijndael_makeKey(&ap->ap_enckey, DIR_ENCRYPT, keylen, key);
|
|
|
|
rijndael_makeKey(&ap->ap_deckey, DIR_DECRYPT, keylen, key);
|
2006-12-01 18:52:55 +03:00
|
|
|
return ap;
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_aes_cbc_destroy(void *data)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct aes_privdata *apd = data;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2013-06-24 08:21:19 +04:00
|
|
|
explicit_memset(apd, 0, sizeof(*apd));
|
2002-10-04 22:22:35 +04:00
|
|
|
free(apd, M_DEVBUF);
|
|
|
|
}
|
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static void
|
|
|
|
cgd_cipher_aes_cbc_prep(void *privdata, char *iv,
|
|
|
|
const char *blkno_buf, size_t blocksize, int dir)
|
|
|
|
{
|
|
|
|
struct aes_privdata *apd = privdata;
|
|
|
|
cipherInstance cipher;
|
|
|
|
int cipher_ok __diagused;
|
|
|
|
|
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, NULL);
|
|
|
|
KASSERT(cipher_ok > 0);
|
|
|
|
rijndael_blockEncrypt(&cipher, &apd->ap_enckey,
|
|
|
|
blkno_buf, blocksize * 8, iv);
|
2017-01-02 17:28:29 +03:00
|
|
|
if (blocksize > CGD_AES_BLOCK_SIZE) {
|
|
|
|
(void)memmove(iv, iv + blocksize - CGD_AES_BLOCK_SIZE,
|
|
|
|
CGD_AES_BLOCK_SIZE);
|
|
|
|
}
|
2016-12-11 03:20:49 +03:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
aes_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct aes_encdata *ae = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
cipherInstance cipher;
|
2016-12-11 03:20:49 +03:00
|
|
|
int cipher_ok __diagused;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
|
|
|
|
KASSERT(cipher_ok > 0);
|
2002-10-04 22:22:35 +04:00
|
|
|
rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ae->ae_iv, (u_int8_t *)dst +
|
|
|
|
(len - CGD_AES_BLOCK_SIZE), CGD_AES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
aes_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct aes_encdata *ae = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
cipherInstance cipher;
|
2016-12-11 03:20:49 +03:00
|
|
|
int cipher_ok __diagused;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_CBC, ae->ae_iv);
|
|
|
|
KASSERT(cipher_ok > 0);
|
2002-10-04 22:22:35 +04:00
|
|
|
rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ae->ae_iv, (const u_int8_t *)src +
|
|
|
|
(len - CGD_AES_BLOCK_SIZE), CGD_AES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2006-12-01 18:52:55 +03:00
|
|
|
cgd_cipher_aes_cbc(void *privdata, struct uio *dstuio,
|
2015-04-25 15:55:04 +03:00
|
|
|
struct uio *srcuio, const void *iv, int dir)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct aes_privdata *apd = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
struct aes_encdata encd;
|
|
|
|
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(encd.ae_iv, iv, CGD_AES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
switch (dir) {
|
|
|
|
case CGD_CIPHER_ENCRYPT:
|
|
|
|
encd.ae_key = &apd->ap_enckey;
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&encd, aes_cbc_enc_int, dstuio, srcuio);
|
|
|
|
break;
|
|
|
|
case CGD_CIPHER_DECRYPT:
|
|
|
|
encd.ae_key = &apd->ap_deckey;
|
|
|
|
cgd_cipher_uio(&encd, aes_cbc_dec_int, dstuio, srcuio);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
cgd_cipher_aes_xts_init(size_t keylen, const void *xtskey, size_t *blocksize)
|
|
|
|
{
|
|
|
|
struct aes_privdata *ap;
|
|
|
|
const char *key, *key2; /* XTS key is made of two AES keys. */
|
|
|
|
|
|
|
|
if (!blocksize)
|
|
|
|
return NULL;
|
|
|
|
if (keylen != 256 && keylen != 512)
|
|
|
|
return NULL;
|
|
|
|
if (*blocksize == (size_t)-1)
|
|
|
|
*blocksize = 128;
|
|
|
|
if (*blocksize != 128)
|
|
|
|
return NULL;
|
|
|
|
ap = malloc(2 * sizeof(*ap), M_DEVBUF, 0);
|
|
|
|
if (!ap)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
keylen /= 2;
|
|
|
|
key = xtskey;
|
|
|
|
key2 = key + keylen / CHAR_BIT;
|
|
|
|
|
|
|
|
rijndael_makeKey(&ap[0].ap_enckey, DIR_ENCRYPT, keylen, key);
|
|
|
|
rijndael_makeKey(&ap[0].ap_deckey, DIR_DECRYPT, keylen, key);
|
|
|
|
rijndael_makeKey(&ap[1].ap_enckey, DIR_ENCRYPT, keylen, key2);
|
|
|
|
|
|
|
|
return ap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cgd_cipher_aes_xts_destroy(void *data)
|
|
|
|
{
|
|
|
|
struct aes_privdata *apd = data;
|
|
|
|
|
|
|
|
explicit_memset(apd, 0, 2 * sizeof(*apd));
|
|
|
|
free(apd, M_DEVBUF);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cgd_cipher_aes_xts_prep(void *privdata, char *iv,
|
|
|
|
const char *blkno_buf, size_t blocksize, int dir)
|
|
|
|
{
|
|
|
|
struct aes_privdata *apd = privdata;
|
|
|
|
cipherInstance cipher;
|
|
|
|
int cipher_ok __diagused;
|
|
|
|
|
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_ECB, NULL);
|
|
|
|
KASSERT(cipher_ok > 0);
|
|
|
|
rijndael_blockEncrypt(&cipher, &apd[1].ap_enckey,
|
|
|
|
blkno_buf, blocksize * 8, iv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
aes_xts_enc_int(void *privdata, void *dst, const void *src, size_t len)
|
|
|
|
{
|
|
|
|
struct aes_encdata *ae = privdata;
|
|
|
|
cipherInstance cipher;
|
|
|
|
int cipher_ok __diagused;
|
|
|
|
|
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_XTS, ae->ae_iv);
|
|
|
|
KASSERT(cipher_ok > 0);
|
|
|
|
rijndael_blockEncrypt(&cipher, ae->ae_key, src, len * 8, dst);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ae->ae_iv, cipher.IV, CGD_AES_BLOCK_SIZE);
|
2016-12-11 03:20:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
aes_xts_dec_int(void *privdata, void *dst, const void *src, size_t len)
|
|
|
|
{
|
|
|
|
struct aes_encdata *ae = privdata;
|
|
|
|
cipherInstance cipher;
|
|
|
|
int cipher_ok __diagused;
|
|
|
|
|
|
|
|
cipher_ok = rijndael_cipherInit(&cipher, MODE_XTS, ae->ae_iv);
|
|
|
|
KASSERT(cipher_ok > 0);
|
|
|
|
rijndael_blockDecrypt(&cipher, ae->ae_key, src, len * 8, dst);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ae->ae_iv, cipher.IV, CGD_AES_BLOCK_SIZE);
|
2016-12-11 03:20:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cgd_cipher_aes_xts(void *privdata, struct uio *dstuio,
|
|
|
|
struct uio *srcuio, const void *iv, int dir)
|
|
|
|
{
|
|
|
|
struct aes_privdata *apd = privdata;
|
|
|
|
struct aes_encdata encd;
|
|
|
|
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(encd.ae_iv, iv, CGD_AES_BLOCK_SIZE);
|
2016-12-11 03:20:49 +03:00
|
|
|
switch (dir) {
|
|
|
|
case CGD_CIPHER_ENCRYPT:
|
|
|
|
encd.ae_key = &apd->ap_enckey;
|
|
|
|
cgd_cipher_uio(&encd, aes_xts_enc_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
case CGD_CIPHER_DECRYPT:
|
|
|
|
encd.ae_key = &apd->ap_deckey;
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&encd, aes_xts_dec_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-15 03:39:14 +03:00
|
|
|
DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 3DES Framework
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct c3des_privdata {
|
|
|
|
des_key_schedule cp_key1;
|
|
|
|
des_key_schedule cp_key2;
|
|
|
|
des_key_schedule cp_key3;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct c3des_encdata {
|
|
|
|
des_key_schedule *ce_key1;
|
|
|
|
des_key_schedule *ce_key2;
|
|
|
|
des_key_schedule *ce_key3;
|
2017-01-02 17:28:29 +03:00
|
|
|
u_int8_t ce_iv[CGD_3DES_BLOCK_SIZE];
|
2002-10-04 22:22:35 +04:00
|
|
|
};
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void *
|
2007-01-22 02:00:08 +03:00
|
|
|
cgd_cipher_3des_init(size_t keylen, const void *key, size_t *blocksize)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
|
|
|
struct c3des_privdata *cp;
|
|
|
|
int error = 0;
|
2007-01-22 02:00:08 +03:00
|
|
|
des_cblock *block;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
if (!blocksize)
|
|
|
|
return NULL;
|
2006-12-01 18:52:55 +03:00
|
|
|
if (*blocksize == (size_t)-1)
|
2002-10-04 22:22:35 +04:00
|
|
|
*blocksize = 64;
|
|
|
|
if (keylen != (DES_KEY_SZ * 3 * 8) || *blocksize != 64)
|
|
|
|
return NULL;
|
|
|
|
cp = malloc(sizeof(*cp), M_DEVBUF, 0);
|
|
|
|
if (!cp)
|
|
|
|
return NULL;
|
2007-01-22 02:00:08 +03:00
|
|
|
block = __UNCONST(key);
|
|
|
|
error = des_key_sched(block, cp->cp_key1);
|
|
|
|
error |= des_key_sched(block + 1, cp->cp_key2);
|
|
|
|
error |= des_key_sched(block + 2, cp->cp_key3);
|
2002-10-04 22:22:35 +04:00
|
|
|
if (error) {
|
2013-06-24 08:21:19 +04:00
|
|
|
explicit_memset(cp, 0, sizeof(*cp));
|
2002-10-04 22:22:35 +04:00
|
|
|
free(cp, M_DEVBUF);
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-12-01 18:52:55 +03:00
|
|
|
return cp;
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2006-12-01 18:52:55 +03:00
|
|
|
cgd_cipher_3des_destroy(void *data)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct c3des_privdata *cp = data;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2013-06-24 08:21:19 +04:00
|
|
|
explicit_memset(cp, 0, sizeof(*cp));
|
2002-10-04 22:22:35 +04:00
|
|
|
free(cp, M_DEVBUF);
|
|
|
|
}
|
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static void
|
|
|
|
cgd_cipher_3des_cbc_prep(void *privdata, char *iv,
|
|
|
|
const char *blkno_buf, size_t blocksize, int dir)
|
|
|
|
{
|
|
|
|
struct c3des_privdata *cp = privdata;
|
2017-01-02 17:28:29 +03:00
|
|
|
char zero_iv[CGD_3DES_BLOCK_SIZE];
|
2016-12-11 03:20:49 +03:00
|
|
|
|
|
|
|
memset(zero_iv, 0, sizeof(zero_iv));
|
|
|
|
des_ede3_cbc_encrypt(blkno_buf, iv, blocksize,
|
|
|
|
cp->cp_key1, cp->cp_key2, cp->cp_key3, (des_cblock *)zero_iv, 1);
|
2017-01-02 17:28:29 +03:00
|
|
|
if (blocksize > CGD_3DES_BLOCK_SIZE) {
|
|
|
|
(void)memmove(iv, iv + blocksize - CGD_3DES_BLOCK_SIZE,
|
|
|
|
CGD_3DES_BLOCK_SIZE);
|
|
|
|
}
|
2016-12-11 03:20:49 +03:00
|
|
|
}
|
|
|
|
|
2002-10-04 22:22:35 +04:00
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
c3des_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct c3des_encdata *ce = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
|
|
|
|
*ce->ce_key3, (des_cblock *)ce->ce_iv, 1);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ce->ce_iv, (const u_int8_t *)dst +
|
|
|
|
(len - CGD_3DES_BLOCK_SIZE), CGD_3DES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
c3des_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct c3des_encdata *ce = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
des_ede3_cbc_encrypt(src, dst, len, *ce->ce_key1, *ce->ce_key2,
|
|
|
|
*ce->ce_key3, (des_cblock *)ce->ce_iv, 0);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ce->ce_iv, (const u_int8_t *)src +
|
|
|
|
(len - CGD_3DES_BLOCK_SIZE), CGD_3DES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2006-12-01 18:52:55 +03:00
|
|
|
cgd_cipher_3des_cbc(void *privdata, struct uio *dstuio,
|
2015-04-25 15:55:04 +03:00
|
|
|
struct uio *srcuio, const void *iv, int dir)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct c3des_privdata *cp = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
struct c3des_encdata ce;
|
|
|
|
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(ce.ce_iv, iv, CGD_3DES_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
ce.ce_key1 = &cp->cp_key1;
|
|
|
|
ce.ce_key2 = &cp->cp_key2;
|
|
|
|
ce.ce_key3 = &cp->cp_key3;
|
|
|
|
switch (dir) {
|
|
|
|
case CGD_CIPHER_ENCRYPT:
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&ce, c3des_cbc_enc_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
case CGD_CIPHER_DECRYPT:
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&ce, c3des_cbc_dec_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-15 03:39:14 +03:00
|
|
|
DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Blowfish Framework
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct bf_privdata {
|
|
|
|
BF_KEY bp_key;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct bf_encdata {
|
|
|
|
BF_KEY *be_key;
|
2017-01-02 17:28:29 +03:00
|
|
|
u_int8_t be_iv[CGD_BF_BLOCK_SIZE];
|
2002-10-04 22:22:35 +04:00
|
|
|
};
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void *
|
2007-01-22 02:00:08 +03:00
|
|
|
cgd_cipher_bf_init(size_t keylen, const void *key, size_t *blocksize)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
|
|
|
struct bf_privdata *bp;
|
|
|
|
|
|
|
|
if (!blocksize)
|
|
|
|
return NULL;
|
Fix a longstanding bug in key-handling for the blowfish cipher.
This is an incompatible change, and will break all existing cgd images
encrypted with blowfish. Users will need to dump their data before
booting a kernel with this change, and recreate cgd's and restore data
afterwards.
I believe this affects a very small number of users other than myself;
indeed after several alert mails in an attempt to find them, only 2
such users have come forward. They have both agreed the requirement
for backwards compatibility does not warrant the effort nor the mess
in the code. This code does exist, if it should later prove to be
needed, but will not be in the tree.
Further, by the nature of the issue, I have strong reasons to believe
that, even if they missed these mails, there would be few other users
of blowfish who update their systems with any regularity; any such
users would have tripped over the problem in the same way I did when
it was first found over a year ago.
The problem stems from two issues with the underlying blowfish
encryption routines used by cgd:
- they take key length arguments counted in bytes, rather than bits
like all the opther ciphers.
- they silently truncate any keys longer than an internal limit,
rather than returning an error (which would have exposed the
previous discrepancy immediately).
As a result, the kernel reads too much data as the key from cgdconfig,
and then truncates most of it. This can easily be demonstrated/tested.
Currently, Blowfish users will find that if they mis-enter the cgd
passphrase on the first attempt, when validation fails and cgdconfig
prompts for the passphrase again, the cgd will not correctly configure
even when given a correct passphrase.
2004-03-18 13:42:08 +03:00
|
|
|
if (keylen < 40 || keylen > 448 || (keylen % 8 != 0))
|
2002-10-04 22:22:35 +04:00
|
|
|
return NULL;
|
2006-12-01 18:52:55 +03:00
|
|
|
if (*blocksize == (size_t)-1)
|
2002-10-04 22:22:35 +04:00
|
|
|
*blocksize = 64;
|
|
|
|
if (*blocksize != 64)
|
|
|
|
return NULL;
|
|
|
|
bp = malloc(sizeof(*bp), M_DEVBUF, 0);
|
|
|
|
if (!bp)
|
|
|
|
return NULL;
|
Fix a longstanding bug in key-handling for the blowfish cipher.
This is an incompatible change, and will break all existing cgd images
encrypted with blowfish. Users will need to dump their data before
booting a kernel with this change, and recreate cgd's and restore data
afterwards.
I believe this affects a very small number of users other than myself;
indeed after several alert mails in an attempt to find them, only 2
such users have come forward. They have both agreed the requirement
for backwards compatibility does not warrant the effort nor the mess
in the code. This code does exist, if it should later prove to be
needed, but will not be in the tree.
Further, by the nature of the issue, I have strong reasons to believe
that, even if they missed these mails, there would be few other users
of blowfish who update their systems with any regularity; any such
users would have tripped over the problem in the same way I did when
it was first found over a year ago.
The problem stems from two issues with the underlying blowfish
encryption routines used by cgd:
- they take key length arguments counted in bytes, rather than bits
like all the opther ciphers.
- they silently truncate any keys longer than an internal limit,
rather than returning an error (which would have exposed the
previous discrepancy immediately).
As a result, the kernel reads too much data as the key from cgdconfig,
and then truncates most of it. This can easily be demonstrated/tested.
Currently, Blowfish users will find that if they mis-enter the cgd
passphrase on the first attempt, when validation fails and cgdconfig
prompts for the passphrase again, the cgd will not correctly configure
even when given a correct passphrase.
2004-03-18 13:42:08 +03:00
|
|
|
BF_set_key(&bp->bp_key, keylen / 8, key);
|
2006-12-01 18:52:55 +03:00
|
|
|
return bp;
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2006-12-01 18:52:55 +03:00
|
|
|
cgd_cipher_bf_destroy(void *data)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct bf_privdata *bp = data;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
2013-06-24 08:21:19 +04:00
|
|
|
explicit_memset(bp, 0, sizeof(*bp));
|
2002-10-04 22:22:35 +04:00
|
|
|
free(bp, M_DEVBUF);
|
|
|
|
}
|
|
|
|
|
2016-12-11 03:20:49 +03:00
|
|
|
static void
|
|
|
|
cgd_cipher_bf_cbc_prep(void *privdata, char *iv,
|
|
|
|
const char *blkno_buf, size_t blocksize, int dir)
|
|
|
|
{
|
|
|
|
struct bf_privdata *bp = privdata;
|
2017-01-02 17:28:29 +03:00
|
|
|
char zero_iv[CGD_BF_BLOCK_SIZE];
|
2016-12-11 03:20:49 +03:00
|
|
|
|
|
|
|
memset(zero_iv, 0, sizeof(zero_iv));
|
|
|
|
BF_cbc_encrypt(blkno_buf, iv, blocksize, &bp->bp_key, zero_iv, 1);
|
2017-01-02 17:28:29 +03:00
|
|
|
if (blocksize > CGD_BF_BLOCK_SIZE) {
|
|
|
|
(void)memmove(iv, iv + blocksize - CGD_BF_BLOCK_SIZE,
|
|
|
|
CGD_BF_BLOCK_SIZE);
|
|
|
|
}
|
2016-12-11 03:20:49 +03:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
bf_cbc_enc_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct bf_encdata *be = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 1);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(be->be_iv, (u_int8_t *)dst +
|
|
|
|
(len - CGD_BF_BLOCK_SIZE), CGD_BF_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2007-01-22 02:00:08 +03:00
|
|
|
bf_cbc_dec_int(void *privdata, void *dst, const void *src, size_t len)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct bf_encdata *be = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
|
|
|
|
BF_cbc_encrypt(src, dst, len, be->be_key, be->be_iv, 0);
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(be->be_iv, (const u_int8_t *)src +
|
|
|
|
(len - CGD_BF_BLOCK_SIZE), CGD_BF_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
2012-12-05 06:23:20 +04:00
|
|
|
static void
|
2006-12-01 18:52:55 +03:00
|
|
|
cgd_cipher_bf_cbc(void *privdata, struct uio *dstuio,
|
2015-04-25 15:55:04 +03:00
|
|
|
struct uio *srcuio, const void *iv, int dir)
|
2002-10-04 22:22:35 +04:00
|
|
|
{
|
2006-12-01 18:52:55 +03:00
|
|
|
struct bf_privdata *bp = privdata;
|
2002-10-04 22:22:35 +04:00
|
|
|
struct bf_encdata be;
|
|
|
|
|
2017-01-02 17:28:29 +03:00
|
|
|
(void)memcpy(be.be_iv, iv, CGD_BF_BLOCK_SIZE);
|
2002-10-04 22:22:35 +04:00
|
|
|
be.be_key = &bp->bp_key;
|
|
|
|
switch (dir) {
|
|
|
|
case CGD_CIPHER_ENCRYPT:
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&be, bf_cbc_enc_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
case CGD_CIPHER_DECRYPT:
|
2016-12-11 03:20:49 +03:00
|
|
|
cgd_cipher_uio(&be, bf_cbc_dec_int, dstuio, srcuio);
|
2002-10-04 22:22:35 +04:00
|
|
|
break;
|
|
|
|
default:
|
2007-12-15 03:39:14 +03:00
|
|
|
DIAGPANIC(("%s: unrecognised direction %d", __func__, dir));
|
2002-10-04 22:22:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|