mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-20 23:35:02 +00:00
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:
parent
30bd3bb07b
commit
c6a26d4c88
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=213067
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in a new issue