[RFC PATCH 3/3] fscrypt: switch to ESSIV shash

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Instead of open coding the shash and cipher operations that make up
the ESSIV transform, switch to the new ESSIV shash template that
encapsulates all of this. Using this more abstract interface provides
more flexibility for the crypto subsystem to do refactoring, and
permits better testing.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>
---
 fs/crypto/Kconfig           |  1 +
 fs/crypto/crypto.c          | 11 ++--
 fs/crypto/fscrypt_private.h |  4 +-
 fs/crypto/keyinfo.c         | 64 +++-----------------
 4 files changed, 18 insertions(+), 62 deletions(-)

diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig
index 24ed99e2eca0..b0292da8613c 100644
--- a/fs/crypto/Kconfig
+++ b/fs/crypto/Kconfig
@@ -5,6 +5,7 @@ config FS_ENCRYPTION
 	select CRYPTO_AES
 	select CRYPTO_CBC
 	select CRYPTO_ECB
+	select CRYPTO_ESSIV
 	select CRYPTO_XTS
 	select CRYPTO_CTS
 	select CRYPTO_SHA256
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 335a362ee446..93d33b55c2fa 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -137,8 +137,13 @@ void fscrypt_generate_iv(union fscrypt_iv *iv, u64 lblk_num,
 	if (ci->ci_flags & FS_POLICY_FLAG_DIRECT_KEY)
 		memcpy(iv->nonce, ci->ci_nonce, FS_KEY_DERIVATION_NONCE_SIZE);
 
-	if (ci->ci_essiv_tfm != NULL)
-		crypto_cipher_encrypt_one(ci->ci_essiv_tfm, iv->raw, iv->raw);
+	if (ci->ci_essiv_tfm != NULL) {
+		SHASH_DESC_ON_STACK(desc, ci->ci_essiv_tfm);
+
+		desc->tfm = ci->ci_essiv_tfm;
+		crypto_shash_digest(desc, (u8 *)&iv->lblk_num,
+				    sizeof(iv->lblk_num), iv->raw);
+	}
 }
 
 int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw,
@@ -492,8 +497,6 @@ static void __exit fscrypt_exit(void)
 		destroy_workqueue(fscrypt_read_workqueue);
 	kmem_cache_destroy(fscrypt_ctx_cachep);
 	kmem_cache_destroy(fscrypt_info_cachep);
-
-	fscrypt_essiv_cleanup();
 }
 module_exit(fscrypt_exit);
 
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 7da276159593..67ea4ca11474 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -62,10 +62,10 @@ struct fscrypt_info {
 	struct crypto_skcipher *ci_ctfm;
 
 	/*
-	 * Cipher for ESSIV IV generation.  Only set for CBC contents
+	 * Shash for ESSIV IV generation.  Only set for CBC contents
 	 * encryption, otherwise is NULL.
 	 */
-	struct crypto_cipher *ci_essiv_tfm;
+	struct crypto_shash *ci_essiv_tfm;
 
 	/*
 	 * Encryption mode used for this inode.  It corresponds to either
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index dcd91a3fbe49..c3d38f72506c 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -15,12 +15,10 @@
 #include <linux/ratelimit.h>
 #include <crypto/aes.h>
 #include <crypto/algapi.h>
+#include <crypto/hash.h>
 #include <crypto/sha.h>
-#include <crypto/skcipher.h>
 #include "fscrypt_private.h"
 
-static struct crypto_shash *essiv_hash_tfm;
-
 /* Table of keys referenced by FS_POLICY_FLAG_DIRECT_KEY policies */
 static DEFINE_HASHTABLE(fscrypt_master_keys, 6); /* 6 bits = 64 buckets */
 static DEFINE_SPINLOCK(fscrypt_master_keys_lock);
@@ -377,70 +375,24 @@ fscrypt_get_master_key(const struct fscrypt_info *ci, struct fscrypt_mode *mode,
 	return ERR_PTR(err);
 }
 
-static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
-{
-	struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);
-
-	/* init hash transform on demand */
-	if (unlikely(!tfm)) {
-		struct crypto_shash *prev_tfm;
-
-		tfm = crypto_alloc_shash("sha256", 0, 0);
-		if (IS_ERR(tfm)) {
-			fscrypt_warn(NULL,
-				     "error allocating SHA-256 transform: %ld",
-				     PTR_ERR(tfm));
-			return PTR_ERR(tfm);
-		}
-		prev_tfm = cmpxchg(&essiv_hash_tfm, NULL, tfm);
-		if (prev_tfm) {
-			crypto_free_shash(tfm);
-			tfm = prev_tfm;
-		}
-	}
-
-	{
-		SHASH_DESC_ON_STACK(desc, tfm);
-		desc->tfm = tfm;
-
-		return crypto_shash_digest(desc, key, keysize, salt);
-	}
-}
-
 static int init_essiv_generator(struct fscrypt_info *ci, const u8 *raw_key,
 				int keysize)
 {
 	int err;
-	struct crypto_cipher *essiv_tfm;
-	u8 salt[SHA256_DIGEST_SIZE];
-
-	essiv_tfm = crypto_alloc_cipher("aes", 0, 0);
-	if (IS_ERR(essiv_tfm))
-		return PTR_ERR(essiv_tfm);
-
-	ci->ci_essiv_tfm = essiv_tfm;
-
-	err = derive_essiv_salt(raw_key, keysize, salt);
-	if (err)
-		goto out;
+	struct crypto_shash *essiv_tfm;
 
 	/*
 	 * Using SHA256 to derive the salt/key will result in AES-256 being
 	 * used for IV generation. File contents encryption will still use the
 	 * configured keysize (AES-128) nevertheless.
 	 */
-	err = crypto_cipher_setkey(essiv_tfm, salt, sizeof(salt));
-	if (err)
-		goto out;
+	essiv_tfm = crypto_alloc_shash("essiv(aes,sha256)", 0, 0);
+	if (IS_ERR(essiv_tfm))
+		return PTR_ERR(essiv_tfm);
 
-out:
-	memzero_explicit(salt, sizeof(salt));
-	return err;
-}
+	ci->ci_essiv_tfm = essiv_tfm;
 
-void __exit fscrypt_essiv_cleanup(void)
-{
-	crypto_free_shash(essiv_hash_tfm);
+	return crypto_shash_setkey(essiv_tfm, raw_key, keysize);
 }
 
 /*
@@ -495,7 +447,7 @@ static void put_crypt_info(struct fscrypt_info *ci)
 		put_master_key(ci->ci_master_key);
 	} else {
 		crypto_free_skcipher(ci->ci_ctfm);
-		crypto_free_cipher(ci->ci_essiv_tfm);
+		crypto_free_shash(ci->ci_essiv_tfm);
 	}
 	kmem_cache_free(fscrypt_info_cachep, ci);
 }
-- 
2.20.1




[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux