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));
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to