Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Sep 2010 11:49:47 +0000 (UTC)
From:      Pawel Jakub Dawidek <pjd@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r213067 - head/sys/geom/eli
Message-ID:  <201009231149.o8NBnlOV068050@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pjd
Date: Thu Sep 23 11:49:47 2010
New Revision: 213067
URL: http://svn.freebsd.org/changeset/base/213067

Log:
  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

Modified:
  head/sys/geom/eli/g_eli.c
  head/sys/geom/eli/g_eli.h
  head/sys/geom/eli/g_eli_integrity.c
  head/sys/geom/eli/g_eli_key.c
  head/sys/geom/eli/g_eli_privacy.c

Modified: head/sys/geom/eli/g_eli.c
==============================================================================
--- head/sys/geom/eli/g_eli.c	Thu Sep 23 11:46:53 2010	(r213066)
+++ head/sys/geom/eli/g_eli.c	Thu Sep 23 11:49:47 2010	(r213067)
@@ -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, struc
 	/* 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, struc
 		    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, struc
 		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, struc
 	 * 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, bo
 	}
 	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 ch
 		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");

Modified: head/sys/geom/eli/g_eli.h
==============================================================================
--- head/sys/geom/eli/g_eli.h	Thu Sep 23 11:46:53 2010	(r213066)
+++ head/sys/geom/eli/g_eli.h	Thu Sep 23 11:49:47 2010	(r213067)
@@ -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 *dat
 }
 
 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, 
 	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, 
 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);
 

Modified: head/sys/geom/eli/g_eli_integrity.c
==============================================================================
--- head/sys/geom/eli/g_eli_integrity.c	Thu Sep 23 11:46:53 2010	(r213066)
+++ head/sys/geom/eli/g_eli_integrity.c	Thu Sep 23 11:49:47 2010	(r213067)
@@ -507,7 +507,7 @@ g_eli_auth_run(struct g_eli_worker *wr, 
 		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));

Modified: head/sys/geom/eli/g_eli_key.c
==============================================================================
--- head/sys/geom/eli/g_eli_key.c	Thu Sep 23 11:46:53 2010	(r213066)
+++ head/sys/geom/eli/g_eli_key.c	Thu Sep 23 11:49:47 2010	(r213067)
@@ -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 
 }
 
 #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 
 	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

Modified: head/sys/geom/eli/g_eli_privacy.c
==============================================================================
--- head/sys/geom/eli/g_eli_privacy.c	Thu Sep 23 11:46:53 2010	(r213066)
+++ head/sys/geom/eli/g_eli_privacy.c	Thu Sep 23 11:49:47 2010	(r213067)
@@ -252,10 +252,12 @@ g_eli_crypto_run(struct g_eli_worker *wr
 		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));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201009231149.o8NBnlOV068050>