From: Ard Biesheuvel <ard.biesheu...@linaro.org>

Replace the explicit ESSIV handling in the dm-crypt driver with calls
into the crypto API, which now possesses the capability to perform
this processing within the crypto subsystem.

Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org>
---
 drivers/md/Kconfig    |   1 +
 drivers/md/dm-crypt.c | 208 +++-----------------
 2 files changed, 31 insertions(+), 178 deletions(-)

diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 45254b3ef715..30ca87cf25db 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -271,6 +271,7 @@ config DM_CRYPT
        depends on BLK_DEV_DM
        select CRYPTO
        select CRYPTO_CBC
+       select CRYPTO_ESSIV
        ---help---
          This device-mapper target allows you to create a device that
          transparently encrypts the data on it. You'll need to activate
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index f001f1104cb5..12d28880ec34 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -98,11 +98,6 @@ struct crypt_iv_operations {
                    struct dm_crypt_request *dmreq);
 };
 
-struct iv_essiv_private {
-       struct crypto_shash *hash_tfm;
-       u8 *salt;
-};
-
 struct iv_benbi_private {
        int shift;
 };
@@ -155,7 +150,6 @@ struct crypt_config {
 
        const struct crypt_iv_operations *iv_gen_ops;
        union {
-               struct iv_essiv_private essiv;
                struct iv_benbi_private benbi;
                struct iv_lmk_private lmk;
                struct iv_tcw_private tcw;
@@ -165,8 +159,6 @@ struct crypt_config {
        unsigned short int sector_size;
        unsigned char sector_shift;
 
-       /* ESSIV: struct crypto_cipher *essiv_tfm */
-       void *iv_private;
        union {
                struct crypto_skcipher **tfms;
                struct crypto_aead **tfms_aead;
@@ -323,161 +315,6 @@ static int crypt_iv_plain64be_gen(struct crypt_config 
*cc, u8 *iv,
        return 0;
 }
 
-/* Initialise ESSIV - compute salt but no local memory allocations */
-static int crypt_iv_essiv_init(struct crypt_config *cc)
-{
-       struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
-       SHASH_DESC_ON_STACK(desc, essiv->hash_tfm);
-       struct crypto_cipher *essiv_tfm;
-       int err;
-
-       desc->tfm = essiv->hash_tfm;
-
-       err = crypto_shash_digest(desc, cc->key, cc->key_size, essiv->salt);
-       shash_desc_zero(desc);
-       if (err)
-               return err;
-
-       essiv_tfm = cc->iv_private;
-
-       err = crypto_cipher_setkey(essiv_tfm, essiv->salt,
-                           crypto_shash_digestsize(essiv->hash_tfm));
-       if (err)
-               return err;
-
-       return 0;
-}
-
-/* Wipe salt and reset key derived from volume key */
-static int crypt_iv_essiv_wipe(struct crypt_config *cc)
-{
-       struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
-       unsigned salt_size = crypto_shash_digestsize(essiv->hash_tfm);
-       struct crypto_cipher *essiv_tfm;
-       int r, err = 0;
-
-       memset(essiv->salt, 0, salt_size);
-
-       essiv_tfm = cc->iv_private;
-       r = crypto_cipher_setkey(essiv_tfm, essiv->salt, salt_size);
-       if (r)
-               err = r;
-
-       return err;
-}
-
-/* Allocate the cipher for ESSIV */
-static struct crypto_cipher *alloc_essiv_cipher(struct crypt_config *cc,
-                                               struct dm_target *ti,
-                                               const u8 *salt,
-                                               unsigned int saltsize)
-{
-       struct crypto_cipher *essiv_tfm;
-       int err;
-
-       /* Setup the essiv_tfm with the given salt */
-       essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
-       if (IS_ERR(essiv_tfm)) {
-               ti->error = "Error allocating crypto tfm for ESSIV";
-               return essiv_tfm;
-       }
-
-       if (crypto_cipher_blocksize(essiv_tfm) != cc->iv_size) {
-               ti->error = "Block size of ESSIV cipher does "
-                           "not match IV size of block cipher";
-               crypto_free_cipher(essiv_tfm);
-               return ERR_PTR(-EINVAL);
-       }
-
-       err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
-       if (err) {
-               ti->error = "Failed to set key for ESSIV cipher";
-               crypto_free_cipher(essiv_tfm);
-               return ERR_PTR(err);
-       }
-
-       return essiv_tfm;
-}
-
-static void crypt_iv_essiv_dtr(struct crypt_config *cc)
-{
-       struct crypto_cipher *essiv_tfm;
-       struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv;
-
-       crypto_free_shash(essiv->hash_tfm);
-       essiv->hash_tfm = NULL;
-
-       kzfree(essiv->salt);
-       essiv->salt = NULL;
-
-       essiv_tfm = cc->iv_private;
-
-       if (essiv_tfm)
-               crypto_free_cipher(essiv_tfm);
-
-       cc->iv_private = NULL;
-}
-
-static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
-                             const char *opts)
-{
-       struct crypto_cipher *essiv_tfm = NULL;
-       struct crypto_shash *hash_tfm = NULL;
-       u8 *salt = NULL;
-       int err;
-
-       if (!opts) {
-               ti->error = "Digest algorithm missing for ESSIV mode";
-               return -EINVAL;
-       }
-
-       /* Allocate hash algorithm */
-       hash_tfm = crypto_alloc_shash(opts, 0, 0);
-       if (IS_ERR(hash_tfm)) {
-               ti->error = "Error initializing ESSIV hash";
-               err = PTR_ERR(hash_tfm);
-               goto bad;
-       }
-
-       salt = kzalloc(crypto_shash_digestsize(hash_tfm), GFP_KERNEL);
-       if (!salt) {
-               ti->error = "Error kmallocing salt storage in ESSIV";
-               err = -ENOMEM;
-               goto bad;
-       }
-
-       cc->iv_gen_private.essiv.salt = salt;
-       cc->iv_gen_private.essiv.hash_tfm = hash_tfm;
-
-       essiv_tfm = alloc_essiv_cipher(cc, ti, salt,
-                                      crypto_shash_digestsize(hash_tfm));
-       if (IS_ERR(essiv_tfm)) {
-               crypt_iv_essiv_dtr(cc);
-               return PTR_ERR(essiv_tfm);
-       }
-       cc->iv_private = essiv_tfm;
-
-       return 0;
-
-bad:
-       if (hash_tfm && !IS_ERR(hash_tfm))
-               crypto_free_shash(hash_tfm);
-       kfree(salt);
-       return err;
-}
-
-static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv,
-                             struct dm_crypt_request *dmreq)
-{
-       struct crypto_cipher *essiv_tfm = cc->iv_private;
-
-       memset(iv, 0, cc->iv_size);
-       *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector);
-       crypto_cipher_encrypt_one(essiv_tfm, iv, iv);
-
-       return 0;
-}
-
 static int crypt_iv_benbi_ctr(struct crypt_config *cc, struct dm_target *ti,
                              const char *opts)
 {
@@ -853,14 +690,6 @@ static const struct crypt_iv_operations 
crypt_iv_plain64be_ops = {
        .generator = crypt_iv_plain64be_gen
 };
 
-static const struct crypt_iv_operations crypt_iv_essiv_ops = {
-       .ctr       = crypt_iv_essiv_ctr,
-       .dtr       = crypt_iv_essiv_dtr,
-       .init      = crypt_iv_essiv_init,
-       .wipe      = crypt_iv_essiv_wipe,
-       .generator = crypt_iv_essiv_gen
-};
-
 static const struct crypt_iv_operations crypt_iv_benbi_ops = {
        .ctr       = crypt_iv_benbi_ctr,
        .dtr       = crypt_iv_benbi_dtr,
@@ -2283,7 +2112,7 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const 
char *ivmode)
        else if (strcmp(ivmode, "plain64be") == 0)
                cc->iv_gen_ops = &crypt_iv_plain64be_ops;
        else if (strcmp(ivmode, "essiv") == 0)
-               cc->iv_gen_ops = &crypt_iv_essiv_ops;
+               cc->iv_gen_ops = &crypt_iv_plain64_ops;
        else if (strcmp(ivmode, "benbi") == 0)
                cc->iv_gen_ops = &crypt_iv_benbi_ops;
        else if (strcmp(ivmode, "null") == 0)
@@ -2397,7 +2226,7 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, 
char *cipher_in, char *key
                                char **ivmode, char **ivopts)
 {
        struct crypt_config *cc = ti->private;
-       char *tmp, *cipher_api;
+       char *tmp, *cipher_api, buf[CRYPTO_MAX_ALG_NAME];
        int ret = -EINVAL;
 
        cc->tfms_count = 1;
@@ -2435,9 +2264,19 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, 
char *cipher_in, char *key
        }
 
        ret = crypt_ctr_blkdev_cipher(cc, cipher_api);
-       if (ret < 0) {
-               ti->error = "Cannot allocate cipher string";
-               return -ENOMEM;
+       if (ret < 0)
+               goto bad_mem;
+
+       if (*ivmode && !strcmp(*ivmode, "essiv")) {
+               if (!*ivopts) {
+                       ti->error = "Digest algorithm missing for ESSIV mode";
+                       return -EINVAL;
+               }
+               ret = snprintf(buf, CRYPTO_MAX_ALG_NAME, "essiv(%s,%s,%s)",
+                              cipher_api, cc->cipher, *ivopts);
+               if (ret < 0)
+                       goto bad_mem;
+               cipher_api = buf;
        }
 
        cc->key_parts = cc->tfms_count;
@@ -2456,6 +2295,9 @@ static int crypt_ctr_cipher_new(struct dm_target *ti, 
char *cipher_in, char *key
                cc->iv_size = crypto_skcipher_ivsize(any_tfm(cc));
 
        return 0;
+bad_mem:
+       ti->error = "Cannot allocate cipher string";
+       return -ENOMEM;
 }
 
 static int crypt_ctr_cipher_old(struct dm_target *ti, char *cipher_in, char 
*key,
@@ -2515,8 +2357,18 @@ static int crypt_ctr_cipher_old(struct dm_target *ti, 
char *cipher_in, char *key
        if (!cipher_api)
                goto bad_mem;
 
-       ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME,
-                      "%s(%s)", chainmode, cipher);
+       if (*ivmode && !strcmp(*ivmode, "essiv")) {
+               if (!*ivopts) {
+                       ti->error = "Digest algorithm missing for ESSIV mode";
+                       return -EINVAL;
+               }
+               ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME,
+                              "essiv(%s(%s),%s,%s)", chainmode, cipher,
+                              cipher, *ivopts);
+       } else {
+               ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME,
+                              "%s(%s)", chainmode, cipher);
+       }
        if (ret < 0) {
                kfree(cipher_api);
                goto bad_mem;
-- 
2.17.1

Reply via email to