Implement switching of data encryption key every 2^20 blocks.

This ensures the same encryption key won't be used for more than
2^20 blocks (sectors). This will be the default now.

MFC after:	1 week
This commit is contained in:
Pawel Jakub Dawidek 2010-09-23 11:49:47 +00:00
parent 30bd3bb07b
commit c6a26d4c88
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213067
5 changed files with 171 additions and 55 deletions

View file

@ -374,6 +374,34 @@ g_eli_worker(void *arg)
}
}
/*
* Select encryption key. If G_ELI_FLAG_SINGLE_KEY is present we only have one
* key available for all the data. If the flag is not present select the key
* based on data offset.
*/
uint8_t *
g_eli_crypto_key(struct g_eli_softc *sc, off_t offset, size_t blocksize)
{
u_int nkey;
if (sc->sc_nekeys == 1)
return (sc->sc_ekeys[0]);
KASSERT(sc->sc_nekeys > 1, ("%s: sc_nekeys=%u", __func__,
sc->sc_nekeys));
KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0,
("%s: SINGLE_KEY flag set, but sc_nekeys=%u", __func__,
sc->sc_nekeys));
/* We switch key every 2^G_ELI_KEY_SHIFT blocks. */
nkey = (offset >> G_ELI_KEY_SHIFT) / blocksize;
KASSERT(nkey < sc->sc_nekeys, ("%s: nkey=%u >= sc_nekeys=%u", __func__,
nkey, sc->sc_nekeys));
return (sc->sc_ekeys[nkey]);
}
/*
* Here we generate IV. It is unique for every sector.
*/
@ -548,13 +576,10 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
/* Backward compatibility. */
if (md->md_version < 4)
sc->sc_flags |= G_ELI_FLAG_NATIVE_BYTE_ORDER;
if (md->md_version < 5)
sc->sc_flags |= G_ELI_FLAG_SINGLE_KEY;
sc->sc_ealgo = md->md_ealgo;
sc->sc_nkey = nkey;
/*
* Remember the keys in our softc structure.
*/
g_eli_mkey_propagate(sc, mkey);
sc->sc_ekeylen = md->md_keylen;
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
sc->sc_akeylen = sizeof(sc->sc_akey) * 8;
@ -584,14 +609,6 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
sizeof(sc->sc_akey));
}
/*
* Precalculate SHA256 for IV generation.
* This is expensive operation and we can do it only once now or for
* every access to sector, so now will be much better.
*/
SHA256_Init(&sc->sc_ivctx);
SHA256_Update(&sc->sc_ivctx, sc->sc_ivkey, sizeof(sc->sc_ivkey));
gp->softc = sc;
sc->sc_geom = gp;
@ -633,12 +650,37 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
goto failed;
}
sc->sc_sectorsize = md->md_sectorsize;
sc->sc_mediasize = bpp->mediasize;
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME))
sc->sc_mediasize -= bpp->sectorsize;
if (!(sc->sc_flags & G_ELI_FLAG_AUTH))
sc->sc_mediasize -= (sc->sc_mediasize % sc->sc_sectorsize);
else {
sc->sc_mediasize /= sc->sc_bytes_per_sector;
sc->sc_mediasize *= sc->sc_sectorsize;
}
/*
* Remember the keys in our softc structure.
*/
g_eli_mkey_propagate(sc, mkey);
sc->sc_ekeylen = md->md_keylen;
/*
* Precalculate SHA256 for IV generation.
* This is expensive operation and we can do it only once now or for
* every access to sector, so now will be much better.
*/
SHA256_Init(&sc->sc_ivctx);
SHA256_Update(&sc->sc_ivctx, sc->sc_ivkey, sizeof(sc->sc_ivkey));
LIST_INIT(&sc->sc_workers);
bzero(&crie, sizeof(crie));
crie.cri_alg = sc->sc_ealgo;
crie.cri_klen = sc->sc_ekeylen;
crie.cri_key = sc->sc_ekey;
crie.cri_key = sc->sc_ekeys[0];
if (sc->sc_flags & G_ELI_FLAG_AUTH) {
bzero(&cria, sizeof(cria));
cria.cri_alg = sc->sc_aalgo;
@ -715,16 +757,8 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
* Create decrypted provider.
*/
pp = g_new_providerf(gp, "%s%s", bpp->name, G_ELI_SUFFIX);
pp->sectorsize = md->md_sectorsize;
pp->mediasize = bpp->mediasize;
if (!(sc->sc_flags & G_ELI_FLAG_ONETIME))
pp->mediasize -= bpp->sectorsize;
if (!(sc->sc_flags & G_ELI_FLAG_AUTH))
pp->mediasize -= (pp->mediasize % pp->sectorsize);
else {
pp->mediasize /= sc->sc_bytes_per_sector;
pp->mediasize *= pp->sectorsize;
}
pp->mediasize = sc->sc_mediasize;
pp->sectorsize = sc->sc_sectorsize;
g_error_provider(pp, 0);
@ -755,6 +789,11 @@ g_eli_create(struct gctl_req *req, struct g_class *mp, struct g_provider *bpp,
}
g_destroy_consumer(cp);
g_destroy_geom(gp);
if (sc->sc_ekeys != NULL) {
bzero(sc->sc_ekeys,
sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN));
free(sc->sc_ekeys, M_ELI);
}
bzero(sc, sizeof(*sc));
free(sc, M_ELI);
return (NULL);
@ -794,6 +833,9 @@ g_eli_destroy(struct g_eli_softc *sc, boolean_t force)
}
mtx_destroy(&sc->sc_queue_mtx);
gp->softc = NULL;
bzero(sc->sc_ekeys,
sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN));
free(sc->sc_ekeys, M_ELI);
bzero(sc, sizeof(*sc));
free(sc, M_ELI);
@ -1042,6 +1084,7 @@ g_eli_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
sbuf_printf(sb, name); \
} \
} while (0)
ADD_FLAG(G_ELI_FLAG_SINGLE_KEY, "SINGLE-KEY");
ADD_FLAG(G_ELI_FLAG_NATIVE_BYTE_ORDER, "NATIVE-BYTE-ORDER");
ADD_FLAG(G_ELI_FLAG_ONETIME, "ONETIME");
ADD_FLAG(G_ELI_FLAG_BOOT, "BOOT");

