summaryrefslogtreecommitdiffstats
path: root/sys/geom
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2010-09-23 11:49:47 +0000
committerpjd <pjd@FreeBSD.org>2010-09-23 11:49:47 +0000
commited0ad07f3dd1bc5f1fad46c75e5d57ecbbca3cf8 (patch)
treeb964c8ab4d3ce3c31a74eb0012bc3b98d1bd45c7 /sys/geom
parent7c5b734f64e42e6d5b7864578947df2fe8b2149b (diff)
downloadFreeBSD-src-ed0ad07f3dd1bc5f1fad46c75e5d57ecbbca3cf8.zip
FreeBSD-src-ed0ad07f3dd1bc5f1fad46c75e5d57ecbbca3cf8.tar.gz
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
Diffstat (limited to 'sys/geom')
-rw-r--r--sys/geom/eli/g_eli.c91
-rw-r--r--sys/geom/eli/g_eli.h53
-rw-r--r--sys/geom/eli/g_eli_integrity.c2
-rw-r--r--sys/geom/eli/g_eli_key.c76
-rw-r--r--sys/geom/eli/g_eli_privacy.c4
5 files changed, 171 insertions, 55 deletions
diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c
index 4bcce3d..c44cddc 100644
--- a/sys/geom/eli/g_eli.c
+++ b/sys/geom/eli/g_eli.c
@@ -375,6 +375,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.
*/
void
@@ -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 @@ failed:
}
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");
diff --git a/sys/geom/eli/g_eli.h b/sys/geom/eli/g_eli.h
index 7c492e0..ab0b2c9 100644
--- a/sys/geom/eli/g_eli.h
+++ b/sys/geom/eli/g_eli.h
@@ -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);
diff --git a/sys/geom/eli/g_eli_integrity.c b/sys/geom/eli/g_eli_integrity.c
index b9a3f31..8b98e21 100644
--- a/sys/geom/eli/g_eli_integrity.c
+++ b/sys/geom/eli/g_eli_integrity.c
@@ -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));
diff --git a/sys/geom/eli/g_eli_key.c b/sys/geom/eli/g_eli_key.c
index 5b024d7..230ae5c 100644
--- a/sys/geom/eli/g_eli_key.c
+++ b/sys/geom/eli/g_eli_key.c
@@ -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
diff --git a/sys/geom/eli/g_eli_privacy.c b/sys/geom/eli/g_eli_privacy.c
index 5951747..7a59d33 100644
--- a/sys/geom/eli/g_eli_privacy.c
+++ b/sys/geom/eli/g_eli_privacy.c
@@ -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));
OpenPOWER on IntegriCloud