View file

@ -60,8 +60,9 @@
* 3 - Added 'configure' subcommand.
* 4 - IV is generated from offset converted to little-endian
* (flag G_ELI_FLAG_NATIVE_BYTE_ORDER will be set for older versions).
* 5 - Added multiple encrypton keys.
*/
#define G_ELI_VERSION 4
#define G_ELI_VERSION 5
/* ON DISK FLAGS. */
/* Use random, onetime keys. */
@ -83,6 +84,8 @@
#define G_ELI_FLAG_DESTROY 0x00020000
/* Provider uses native byte-order for IV generation. */
#define G_ELI_FLAG_NATIVE_BYTE_ORDER 0x00040000
/* Provider uses single encryption key. */
#define G_ELI_FLAG_SINGLE_KEY 0x00080000
#define SHA512_MDLEN 64
#define G_ELI_AUTH_SECKEYLEN SHA256_DIGEST_LENGTH
@ -98,6 +101,8 @@
/* Data-Key, IV-Key, HMAC_SHA512(Derived-Key, Data-Key+IV-Key) */
#define G_ELI_MKEYLEN (G_ELI_DATAIVKEYLEN + SHA512_MDLEN)
#define G_ELI_OVERWRITES 5
/* Switch data encryption key every 2^20 blocks. */
#define G_ELI_KEY_SHIFT 20
#ifdef _KERNEL
extern u_int g_eli_debug;
@ -139,27 +144,30 @@ struct g_eli_worker {
};
struct g_eli_softc {
struct g_geom *sc_geom;
u_int sc_crypto;
uint8_t sc_mkey[G_ELI_DATAIVKEYLEN];
uint8_t sc_ekey[G_ELI_DATAKEYLEN];
u_int sc_ealgo;
u_int sc_ekeylen;
uint8_t sc_akey[G_ELI_AUTHKEYLEN];
u_int sc_aalgo;
u_int sc_akeylen;
u_int sc_alen;
SHA256_CTX sc_akeyctx;
uint8_t sc_ivkey[G_ELI_IVKEYLEN];
SHA256_CTX sc_ivctx;
int sc_nkey;
uint32_t sc_flags;
u_int sc_bytes_per_sector;
u_int sc_data_per_sector;
struct g_geom *sc_geom;
u_int sc_crypto;
uint8_t sc_mkey[G_ELI_DATAIVKEYLEN];
uint8_t **sc_ekeys;
u_int sc_nekeys;
u_int sc_ealgo;
u_int sc_ekeylen;
uint8_t sc_akey[G_ELI_AUTHKEYLEN];
u_int sc_aalgo;
u_int sc_akeylen;
u_int sc_alen;
SHA256_CTX sc_akeyctx;
uint8_t sc_ivkey[G_ELI_IVKEYLEN];
SHA256_CTX sc_ivctx;
int sc_nkey;
uint32_t sc_flags;
off_t sc_mediasize;
size_t sc_sectorsize;
u_int sc_bytes_per_sector;
u_int sc_data_per_sector;
/* Only for software cryptography. */
struct bio_queue_head sc_queue;
struct mtx sc_queue_mtx;
struct mtx sc_queue_mtx;
LIST_HEAD(, g_eli_worker) sc_workers;
};
#define sc_name sc_geom->name
@ -231,7 +239,7 @@ eli_metadata_decode_v0(const u_char *data, struct g_eli_metadata *md)
}
static __inline int
eli_metadata_decode_v1v2v3v4(const u_char *data, struct g_eli_metadata *md)
eli_metadata_decode_v1v2v3v4v5(const u_char *data, struct g_eli_metadata *md)
{
MD5_CTX ctx;
const u_char *p;
@ -269,7 +277,8 @@ eli_metadata_decode(const u_char *data, struct g_eli_metadata *md)
case 2:
case 3:
case 4:
error = eli_metadata_decode_v1v2v3v4(data, md);
case 5:
error = eli_metadata_decode_v1v2v3v4v5(data, md);
break;
default:
error = EINVAL;
@ -461,6 +470,8 @@ void g_eli_config(struct gctl_req *req, struct g_class *mp, const char *verb);
void g_eli_read_done(struct bio *bp);
void g_eli_write_done(struct bio *bp);
int g_eli_crypto_rerun(struct cryptop *crp);
uint8_t *g_eli_crypto_key(struct g_eli_softc *sc, off_t offset,
size_t blocksize);
void g_eli_crypto_ivgen(struct g_eli_softc *sc, off_t offset, u_char *iv,
size_t size);

View file

@ -507,7 +507,7 @@ g_eli_auth_run(struct g_eli_worker *wr, struct bio *bp)
if (bp->bio_cmd == BIO_WRITE)
crde->crd_flags |= CRD_F_ENCRYPT;
crde->crd_alg = sc->sc_ealgo;
crde->crd_key = sc->sc_ekey;
crde->crd_key = g_eli_crypto_key(sc, dstoff, encr_secsize);
crde->crd_klen = sc->sc_ekeylen;
g_eli_crypto_ivgen(sc, dstoff, crde->crd_iv,
sizeof(crde->crd_iv));

View file

@ -43,6 +43,9 @@ __FBSDID("$FreeBSD$");
#include <geom/eli/g_eli.h>
#ifdef _KERNEL
MALLOC_DECLARE(M_ELI);
#endif
/*
* Verify if the given 'key' is correct.
@ -178,6 +181,46 @@ g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
}
#ifdef _KERNEL
static void
g_eli_ekeys_generate(struct g_eli_softc *sc)
{
uint8_t *keys;
u_int kno;
off_t mediasize;
size_t blocksize;
struct {
char magic[4];
uint8_t keyno[8];
} __packed hmacdata;
KASSERT((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) == 0,
("%s: G_ELI_FLAG_SINGLE_KEY flag present", __func__));
if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
struct g_provider *pp;
pp = LIST_FIRST(&sc->sc_geom->consumer)->provider;
mediasize = pp->mediasize;
blocksize = pp->sectorsize;
} else {
mediasize = sc->sc_mediasize;
blocksize = sc->sc_sectorsize;
}
sc->sc_nekeys = ((mediasize - 1) >> G_ELI_KEY_SHIFT) / blocksize + 1;
sc->sc_ekeys =
malloc(sc->sc_nekeys * (sizeof(uint8_t *) + G_ELI_DATAKEYLEN),
M_ELI, M_WAITOK);
keys = (uint8_t *)(sc->sc_ekeys + sc->sc_nekeys);
bcopy("ekey", hmacdata.magic, 4);
for (kno = 0; kno < sc->sc_nekeys; kno++, keys += G_ELI_DATAKEYLEN) {
sc->sc_ekeys[kno] = keys;
le64enc(hmacdata.keyno, (uint64_t)kno);
g_eli_crypto_hmac(sc->sc_mkey, G_ELI_MAXKEYLEN,
(uint8_t *)&hmacdata, sizeof(hmacdata),
sc->sc_ekeys[kno], 0);
}
}
/*
* When doing encryption only, copy IV key and encryption key.
* When doing encryption and authentication, copy IV key, generate encryption
@ -193,16 +236,33 @@ g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey)
bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
mkey += sizeof(sc->sc_ivkey);
if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) {
bcopy(mkey, sc->sc_ekey, sizeof(sc->sc_ekey));
/*
* The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11)
*/
if ((sc->sc_flags & G_ELI_FLAG_AUTH) != 0) {
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1,
sc->sc_akey, 0);
} else {
/*
* The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10)
* The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11)
*/
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, sc->sc_ekey, 0);
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1, sc->sc_akey, 0);
arc4rand(sc->sc_akey, sizeof(sc->sc_akey), 0);
}
if ((sc->sc_flags & G_ELI_FLAG_SINGLE_KEY) != 0) {
sc->sc_nekeys = 1;
sc->sc_ekeys = malloc(sc->sc_nekeys *
(sizeof(uint8_t *) + G_ELI_DATAKEYLEN), M_ELI, M_WAITOK);
sc->sc_ekeys[0] = (uint8_t *)(sc->sc_ekeys + sc->sc_nekeys);
if ((sc->sc_flags & G_ELI_FLAG_AUTH) == 0)
bcopy(mkey, sc->sc_ekeys[0], G_ELI_DATAKEYLEN);
else {
/*
* The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10)
*/
g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1,
sc->sc_ekeys[0], 0);
}
} else {
/* Generate all encryption keys. */
g_eli_ekeys_generate(sc);
}
}
#endif

View file

@ -252,10 +252,12 @@ g_eli_crypto_run(struct g_eli_worker *wr, struct bio *bp)
crd->crd_skip = 0;
crd->crd_len = secsize;
crd->crd_flags = CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT;
if (sc->sc_nekeys > 1)
crd->crd_flags |= CRD_F_KEY_EXPLICIT;
if (bp->bio_cmd == BIO_WRITE)
crd->crd_flags |= CRD_F_ENCRYPT;
crd->crd_alg = sc->sc_ealgo;
crd->crd_key = sc->sc_ekey;
crd->crd_key = g_eli_crypto_key(sc, dstoff, secsize);
crd->crd_klen = sc->sc_ekeylen;
g_eli_crypto_ivgen(sc, dstoff, crd->crd_iv,
sizeof(crd->crd_iv));